-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsqlite_backend.py
104 lines (84 loc) · 3.14 KB
/
sqlite_backend.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
import sqlalchemy.exc
import os
# Construct the ORM for the SQLite database.
Base = declarative_base()
class Datum(Base):
__tablename__ = 'data'
# Our table has three columns:
key = Column(String, primary_key=True)
value = Column(String) # TODO could specify string lengths by String(100) or similar
refCount = Column(Integer)
def __init__(self, key, value):
self.key = key
self.value = value
self.refCount = 1
# Backend that uses a local SQLite database with one table. The table has
# three columns: key, value, and refCount. We assume single-threaded use
# of this backend.
class SQLiteBackend:
# filename is the local file for the SQLite database.
def __init__(self, filename):
self.filename = filename;
try:
self.initSession()
except sqlalchemy.exc.DatabaseError:
# If the file is of the wrong format, delete it and start over with a clean
# database.
self.nuke()
# Sets up the SQLAlchemy session object.
def initSession(self):
# Open a connection to the database.
url = 'sqlite:///' + self.filename
engine = create_engine(url)
# Create all the necessary tables. This will do nothing if the tables already exist.
Base.metadata.create_all(engine)
# Open a session.
Session = sessionmaker(bind=engine)
self.session = Session()
def __del__(self):
self.session.close()
# Returns None if there is no datum with the given key.
def getDatum(self, key):
return self.session.query(Datum).filter_by(key=key).first()
def put(self, key, value):
# Query the datum, if it already exists.
datum = self.getDatum(key)
if datum is None:
# This key isn't in use yet. Set the refCount to 1.
self.session.add(Datum(key, value))
else:
# This key has already been written to, so just increment the
# reference count.
datum.refCount += 1
self.session.commit()
return key
def get(self, key):
datum = self.getDatum(key)
if datum is None:
raise KeyError
else:
return datum.value
def incRefCount(self, key):
self.getDatum(key).refCount += 1
self.session.commit()
def decRefCount(self, key):
datum = self.getDatum(key)
datum.refCount -= 1
# Garbage collection.
if datum.refCount == 0:
self.session.delete(datum)
self.session.commit()
def nuke(self):
# Delete the backing store and reinitialize the session from a newly
# created, empty database.
try:
os.unlink(self.filename)
except OSError:
pass # The file must have never existed; that's fine.
self.initSession()
def flush(self):
pass # No-op.