+class PackIndex:
+ def __init__(self, filename):
+ self.name = filename
+ f = open(filename)
+ self.map = mmap.mmap(f.fileno(), 0,
+ mmap.MAP_SHARED, mmap.PROT_READ)
+ f.close() # map will persist beyond file close
+ assert(str(self.map[0:8]) == '\377tOc\0\0\0\2')
+ self.fanout = list(struct.unpack('!256I', buffer(self.map, 8, 256*4)))
+ self.fanout.append(0) # entry "-1"
+ nsha = self.fanout[255]
+ self.ofstable = buffer(self.map,
+ 8 + 256*4 + nsha*20 + nsha*4,
+ nsha*4)
+ self.ofs64table = buffer(self.map,
+ 8 + 256*4 + nsha*20 + nsha*4 + nsha*4)
+
+ def _ofs_from_idx(self, idx):
+ ofs = struct.unpack('!I', buffer(self.ofstable, idx*4, 4))[0]
+ if ofs & 0x80000000:
+ idx64 = ofs & 0x7fffffff
+ ofs = struct.unpack('!I', buffer(self.ofs64table, idx64*8, 8))[0]
+ return ofs
+
+ def _idx_from_hash(self, hash):
+ assert(len(hash) == 20)
+ b1 = ord(hash[0])
+ start = self.fanout[b1-1] # range -1..254
+ end = self.fanout[b1] # range 0..255
+ buf = buffer(self.map, 8 + 256*4, end*20)
+ want = buffer(hash)
+ while start < end:
+ mid = start + (end-start)/2
+ v = buffer(buf, mid*20, 20)
+ if v < want:
+ start = mid+1
+ elif v > want:
+ end = mid
+ else: # got it!
+ return mid
+ return None
+ def find_offset(self, hash):
+ idx = self._idx_from_hash(hash)
+ if idx != None:
+ return self._ofs_from_idx(idx)
+ return None
+
+ def exists(self, hash):
+ return (self._idx_from_hash(hash) != None) and True or None
+
+
+class MultiPackIndex:
+ def __init__(self, dir):
+ self.packs = []
+ for f in os.listdir(dir):
+ if f.endswith('.idx'):
+ self.packs.append(PackIndex(os.path.join(dir, f)))
+
+ def exists(self, hash):
+ for i in range(len(self.packs)):
+ p = self.packs[i]
+ if p.exists(hash):
+ # reorder so most recently used packs are searched first
+ self.packs = [p] + self.packs[:i] + self.packs[i+1:]
+ return True
+ return None
+
+