sqlitestore.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #!/usr/bin/env python
  2. import os
  3. import tempfile
  4. import shutil
  5. import unittest
  6. import sqlite3
  7. import uuid
  8. class SqliteStore(object):
  9. """
  10. """
  11. class DoesNotExist(KeyError):
  12. """"""
  13. class AlreadyExists(KeyError):
  14. """"""
  15. IDLE = 'Idle'
  16. OPEN = 'Open'
  17. ACTIVE = 'Active'
  18. VERSION = 'DEDUPESTORE VERSION 1'
  19. def __init__(self, path):
  20. if not os.path.exists(path):
  21. self.create(path)
  22. self.cnx = sqlite3.connect(path)
  23. self.cursor = self.cnx.cursor()
  24. self.uuid, self.tid = self.cursor.execute('SELECT uuid, tid FROM system').fetchone()
  25. self.state = self.OPEN
  26. def create(self, path):
  27. cnx = sqlite3.connect(path)
  28. cnx.execute('PRAGMA auto_vacuum=full')
  29. cnx.execute('CREATE TABLE objects(ns TEXT NOT NULL, id NOT NULL, data NOT NULL)')
  30. cnx.execute('CREATE TABLE system(uuid NOT NULL, tid NOT NULL)')
  31. cnx.execute('INSERT INTO system VALUES(?,?)', (uuid.uuid1().hex, 0))
  32. cnx.execute('CREATE UNIQUE INDEX objects_pk ON objects(ns, id)')
  33. def close(self):
  34. self.cnx.close()
  35. def commit(self):
  36. """
  37. """
  38. self.cursor.execute('UPDATE system SET tid=tid+1')
  39. import time
  40. t = time.time()
  41. self.cnx.commit()
  42. print time.time() - t
  43. self.tid += 1
  44. def rollback(self):
  45. """
  46. """
  47. self.cnx.rollback()
  48. def get(self, ns, id):
  49. """
  50. """
  51. self.cursor.execute('SELECT data FROM objects WHERE ns=? and id=?',
  52. (ns.encode('hex'), id.encode('hex')))
  53. row = self.cursor.fetchone()
  54. if row:
  55. return str(row[0])
  56. else:
  57. raise self.DoesNotExist
  58. def put(self, ns, id, data):
  59. """
  60. """
  61. try:
  62. self.cursor.execute('INSERT INTO objects (ns, id, data) '
  63. 'VALUES(?, ?, ?)',
  64. (ns.encode('hex'), id.encode('hex'),
  65. sqlite3.Binary(data)))
  66. except sqlite3.IntegrityError:
  67. raise self.AlreadyExists
  68. def delete(self, ns, id):
  69. """
  70. """
  71. self.cursor.execute('DELETE FROM objects WHERE ns=? AND id=?',
  72. (ns.encode('hex'), id.encode('hex')))
  73. def list(self, ns, prefix='', marker=None, max_keys=1000000):
  74. """
  75. """
  76. condition = ''
  77. if prefix:
  78. condition += ' AND id LIKE :prefix'
  79. if marker:
  80. condition += ' AND id >= :marker'
  81. args = dict(ns=ns.encode('hex'), prefix=prefix.encode('hex') + '%',
  82. marker=marker and marker.encode('hex'))
  83. for row in self.cursor.execute('SELECT id FROM objects WHERE '
  84. 'ns=:ns ' + condition + ' LIMIT ' + str(max_keys),
  85. args):
  86. yield row[0].decode('hex')
  87. class SqliteStoreTestCase(unittest.TestCase):
  88. def setUp(self):
  89. self.tmppath = tempfile.mkdtemp()
  90. self.store = SqliteStore(os.path.join(self.tmppath, 'store'))
  91. def tearDown(self):
  92. shutil.rmtree(self.tmppath)
  93. def test1(self):
  94. self.assertEqual(self.store.tid, 0)
  95. self.assertEqual(self.store.state, self.store.OPEN)
  96. self.store.put('SOMENS', 'SOMEID', 'SOMEDATA')
  97. self.assertRaises(self.store.AlreadyExists, lambda: self.store.put('SOMENS', 'SOMEID', 'SOMEDATA'))
  98. self.assertEqual(self.store.get('SOMENS', 'SOMEID'), 'SOMEDATA')
  99. self.store.rollback()
  100. self.assertRaises(self.store.DoesNotExist, lambda: self.store.get('SOMENS', 'SOMEID'))
  101. self.assertEqual(self.store.tid, 0)
  102. def test2(self):
  103. self.assertEqual(self.store.tid, 0)
  104. self.assertEqual(self.store.state, self.store.OPEN)
  105. self.store.put('SOMENS', 'SOMEID', 'SOMEDATA')
  106. self.assertEqual(self.store.get('SOMENS', 'SOMEID'), 'SOMEDATA')
  107. self.store.commit()
  108. self.assertEqual(self.store.tid, 1)
  109. self.assertEqual(self.store.get('SOMENS', 'SOMEID'), 'SOMEDATA')
  110. self.store.delete('SOMENS', 'SOMEID')
  111. self.assertRaises(self.store.DoesNotExist, lambda: self.store.get('SOMENS', 'SOMEID'))
  112. self.store.rollback()
  113. self.assertEqual(self.store.get('SOMENS', 'SOMEID'), 'SOMEDATA')
  114. self.store.delete('SOMENS', 'SOMEID')
  115. self.assertRaises(self.store.DoesNotExist, lambda: self.store.get('SOMENS', 'SOMEID'))
  116. self.store.commit()
  117. self.assertEqual(self.store.tid, 2)
  118. self.assertRaises(self.store.DoesNotExist, lambda: self.store.get('SOMENS', 'SOMEID'))
  119. def test_list(self):
  120. self.store.put('SOMENS', 'SOMEID12', 'SOMEDATA')
  121. self.store.put('SOMENS', 'SOMEID', 'SOMEDATA')
  122. self.store.put('SOMENS', 'SOMEID1', 'SOMEDATA')
  123. self.store.put('SOMENS', 'SOMEID123', 'SOMEDATA')
  124. self.store.commit()
  125. self.assertEqual(list(self.store.list('SOMENS', max_keys=3)),
  126. ['SOMEID', 'SOMEID1', 'SOMEID12'])
  127. self.assertEqual(list(self.store.list('SOMENS', marker='SOMEID12')),
  128. ['SOMEID12', 'SOMEID123'])
  129. self.assertEqual(list(self.store.list('SOMENS', prefix='SOMEID1', max_keys=2)),
  130. ['SOMEID1', 'SOMEID12'])
  131. self.assertEqual(list(self.store.list('SOMENS', prefix='SOMEID1', marker='SOMEID12')),
  132. ['SOMEID12', 'SOMEID123'])
  133. if __name__ == '__main__':
  134. unittest.main()