##// END OF EJS Templates
revlogv2: also keep track for the size of the "data" file...
revlogv2: also keep track for the size of the "data" file This is useful to make sure we always start writing at the right location, without effort. Differential Revision: https://phab.mercurial-scm.org/D10632

File last commit:

r48016:4abd474a default
r48016:4abd474a default
Show More
docket.py
167 lines | 5.2 KiB | text/x-python | PythonLexer
revlogv2: introduce a very basic docket file...
r48008 # docket - code related to revlog "docket"
#
# Copyright 2021 Pierre-Yves David <pierre-yves.david@octobus.net>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
### Revlog docket file
#
# The revlog is stored on disk using multiple files:
#
# * a small docket file, containing metadata and a pointer,
#
# * an index file, containing fixed width information about revisions,
#
# * a data file, containing variable width data for these revisions,
from __future__ import absolute_import
import struct
revlogv2: track pending write in the docket and expose it to hooks...
r48015 from .. import (
error,
)
revlogv2: introduce a very basic docket file...
r48008 from . import (
constants,
)
# Docket format
#
# * 4 bytes: revlog version
# | This is mandatory as docket must be compatible with the previous
# | revlog index header.
revlogv2: also keep track for the size of the "data" file...
r48016 # * 8 bytes: size of index-data
# * 8 bytes: pending size of index-data
# * 8 bytes: size of data
# * 8 bytes: pending size of data
S_HEADER = struct.Struct(constants.INDEX_HEADER.format + 'LLLL')
revlogv2: introduce a very basic docket file...
r48008
class RevlogDocket(object):
"""metadata associated with revlog"""
revlogv2: track pending write in the docket and expose it to hooks...
r48015 def __init__(
self,
revlog,
use_pending=False,
version_header=None,
index_end=0,
pending_index_end=0,
revlogv2: also keep track for the size of the "data" file...
r48016 data_end=0,
pending_data_end=0,
revlogv2: track pending write in the docket and expose it to hooks...
r48015 ):
revlogv2: introduce a very basic docket file...
r48008 self._version_header = version_header
revlogv2: track pending write in the docket and expose it to hooks...
r48015 self._read_only = bool(use_pending)
revlogv2: introduce a very basic docket file...
r48008 self._dirty = False
self._radix = revlog.radix
self._path = revlog._docket_file
self._opener = revlog.opener
revlogv2: also keep track for the size of the "data" file...
r48016 # thes asserts should be True as long as we have a single index filename
revlogv2: track pending write in the docket and expose it to hooks...
r48015 assert index_end <= pending_index_end
revlogv2: also keep track for the size of the "data" file...
r48016 assert data_end <= pending_data_end
revlogv2: track pending write in the docket and expose it to hooks...
r48015 self._initial_index_end = index_end
self._pending_index_end = pending_index_end
revlogv2: also keep track for the size of the "data" file...
r48016 self._initial_data_end = data_end
self._pending_data_end = pending_data_end
revlogv2: track pending write in the docket and expose it to hooks...
r48015 if use_pending:
self._index_end = self._pending_index_end
revlogv2: also keep track for the size of the "data" file...
r48016 self._data_end = self._pending_data_end
revlogv2: track pending write in the docket and expose it to hooks...
r48015 else:
self._index_end = self._initial_index_end
revlogv2: also keep track for the size of the "data" file...
r48016 self._data_end = self._initial_data_end
revlogv2: introduce a very basic docket file...
r48008
def index_filepath(self):
"""file path to the current index file associated to this docket"""
# very simplistic version at first
return b"%s.idx" % self._radix
revlogv2: track current index size in the docket...
r48012 @property
def index_end(self):
return self._index_end
@index_end.setter
def index_end(self, new_size):
if new_size != self._index_end:
self._index_end = new_size
self._dirty = True
revlogv2: also keep track for the size of the "data" file...
r48016 @property
def data_end(self):
return self._data_end
@data_end.setter
def data_end(self, new_size):
if new_size != self._data_end:
self._data_end = new_size
self._dirty = True
revlogv2: track pending write in the docket and expose it to hooks...
r48015 def write(self, transaction, pending=False, stripping=False):
revlogv2: introduce a very basic docket file...
r48008 """write the modification of disk if any
This make the new content visible to all process"""
revlogv2: track pending write in the docket and expose it to hooks...
r48015 if not self._dirty:
return False
else:
if self._read_only:
msg = b'writing read-only docket: %s'
msg %= self._path
raise error.ProgrammingError(msg)
revlogv2: track current index size in the docket...
r48012 if not stripping:
# XXX we could, leverage the docket while stripping. However it
# is not powerfull enough at the time of this comment
transaction.addbackup(self._path, location=b'store')
revlogv2: introduce a very basic docket file...
r48008 with self._opener(self._path, mode=b'w', atomictemp=True) as f:
revlogv2: track pending write in the docket and expose it to hooks...
r48015 f.write(self._serialize(pending=pending))
# if pending we still need to the write final data eventually
self._dirty = pending
return True
revlogv2: introduce a very basic docket file...
r48008
revlogv2: track pending write in the docket and expose it to hooks...
r48015 def _serialize(self, pending=False):
if pending:
official_index_end = self._initial_index_end
revlogv2: also keep track for the size of the "data" file...
r48016 official_data_end = self._initial_data_end
revlogv2: track pending write in the docket and expose it to hooks...
r48015 else:
official_index_end = self._index_end
revlogv2: also keep track for the size of the "data" file...
r48016 official_data_end = self._data_end
revlogv2: track pending write in the docket and expose it to hooks...
r48015
# this assert should be True as long as we have a single index filename
revlogv2: also keep track for the size of the "data" file...
r48016 assert official_data_end <= self._data_end
revlogv2: track current index size in the docket...
r48012 data = (
self._version_header,
revlogv2: track pending write in the docket and expose it to hooks...
r48015 official_index_end,
revlogv2: track current index size in the docket...
r48012 self._index_end,
revlogv2: also keep track for the size of the "data" file...
r48016 official_data_end,
self._data_end,
revlogv2: track current index size in the docket...
r48012 )
return S_HEADER.pack(*data)
revlogv2: introduce a very basic docket file...
r48008
def default_docket(revlog, version_header):
"""given a revlog version a new docket object for the given revlog"""
if (version_header & 0xFFFF) != constants.REVLOGV2:
return None
docket = RevlogDocket(revlog, version_header=version_header)
docket._dirty = True
return docket
revlogv2: track pending write in the docket and expose it to hooks...
r48015 def parse_docket(revlog, data, use_pending=False):
revlogv2: introduce a very basic docket file...
r48008 """given some docket data return a docket object for the given revlog"""
header = S_HEADER.unpack(data[: S_HEADER.size])
revlogv2: also keep track for the size of the "data" file...
r48016 version_header = header[0]
index_size = header[1]
pending_index_size = header[2]
data_size = header[3]
pending_data_size = header[4]
revlogv2: introduce a very basic docket file...
r48008 docket = RevlogDocket(
revlog,
revlogv2: track pending write in the docket and expose it to hooks...
r48015 use_pending=use_pending,
revlogv2: introduce a very basic docket file...
r48008 version_header=version_header,
revlogv2: track current index size in the docket...
r48012 index_end=index_size,
revlogv2: track pending write in the docket and expose it to hooks...
r48015 pending_index_end=pending_index_size,
revlogv2: also keep track for the size of the "data" file...
r48016 data_end=data_size,
pending_data_end=pending_data_size,
revlogv2: introduce a very basic docket file...
r48008 )
return docket