comparison mercurial/revlogutils/nodemap.py @ 47312:7ea39d633cf3

docket: move the uid logic in the `revlogutils.docket` module We want to use it for revlog-v2 (& Co), it seems more logical to have the logic lives inside the `docket` file than the `nodemap` file. Differential Revision: https://phab.mercurial-scm.org/D10755
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 19 May 2021 19:57:55 +0200
parents 5bc6d2fc1cfc
children f70ca39d0ab8
comparison
equal deleted inserted replaced
47311:5bc6d2fc1cfc 47312:7ea39d633cf3
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 errno
12 import os
13 import random
14 import re 12 import re
15 import struct 13 import struct
16 14
17 from ..node import hex 15 from ..node import hex
18 16
19 from .. import ( 17 from .. import (
20 encoding,
21 error, 18 error,
22 pycompat,
23 util, 19 util,
24 ) 20 )
21 from . import docket as docket_mod
25 22
26 23
27 class NodeMap(dict): 24 class NodeMap(dict):
28 def __missing__(self, x): 25 def __missing__(self, x):
29 raise error.RevlogError(b'unknown node: %s' % x) 26 raise error.RevlogError(b'unknown node: %s' % x)
279 276
280 ONDISK_VERSION = 1 277 ONDISK_VERSION = 1
281 S_VERSION = struct.Struct(">B") 278 S_VERSION = struct.Struct(">B")
282 S_HEADER = struct.Struct(">BQQQQ") 279 S_HEADER = struct.Struct(">BQQQQ")
283 280
284 ID_SIZE = 8
285
286
287 def _make_uid():
288 """return a new unique identifier.
289
290 The identifier is random and composed of ascii characters."""
291 # size we "hex" the result we need half the number of bits to have a final
292 # uuid of size ID_SIZE
293 return hex(os.urandom(ID_SIZE // 2))
294
295
296 # some special test logic to avoid anoying random output in the test
297 stable_docket_file = encoding.environ.get(b'HGTEST_DOCKETIDFILE')
298
299 if stable_docket_file:
300
301 def _make_uid():
302 try:
303 with open(stable_docket_file, mode='rb') as f:
304 seed = f.read().strip()
305 except IOError as inst:
306 if inst.errno != errno.ENOENT:
307 raise
308 seed = b'4' # chosen by a fair dice roll. garanteed to be random
309 if pycompat.ispy3:
310 iter_seed = iter(seed)
311 else:
312 iter_seed = (ord(c) for c in seed)
313 # some basic circular sum hashing on 64 bits
314 int_seed = 0
315 low_mask = int('1' * 35, 2)
316 for i in iter_seed:
317 high_part = int_seed >> 35
318 low_part = (int_seed & low_mask) << 28
319 int_seed = high_part + low_part + i
320 r = random.Random()
321 if pycompat.ispy3:
322 r.seed(int_seed, version=1)
323 else:
324 r.seed(int_seed)
325 # once we drop python 3.8 support we can simply use r.randbytes
326 raw = r.getrandbits(ID_SIZE * 4)
327 assert ID_SIZE == 8
328 p = struct.pack('>L', raw)
329 new = hex(p)
330 with open(stable_docket_file, 'wb') as f:
331 f.write(new)
332 return new
333
334 281
335 class NodeMapDocket(object): 282 class NodeMapDocket(object):
336 """metadata associated with persistent nodemap data 283 """metadata associated with persistent nodemap data
337 284
338 The persistent data may come from disk or be on their way to disk. 285 The persistent data may come from disk or be on their way to disk.
339 """ 286 """
340 287
341 def __init__(self, uid=None): 288 def __init__(self, uid=None):
342 if uid is None: 289 if uid is None:
343 uid = _make_uid() 290 uid = docket_mod.make_uid()
344 # a unique identifier for the data file: 291 # a unique identifier for the data file:
345 # - When new data are appended, it is preserved. 292 # - When new data are appended, it is preserved.
346 # - When a new data file is created, a new identifier is generated. 293 # - When a new data file is created, a new identifier is generated.
347 self.uid = uid 294 self.uid = uid
348 # the tipmost revision stored in the data file. This revision and all 295 # the tipmost revision stored in the data file. This revision and all