|
|
|
|
@ -177,6 +177,79 @@ static void quota_commit(struct mf_storage* s, uint64_t group) {
|
|
|
|
|
q.data_len = 0; run(s, group, q.owner, MF_COMMIT, MF_OK); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void check_counts(struct mf_storage* s, uint64_t group, uint64_t owner, uint64_t files, uint64_t directories) { |
|
|
|
|
struct mf_message request = { .command = MF_QUOTA, .kind = MF_REQUEST, .owner = owner, .request_id = ++sequence }, response; |
|
|
|
|
mf_storage_execute(s, group, owner, &request, &response); |
|
|
|
|
EXPECT(response.status == MF_OK && response.data_len == MF_QUOTA_BYTES, "count snapshot response"); |
|
|
|
|
EXPECT(mf_get64(response.data + 24) == files && mf_get64(response.data + 32) == directories, "file/directory counters"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void count_mutation(struct mf_storage* s, uint64_t group, uint64_t owner, const char* path, |
|
|
|
|
const char* target, int command, int status) { |
|
|
|
|
memset(&q, 0, sizeof(q)); q.owner = owner; snprintf(q.path, sizeof(q.path), "%s", path); |
|
|
|
|
if (command != MF_MKDIR) { run(s, group, owner, MF_STAT, MF_OK); memcpy(q.version, r.version, 16); } |
|
|
|
|
if (target) snprintf(q.target, sizeof(q.target), "%s", target); |
|
|
|
|
run(s, group, owner, command, status); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void count_test(const char* directory) { |
|
|
|
|
char root[1200]; snprintf(root, sizeof(root), "%s/counts", directory); |
|
|
|
|
struct mf_storage* s = mf_storage_create(root, 40, 200000); |
|
|
|
|
EXPECT(s && !mf_storage_initialize(s), "count storage startup"); if (!s) return; |
|
|
|
|
check_counts(s, 10, 101, 0, 0); |
|
|
|
|
count_mutation(s, 10, 101, "folder", NULL, MF_MKDIR, MF_OK); |
|
|
|
|
check_counts(s, 20, 101, 0, 1); |
|
|
|
|
mf_storage_execute(s, 10, 101, &q, &r); EXPECT(r.status == MF_OK, "mkdir replay"); |
|
|
|
|
run(s, 10, 101, MF_MKDIR, MF_EXISTS); check_counts(s, 10, 101, 0, 1); |
|
|
|
|
count_mutation(s, 10, 101, "folder/sub", NULL, MF_MKDIR, MF_OK); |
|
|
|
|
check_counts(s, 10, 101, 0, 2); |
|
|
|
|
quota_begin(s, 10, 101, "folder/zero", 0, 61, NULL, MF_OK); |
|
|
|
|
check_counts(s, 10, 101, 0, 2); quota_commit(s, 10); check_counts(s, 10, 101, 1, 2); |
|
|
|
|
uint8_t version[16]; memcpy(version, r.version, 16); |
|
|
|
|
quota_begin(s, 10, 101, "folder/zero", 0, 62, version, MF_OK); quota_commit(s, 10); |
|
|
|
|
memcpy(version, r.version, 16); check_counts(s, 10, 101, 1, 2); |
|
|
|
|
quota_begin(s, 10, 101, "folder/zero", 2, 63, version, MF_OK); quota_commit(s, 10); |
|
|
|
|
mf_storage_execute(s, 10, 101, &q, &r); EXPECT(r.status == MF_OK, "replacement replay"); |
|
|
|
|
check_counts(s, 20, 101, 1, 2); |
|
|
|
|
quota_begin(s, 20, 101, "other", 3, 64, NULL, MF_OK); quota_commit(s, 20); |
|
|
|
|
check_counts(s, 10, 101, 2, 2); check_quota(s, 10, 101, 5, 0, 40); |
|
|
|
|
quota_begin(s, 10, 202, "other-user", 3, 65, NULL, MF_OK); quota_commit(s, 10); |
|
|
|
|
check_counts(s, 10, 101, 2, 2); check_counts(s, 10, 202, 1, 0); |
|
|
|
|
count_mutation(s, 10, 101, "folder", "moved", MF_RENAME, MF_OK); |
|
|
|
|
check_counts(s, 10, 101, 2, 2); |
|
|
|
|
count_mutation(s, 10, 101, "moved", NULL, MF_REMOVE, MF_IO_ERROR); |
|
|
|
|
check_counts(s, 10, 101, 2, 2); |
|
|
|
|
count_mutation(s, 10, 101, "moved/zero", NULL, MF_REMOVE, MF_OK); |
|
|
|
|
mf_storage_execute(s, 10, 101, &q, &r); EXPECT(r.status == MF_OK, "file remove replay"); |
|
|
|
|
check_counts(s, 20, 101, 1, 2); check_quota(s, 20, 101, 3, 0, 40); |
|
|
|
|
count_mutation(s, 10, 101, "moved/sub", NULL, MF_REMOVE, MF_OK); |
|
|
|
|
mf_storage_execute(s, 10, 101, &q, &r); EXPECT(r.status == MF_OK, "directory remove replay"); |
|
|
|
|
check_counts(s, 20, 101, 1, 1); |
|
|
|
|
count_mutation(s, 10, 101, "moved", NULL, MF_REMOVE, MF_OK); check_counts(s, 10, 101, 1, 0); |
|
|
|
|
quota_begin(s, 10, 101, "aborted", 4, 66, NULL, MF_OK); |
|
|
|
|
check_counts(s, 10, 101, 1, 0); run(s, 10, 101, MF_ABORT, MF_OK); check_counts(s, 10, 101, 1, 0); |
|
|
|
|
quota_begin(s, 10, 101, "expired", 4, 67, NULL, MF_OK); |
|
|
|
|
mf_storage_sweep(s, get_time_tb() + 200001); check_counts(s, 20, 101, 1, 0); |
|
|
|
|
// Внешние изменения появляются в статистике только после нового старта, не после мутации/QUOTA.
|
|
|
|
|
char external[1400], folder[1400]; |
|
|
|
|
snprintf(external, sizeof(external), "%s/10/101/external.bin", root); |
|
|
|
|
FILE* file = fopen(external, "wb"); EXPECT(file != NULL, "external file fixture"); |
|
|
|
|
if (file) { fputs("extra", file); fclose(file); } |
|
|
|
|
snprintf(folder, sizeof(folder), "10/101/external-dir"); |
|
|
|
|
struct mf_disk_root disk; EXPECT(!mf_disk_root_open(&disk, root), "external directory fixture root"); |
|
|
|
|
int created = 0; EXPECT(!mf_disk_mkdir(&disk, folder, &created) && created, "mkdir reports creation"); |
|
|
|
|
created = 1; EXPECT(mf_disk_mkdir(&disk, folder, &created) == MF_EXISTS && !created, "existing mkdir reports no creation"); |
|
|
|
|
mf_disk_root_close(&disk); |
|
|
|
|
count_mutation(s, 10, 101, "api-dir", NULL, MF_MKDIR, MF_OK); |
|
|
|
|
check_counts(s, 10, 101, 1, 1); check_quota(s, 20, 101, 3, 0, 40); |
|
|
|
|
quota_begin(s, 10, 101, "api-file", 1, 68, NULL, MF_OK); quota_commit(s, 10); |
|
|
|
|
check_counts(s, 20, 101, 2, 1); check_quota(s, 10, 101, 4, 0, 40); |
|
|
|
|
mf_storage_destroy(s); s = mf_storage_create(root, 40, 200000); |
|
|
|
|
EXPECT(s && !mf_storage_initialize(s), "count restart scan"); if (!s) return; |
|
|
|
|
check_counts(s, 20, 101, 3, 2); check_quota(s, 10, 101, 9, 0, 40); |
|
|
|
|
check_counts(s, 10, 202, 1, 0); mf_storage_destroy(s); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void quota_test(const char* directory) { |
|
|
|
|
char root[1200]; snprintf(root, sizeof(root), "%s/quota", directory); |
|
|
|
|
struct mf_storage* s = mf_storage_create(root, 40, 200000); |
|
|
|
|
@ -273,7 +346,7 @@ int main(void) {
|
|
|
|
|
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); debug_set_category_level(DEBUG_CATEGORY_MEDIA, DEBUG_LEVEL_DEBUG); |
|
|
|
|
char directory[1024] = "/tmp/utun_member_files_XXXXXX"; |
|
|
|
|
if (test_mkdtemp(directory)) return 1; |
|
|
|
|
protocol_test(); storage_test(directory); quota_test(directory); quota_scan_failure_test(directory); worker_test(); |
|
|
|
|
protocol_test(); storage_test(directory); quota_test(directory); count_test(directory); quota_scan_failure_test(directory); worker_test(); |
|
|
|
|
#ifndef _WIN32 |
|
|
|
|
large_offset_test(directory); |
|
|
|
|
#endif |
|
|
|
|
|