treestate: make treestate a hard requirement

Summary:
We want to delete all the non-treestate dirstate implementations. Let's
start throwing an exception if treestate is not enabled. We temporarily have a
bypass in case we break an important usecase in the process.

This also sets the standard new repo to be created in treestate mode, but adding
treestate to newreporequirements.

Reviewed By: quark-zju

Differential Revision: D19204621

fbshipit-source-id: 61c0c69ce6e559615ef570d2343bea78c1b5d5ee
This commit is contained in:
Durham Goode 2020-01-06 21:35:23 -08:00 committed by Facebook Github Bot
parent a7aeb5d7a6
commit 898149fa37
12 changed files with 16 additions and 417 deletions

View File

@ -770,7 +770,6 @@ def perfdirs(ui, repo, **opts):
def d():
dirstate.hasdir("a")
del dirstate._map._dirs
timer(d)
fm.end()
@ -796,7 +795,6 @@ def perfdirstatedirs(ui, repo, **opts):
def d():
repo.dirstate.hasdir("a")
del repo.dirstate._map._dirs
timer(d)
fm.end()
@ -810,7 +808,7 @@ def perfdirstatefoldmap(ui, repo, **opts):
def d():
dirstate._map.filefoldmap.get("a")
del dirstate._map.filefoldmap
dirstate._map.filefoldmap.clear()
timer(d)
fm.end()
@ -824,8 +822,7 @@ def perfdirfoldmap(ui, repo, **opts):
def d():
dirstate._map.dirfoldmap.get("a")
del dirstate._map.dirfoldmap
del dirstate._map._dirs
dirstate._map.dirfoldmap.clear()
timer(d)
fm.end()

View File

@ -903,6 +903,12 @@ class localrepository(object):
return self._eden_dirstate
istreestate = "treestate" in self.requirements
# Block nontreestate repos entirely. Add a config to bypass in case we
# break something.
if not istreestate and self.ui.configbool("treestate", "required", True):
raise errormod.RequirementError(
"legacy dirstate implementations are no longer supported"
)
istreedirstate = "treedirstate" in self.requirements
return dirstate.dirstate(
@ -2805,10 +2811,7 @@ def newreporequirements(repo):
% compengine,
hint=_('run "hg debuginstall" to list available ' "compression engines"),
)
dirstateversion = ui.configint("format", "dirstate")
if dirstateversion == 1:
requirements.add("treedirstate")
elif dirstateversion == 2:
requirements.add("treestate")
# zlib is the historical default and doesn't need an explicit requirement.

View File

@ -127,6 +127,7 @@ New errors are not allowed. Warnings are strongly discouraged.
undocumented: ssl.signal_status (bool) [True]
undocumented: ssl.timeout (int) [10]
undocumented: treemanifest.verifyautocreate (bool)
undocumented: treestate.required (bool) [True]
undocumented: ui.editor.chunkselector (str)
undocumented: ui.hyperlink (bool)
undocumented: workingcopy.enablerustwalker (bool)

View File

@ -558,13 +558,13 @@ Test clone from the repository in (emulated) revlog format 0 (issue4203):
$ mkdir -p src/.hg
$ echo foo > src/foo
$ hg -R src add src/foo
abort: repo is corrupted: 00changelog.i
abort: legacy dirstate implementations are no longer supported!
[255]
$ hg -R src commit -m '#0'
abort: repo is corrupted: 00changelog.i
abort: legacy dirstate implementations are no longer supported!
[255]
$ hg -R src log -q
abort: repo is corrupted: 00changelog.i
abort: legacy dirstate implementations are no longer supported!
[255]
$ hg clone -U -q src dst
abort: repo is corrupted: 00changelog.i

View File

@ -11,7 +11,6 @@ Set vars:
Prepare repo:
$ hg init
$ hg debugtreedirstate off
$ echo this is file a > a
$ hg add a

View File

