Files
ToastyFS/examples/example_large.c
T
Claude b0cc529773 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
2026-02-21 22:31:33 +00:00

106 lines
3.1 KiB
C

/*
* example_large.c - Test with data larger than CHUNK_SIZE (32 bytes).
*
* This tests multi-chunk PUT/GET to expose potential bugs in
* chunk transfer logic.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <toastyfs.h>
static const char *error_name(ToastyFS_Error e)
{
switch (e) {
case TOASTYFS_ERROR_VOID: return "OK";
case TOASTYFS_ERROR_OUT_OF_MEMORY: return "OUT_OF_MEMORY";
case TOASTYFS_ERROR_UNEXPECTED_MESSAGE: return "UNEXPECTED_MESSAGE";
case TOASTYFS_ERROR_REJECTED: return "REJECTED";
case TOASTYFS_ERROR_FULL: return "FULL";
case TOASTYFS_ERROR_NOT_FOUND: return "NOT_FOUND";
case TOASTYFS_ERROR_TRANSFER_FAILED: return "TRANSFER_FAILED";
}
return "UNKNOWN";
}
int main(void)
{
char addr1[] = "127.0.0.1:8081";
char addr2[] = "127.0.0.1:8082";
char addr3[] = "127.0.0.1:8083";
char *addrs[] = { addr1, addr2, addr3 };
printf("Connecting to cluster...\n");
ToastyFS *tfs = toastyfs_init(1, addrs, 3);
if (tfs == NULL) {
fprintf(stderr, "toastyfs_init failed\n");
return 1;
}
ToastyFS_Result res;
int ret;
// Create 100-byte test data (4 chunks: 32+32+32+4)
char data[100];
for (int i = 0; i < 100; i++)
data[i] = 'A' + (i % 26);
char key[] = "testkey";
printf("PUT key=\"%s\" data_len=%d (should be 4 chunks of 32 bytes)\n",
key, (int)sizeof(data));
ret = toastyfs_put(tfs, key, strlen(key), data, sizeof(data), &res);
if (ret < 0) {
fprintf(stderr, "toastyfs_put returned %d\n", ret);
toastyfs_free(tfs);
return 1;
}
printf(" result: %s\n", error_name(res.error));
if (res.error != TOASTYFS_ERROR_VOID) {
fprintf(stderr, "PUT failed: %s\n", error_name(res.error));
toastyfs_free(tfs);
return 1;
}
printf("GET key=\"%s\"\n", key);
ret = toastyfs_get(tfs, key, strlen(key), &res);
if (ret < 0) {
fprintf(stderr, "toastyfs_get returned %d\n", ret);
toastyfs_free(tfs);
return 1;
}
printf(" result: %s\n", error_name(res.error));
if (res.error == TOASTYFS_ERROR_VOID && res.data) {
printf(" size: %d (expected %d)\n", res.size, (int)sizeof(data));
if (res.size != (int)sizeof(data)) {
printf(" FAIL - size mismatch\n");
} else if (memcmp(res.data, data, res.size) == 0) {
printf(" PASS - data matches\n");
} else {
printf(" FAIL - data mismatch!\n");
printf(" First differing byte:\n");
for (int i = 0; i < res.size; i++) {
if (res.data[i] != data[i]) {
printf(" offset %d: got 0x%02x ('%c'), expected 0x%02x ('%c')\n",
i,
(unsigned char)res.data[i], res.data[i],
(unsigned char)data[i], data[i]);
break;
}
}
}
free(res.data);
} else {
printf(" FAIL - error or no data: %s\n", error_name(res.error));
}
printf("Done.\n");
toastyfs_free(tfs);
return 0;
}