1818# You should have received a copy of the GNU Affero General Public License
1919# along with Elixir. If not, see <http://www.gnu.org/licenses/>.
2020
21+ from typing import OrderedDict
2122import berkeleydb
2223import re
2324from . import lib
@@ -208,18 +209,94 @@ def close(self):
208209 def __len__ (self ):
209210 return self .db .stat ()["nkeys" ]
210211
212+ class CachedBsdDB :
213+ def __init__ (self , filename , readonly , contentType , cachesize ):
214+ self .filename = filename
215+ self .db = berkeleydb .db .DB ()
216+ flags = 0
217+
218+ self .cachesize = cachesize
219+ self .cache = OrderedDict ()
220+
221+ if readonly :
222+ flags |= berkeleydb .db .DB_RDONLY
223+ self .db .open (filename , flags = flags )
224+ else :
225+ flags |= berkeleydb .db .DB_CREATE
226+ self .db .open (filename , flags = flags , mode = 0o644 , dbtype = berkeleydb .db .DB_BTREE )
227+ self .ctype = contentType
228+
229+ def exists (self , key ):
230+ if key in self .cache :
231+ return True
232+
233+ key = autoBytes (key )
234+ return self .db .exists (key )
235+
236+ def get (self , key ):
237+ if key in self .cache :
238+ self .cache .move_to_end (key )
239+ return self .cache [key ]
240+
241+ key = autoBytes (key )
242+ p = self .db .get (key )
243+ if p is None :
244+ return None
245+ p = self .ctype (p )
246+
247+ self .cache [key ] = p
248+ self .cache .move_to_end (key )
249+ if len (self .cache ) > self .cachesize :
250+ old_k , old_v = self .cache .popitem (last = False )
251+ self .put_raw (old_k , old_v )
252+
253+ return p
254+
255+ def get_keys (self ):
256+ return self .db .keys ()
257+
258+ def put (self , key , val ):
259+ self .cache [key ] = val
260+ self .cache .move_to_end (key )
261+ if len (self .cache ) > self .cachesize :
262+ old_k , old_v = self .cache .popitem (last = False )
263+ self .put_raw (old_k , old_v )
264+
265+ def put_raw (self , key , val , sync = False ):
266+ key = autoBytes (key )
267+ val = autoBytes (val )
268+ if type (val ) is not bytes :
269+ val = val .pack ()
270+ self .db .put (key , val )
271+ if sync :
272+ self .db .sync ()
273+
274+ def sync (self ):
275+ for k , v in self .cache .items ():
276+ self .put_raw (k , v )
277+
278+ self .db .sync ()
279+
280+ def close (self ):
281+ self .sync ()
282+ self .db .close ()
283+
284+ def __len__ (self ):
285+ return self .db .stat ()["nkeys" ]
286+
211287class DB :
212- def __init__ (self , dir , readonly = True , dtscomp = False , shared = False , update_cache = False ):
288+ def __init__ (self , dir , readonly = True , dtscomp = False , shared = False , update_cache = None ):
213289 if os .path .isdir (dir ):
214290 self .dir = dir
215291 else :
216292 raise FileNotFoundError (errno .ENOENT , os .strerror (errno .ENOENT ), dir )
217293
218294 ro = readonly
219- cachesize = None
220295
221296 if update_cache :
222- cachesize = CACHESIZE
297+ db_cls = lambda dir , ro , ctype : CachedBsdDB (dir , ro , ctype , cachesize = update_cache )
298+ else :
299+ db_cls = lambda dir , ro , ctype : BsdDB (dir , ro , ctype , shared = shared )
223300
224301 self .vars = BsdDB (dir + '/variables.db' , ro , lambda x : int (x .decode ()), shared = shared )
225302 # Key-value store of basic information
@@ -230,20 +307,20 @@ def __init__(self, dir, readonly=True, dtscomp=False, shared=False, update_cache
230307 self .file = BsdDB (dir + '/filenames.db' , ro , lambda x : x .decode (), shared = shared )
231308 # Map serial number to filename
232309 self .vers = BsdDB (dir + '/versions.db' , ro , PathList , shared = shared )
233- self .defs = BsdDB (dir + '/definitions.db' , ro , DefList , shared = shared , cachesize = cachesize )
310+ self .defs = db_cls (dir + '/definitions.db' , ro , DefList )
234311 self .defs_cache = {}
235312 NOOP = lambda x : x
236313 self .defs_cache ['C' ] = BsdDB (dir + '/definitions-cache-C.db' , ro , NOOP , shared = shared )
237314 self .defs_cache ['K' ] = BsdDB (dir + '/definitions-cache-K.db' , ro , NOOP , shared = shared )
238315 self .defs_cache ['D' ] = BsdDB (dir + '/definitions-cache-D.db' , ro , NOOP , shared = shared )
239316 self .defs_cache ['M' ] = BsdDB (dir + '/definitions-cache-M.db' , ro , NOOP , shared = shared )
240317 assert sorted (self .defs_cache .keys ()) == sorted (lib .CACHED_DEFINITIONS_FAMILIES )
241- self .refs = BsdDB (dir + '/references.db' , ro , RefList , shared = shared , cachesize = cachesize )
242- self .docs = BsdDB (dir + '/doccomments.db' , ro , RefList , shared = shared , cachesize = cachesize )
318+ self .refs = db_cls (dir + '/references.db' , ro , RefList )
319+ self .docs = db_cls (dir + '/doccomments.db' , ro , RefList )
243320 self .dtscomp = dtscomp
244321 if dtscomp :
245- self .comps = BsdDB (dir + '/compatibledts.db' , ro , RefList , shared = shared , cachesize = cachesize )
246- self .comps_docs = BsdDB (dir + '/compatibledts_docs.db' , ro , RefList , shared = shared , cachesize = cachesize )
322+ self .comps = db_cls (dir + '/compatibledts.db' , ro , RefList )
323+ self .comps_docs = db_cls (dir + '/compatibledts_docs.db' , ro , RefList )
247324 # Use a RefList in case there are multiple doc comments for an identifier
248325
249326 def close (self ):
0 commit comments