treestate: backout making it a hard requirement

Summary:
It turns out some old repos are still using the legacy treedirstate
format, which broke when I made this a hard requirement. Let's roll this back
for now.

Reviewed By: singhsrb

Differential Revision: D19313773

fbshipit-source-id: ded78be033cb04323a2e1d237059947dee509df9
This commit is contained in:
Durham Goode 2020-01-08 11:31:35 -08:00 committed by Facebook Github Bot
parent 43550ca5bb
commit d8663cb534
12 changed files with 417 additions and 16 deletions

View File

@ -723,6 +723,7 @@ def perfdirs(ui, repo, **opts):
def d():
dirstate.hasdir("a")
del dirstate._map._dirs
timer(d)
fm.end()
@ -748,6 +749,7 @@ def perfdirstatedirs(ui, repo, **opts):
def d():
repo.dirstate.hasdir("a")
del repo.dirstate._map._dirs
timer(d)
fm.end()
@ -761,7 +763,7 @@ def perfdirstatefoldmap(ui, repo, **opts):
def d():
dirstate._map.filefoldmap.get("a")
dirstate._map.filefoldmap.clear()
del dirstate._map.filefoldmap
timer(d)
fm.end()
@ -775,7 +777,8 @@ def perfdirfoldmap(ui, repo, **opts):
def d():
dirstate._map.dirfoldmap.get("a")
dirstate._map.dirfoldmap.clear()
del dirstate._map.dirfoldmap
del dirstate._map._dirs
timer(d)
fm.end()

View File

@ -902,12 +902,6 @@ 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(
@ -2632,8 +2626,11 @@ def newreporequirements(repo):
% compengine,
hint=_('run "hg debuginstall" to list available ' "compression engines"),
)
requirements.add("treestate")
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.
if compengine != "zlib":

View File

@ -126,7 +126,6 @@ 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

@ -555,13 +555,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: legacy dirstate implementations are no longer supported!
abort: repo is corrupted: 00changelog.i
[255]
$ hg -R src commit -m '#0'
abort: legacy dirstate implementations are no longer supported!
abort: repo is corrupted: 00changelog.i
[255]
$ hg -R src log -q
abort: legacy dirstate implementations are no longer supported!
abort: repo is corrupted: 00changelog.i
[255]
$ hg clone -U -q src dst
abort: repo is corrupted: 00changelog.i

View File

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

View File

@ -0,0 +1,92 @@
#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,6 +1,22 @@
#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
@ -47,6 +63,21 @@ 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

@ -0,0 +1,19 @@
#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: legacy dirstate implementations are no longer supported!
abort: index 00changelog.i is corrupted!
[255]"""
sh % "echo indoor-pool" > ".hg/requires"
sh % "hg tip" == r"""

View File

@ -0,0 +1,211 @@
#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

@ -0,0 +1,48 @@
#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: legacy dirstate implementations are no longer supported!
abort: repo is corrupted: 00changelog.i
[255]
$ cd ..