mercurial/revlogutils/docket.py
changeset 47241 2219853a1503
parent 47238 6597255a4f94
child 47242 4abd474a10af
equal deleted inserted replaced
47240:4f38ada3fc26 47241:2219853a1503
    17 
    17 
    18 from __future__ import absolute_import
    18 from __future__ import absolute_import
    19 
    19 
    20 import struct
    20 import struct
    21 
    21 
       
    22 from .. import (
       
    23     error,
       
    24 )
       
    25 
    22 from . import (
    26 from . import (
    23     constants,
    27     constants,
    24 )
    28 )
    25 
    29 
    26 # Docket format
    30 # Docket format
    27 #
    31 #
    28 # * 4 bytes: revlog version
    32 # * 4 bytes: revlog version
    29 #          |   This is mandatory as docket must be compatible with the previous
    33 #          |   This is mandatory as docket must be compatible with the previous
    30 #          |   revlog index header.
    34 #          |   revlog index header.
    31 # * 8 bytes: size of index data
    35 # * 8 bytes: size of index data
    32 S_HEADER = struct.Struct(constants.INDEX_HEADER.format + 'L')
    36 # * 8 bytes: pending size of index data
       
    37 S_HEADER = struct.Struct(constants.INDEX_HEADER.format + 'LL')
    33 
    38 
    34 
    39 
    35 class RevlogDocket(object):
    40 class RevlogDocket(object):
    36     """metadata associated with revlog"""
    41     """metadata associated with revlog"""
    37 
    42 
    38     def __init__(self, revlog, version_header=None, index_end=0):
    43     def __init__(
       
    44         self,
       
    45         revlog,
       
    46         use_pending=False,
       
    47         version_header=None,
       
    48         index_end=0,
       
    49         pending_index_end=0,
       
    50     ):
    39         self._version_header = version_header
    51         self._version_header = version_header
       
    52         self._read_only = bool(use_pending)
    40         self._dirty = False
    53         self._dirty = False
    41         self._radix = revlog.radix
    54         self._radix = revlog.radix
    42         self._path = revlog._docket_file
    55         self._path = revlog._docket_file
    43         self._opener = revlog.opener
    56         self._opener = revlog.opener
    44         self._index_end = index_end
    57         # this assert should be True as long as we have a single index filename
       
    58         assert index_end <= pending_index_end
       
    59         self._initial_index_end = index_end
       
    60         self._pending_index_end = pending_index_end
       
    61         if use_pending:
       
    62             self._index_end = self._pending_index_end
       
    63         else:
       
    64             self._index_end = self._initial_index_end
    45 
    65 
    46     def index_filepath(self):
    66     def index_filepath(self):
    47         """file path to the current index file associated to this docket"""
    67         """file path to the current index file associated to this docket"""
    48         # very simplistic version at first
    68         # very simplistic version at first
    49         return b"%s.idx" % self._radix
    69         return b"%s.idx" % self._radix
    56     def index_end(self, new_size):
    76     def index_end(self, new_size):
    57         if new_size != self._index_end:
    77         if new_size != self._index_end:
    58             self._index_end = new_size
    78             self._index_end = new_size
    59             self._dirty = True
    79             self._dirty = True
    60 
    80 
    61     def write(self, transaction, stripping=False):
    81     def write(self, transaction, pending=False, stripping=False):
    62         """write the modification of disk if any
    82         """write the modification of disk if any
    63 
    83 
    64         This make the new content visible to all process"""
    84         This make the new content visible to all process"""
    65         if self._dirty:
    85         if not self._dirty:
       
    86             return False
       
    87         else:
       
    88             if self._read_only:
       
    89                 msg = b'writing read-only docket: %s'
       
    90                 msg %= self._path
       
    91                 raise error.ProgrammingError(msg)
    66             if not stripping:
    92             if not stripping:
    67                 # XXX we could, leverage the docket while stripping. However it
    93                 # XXX we could, leverage the docket while stripping. However it
    68                 # is not powerfull enough at the time of this comment
    94                 # is not powerfull enough at the time of this comment
    69                 transaction.addbackup(self._path, location=b'store')
    95                 transaction.addbackup(self._path, location=b'store')
    70             with self._opener(self._path, mode=b'w', atomictemp=True) as f:
    96             with self._opener(self._path, mode=b'w', atomictemp=True) as f:
    71                 f.write(self._serialize())
    97                 f.write(self._serialize(pending=pending))
    72             self._dirty = False
    98             # if pending we still need to the write final data eventually
       
    99             self._dirty = pending
       
   100             return True
    73 
   101 
    74     def _serialize(self):
   102     def _serialize(self, pending=False):
       
   103         if pending:
       
   104             official_index_end = self._initial_index_end
       
   105         else:
       
   106             official_index_end = self._index_end
       
   107 
       
   108         # this assert should be True as long as we have a single index filename
       
   109         assert official_index_end <= self._index_end
    75         data = (
   110         data = (
    76             self._version_header,
   111             self._version_header,
       
   112             official_index_end,
    77             self._index_end,
   113             self._index_end,
    78         )
   114         )
    79         return S_HEADER.pack(*data)
   115         return S_HEADER.pack(*data)
    80 
   116 
    81 
   117 
    86     docket = RevlogDocket(revlog, version_header=version_header)
   122     docket = RevlogDocket(revlog, version_header=version_header)
    87     docket._dirty = True
   123     docket._dirty = True
    88     return docket
   124     return docket
    89 
   125 
    90 
   126 
    91 def parse_docket(revlog, data):
   127 def parse_docket(revlog, data, use_pending=False):
    92     """given some docket data return a docket object for the given revlog"""
   128     """given some docket data return a docket object for the given revlog"""
    93     header = S_HEADER.unpack(data[: S_HEADER.size])
   129     header = S_HEADER.unpack(data[: S_HEADER.size])
    94     version_header, index_size = header
   130     version_header, index_size, pending_index_size = header
    95     docket = RevlogDocket(
   131     docket = RevlogDocket(
    96         revlog,
   132         revlog,
       
   133         use_pending=use_pending,
    97         version_header=version_header,
   134         version_header=version_header,
    98         index_end=index_size,
   135         index_end=index_size,
       
   136         pending_index_end=pending_index_size,
    99     )
   137     )
   100     return docket
   138     return docket