git-remote-testgit: fix race when spawning fast-import
Test "pushing to local repo" in t5800-remote-helpers can hang due to a race condition in git-remote-testgit. Fix it by setting stdin to unbuffered. On the writer side, "git push" invokes push_refs_with_export(), which sends to stdout the command "export\n" and immediately starts up "git fast-export". The latter writes its output stream to the same stdout. On the reader side, remote helper "git-remote-testgit" reads from stdin to get its next command. It uses getc() to read characters from libc up until \n. Libc has buffered a potentially much larger chunk of stdin. When it sees the "export\n" command, it forks "git fast-import" to read the stream. If fast-export finishes before git fast-import starts, the fast-export output can end up in libc's buffer in git-remote-testgit, rather than in git fast-import. The latter hangs indefinitely on a now-empty stdin. Signed-off-by: Pete Wyckoff <pw@padd.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									fdec2eb8eb
								
							
						
					
					
						commit
						7fb8e163bd
					
				|  | @ -22,6 +22,7 @@ except ImportError: | ||||||
|     _digest = sha.new |     _digest = sha.new | ||||||
| import sys | import sys | ||||||
| import os | import os | ||||||
|  | import time | ||||||
| sys.path.insert(0, os.getenv("GITPYTHONLIB",".")) | sys.path.insert(0, os.getenv("GITPYTHONLIB",".")) | ||||||
|  |  | ||||||
| from git_remote_helpers.util import die, debug, warn | from git_remote_helpers.util import die, debug, warn | ||||||
|  | @ -204,6 +205,11 @@ def read_one_line(repo): | ||||||
|     """Reads and processes one command. |     """Reads and processes one command. | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|  |     sleepy = os.environ.get("GIT_REMOTE_TESTGIT_SLEEPY") | ||||||
|  |     if sleepy: | ||||||
|  |         debug("Sleeping %d sec before readline" % int(sleepy)) | ||||||
|  |         time.sleep(int(sleepy)) | ||||||
|  |  | ||||||
|     line = sys.stdin.readline() |     line = sys.stdin.readline() | ||||||
|  |  | ||||||
|     cmdline = line |     cmdline = line | ||||||
|  | @ -258,6 +264,7 @@ def main(args): | ||||||
|  |  | ||||||
|     more = True |     more = True | ||||||
|  |  | ||||||
|  |     sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0) | ||||||
|     while (more): |     while (more): | ||||||
|         more = read_one_line(repo) |         more = read_one_line(repo) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -72,6 +72,19 @@ test_expect_success 'pushing to local repo' ' | ||||||
| 	compare_refs localclone HEAD server HEAD | 	compare_refs localclone HEAD server HEAD | ||||||
| ' | ' | ||||||
|  |  | ||||||
|  | # Generally, skip this test.  It demonstrates a now-fixed race in | ||||||
|  | # git-remote-testgit, but is too slow to leave in for general use. | ||||||
|  | : test_expect_success 'racily pushing to local repo' ' | ||||||
|  | 	test_when_finished "rm -rf server2 localclone2" && | ||||||
|  | 	cp -a server server2 && | ||||||
|  | 	git clone "testgit::${PWD}/server2" localclone2 && | ||||||
|  | 	(cd localclone2 && | ||||||
|  | 	echo content >>file && | ||||||
|  | 	git commit -a -m three && | ||||||
|  | 	GIT_REMOTE_TESTGIT_SLEEPY=2 git push) && | ||||||
|  | 	compare_refs localclone2 HEAD server2 HEAD | ||||||
|  | ' | ||||||
|  |  | ||||||
| test_expect_success 'synch with changes from localclone' ' | test_expect_success 'synch with changes from localclone' ' | ||||||
| 	(cd clone && | 	(cd clone && | ||||||
| 	 git pull) | 	 git pull) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Pete Wyckoff
						Pete Wyckoff