Skip to content

Commit 1051ef0

Browse files
luked99gitster
authored andcommitted
git-p4: fixing --changes-block-size handling
The --changes-block-size handling was intended to help when a user has a limited "maxscanrows" (see "p4 group"). It used "p4 changes -m $maxchanges" to limit the number of results. Unfortunately, it turns out that the "maxscanrows" and "maxresults" limits are actually applied *before* the "-m maxchanges" parameter is considered (experimentally). Fix the block-size handling so that it gets blocks of changes limited by revision number ($Start..$Start+$N, etc). This limits the number of results early enough that both sets of tests pass. Note that many other Perforce operations can fail for the same reason (p4 print, p4 files, etc) and it's probably not possible to workaround this. In the real world, this is probably not usually a problem. Signed-off-by: Luke Diamand <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent eceafff commit 1051ef0

File tree

2 files changed

+69
-28
lines changed

2 files changed

+69
-28
lines changed

git-p4.py

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ def __str__(self):
4343
# Only labels/tags matching this will be imported/exported
4444
defaultLabelRegexp = r'[a-zA-Z0-9_\-.]+$'
4545

46+
# Grab changes in blocks of this many revisions, unless otherwise requested
47+
defaultBlockSize = 512
48+
4649
def p4_build_cmd(cmd):
4750
"""Build a suitable p4 command line.
4851
@@ -249,6 +252,10 @@ def p4_reopen(type, f):
249252
def p4_move(src, dest):
250253
p4_system(["move", "-k", wildcard_encode(src), wildcard_encode(dest)])
251254

255+
def p4_last_change():
256+
results = p4CmdList(["changes", "-m", "1"])
257+
return int(results[0]['change'])
258+
252259
def p4_describe(change):
253260
"""Make sure it returns a valid result by checking for
254261
the presence of field "time". Return a dict of the
@@ -742,43 +749,77 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent
742749
def originP4BranchesExist():
743750
return gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master")
744751

745-
def p4ChangesForPaths(depotPaths, changeRange, block_size):
752+
753+
def p4ParseNumericChangeRange(parts):
754+
changeStart = int(parts[0][1:])
755+
if parts[1] == '#head':
756+
changeEnd = p4_last_change()
757+
else:
758+
changeEnd = int(parts[1])
759+
760+
return (changeStart, changeEnd)
761+
762+
def chooseBlockSize(blockSize):
763+
if blockSize:
764+
return blockSize
765+
else:
766+
return defaultBlockSize
767+
768+
def p4ChangesForPaths(depotPaths, changeRange, requestedBlockSize):
746769
assert depotPaths
747-
assert block_size
748770

749-
# Parse the change range into start and end
771+
# Parse the change range into start and end. Try to find integer
772+
# revision ranges as these can be broken up into blocks to avoid
773+
# hitting server-side limits (maxrows, maxscanresults). But if
774+
# that doesn't work, fall back to using the raw revision specifier
775+
# strings, without using block mode.
776+
750777
if changeRange is None or changeRange == '':
751-
changeStart = '@1'
752-
changeEnd = '#head'
778+
changeStart = 1
779+
changeEnd = p4_last_change()
780+
block_size = chooseBlockSize(requestedBlockSize)
753781
else:
754782
parts = changeRange.split(',')
755783
assert len(parts) == 2
756-
changeStart = parts[0]
757-
changeEnd = parts[1]
784+
try:
785+
(changeStart, changeEnd) = p4ParseNumericChangeRange(parts)
786+
block_size = chooseBlockSize(requestedBlockSize)
787+
except:
788+
changeStart = parts[0][1:]
789+
changeEnd = parts[1]
790+
if requestedBlockSize:
791+
die("cannot use --changes-block-size with non-numeric revisions")
792+
block_size = None
758793

759794
# Accumulate change numbers in a dictionary to avoid duplicates
760795
changes = {}
761796

762797
for p in depotPaths:
763798
# Retrieve changes a block at a time, to prevent running
764-
# into a MaxScanRows error from the server.
765-
start = changeStart
766-
end = changeEnd
767-
get_another_block = True
768-
while get_another_block:
769-
new_changes = []
799+
# into a MaxResults/MaxScanRows error from the server.
800+
801+
while True:
770802
cmd = ['changes']
771-
cmd += ['-m', str(block_size)]
772-
cmd += ["%s...%s,%s" % (p, start, end)]
803+
804+
if block_size:
805+
end = min(changeEnd, changeStart + block_size)
806+
revisionRange = "%d,%d" % (changeStart, end)
807+
else:
808+
revisionRange = "%s,%s" % (changeStart, changeEnd)
809+
810+
cmd += ["%s...@%s" % (p, revisionRange)]
811+
773812
for line in p4_read_pipe_lines(cmd):
774813
changeNum = int(line.split(" ")[1])
775-
new_changes.append(changeNum)
776814
changes[changeNum] = True
777-
if len(new_changes) == block_size:
778-
get_another_block = True
779-
end = '@' + str(min(new_changes))
780-
else:
781-
get_another_block = False
815+
816+
if not block_size:
817+
break
818+
819+
if end >= changeEnd:
820+
break
821+
822+
changeStart = end + 1
782823

783824
changelist = changes.keys()
784825
changelist.sort()
@@ -1974,7 +2015,7 @@ def __init__(self):
19742015
self.syncWithOrigin = True
19752016
self.importIntoRemotes = True
19762017
self.maxChanges = ""
1977-
self.changes_block_size = 500
2018+
self.changes_block_size = None
19782019
self.keepRepoPath = False
19792020
self.depotPaths = None
19802021
self.p4BranchesInGit = []

t/t9818-git-p4-block.sh

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,30 +49,30 @@ test_expect_success 'Default user cannot fetch changes' '
4949
! p4 changes -m 1 //depot/...
5050
'
5151

52-
test_expect_failure 'Clone the repo' '
52+
test_expect_success 'Clone the repo' '
5353
git p4 clone --dest="$git" --changes-block-size=7 --verbose //depot/included@all
5454
'
5555

56-
test_expect_failure 'All files are present' '
56+
test_expect_success 'All files are present' '
5757
echo file.txt >expected &&
5858
test_write_lines outer0.txt outer1.txt outer2.txt outer3.txt outer4.txt >>expected &&
5959
test_write_lines outer5.txt >>expected &&
6060
ls "$git" >current &&
6161
test_cmp expected current
6262
'
6363

64-
test_expect_failure 'file.txt is correct' '
64+
test_expect_success 'file.txt is correct' '
6565
echo 55 >expected &&
6666
test_cmp expected "$git/file.txt"
6767
'
6868

69-
test_expect_failure 'Correct number of commits' '
69+
test_expect_success 'Correct number of commits' '
7070
(cd "$git" && git log --oneline) >log &&
7171
wc -l log &&
7272
test_line_count = 43 log
7373
'
7474

75-
test_expect_failure 'Previous version of file.txt is correct' '
75+
test_expect_success 'Previous version of file.txt is correct' '
7676
(cd "$git" && git checkout HEAD^^) &&
7777
echo 53 >expected &&
7878
test_cmp expected "$git/file.txt"
@@ -102,7 +102,7 @@ test_expect_success 'Add some more files' '
102102

103103
# This should pick up the 10 new files in "included", but not be confused
104104
# by the additional files in "excluded"
105-
test_expect_failure 'Syncing files' '
105+
test_expect_success 'Syncing files' '
106106
(
107107
cd "$git" &&
108108
git p4 sync --changes-block-size=7 &&

0 commit comments

Comments
 (0)