Fix GET request returning corrupted data for multi-chunk blobs

Four bugs caused data mismatches between PUT and GET operations:

1. chunk_store_exists() used file_open (O_CREAT) to check if a chunk
   file exists, which created empty files as a side effect. Servers
   would then read from these empty files and return uninitialized
   heap memory as chunk data. Fixed by using file_exists (access())
   instead.

2. Server's process_fetch_chunk checked `ret < 0` after
   chunk_store_read, missing the EOF case (ret == 0) from empty
   files. Changed to `ret <= 0`.

3. begin_transfers() == 0 was used as a completion check in both
   STEP_FETCH_CHUNK and STEP_STORE_CHUNK, but returning 0 only means
   "no new transfers started", not "all done". With concurrent chunk
   transfers, this caused premature completion, leaving in-flight
   transfers to hit UNREACHABLE. Fixed by using
   all_chunk_transfers_completed() instead.

4. choose_store_locations_for_chunk() returned [0, 1] for ALL chunks
   regardless of index, while GET fetches chunk i from servers
   (i+j) % num_servers. This made some chunks unreachable. Fixed by
   using (chunk_idx + j) % num_servers for store locations.

Also added SO_REUSEADDR to the server listen socket so restarting
the cluster doesn't fail with "Couldn't setup TCP listener", and
added a note on mock_access about the simulation mismatch.

https://claude.ai/code/session_01JniNxxDP4NbsDXNGmGNG7H
This commit is contained in:
Claude
2026-02-21 22:31:33 +00:00
parent fa3dc2483b
commit b0cc529773
6 changed files with 126 additions and 20 deletions
+6
View File
@@ -3241,6 +3241,12 @@ int mock_close(int fd)
return 0;
}
// NOTE: mock_access must be implemented for simulation to work correctly.
// chunk_store_exists() uses file_exists() which calls access(). Without a
// working mock_access, the simulation cannot check chunk existence and
// must fall back to file_open (O_CREAT), which creates empty files as a
// side effect and leads to data corruption (servers return uninitialized
// data for chunks they don't actually have).
int mock_access(const char *path, int mode)
{
assert(0); // TODO