@ -1,92 +0,0 @@
#chg-compatible
$ for src in 0 1 2; do
> for dst in 0 1 2; do
> [ $src = $dst ] && continue
> echo ==== Migrating dirstate v$src to v$dst ====
> cd $TESTTMP
> setconfig format.dirstate=$src
> newrepo
> touch normal modified removed deleted
> hg ci -A . -q -m init
> hg rm removed
> rm deleted
> touch untracked
> echo 1 > modified
> hg status
> hg debugtreestate status
> hg debugtreestate v$dst
> hg status
> hg debugtreestate status
> done
> done
==== Migrating dirstate v0 to v1 ====
M modified
R removed
! deleted
? untracked
dirstate v0 (flat dirstate, 4 files tracked)
M modified
R removed
! deleted
? untracked
dirstate v1 (using dirstate.tree.*, 4 files tracked) (glob)
==== Migrating dirstate v0 to v2 ====
M modified
R removed
! deleted
? untracked
dirstate v0 (flat dirstate, 4 files tracked)
M modified
R removed
! deleted
? untracked
dirstate v2 (using treestate*, offset *, 4 files tracked) (glob) (no-fsmonitor !)
dirstate v2 (using treestate*, offset *, 5 files tracked) (glob) (fsmonitor !)
==== Migrating dirstate v1 to v0 ====
M modified
R removed
! deleted
? untracked
dirstate v1 (using dirstate.tree*, 4 files tracked) (glob)
M modified
R removed
! deleted
? untracked
dirstate v0 (flat dirstate, 4 files tracked)
==== Migrating dirstate v1 to v2 ====
M modified
R removed
! deleted
? untracked
dirstate v1 (using dirstate.tree*, 4 files tracked) (glob)
M modified
R removed
! deleted
? untracked
dirstate v2 (using treestate*, offset *, 4 files tracked) (glob) (no-fsmonitor !)
dirstate v2 (using treestate*, offset *, 5 files tracked) (glob) (fsmonitor !)
==== Migrating dirstate v2 to v0 ====
M modified
R removed
! deleted
? untracked
dirstate v2 (using treestate*, offset *, 4 files tracked) (glob) (no-fsmonitor !)
dirstate v2 (using treestate*, offset *, 5 files tracked) (glob) (fsmonitor !)
M modified
R removed
! deleted
? untracked
dirstate v0 (flat dirstate, 4 files tracked)
==== Migrating dirstate v2 to v1 ====
M modified
R removed
! deleted
? untracked
dirstate v2 (using treestate*, offset *, 4 files tracked) (glob) (no-fsmonitor !)
dirstate v2 (using treestate*, offset *, 5 files tracked) (glob) (fsmonitor !)
M modified
R removed
! deleted
? untracked
dirstate v1 (using dirstate.tree*, 4 files tracked) (glob)

View File

@ -1,22 +1,6 @@
#chg-compatible
#chg-compatible
#chg-compatible
#testcases v0 v1 v2
#if v0
$ setconfig format.dirstate=0
#endif
#if v1
$ setconfig format.dirstate=1
#endif
#if v2
$ setconfig format.dirstate=2
#endif
------ Test dirstate._dirs refcounting
@ -63,21 +47,6 @@ Prepare test repo:
adding a
$ hg ci -m1
#if no-v2
Set mtime of a into the future:
$ touch -t 202101011200 a
Status must not set a's entry to unset (issue1790):
$ hg status
$ hg debugstate
n 644 2 2021-01-01 12:00:00 a
Note: issue1790 is about thg compatibility. In this case, setting mtime to
"unset" is also correct since "a" needs to be checked.
#endif
Test modulo storage/comparison of absurd dates:
#if no-aix

View File

@ -1,19 +0,0 @@
#require fsmonitor
$ setconfig fsmonitor.warn-fresh-instance=true
$ newrepo
A warning is printed for the first use
$ hg status --debug
warning: watchman has recently started (pid *) - operation will be slower than usual (glob)
poststatusfixup decides to wait for wlock since watchman reported fresh instance
$ hg status --debug
Verify that we can fallback to walking
- Migrate the dirstate to reset the clock
$ hg debugtreestate v0
$ hg debugtreestate on
$ hg status --config fsmonitor.walk_on_invalidate=True --debug
fsmonitor: fallback to core status, no clock

View File

