Process content info values in contiguous runs

This commit is contained in:
Andrea Mazzoleni 2026-09-10 00:08:58 +02:00
parent 62ef259edc
commit e45e467b1a
3 changed files with 125 additions and 19 deletions

View file

@ -1395,6 +1395,80 @@ static inline snapraid_info info_get(tommy_arrayblkof* array, block_off_t pos)
return info;
}
/**
* Set a run of info values.
*
* Grow the array once and process each internal block directly, avoiding the
* per-position grow and lookup performed by info_set().
*/
static inline void info_set_run(tommy_arrayblkof* array, block_off_t pos, block_off_t count, snapraid_info info)
{
tommy_arrayblkof_grow(array, pos + count);
while (count) {
block_off_t offset = pos % TOMMY_ARRAYBLKOF_SIZE;
block_off_t run = TOMMY_ARRAYBLKOF_SIZE - offset;
snapraid_info* data;
block_off_t i;
if (run > count)
run = count;
data = tommy_arrayblkof_ref(array, pos);
for (i = 0; i < run; ++i)
data[i] = info;
pos += run;
count -= run;
}
}
/**
* Get the value and length of an info run, up to count positions.
*
* Unallocated positions have the same zero value returned by info_get().
* Process allocated storage a block at a time to avoid resolving every array
* position independently.
*/
static inline block_off_t info_get_run(tommy_arrayblkof* array, block_off_t pos, block_off_t count, snapraid_info* info)
{
block_off_t size = tommy_arrayblkof_size(array);
block_off_t total = 0;
if (pos >= size) {
*info = 0;
return count;
}
memcpy(info, tommy_arrayblkof_ref(array, pos), sizeof(snapraid_info));
while (total < count && pos + total < size) {
block_off_t current = pos + total;
block_off_t offset = current % TOMMY_ARRAYBLKOF_SIZE;
block_off_t run = TOMMY_ARRAYBLKOF_SIZE - offset;
snapraid_info* data;
block_off_t i;
if (run > count - total)
run = count - total;
if (run > size - current)
run = size - current;
data = tommy_arrayblkof_ref(array, current);
for (i = 0; i < run; ++i)
if (data[i] != *info)
return total + i;
total += run;
}
/* info_get() returns zero for the whole unallocated tail */
if (total < count && *info == 0)
return count;
return total;
}
/****************************************************************************/
/* bucket */

View file

@ -600,6 +600,50 @@ bail:
/* LCOV_EXCL_STOP */
}
static void test_info_run(void)
{
tommy_arrayblkof array;
const block_off_t start = TOMMY_ARRAYBLKOF_SIZE - 2;
const block_off_t count = TOMMY_ARRAYBLKOF_SIZE + 4;
const snapraid_info first = 0x100;
const snapraid_info second = 0x200;
snapraid_info info;
tommy_arrayblkof_init(&array, sizeof(snapraid_info));
/* check an entirely unallocated zero run */
if (info_get_run(&array, 0, count, &info) != count || info != 0)
goto bail;
/* cross two internal array block boundaries */
info_set_run(&array, start, count, first);
if (info_get_run(&array, 0, start + count, &info) != start || info != 0)
goto bail;
if (info_get_run(&array, start, count + 1, &info) != count || info != first)
goto bail;
if (info_get_run(&array, start + count, count, &info) != count || info != 0)
goto bail;
/* split the first run without changing the allocated size */
info_set_run(&array, start + 100, 10, second);
if (info_get_run(&array, start, count, &info) != 100 || info != first)
goto bail;
if (info_get_run(&array, start + 100, count, &info) != 10 || info != second)
goto bail;
if (info_get_run(&array, start + 110, count, &info) != count - 110 || info != first)
goto bail;
tommy_arrayblkof_done(&array);
return;
bail:
/* LCOV_EXCL_START */
tommy_arrayblkof_done(&array);
log_fatal(EINTERNAL, "Failed info run test\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
struct {
const char* pattern;
const char* text;
@ -2492,6 +2536,7 @@ void selftest(void)
/* tommyds data structures (hash tables, lists, search, sort) */
test_tommy();
test_info_run();
/* cauchy raid module self-test */
raid_mode(RAID_MODE_CAUCHY_RAID);

View file

@ -2772,14 +2772,9 @@ static void state_read_content(struct snapraid_state* state, const char* path, S
bucket_insert(&bucket_hash, t64 + v_oldest, v_count, justsynced);
while (v_count) {
/* insert the info in the array */
info_set(&state->infoarr, v_pos, info);
/* go to next block */
++v_pos;
--v_count;
}
/* insert the complete run in the info array */
info_set_run(&state->infoarr, v_pos, v_count, info);
v_pos += v_count;
} else {
while (v_count) {
/* ensure that an info is present only for used positions */
@ -4405,17 +4400,9 @@ static void* state_write_thread(void* arg)
time_t t;
unsigned flag;
info = info_get(&state->infoarr, begin);
/* find the end of run of blocks */
end = begin + 1;
while (end < blockmax
&& info == info_get(&state->infoarr, end)
) {
++end;
}
count = end - begin;
/* find the complete run without resolving each array position */
count = info_get_run(&state->infoarr, begin, blockmax - begin, &info);
end = begin + count;
sputb64(count, f);
/* if there is info */