##// END OF EJS Templates
dirstate-v2: Separate HAS_FILE_MTIME and HAS_DIRECTORY_MTIME flags...
Simon Sapin -
r49046:f7fd629f default
parent child Browse files
Show More
@@ -119,7 +119,7 b' static PyObject *dirstate_item_new(PyTyp'
119 119 t->size = 0;
120 120 }
121 121 if (has_meaningful_mtime) {
122 t->flags |= dirstate_flag_has_meaningful_mtime;
122 t->flags |= dirstate_flag_has_file_mtime;
123 123 t->mtime = mtime;
124 124 } else {
125 125 t->mtime = 0;
@@ -225,7 +225,7 b' static inline int dirstate_item_c_v1_mti'
225 225 {
226 226 if (dirstate_item_c_removed(self)) {
227 227 return 0;
228 } else if (!(self->flags & dirstate_flag_has_meaningful_mtime) ||
228 } else if (!(self->flags & dirstate_flag_has_file_mtime) ||
229 229 !(self->flags & dirstate_flag_p1_tracked) ||
230 230 !(self->flags & dirstate_flag_wc_tracked) ||
231 231 (self->flags & dirstate_flag_p2_info)) {
@@ -334,7 +334,7 b' dirstate_item_from_v1_data(char state, i'
334 334 t->flags = (dirstate_flag_wc_tracked |
335 335 dirstate_flag_p1_tracked |
336 336 dirstate_flag_has_meaningful_data |
337 dirstate_flag_has_meaningful_mtime);
337 dirstate_flag_has_file_mtime);
338 338 t->mode = mode;
339 339 t->size = size;
340 340 t->mtime = mtime;
@@ -395,7 +395,7 b' static PyObject *dirstate_item_from_v2_m'
395 395 to make sure it is correct. */
396 396 static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
397 397 {
398 self->flags &= ~dirstate_flag_has_meaningful_mtime;
398 self->flags &= ~dirstate_flag_has_file_mtime;
399 399 Py_RETURN_NONE;
400 400 }
401 401
@@ -409,7 +409,7 b' static PyObject *dirstate_item_set_clean'
409 409 }
410 410 self->flags = dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
411 411 dirstate_flag_has_meaningful_data |
412 dirstate_flag_has_meaningful_mtime;
412 dirstate_flag_has_file_mtime;
413 413 self->mode = mode;
414 414 self->size = size;
415 415 self->mtime = mtime;
@@ -419,7 +419,7 b' static PyObject *dirstate_item_set_clean'
419 419 static PyObject *dirstate_item_set_tracked(dirstateItemObject *self)
420 420 {
421 421 self->flags |= dirstate_flag_wc_tracked;
422 self->flags &= ~dirstate_flag_has_meaningful_mtime;
422 self->flags &= ~dirstate_flag_has_file_mtime;
423 423 Py_RETURN_NONE;
424 424 }
425 425
@@ -437,7 +437,7 b' static PyObject *dirstate_item_drop_merg'
437 437 if (self->flags & dirstate_flag_p2_info) {
438 438 self->flags &= ~(dirstate_flag_p2_info |
439 439 dirstate_flag_has_meaningful_data |
440 dirstate_flag_has_meaningful_mtime);
440 dirstate_flag_has_file_mtime);
441 441 self->mode = 0;
442 442 self->mtime = 0;
443 443 self->size = 0;
@@ -35,9 +35,10 b' static const unsigned char dirstate_flag'
35 35 static const unsigned char dirstate_flag_p1_tracked = 1 << 1;
36 36 static const unsigned char dirstate_flag_p2_info = 1 << 2;
37 37 static const unsigned char dirstate_flag_has_meaningful_data = 1 << 3;
38 static const unsigned char dirstate_flag_has_meaningful_mtime = 1 << 4;
39 static const unsigned char dirstate_flag_mode_exec_perm = 1 << 5;
40 static const unsigned char dirstate_flag_mode_is_symlink = 1 << 6;
38 static const unsigned char dirstate_flag_has_file_mtime = 1 << 4;
39 static const unsigned char dirstate_flag_has_directory_mtime = 1 << 5;
40 static const unsigned char dirstate_flag_mode_exec_perm = 1 << 6;
41 static const unsigned char dirstate_flag_mode_is_symlink = 1 << 7;
41 42
42 43 extern PyTypeObject dirstateItemType;
43 44 #define dirstate_tuple_check(op) (Py_TYPE(op) == &dirstateItemType)
@@ -379,9 +379,10 b' Node components are:'
379 379 P1_TRACKED = 1 << 1
380 380 P2_INFO = 1 << 2
381 381 HAS_MODE_AND_SIZE = 1 << 3
382 HAS_MTIME = 1 << 4
383 MODE_EXEC_PERM = 1 << 5
384 MODE_IS_SYMLINK = 1 << 6
382 HAS_FILE_MTIME = 1 << 4
383 HAS_DIRECTORY_MTIME = 1 << 5
384 MODE_EXEC_PERM = 1 << 6
385 MODE_IS_SYMLINK = 1 << 7
385 386
386 387 The meaning of each bit is described below.
387 388
@@ -401,10 +402,25 b' Node components are:'
401 402 The seconds component of an `mtime` field described below,
402 403 as a 32-bit integer.
403 404 Unlike in dirstate-v1, negative values are not used.
405 When `mtime` is used, this is number of seconds since the Unix epoch
406 truncated to its lower 31 bits.
404 407
405 408 * Offset 40:
406 409 The nanoseconds component of an `mtime` field described below,
407 410 as a 32-bit integer.
411 When `mtime` is used,
412 this is the number of nanoseconds since `mtime.seconds`,
413 always stritctly less than one billion.
414
415 This may be zero if more precision is not available.
416 (This can happen because of limitations in any of Mercurial, Python,
417 libc, the operating system, …)
418
419 When comparing two mtimes and either has this component set to zero,
420 the sub-second precision of both should be ignored.
421 False positives when checking mtime equality due to clock resolution
422 are always possible and the status algorithm needs to deal with them,
423 but having too many false negatives could be harmful too.
408 424
409 425 * (Offset 44: end of this node)
410 426
@@ -454,21 +470,18 b' by enabling it to skip `readdir` in more'
454 470 If this is unset the expected size, permission, and file type are unknown.
455 471 The `size` field is unused (set to zero).
456 472
457 `HAS_MTIME`
458 If unset, the `mtime` field is unused (set to zero).
459 If set, it contains a timestamp represented as
460 - the number of seconds since the Unix epoch,
461 truncated to its lower 31 bits.
462 - and the number of nanoseconds since `mtime.seconds`,
463 always stritctly less than one billion.
464 This may be zero if more precision is not available.
465 (This can happen because of limitations in any of Mercurial, Python,
466 libc, the operating system, …)
473 `HAS_FILE_MTIME`
474 Must be unset for untracked nodes.
475 If this and `HAS_DIRECTORY_MTIME` are both unset,
476 the `mtime` field is unused (set to zero).
477 If this is set, `mtime` is the modification time
478 expected for the file to be considered clean.
467 479
468 If set for a file tracked anywhere,
469 `mtime` is the expected modification time for the file to be clean.
470
471 If set for an untracked node, at some point,
480 `HAS_DIRECTORY_MTIME`
481 Must be unset for file tracked anywhere.
482 If this and `HAS_DIRECTORY_MTIME` are both unset,
483 the `mtime` field is unused (set to zero).
484 If this is set, at some point,
472 485 this path in the working directory was observed:
473 486
474 487 - To be a directory
@@ -49,9 +49,10 b' DIRSTATE_V2_WDIR_TRACKED = 1 << 0'
49 49 DIRSTATE_V2_P1_TRACKED = 1 << 1
50 50 DIRSTATE_V2_P2_INFO = 1 << 2
51 51 DIRSTATE_V2_HAS_MODE_AND_SIZE = 1 << 3
52 DIRSTATE_V2_HAS_MTIME = 1 << 4
53 DIRSTATE_V2_MODE_EXEC_PERM = 1 << 5
54 DIRSTATE_V2_MODE_IS_SYMLINK = 1 << 6
52 DIRSTATE_V2_HAS_FILE_MTIME = 1 << 4
53 _DIRSTATE_V2_HAS_DIRCTORY_MTIME = 1 << 5 # Unused when Rust is not available
54 DIRSTATE_V2_MODE_EXEC_PERM = 1 << 6
55 DIRSTATE_V2_MODE_IS_SYMLINK = 1 << 7
55 56
56 57
57 58 @attr.s(slots=True, init=False)
@@ -138,7 +139,7 b' class DirstateItem(object):'
138 139 p1_tracked=bool(flags & DIRSTATE_V2_P1_TRACKED),
139 140 p2_info=bool(flags & DIRSTATE_V2_P2_INFO),
140 141 has_meaningful_data=has_mode_size,
141 has_meaningful_mtime=bool(flags & DIRSTATE_V2_HAS_MTIME),
142 has_meaningful_mtime=bool(flags & DIRSTATE_V2_HAS_FILE_MTIME),
142 143 parentfiledata=(mode, size, mtime),
143 144 )
144 145
@@ -329,7 +330,7 b' class DirstateItem(object):'
329 330 if stat.S_ISLNK(self.mode):
330 331 flags |= DIRSTATE_V2_MODE_IS_SYMLINK
331 332 if self._mtime is not None:
332 flags |= DIRSTATE_V2_HAS_MTIME
333 flags |= DIRSTATE_V2_HAS_FILE_MTIME
333 334 return (flags, self._size or 0, self._mtime or 0)
334 335
335 336 def v1_state(self):
@@ -106,9 +106,10 b' bitflags! {'
106 106 const P1_TRACKED = 1 << 1;
107 107 const P2_INFO = 1 << 2;
108 108 const HAS_MODE_AND_SIZE = 1 << 3;
109 const HAS_MTIME = 1 << 4;
110 const MODE_EXEC_PERM = 1 << 5;
111 const MODE_IS_SYMLINK = 1 << 6;
109 const HAS_FILE_MTIME = 1 << 4;
110 const HAS_DIRECTORY_MTIME = 1 << 5;
111 const MODE_EXEC_PERM = 1 << 6;
112 const MODE_IS_SYMLINK = 1 << 7;
112 113 }
113 114 }
114 115
@@ -320,13 +321,15 b' impl Node {'
320 321 pub(super) fn cached_directory_mtime(
321 322 &self,
322 323 ) -> Result<Option<TruncatedTimestamp>, DirstateV2ParseError> {
323 Ok(
324 if self.flags().contains(Flags::HAS_MTIME) && !self.has_entry() {
325 Some(self.mtime.try_into()?)
324 if self.flags().contains(Flags::HAS_DIRECTORY_MTIME) {
325 if self.flags().contains(Flags::HAS_FILE_MTIME) {
326 Err(DirstateV2ParseError)
326 327 } else {
327 None
328 },
329 )
328 Ok(Some(self.mtime.try_into()?))
329 }
330 } else {
331 Ok(None)
332 }
330 333 }
331 334
332 335 fn synthesize_unix_mode(&self) -> u32 {
@@ -353,7 +356,7 b' impl Node {'
353 356 } else {
354 357 None
355 358 };
356 let mtime = if self.flags().contains(Flags::HAS_MTIME) {
359 let mtime = if self.flags().contains(Flags::HAS_FILE_MTIME) {
357 360 Some(self.mtime.truncated_seconds.into())
358 361 } else {
359 362 None
@@ -422,7 +425,7 b' impl Node {'
422 425 0.into()
423 426 };
424 427 let mtime = if let Some(m) = mtime_opt {
425 flags.insert(Flags::HAS_MTIME);
428 flags.insert(Flags::HAS_FILE_MTIME);
426 429 PackedTruncatedTimestamp {
427 430 truncated_seconds: m.into(),
428 431 nanoseconds: 0.into(),
@@ -580,9 +583,11 b" impl Writer<'_, '_> {"
580 583 dirstate_map::NodeData::Entry(entry) => {
581 584 Node::from_dirstate_entry(entry)
582 585 }
583 dirstate_map::NodeData::CachedDirectory { mtime } => {
584 (Flags::HAS_MTIME, 0.into(), (*mtime).into())
585 }
586 dirstate_map::NodeData::CachedDirectory { mtime } => (
587 Flags::HAS_DIRECTORY_MTIME,
588 0.into(),
589 (*mtime).into(),
590 ),
586 591 dirstate_map::NodeData::None => (
587 592 Flags::empty(),
588 593 0.into(),
General Comments 0
You need to be logged in to leave comments. Login now