@@ -115,15 +115,13 @@ def __init__(
115115 location = Location (url )
116116 self ._location = location
117117 self .url = url
118- # lots of stuff in data: use 2 levels by default (data/00/00/ .. data/ff/ff/ dirs)!
119- data_levels = int (os .environ .get ("BORG_STORE_DATA_LEVELS" , "2" ))
120118 ns_config = {
121119 "archives/" : {"levels" : [0 ]},
122120 "cache/" : {"levels" : [0 ]},
123121 "config/" : {"levels" : [0 ]},
124- "data/" : {"levels" : [data_levels ]},
125122 "keys/" : {"levels" : [0 ]},
126123 "locks/" : {"levels" : [0 ]},
124+ "packs/" : {"levels" : [1 ]},
127125 }
128126 # Get permissions from parameter or environment variable
129127 permissions = permissions if permissions is not None else os .environ .get ("BORG_REPO_PERMISSIONS" , "all" )
@@ -136,19 +134,19 @@ def __init__(
136134 "archives" : "lrw" ,
137135 "cache" : "lrwWD" , # WD for chunks.<HASH>, last-key-checked, ...
138136 "config" : "lrW" , # W for manifest
139- "data" : "lrw" ,
140137 "keys" : "lr" ,
141138 "locks" : "lrwD" , # borg needs to create/delete a shared lock here
139+ "packs" : "lrw" ,
142140 }
143141 elif permissions == "write-only" : # mostly no reading
144142 permissions = {
145143 "" : "l" ,
146144 "archives" : "lw" ,
147145 "cache" : "lrwWD" , # read allowed, e.g. for chunks.<HASH> cache
148146 "config" : "lrW" , # W for manifest
149- "data" : "lw" , # no r!
150147 "keys" : "lr" ,
151148 "locks" : "lrwD" , # borg needs to create/delete a shared lock here
149+ "packs" : "lw" , # no r!
152150 }
153151 elif permissions == "read-only" : # mostly r/o
154152 permissions = {"" : "lr" , "locks" : "lrwD" }
@@ -171,7 +169,7 @@ def __init__(
171169 self ._send_log = send_log_cb or (lambda : None )
172170 self .do_create = create
173171 self .created = False
174- self .acceptable_repo_versions = (3 ,)
172+ self .acceptable_repo_versions = (4 ,)
175173 self .opened = False
176174 self .lock = None
177175 self .do_lock = lock
@@ -209,10 +207,10 @@ def create(self):
209207 self .store .open ()
210208 try :
211209 self .store .store ("config/readme" , REPOSITORY_README .encode ())
212- self .version = 3
210+ self .version = 4
213211 self .store .store ("config/version" , str (self .version ).encode ())
214212 self .store .store ("config/id" , bin_to_hex (os .urandom (32 )).encode ())
215- # we know repo/data / still does not have any chunks stored in it,
213+ # we know repo/packs / still does not have any chunks stored in it,
216214 # but for some stores, there might be a lot of empty directories and
217215 # listing them all might be rather slow, so we better cache an empty
218216 # ChunkIndex from here so that the first repo operation does not have
@@ -327,22 +325,21 @@ def log_error(msg):
327325 def check_object (obj ):
328326 """Check if obj looks valid."""
329327 hdr_size = RepoObj .obj_header .size
330- obj_size = len (obj )
331- if obj_size >= hdr_size :
332- hdr = RepoObj .ObjHeader (* RepoObj .obj_header .unpack (obj [:hdr_size ]))
333- if hdr .magic != OBJ_MAGIC :
334- log_error ("invalid object magic." )
335- elif hdr .version != OBJ_VERSION :
336- log_error (f"unsupported object version: { hdr .version } ." )
337- else :
338- meta = obj [hdr_size : hdr_size + hdr .meta_size ]
339- if hdr .meta_size != len (meta ):
340- log_error ("metadata size mismatch." )
341- data = obj [hdr_size + hdr .meta_size : hdr_size + hdr .meta_size + hdr .data_size ]
342- if hdr .data_size != len (data ):
343- log_error ("data size mismatch." )
344- else :
328+ if len (obj ) < hdr_size :
345329 log_error ("too small." )
330+ return
331+ hdr = RepoObj .ObjHeader (* RepoObj .obj_header .unpack (obj [:hdr_size ]))
332+ if hdr .magic != OBJ_MAGIC :
333+ log_error ("invalid object magic." )
334+ elif hdr .version != OBJ_VERSION :
335+ log_error (f"unsupported object version: { hdr .version } ." )
336+ else :
337+ meta = obj [hdr_size : hdr_size + hdr .meta_size ]
338+ if hdr .meta_size != len (meta ):
339+ log_error ("metadata size mismatch." )
340+ data = obj [hdr_size + hdr .meta_size : hdr_size + hdr .meta_size + hdr .data_size ]
341+ if hdr .data_size != len (data ):
342+ log_error ("data size mismatch." )
346343
347344 # TODO: progress indicator, ...
348345 partial = bool (max_duration )
@@ -376,11 +373,11 @@ def check_object(obj):
376373 # As we don't do garbage collection here, this is not a problem.
377374 # We also don't know the plaintext size, so we set it to 0.
378375 init_entry = ChunkIndexEntry (flags = ChunkIndex .F_USED , size = 0 )
379- infos = self .store .list ("data " )
376+ infos = self .store .list ("packs " )
380377 try :
381378 for info in infos :
382379 self ._lock_refresh ()
383- key = "data /%s" % info .name
380+ key = "packs /%s" % info .name
384381 if key <= last_key_checked : # needs sorted keys
385382 continue
386383 try :
@@ -412,8 +409,9 @@ def check_object(obj):
412409 # add all existing objects to the index.
413410 # borg check: the index may have corrupted objects (we did not delete them)
414411 # borg check --repair: the index will only have non-corrupted objects.
415- id = hex_to_bin (info .name )
416- chunks [id ] = init_entry
412+ pack_id = hex_to_bin (info .name )
413+ chunk_id = pack_id # N=1: chunk_id == pack_id
414+ chunks [chunk_id ] = init_entry
417415 now = time .monotonic ()
418416 if now > t_last_checkpoint + 300 : # checkpoint every 5 mins
419417 t_last_checkpoint = now
@@ -437,7 +435,7 @@ def check_object(obj):
437435 self , chunks , incremental = False , clear = True , force_write = True , delete_other = True
438436 )
439437 except StoreObjectNotFound :
440- # it can be that there is no "data /" at all, then it crashes when iterating infos.
438+ # it can be that there is no "packs /" at all, then it crashes when iterating infos.
441439 pass
442440 logger .info (f"Checked { objs_checked } repository objects, { objs_errors } errors." )
443441 if objs_errors == 0 :
@@ -456,33 +454,35 @@ def list(self, limit=None, marker=None):
456454 """
457455 collect = True if marker is None else False
458456 result = []
459- infos = self .store .list ("data " ) # generator yielding ItemInfos
457+ infos = self .store .list ("packs " ) # generator yielding ItemInfos
460458 while True :
461459 self ._lock_refresh ()
462460 try :
463461 info = next (infos )
464462 except StoreObjectNotFound :
465- break # can happen e.g. if "data " does not exist, pointless to continue in that case
463+ break # can happen e.g. if "packs " does not exist, pointless to continue in that case
466464 except StopIteration :
467465 break
468466 else :
469- id = hex_to_bin (info .name )
467+ pack_id = hex_to_bin (info .name )
468+ chunk_id = pack_id # N=1: chunk_id == pack_id
470469 if collect :
471- result .append ((id , info .size ))
470+ chunk_size = info .size # only correct for N=1
471+ result .append ((chunk_id , chunk_size ))
472472 if len (result ) == limit :
473473 break
474- elif id == marker :
474+ elif chunk_id == marker :
475475 collect = True
476476 # note: do not collect the marker id
477477 return result
478478
479479 def get (self , id , read_data = True , raise_missing = True ):
480480 self ._lock_refresh ()
481+ pack_id = id # N=1: pack_id == chunk_id
481482 id_hex = bin_to_hex (id )
482- key = "data /" + id_hex
483+ key = "packs /" + bin_to_hex ( pack_id )
483484 try :
484485 if read_data :
485- # read everything
486486 return self .store .load (key )
487487 else :
488488 # RepoObj layout supports separately encrypted metadata and data.
@@ -523,7 +523,8 @@ def put(self, id, data, wait=True):
523523 if data_size > MAX_DATA_SIZE :
524524 raise IntegrityError (f"More than allowed put data [{ data_size } > { MAX_DATA_SIZE } ]" )
525525
526- key = "data/" + bin_to_hex (id )
526+ pack_id = id # N=1: pack_id == chunk_id
527+ key = "packs/" + bin_to_hex (pack_id )
527528 self .store .store (key , data )
528529
529530 def delete (self , id , wait = True ):
@@ -533,7 +534,8 @@ def delete(self, id, wait=True):
533534 deal with async results / exceptions later.
534535 """
535536 self ._lock_refresh ()
536- key = "data/" + bin_to_hex (id )
537+ pack_id = id # N=1: pack_id == chunk_id
538+ key = "packs/" + bin_to_hex (pack_id )
537539 try :
538540 self .store .delete (key )
539541 except StoreObjectNotFound :
0 commit comments