Mercurial > public > mercurial-scm > hg
comparison mercurial/scmutil.py @ 51802:95cdc01f313d
sparse: reliably avoid writing to store without a lock
With the code as written before this patch we can still end up writing to
store in `debugsparse`. Obviously we'll write to it if by accident a store
requirement is modified, but more importantly we write to it if another
concurrent transaction modifies the requirements file on disk.
We can't rule this out since we're not holding the store lock,
so it's better to explicitly pass a permission to write instead
of inferring it based on file contents.
author | Arseniy Alekseyev <aalekseyev@janestreet.com> |
---|---|
date | Fri, 16 Aug 2024 11:12:19 +0100 |
parents | e69e3d585f07 |
children | f4733654f144 |
comparison
equal
deleted
inserted
replaced
51801:0d7ccb163b4f | 51802:95cdc01f313d |
---|---|
1666 def istreemanifest(repo) -> bool: | 1666 def istreemanifest(repo) -> bool: |
1667 """returns whether the repository is using treemanifest or not""" | 1667 """returns whether the repository is using treemanifest or not""" |
1668 return requirementsmod.TREEMANIFEST_REQUIREMENT in repo.requirements | 1668 return requirementsmod.TREEMANIFEST_REQUIREMENT in repo.requirements |
1669 | 1669 |
1670 | 1670 |
1671 def writereporequirements(repo, requirements=None) -> None: | 1671 def writereporequirements(repo, requirements=None, maywritestore=True) -> None: |
1672 """writes requirements for the repo | 1672 """writes requirements for the repo |
1673 | 1673 |
1674 Requirements are written to .hg/requires and .hg/store/requires based | 1674 Requirements are written to .hg/requires and .hg/store/requires based |
1675 on whether share-safe mode is enabled and which requirements are wdir | 1675 on whether share-safe mode is enabled and which requirements are wdir |
1676 requirements and which are store requirements | 1676 requirements and which are store requirements |
1679 repo.requirements = requirements | 1679 repo.requirements = requirements |
1680 wcreq, storereq = filterrequirements(repo.requirements) | 1680 wcreq, storereq = filterrequirements(repo.requirements) |
1681 if wcreq is not None: | 1681 if wcreq is not None: |
1682 writerequires(repo.vfs, wcreq) | 1682 writerequires(repo.vfs, wcreq) |
1683 if storereq is not None: | 1683 if storereq is not None: |
1684 writerequires(repo.svfs, storereq) | 1684 writerequires(repo.svfs, storereq, maywrite=maywritestore) |
1685 elif repo.ui.configbool(b'format', b'usestore'): | 1685 elif repo.ui.configbool(b'format', b'usestore'): |
1686 # only remove store requires if we are using store | 1686 # only remove store requires if we are using store |
1687 repo.svfs.tryunlink(b'requires') | 1687 if maywritestore: |
1688 repo.svfs.tryunlink(b'requires') | |
1688 | 1689 |
1689 | 1690 |
1690 def readrequires(vfs, allowmissing): | 1691 def readrequires(vfs, allowmissing): |
1691 """reads the require file present at root of this vfs | 1692 """reads the require file present at root of this vfs |
1692 and return a set of requirements | 1693 and return a set of requirements |
1699 # a missing file translates to no requirements. | 1700 # a missing file translates to no requirements. |
1700 read = vfs.tryread if allowmissing else vfs.read | 1701 read = vfs.tryread if allowmissing else vfs.read |
1701 return set(read(b'requires').splitlines()) | 1702 return set(read(b'requires').splitlines()) |
1702 | 1703 |
1703 | 1704 |
1704 def writerequires(opener, requirements) -> None: | 1705 def writerequires(opener, requirements, maywrite=True) -> None: |
1705 on_disk = readrequires(opener, True) | 1706 on_disk = readrequires(opener, True) |
1706 if not (on_disk == set(requirements)): | 1707 if not (on_disk == set(requirements)): |
1708 if not maywrite: | |
1709 raise error.Abort(_(b"store requirements are not as expected")) | |
1707 with opener(b'requires', b'w', atomictemp=True) as fp: | 1710 with opener(b'requires', b'w', atomictemp=True) as fp: |
1708 for r in sorted(requirements): | 1711 for r in sorted(requirements): |
1709 fp.write(b"%s\n" % r) | 1712 fp.write(b"%s\n" % r) |
1710 | 1713 |
1711 | 1714 |