mercurial/revlogutils/nodemap.py
changeset 44363 f7459da77f23
parent 44340 6ecc34b31137
child 44445 336ec75ed1ac
equal deleted inserted replaced
44362:c089a0947f3e 44363:f7459da77f23
     6 # This software may be used and distributed according to the terms of the
     6 # This software may be used and distributed according to the terms of the
     7 # GNU General Public License version 2 or any later version.
     7 # GNU General Public License version 2 or any later version.
     8 
     8 
     9 from __future__ import absolute_import
     9 from __future__ import absolute_import
    10 
    10 
       
    11 import errno
    11 import os
    12 import os
    12 import re
    13 import re
    13 import struct
    14 import struct
    14 
    15 
    15 from .. import (
    16 from .. import (
    43     docket.tip_rev = tip_rev
    44     docket.tip_rev = tip_rev
    44     docket.data_length = data_length
    45     docket.data_length = data_length
    45     docket.data_unused = data_unused
    46     docket.data_unused = data_unused
    46 
    47 
    47     filename = _rawdata_filepath(revlog, docket)
    48     filename = _rawdata_filepath(revlog, docket)
    48     data = revlog.opener.tryread(filename)
    49     use_mmap = revlog.opener.options.get("exp-persistent-nodemap.mmap")
       
    50     try:
       
    51         with revlog.opener(filename) as fd:
       
    52             if use_mmap:
       
    53                 data = util.buffer(util.mmapread(fd, data_length))
       
    54             else:
       
    55                 data = fd.read(data_length)
       
    56     except OSError as e:
       
    57         if e.errno != errno.ENOENT:
       
    58             raise
    49     if len(data) < data_length:
    59     if len(data) < data_length:
    50         return None
    60         return None
    51     elif len(data) > data_length:
       
    52         data = data[:data_length]
       
    53     return docket, data
    61     return docket, data
    54 
    62 
    55 
    63 
    56 def setup_persistent_nodemap(tr, revlog):
    64 def setup_persistent_nodemap(tr, revlog):
    57     """Install whatever is needed transaction side to persist a nodemap on disk
    65     """Install whatever is needed transaction side to persist a nodemap on disk
    79         msg = "calling persist nodemap on a revlog without the feature enableb"
    87         msg = "calling persist nodemap on a revlog without the feature enableb"
    80         raise error.ProgrammingError(msg)
    88         raise error.ProgrammingError(msg)
    81 
    89 
    82     can_incremental = util.safehasattr(revlog.index, "nodemap_data_incremental")
    90     can_incremental = util.safehasattr(revlog.index, "nodemap_data_incremental")
    83     ondisk_docket = revlog._nodemap_docket
    91     ondisk_docket = revlog._nodemap_docket
       
    92     feed_data = util.safehasattr(revlog.index, "update_nodemap_data")
       
    93     use_mmap = revlog.opener.options.get("exp-persistent-nodemap.mmap")
    84 
    94 
    85     data = None
    95     data = None
    86     # first attemp an incremental update of the data
    96     # first attemp an incremental update of the data
    87     if can_incremental and ondisk_docket is not None:
    97     if can_incremental and ondisk_docket is not None:
    88         target_docket = revlog._nodemap_docket.copy()
    98         target_docket = revlog._nodemap_docket.copy()
    95             data = None
   105             data = None
    96         else:
   106         else:
    97             datafile = _rawdata_filepath(revlog, target_docket)
   107             datafile = _rawdata_filepath(revlog, target_docket)
    98             # EXP-TODO: if this is a cache, this should use a cache vfs, not a
   108             # EXP-TODO: if this is a cache, this should use a cache vfs, not a
    99             # store vfs
   109             # store vfs
       
   110             new_length = target_docket.data_length + len(data)
   100             with revlog.opener(datafile, b'r+') as fd:
   111             with revlog.opener(datafile, b'r+') as fd:
   101                 fd.seek(target_docket.data_length)
   112                 fd.seek(target_docket.data_length)
   102                 fd.write(data)
   113                 fd.write(data)
   103                 fd.seek(0)
   114                 if feed_data:
   104                 new_data = fd.read(target_docket.data_length + len(data))
   115                     if use_mmap:
   105             target_docket.data_length += len(data)
   116                         fd.seek(0)
       
   117                         new_data = fd.read(new_length)
       
   118                     else:
       
   119                         fd.flush()
       
   120                         new_data = util.buffer(util.mmapread(fd, new_length))
       
   121             target_docket.data_length = new_length
   106             target_docket.data_unused += data_changed_count
   122             target_docket.data_unused += data_changed_count
   107 
   123 
   108     if data is None:
   124     if data is None:
   109         # otherwise fallback to a full new export
   125         # otherwise fallback to a full new export
   110         target_docket = NodeMapDocket()
   126         target_docket = NodeMapDocket()
   113             data = revlog.index.nodemap_data_all()
   129             data = revlog.index.nodemap_data_all()
   114         else:
   130         else:
   115             data = persistent_data(revlog.index)
   131             data = persistent_data(revlog.index)
   116         # EXP-TODO: if this is a cache, this should use a cache vfs, not a
   132         # EXP-TODO: if this is a cache, this should use a cache vfs, not a
   117         # store vfs
   133         # store vfs
   118         new_data = data
   134         with revlog.opener(datafile, b'w+') as fd:
   119         with revlog.opener(datafile, b'w') as fd:
       
   120             fd.write(data)
   135             fd.write(data)
       
   136             if feed_data:
       
   137                 if use_mmap:
       
   138                     new_data = data
       
   139                 else:
       
   140                     fd.flush()
       
   141                     new_data = util.buffer(util.mmapread(fd, len(data)))
   121         target_docket.data_length = len(data)
   142         target_docket.data_length = len(data)
   122     target_docket.tip_rev = revlog.tiprev()
   143     target_docket.tip_rev = revlog.tiprev()
   123     # EXP-TODO: if this is a cache, this should use a cache vfs, not a
   144     # EXP-TODO: if this is a cache, this should use a cache vfs, not a
   124     # store vfs
   145     # store vfs
   125     with revlog.opener(revlog.nodemap_file, b'w', atomictemp=True) as fp:
   146     with revlog.opener(revlog.nodemap_file, b'w', atomictemp=True) as fp:
   126         fp.write(target_docket.serialize())
   147         fp.write(target_docket.serialize())
   127     revlog._nodemap_docket = target_docket
   148     revlog._nodemap_docket = target_docket
   128     if util.safehasattr(revlog.index, "update_nodemap_data"):
   149     if feed_data:
   129         revlog.index.update_nodemap_data(target_docket, new_data)
   150         revlog.index.update_nodemap_data(target_docket, new_data)
   130 
   151 
   131     # EXP-TODO: if the transaction abort, we should remove the new data and
   152     # EXP-TODO: if the transaction abort, we should remove the new data and
   132     # reinstall the old one.
   153     # reinstall the old one.
   133 
   154