remotefilelog: move constants to class to prepare index format change

Summary:
To be able to bump version and change formats, the related constants need to
be moved to individual classes. So a class (ex. datapack) can be subclassed to
handle different formats.

Test Plan: `arc unit`

Reviewers: #mercurial, durham

Reviewed By: durham

Subscribers: mjpieters

Differential Revision: https://phabricator.intern.facebook.com/D4927284

Signature: t1:4927284:1493152641:e3274dd735d50baf193b7615dd314f4e6cf161f0
This commit is contained in:
Jun Wu 2017-04-26 13:34:15 -07:00
parent 0e2c18e2cd
commit 8fcd86af16
3 changed files with 47 additions and 27 deletions

View File

@ -8,7 +8,6 @@ import shallowutil
# The pack version supported by this implementation. This will need to be
# rev'd whenever the byte format changes. Ex: changing the fanout prefix,
# changing any of the int sizes, changing the delta algorithm, etc.
VERSION = 0
PACKVERSIONSIZE = 1
INDEXVERSIONSIZE = 2
@ -134,6 +133,7 @@ class basepack(object):
# The maximum amount we should read via mmap before remmaping so the old
# pages can be released (100MB)
MAXPAGEDIN = 100 * 1024**2
VERSION = 0
def __init__(self, path):
self.path = path
@ -151,13 +151,13 @@ class basepack(object):
self.freememory() # initialize the mmap
version = struct.unpack('!B', self._data[:PACKVERSIONSIZE])[0]
if version != VERSION:
if version != self.VERSION:
raise RuntimeError("unsupported pack version '%s'" %
version)
version, config = struct.unpack('!BB',
self._index[:INDEXVERSIONSIZE])
if version != VERSION:
if version != self.VERSION:
raise RuntimeError("unsupported pack index version '%s'" %
version)
@ -210,6 +210,8 @@ class basepack(object):
raise NotImplemented()
class mutablebasepack(object):
VERSION = 0
def __init__(self, ui, packdir):
opener = vfsmod.vfs(packdir)
opener.createmode = 0o444
@ -236,7 +238,7 @@ class mutablebasepack(object):
# Write header
# TODO: make it extensible (ex: allow specifying compression algorithm,
# a flexible key/value header, delta algorithm, fanout size, etc)
version = struct.pack('!B', VERSION) # unsigned 1 byte int
version = struct.pack('!B', self.VERSION) # unsigned 1 byte int
self.writeraw(version)
def __enter__(self):
@ -334,7 +336,7 @@ class mutablebasepack(object):
config = 0
if indexparams.fanoutprefix == LARGEFANOUTPREFIX:
config = 0b10000000
self.idxfp.write(struct.pack('!BB', VERSION, config))
self.idxfp.write(struct.pack('!BB', self.VERSION, config))
class indexparams(object):
__slots__ = ('fanoutprefix', 'fanoutstruct', 'fanoutcount', 'fanoutsize',

View File

@ -10,10 +10,6 @@ try:
except ImportError:
cstore = None
# Index entry format is: <node><delta offset><pack data offset><pack data size>
# See the mutabledatapack doccomment for more details.
INDEXFORMAT = '!20siQQ'
INDEXENTRYLENGTH = 40
NODELENGTH = 20
# The indicator value in the index for a fulltext entry.
@ -62,6 +58,11 @@ class datapack(basepack.basepack):
INDEXSUFFIX = INDEXSUFFIX
PACKSUFFIX = PACKSUFFIX
# Format is <node><delta offset><pack data offset><pack data size>
# See the mutabledatapack doccomment for more details.
INDEXFORMAT = '!20siQQ'
INDEXENTRYLENGTH = 40
def getmissing(self, keys):
missing = []
for name, node in keys:
@ -85,11 +86,12 @@ class datapack(basepack.basepack):
# Precompute chains
chain = [value]
deltabaseoffset = value[1]
entrylen = self.INDEXENTRYLENGTH
while (deltabaseoffset != FULLTEXTINDEXMARK
and deltabaseoffset != NOBASEINDEXMARK):
loc = params.indexstart + deltabaseoffset
value = struct.unpack(INDEXFORMAT, self._index[loc:loc +
INDEXENTRYLENGTH])
value = struct.unpack(self.INDEXFORMAT,
self._index[loc:loc + entrylen])
deltabaseoffset = value[1]
chain.append(value)
@ -148,17 +150,18 @@ class datapack(basepack.basepack):
index = self._index
startnode = index[start:start + NODELENGTH]
endnode = index[end:end + NODELENGTH]
entrylen = self.INDEXENTRYLENGTH
if startnode == node:
entry = index[start:start + INDEXENTRYLENGTH]
entry = index[start:start + entrylen]
elif endnode == node:
entry = index[end:end + INDEXENTRYLENGTH]
entry = index[end:end + entrylen]
else:
while start < end - INDEXENTRYLENGTH:
while start < end - entrylen:
mid = start + (end - start) / 2
mid = mid - ((mid - params.indexstart) % INDEXENTRYLENGTH)
mid = mid - ((mid - params.indexstart) % entrylen)
midnode = index[mid:mid + NODELENGTH]
if midnode == node:
entry = index[mid:mid + INDEXENTRYLENGTH]
entry = index[mid:mid + entrylen]
break
if node > midnode:
start = mid
@ -169,7 +172,7 @@ class datapack(basepack.basepack):
else:
return None
return struct.unpack(INDEXFORMAT, entry)
return struct.unpack(self.INDEXFORMAT, entry)
def markledger(self, ledger):
for filename, node in self:
@ -349,7 +352,10 @@ class mutabledatapack(basepack.mutablebasepack):
"""
INDEXSUFFIX = INDEXSUFFIX
PACKSUFFIX = PACKSUFFIX
INDEXENTRYLENGTH = INDEXENTRYLENGTH
# v0 index format: <node><delta offset><pack data offset><pack data size>
INDEXFORMAT = datapack.INDEXFORMAT
INDEXENTRYLENGTH = datapack.INDEXENTRYLENGTH
def add(self, name, node, deltabasenode, delta):
if len(name) > 2**16:
@ -384,6 +390,7 @@ class mutabledatapack(basepack.mutablebasepack):
in self.entries.iteritems())
rawindex = ''
fmt = self.INDEXFORMAT
for node, deltabase, offset, size in entries:
if deltabase == nullid:
deltabaselocation = FULLTEXTINDEXMARK
@ -393,8 +400,7 @@ class mutabledatapack(basepack.mutablebasepack):
deltabaselocation = nodelocations.get(deltabase,
NOBASEINDEXMARK)
entry = struct.pack(INDEXFORMAT, node, deltabaselocation, offset,
size)
entry = struct.pack(fmt, node, deltabaselocation, offset, size)
rawindex += entry
return rawindex

View File

@ -53,6 +53,11 @@ class historypack(basepack.basepack):
INDEXSUFFIX = INDEXSUFFIX
PACKSUFFIX = PACKSUFFIX
INDEXFORMAT = INDEXFORMAT
INDEXENTRYLENGTH = INDEXENTRYLENGTH
VERSION = 0
def getmissing(self, keys):
missing = []
for name, node in keys:
@ -167,17 +172,19 @@ class historypack(basepack.basepack):
# Bisect between start and end to find node
startnode = self._index[start:start + NODELENGTH]
endnode = self._index[end:end + NODELENGTH]
entrylen = self.INDEXENTRYLENGTH
if startnode == namehash:
entry = self._index[start:start + INDEXENTRYLENGTH]
entry = self._index[start:start + entrylen]
elif endnode == namehash:
entry = self._index[end:end + INDEXENTRYLENGTH]
entry = self._index[end:end + entrylen]
else:
while start < end - INDEXENTRYLENGTH:
while start < end - entrylen:
mid = start + (end - start) / 2
mid = mid - ((mid - params.indexstart) % INDEXENTRYLENGTH)
mid = mid - ((mid - params.indexstart) % entrylen)
midnode = self._index[mid:mid + NODELENGTH]
if midnode == namehash:
entry = self._index[mid:mid + INDEXENTRYLENGTH]
entry = self._index[mid:mid + entrylen]
break
if namehash > midnode:
start = mid
@ -188,7 +195,7 @@ class historypack(basepack.basepack):
else:
raise KeyError(name)
filenamehash, offset, size = struct.unpack(INDEXFORMAT, entry)
filenamehash, offset, size = struct.unpack(self.INDEXFORMAT, entry)
filenamelength = struct.unpack('!H', self._data[offset:offset +
constants.FILENAMESIZE])[0]
offset += constants.FILENAMESIZE
@ -318,8 +325,12 @@ class mutablehistorypack(basepack.mutablebasepack):
"""
INDEXSUFFIX = INDEXSUFFIX
PACKSUFFIX = PACKSUFFIX
INDEXFORMAT = INDEXFORMAT
INDEXENTRYLENGTH = INDEXENTRYLENGTH
VERSION = 0
def __init__(self, ui, packpath):
super(mutablehistorypack, self).__init__(ui, packpath)
self.pastfiles = {}
@ -379,7 +390,8 @@ class mutablehistorypack(basepack.mutablebasepack):
files = sorted(files)
rawindex = ""
fmt = self.INDEXFORMAT
for namehash, offset, size in files:
rawindex += struct.pack(INDEXFORMAT, namehash, offset, size)
rawindex += struct.pack(fmt, namehash, offset, size)
return rawindex