47
by Robey Pointer
slowly moving the branch-specific stuff into a common structure... |
1 |
#
|
2 |
# Copyright (C) 2006 Robey Pointer <robey@lag.net>
|
|
3 |
#
|
|
4 |
# This program is free software; you can redistribute it and/or modify
|
|
5 |
# it under the terms of the GNU General Public License as published by
|
|
6 |
# the Free Software Foundation; either version 2 of the License, or
|
|
7 |
# (at your option) any later version.
|
|
8 |
#
|
|
9 |
# This program is distributed in the hope that it will be useful,
|
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12 |
# GNU General Public License for more details.
|
|
13 |
#
|
|
14 |
# You should have received a copy of the GNU General Public License
|
|
15 |
# along with this program; if not, write to the Free Software
|
|
467.2.1
by Toshio Kuratomi
Change to the FSF address in license headers |
16 |
# Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
47
by Robey Pointer
slowly moving the branch-specific stuff into a common structure... |
17 |
#
|
18 |
||
19 |
"""
|
|
312.1.3
by Michael Hudson
docs/clarifications |
20 |
a cache for chewed-up 'file change' data structures, which are basically just
|
21 |
a different way of storing a revision delta. the cache improves lookup times
|
|
22 |
10x over bazaar's xml revision structure, though, so currently still worth
|
|
23 |
doing.
|
|
47
by Robey Pointer
slowly moving the branch-specific stuff into a common structure... |
24 |
|
25 |
once a revision is committed in bazaar, it never changes, so once we have
|
|
26 |
cached a change, it's good forever.
|
|
27 |
"""
|
|
28 |
||
332.2.5
by Michael Hudson
refactor in the direction of maybe making sense one day |
29 |
import marshal |
47
by Robey Pointer
slowly moving the branch-specific stuff into a common structure... |
30 |
import os |
543.2.1
by Jelmer Vernooij
Sort Python import definitions with isort |
31 |
import pickle |
312.1.1
by Michael Hudson
a more intelligent (?) approach to concurrency |
32 |
import tempfile |
332.2.6
by Michael Hudson
zlib compress the marshalled data -- the data seems to compress by about 4:1 |
33 |
import zlib |
519.1.2
by Jelmer Vernooij
Drop support for Python < 3 and Breezy < 3.1. |
34 |
from sqlite3 import dbapi2 |
128.4.11
by Michael Hudson
fiddle things around so you can use the python-sqlite or python-pysqlite |
35 |
|
312.1.3
by Michael Hudson
docs/clarifications |
36 |
# We take an optimistic approach to concurrency here: we might do work twice
|
37 |
# in the case of races, but not crash or corrupt data.
|
|
128.4.5
by Michael Hudson
reorganizations, cleanups. still utterly horrid though. |
38 |
|
332.2.8
by Michael Hudson
docstrings (omg!!) |
39 |
def safe_init_db(filename, init_sql): |
40 |
# To avoid races around creating the database, we create the db in
|
|
41 |
# a temporary file and rename it into the ultimate location.
|
|
42 |
fd, temp_path = tempfile.mkstemp(dir=os.path.dirname(filename)) |
|
336
by Matt Nordhoff
Make sure to close mkstemp's file descriptor (bug #370845) |
43 |
os.close(fd) |
332.2.8
by Michael Hudson
docstrings (omg!!) |
44 |
con = dbapi2.connect(temp_path) |
45 |
cur = con.cursor() |
|
46 |
cur.execute(init_sql) |
|
47 |
con.commit() |
|
48 |
con.close() |
|
49 |
os.rename(temp_path, filename) |
|
50 |
||
128.4.5
by Michael Hudson
reorganizations, cleanups. still utterly horrid though. |
51 |
class FakeShelf(object): |
230.1.1
by Steve 'Ashcrow' Milner
Updated to follow pep8. |
52 |
|
128.4.6
by Michael Hudson
remove one layer of ick |
53 |
def __init__(self, filename): |
54 |
create_table = not os.path.exists(filename) |
|
312.1.1
by Michael Hudson
a more intelligent (?) approach to concurrency |
55 |
if create_table: |
332.2.8
by Michael Hudson
docstrings (omg!!) |
56 |
safe_init_db( |
57 |
filename, "create table RevisionData " |
|
58 |
"(revid binary primary key, data binary)") |
|
128.4.8
by Michael Hudson
remove storm dependency (it'll be back) |
59 |
self.connection = dbapi2.connect(filename) |
128.4.11
by Michael Hudson
fiddle things around so you can use the python-sqlite or python-pysqlite |
60 |
self.cursor = self.connection.cursor() |
230.1.1
by Steve 'Ashcrow' Milner
Updated to follow pep8. |
61 |
|
312.1.1
by Michael Hudson
a more intelligent (?) approach to concurrency |
62 |
def _create_table(self, filename): |
63 |
con = dbapi2.connect(filename) |
|
64 |
cur = con.cursor() |
|
65 |
cur.execute( |
|
128.4.6
by Michael Hudson
remove one layer of ick |
66 |
"create table RevisionData "
|
128.4.9
by Michael Hudson
gar, fix problem with NULLs |
67 |
"(revid binary primary key, data binary)") |
312.1.1
by Michael Hudson
a more intelligent (?) approach to concurrency |
68 |
con.commit() |
69 |
con.close() |
|
230.1.1
by Steve 'Ashcrow' Milner
Updated to follow pep8. |
70 |
|
128.4.9
by Michael Hudson
gar, fix problem with NULLs |
71 |
def _serialize(self, obj): |
491.2.32
by Jelmer Vernooij
Fix some more import errors. |
72 |
return dbapi2.Binary(pickle.dumps(obj, protocol=2)) |
230.1.1
by Steve 'Ashcrow' Milner
Updated to follow pep8. |
73 |
|
128.4.9
by Michael Hudson
gar, fix problem with NULLs |
74 |
def _unserialize(self, data): |
491.2.32
by Jelmer Vernooij
Fix some more import errors. |
75 |
return pickle.loads(str(data)) |
230.1.1
by Steve 'Ashcrow' Milner
Updated to follow pep8. |
76 |
|
128.4.5
by Michael Hudson
reorganizations, cleanups. still utterly horrid though. |
77 |
def get(self, revid): |
221.1.2
by Michael Hudson
remove pointless parameterization |
78 |
self.cursor.execute( |
230.1.1
by Steve 'Ashcrow' Milner
Updated to follow pep8. |
79 |
"select data from revisiondata where revid = ?", (revid, )) |
128.4.11
by Michael Hudson
fiddle things around so you can use the python-sqlite or python-pysqlite |
80 |
filechange = self.cursor.fetchone() |
128.4.5
by Michael Hudson
reorganizations, cleanups. still utterly horrid though. |
81 |
if filechange is None: |
82 |
return None |
|
83 |
else: |
|
128.4.9
by Michael Hudson
gar, fix problem with NULLs |
84 |
return self._unserialize(filechange[0]) |
230.1.1
by Steve 'Ashcrow' Milner
Updated to follow pep8. |
85 |
|
305.1.6
by Michael Hudson
further simplification |
86 |
def add(self, revid, object): |
312.1.1
by Michael Hudson
a more intelligent (?) approach to concurrency |
87 |
try: |
88 |
self.cursor.execute( |
|
89 |
"insert into revisiondata (revid, data) values (?, ?)", |
|
90 |
(revid, self._serialize(object))) |
|
91 |
self.connection.commit() |
|
92 |
except dbapi2.IntegrityError: |
|
312.1.3
by Michael Hudson
docs/clarifications |
93 |
# If another thread or process attempted to set the same key, we
|
94 |
# assume it set it to the same value and carry on with our day.
|
|
312.1.1
by Michael Hudson
a more intelligent (?) approach to concurrency |
95 |
pass
|
47
by Robey Pointer
slowly moving the branch-specific stuff into a common structure... |
96 |
|
128.13.20
by Martin Albisetti
Merge from trunk! Yay! |
97 |
|
332.2.5
by Michael Hudson
refactor in the direction of maybe making sense one day |
98 |
class RevInfoDiskCache(object): |
332.2.8
by Michael Hudson
docstrings (omg!!) |
99 |
"""Like `RevInfoMemoryCache` but backed in a sqlite DB."""
|
332.2.3
by Michael Hudson
fairly tortuous two level caching |
100 |
|
101 |
def __init__(self, cache_path): |
|
102 |
if not os.path.exists(cache_path): |
|
103 |
os.mkdir(cache_path) |
|
332.2.5
by Michael Hudson
refactor in the direction of maybe making sense one day |
104 |
filename = os.path.join(cache_path, 'revinfo.sql') |
332.2.3
by Michael Hudson
fairly tortuous two level caching |
105 |
create_table = not os.path.exists(filename) |
106 |
if create_table: |
|
332.2.8
by Michael Hudson
docstrings (omg!!) |
107 |
safe_init_db( |
108 |
filename, "create table Data " |
|
109 |
"(key binary primary key, revid binary, data binary)") |
|
332.2.3
by Michael Hudson
fairly tortuous two level caching |
110 |
self.connection = dbapi2.connect(filename) |
111 |
self.cursor = self.connection.cursor() |
|
112 |
||
332.2.5
by Michael Hudson
refactor in the direction of maybe making sense one day |
113 |
def get(self, key, revid): |
491.2.39
by Jelmer Vernooij
More python3 porting. |
114 |
if not isinstance(key, bytes): |
115 |
raise TypeError(key) |
|
116 |
if not isinstance(revid, bytes): |
|
117 |
raise TypeError(revid) |
|
332.2.3
by Michael Hudson
fairly tortuous two level caching |
118 |
self.cursor.execute( |
332.2.8
by Michael Hudson
docstrings (omg!!) |
119 |
"select revid, data from data where key = ?", (dbapi2.Binary(key),)) |
332.2.3
by Michael Hudson
fairly tortuous two level caching |
120 |
row = self.cursor.fetchone() |
121 |
if row is None: |
|
332.2.5
by Michael Hudson
refactor in the direction of maybe making sense one day |
122 |
return None |
123 |
elif str(row[0]) != revid: |
|
124 |
return None |
|
332.2.3
by Michael Hudson
fairly tortuous two level caching |
125 |
else: |
515.3.1
by Colin Watson
Make RevInfoDiskCache use a marshal version supported by Python 2. |
126 |
try: |
127 |
return marshal.loads(zlib.decompress(row[1])) |
|
128 |
except (EOFError, ValueError, TypeError): |
|
129 |
return None |
|
332.2.3
by Michael Hudson
fairly tortuous two level caching |
130 |
|
131 |
def set(self, key, revid, data): |
|
491.2.39
by Jelmer Vernooij
More python3 porting. |
132 |
if not isinstance(key, bytes): |
133 |
raise TypeError(key) |
|
134 |
if not isinstance(revid, bytes): |
|
135 |
raise TypeError(revid) |
|
332.2.3
by Michael Hudson
fairly tortuous two level caching |
136 |
try: |
137 |
self.cursor.execute( |
|
138 |
'delete from data where key = ?', (dbapi2.Binary(key), )) |
|
518.1.1
by Colin Watson
Fix marshal.dumps call. |
139 |
blob = zlib.compress(marshal.dumps(data, 2)) |
332.2.3
by Michael Hudson
fairly tortuous two level caching |
140 |
self.cursor.execute( |
141 |
"insert into data (key, revid, data) values (?, ?, ?)", |
|
491.2.39
by Jelmer Vernooij
More python3 porting. |
142 |
list(map(dbapi2.Binary, [key, revid, blob]))) |
332.2.3
by Michael Hudson
fairly tortuous two level caching |
143 |
self.connection.commit() |
144 |
except dbapi2.IntegrityError: |
|
145 |
# If another thread or process attempted to set the same key, we
|
|
332.2.6
by Michael Hudson
zlib compress the marshalled data -- the data seems to compress by about 4:1 |
146 |
# don't care too much -- it's only a cache after all!
|
332.2.3
by Michael Hudson
fairly tortuous two level caching |
147 |
pass
|