Skip to content

Commit 16a0c64

Browse files
committed
index: IndexLock added to provide some kind of critical section for index based git operations in concurrent environments
1 parent 54844a9 commit 16a0c64

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

lib/git/index.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
from errors import GitCommandError
2323
from git.objects import Blob, Tree, Object, Commit
24-
from git.utils import SHA1Writer, LazyMixin, ConcurrentWriteOperation, join_path_native
24+
from git.utils import SHA1Writer, LazyMixin, ConcurrentWriteOperation, join_path_native, BlockingLockFile
2525

2626

2727
class CheckoutError( Exception ):
@@ -70,6 +70,38 @@ def __del__(self):
7070
os.rename(self.tmp_file_path, self.file_path)
7171
# END temp file exists
7272

73+
class IndexLock(BlockingLockFile):
74+
"""Specialized lock that will wait for the index to be locked and immediately
75+
move the lock out of the way. This allows a git command to take the lock
76+
which has to follow right after the lock() call.
77+
78+
Right before the lock is released, we will move our original lock back into place.
79+
This lock should be used to gain fine-grained control over multiple processes
80+
or threads that try to manipulate the index and would otherwise fail.
81+
Using this lock, these will wait for each other.
82+
83+
NOTE:
84+
There is still a small chance that git will fail as file system
85+
operations take time as well.
86+
"""
87+
__slots__ = '_tmp_file_path'
88+
89+
def _obtain_lock_or_raise(self):
90+
super(IndexLock, self)._obtain_lock_or_raise()
91+
self._tmp_file_path = self._lock_file_path() + tempfile.mktemp('','','')
92+
# rename lock we aquired to move it out of the way
93+
os.rename(self._lock_file_path(), self._tmp_file_path)
94+
95+
def _release_lock(self):
96+
# move our lock back into place
97+
if hasattr(self, '_tmp_file_path') and os.path.isfile(self._tmp_file_path):
98+
lock_file = self._lock_file_path()
99+
if os.name == 'nt' and os.path.exists(lock_file):
100+
os.remove(lock_file)
101+
os.rename(self._tmp_file_path, lock_file)
102+
# END temp file exists
103+
super(IndexLock, self)._release_lock()
104+
73105
class BlobFilter(object):
74106
"""
75107
Predicate to be used by iter_blobs allowing to filter only return blobs which

0 commit comments

Comments
 (0)