@ -16,7 +16,7 @@ sh % "hg add a"
sh % "hg commit -m test"
sh % "rm .hg/requires"
sh % "hg tip" == r"""
abort: index 00changelog.i is corrupted!
abort: legacy dirstate implementations are no longer supported!
[255]"""
sh % "echo indoor-pool" > ".hg/requires"
sh % "hg tip" == r"""

View File

@ -1,211 +0,0 @@
#chg-compatible
$ setconfig extensions.treemanifest=!
Setup
$ setconfig format.dirstate=1
$ setconfig treestate.mingcage=0
$ hg init repo
$ cd repo
$ echo base > base
$ hg add base
$ hg debugdirstate
a 0 -1 unset base
$ hg commit -m "base"
$ hg debugdirstate
n 644 5 * base (glob)
Create path-conflicting dirstates
$ hg up -q 0
$ echo a > a
$ hg add a
$ hg commit -m a
$ hg bookmark a
$ hg up -q 0
$ mkdir a
$ echo a/a > a/a
$ hg add a/a
$ hg commit -m a/a
$ hg bookmark a/a
$ hg up -q a
$ hg status
$ hg rm a
$ hg status
R a
$ hg merge --force a/a
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg status
M a/a
R a
$ hg rm --force a/a
$ hg status
R a
R a/a
$ hg up -Cq 0
Attempt to create a path conflict in the manifest
$ echo b > b
$ hg add b
$ hg commit -m b
$ rm b
$ mkdir b
$ echo b/b > b/b
$ hg add b/b
abort: file 'b' in dirstate clashes with 'b/b'
[255]
$ rm -rf b
$ hg up -Cq 0
Test warning when creating files that might give a casefold collision
#if no-icasefs
$ echo data > FiLeNaMe
$ hg add FiLeNaMe
$ echo data > FILENAME
$ hg add FILENAME
warning: possible case-folding collision for FILENAME
$ rm -f FiLeNaMe FILENAME
$ hg up -Cq 0
#endif
Test dirfoldmap and filefoldmap on case insensitive filesystems
#if icasefs
$ mkdir -p dirA/dirB/dirC
$ echo file1 > dira/File1
$ echo file2 > dira/dirb/FILE2
$ echo file3 > dira/dirb/dirc/FiLe3
$ echo file4 > dira/dirb/dirc/file4
$ hg add DIRA
adding dirA/File1
adding dirA/dirB/FILE2
adding dirA/dirB/dirC/FiLe3
adding dirA/dirB/dirC/file4
$ hg status
A dirA/File1
A dirA/dirB/FILE2
A dirA/dirB/dirC/FiLe3
A dirA/dirB/dirC/file4
$ hg forget dira/DIRB
removing dirA/dirB/FILE2
removing dirA/dirB/dirC/FiLe3
removing dirA/dirB/dirC/file4
$ hg status
A dirA/File1
? dirA/dirB/FILE2
? dirA/dirB/dirC/FiLe3
? dirA/dirB/dirC/file4
$ hg add dira/dirb/file2
$ hg status
A dirA/File1
A dirA/dirB/FILE2
? dirA/dirB/dirC/FiLe3
? dirA/dirB/dirC/file4
$ rm -rf dirA
#endif
Test autorepack
$ ls .hg/dirstate.tree.*
.hg/dirstate.tree.* (glob)
$ echo data > file
After the first repack, the old trees are kept around by the transaction undo backups.
$ hg add file --config treestate.minrepackthreshold=1 --config treestate.repackfactor=0 --debug | grep -v 'in use by'
adding file
auto-repacking treedirstate
$ ls .hg/dirstate.tree.*
.hg/dirstate.tree.* (glob)
.hg/dirstate.tree.* (glob)
After the second repack, the old trees are still kept around.
$ hg forget file --config treestate.minrepackthreshold=1 --config treestate.repackfactor=0 --debug | grep -v 'in use by'
removing file
auto-repacking treedirstate
$ ls .hg/dirstate.tree.*
.hg/dirstate.tree.* (glob)
.hg/dirstate.tree.* (glob)
.hg/dirstate.tree.* (glob)
On the third repack, the original tree is removed.
$ hg add file --config treestate.minrepackthreshold=1 --config treestate.repackfactor=0 --debug | grep -v 'in use by'
adding file
auto-repacking treedirstate
removing old unreferenced dirstate tree * (glob)
$ ls .hg/dirstate.tree.*
.hg/dirstate.tree.* (glob)
.hg/dirstate.tree.* (glob)
.hg/dirstate.tree.* (glob)
On the fourth repack, the second tree is removed.
$ hg forget file --config treestate.minrepackthreshold=1 --config treestate.repackfactor=0 --debug | grep -v 'in use by'
removing file
auto-repacking treedirstate
removing old unreferenced dirstate tree * (glob)
$ ls .hg/dirstate.tree.*
.hg/dirstate.tree.* (glob)
.hg/dirstate.tree.* (glob)
.hg/dirstate.tree.* (glob)
Test downgrade on pull
$ for f in 1 2 3 4 5 ; do mkdir dir$f ; echo $f > dir$f/file$f ; hg add dir$f/file$f ; done
$ echo x > a
$ hg add a
$ hg commit -m "add files"
$ cd ..
$ hg clone repo clone
updating to branch default
7 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd clone
$ hg merge 1
merging a
warning: 1 conflicts while merging a! (edit, then use 'hg resolve --mark')
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
[1]
$ echo data > newfile
$ hg add newfile
$ hg rm dir3/file3
$ grep treedirstate .hg/requires
treedirstate
$ hg pull --config treestate.automigrate=true --config format.dirstate=0
downgrading dirstate format...
pulling from $TESTTMP/repo (glob)
searching for changes
no changes found
$ hg debugdirstate
m 0 -2 * a (glob)
n 644 5 * base (glob)
n 644 2 * dir1/file1 (glob)
n 644 2 * dir2/file2 (glob)
r 0 0 * dir3/file3 (glob)
n 644 2 * dir4/file4 (glob)
n 644 2 * dir5/file5 (glob)
a 0 -1 * newfile (glob)
$ grep treedirstate .hg/requires
[1]
Test upgrade on pull
$ hg pull --config treestate.automigrate=true --config format.dirstate=1
please wait while we migrate dirstate format to version 1
this will make your hg commands faster...
pulling from $TESTTMP/repo (glob)
searching for changes
no changes found
$ hg debugdirstate
m 0 -2 * a (glob)
n 644 5 * base (glob)
n 644 2 * dir1/file1 (glob)
n 644 2 * dir2/file2 (glob)
r 0 0 * dir3/file3 (glob)
n 644 2 * dir4/file4 (glob)
n 644 2 * dir5/file5 (glob)
a 0 -1 * newfile (glob)
$ grep treedirstate .hg/requires
treedirstate

View File

@ -1,48 +0,0 @@
#require fsmonitor
$ setconfig extensions.treemanifest=!
Fsmonitor is required for treestate to track untracked files.
Nonnormalset, otherparentset, copymap might have reference to untracked files.
They should be filtered out when downgrading from treestate to treedirstate.
Create a treestate repo
$ hg init repo1 --config format.dirstate=2
$ cd repo1
$ touch x
Write the untracked file to treestate
$ hg status
? x
$ hg debugtree
dirstate v2 (* 1 files tracked) (glob)
Downgrade to treedirstate
$ hg debugtree v1
Check nonnormalset
$ hg debugshell --command 'print(repr(sorted(repo.dirstate._map.nonnormalset)))'
[]
Check downgrade with "hg pull"
$ hg init $TESTTMP/repo2 --config format.dirstate=2
$ cd $TESTTMP/repo2
$ touch x
$ hg ci -m init -A x -q
$ hg init $TESTTMP/repo3 --config format.dirstate=2
$ cd $TESTTMP/repo3
$ hg pull ../repo2 --config format.dirstate=1 --config treestate.automigrate=true --config extensions.rebase= --rebase -q
fsmonitor state is invalidated after upgrade
$ ls .hg/fsmonitor.state
.hg/fsmonitor.state
$ hg pull ../repo2 --config format.dirstate=2 --config treestate.automigrate=true --config extensions.rebase= --rebase -q
$ [ -f .hg/fsmonitor.state ]
[1]

View File

@ -457,7 +457,7 @@ test revlog format 0
$ revlog-formatv0.py
$ cd formatv0
$ hg verify
abort: repo is corrupted: 00changelog.i
abort: legacy dirstate implementations are no longer supported!
[255]
$ cd ..