Speed up the status command
Some checks failed
Build / build-mac (push) Has been cancelled
Build / build-linux (push) Has been cancelled
Build / build-win (push) Has been cancelled
CodeQL Advanced / Analyze (c-cpp) (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled

This commit is contained in:
Andrea Mazzoleni 2026-02-02 16:32:16 +01:00
parent 4da11411f1
commit 025816d151
9 changed files with 139 additions and 28 deletions

View file

@ -2009,19 +2009,18 @@ static int state_diffscan(struct snapraid_state* state, int is_diff)
no_difference = !total.count_move && !total.count_copy && !total.count_restore
&& !total.count_change && !total.count_remove && !total.count_insert;
int parity_invalid = state->parity_is_invalid;
if (is_diff) {
if (!no_difference) {
msg_status("There are differences!\n");
} else {
msg_status("No differences\n");
}
if (parity_invalid)
if (state->unsynced_blocks != 0)
log_error(EUSER, "The last sync was interrupted. Run it again!\n");
}
if (parity_invalid) {
log_tag("summary:exit:incomplete_sync\n");
if (state->unsynced_blocks != 0) {
log_tag("summary:exit:unsynced\n");
} else if (!no_difference) {
log_tag("summary:exit:diff\n");
} else {
@ -2040,7 +2039,7 @@ static int state_diffscan(struct snapraid_state* state, int is_diff)
return 1;
/* check also for incomplete "sync" */
if (parity_invalid)
if (state->unsynced_blocks != 0)
return 1;
}

View file

@ -181,7 +181,7 @@ void state_init(struct snapraid_state* state)
state->no_conf = 0;
for (i = 0; i < SMART_IGNORE_MAX; ++i)
state->smartignore[i] = 0;
state->parity_is_invalid = 0;
state->unsynced_blocks = 0;
state->thermal_stop_gathering = 0;
state->thermal_ambient_temperature = 0;
state->thermal_highest_temperature = 0;
@ -3129,8 +3129,8 @@ static void state_read_content(struct snapraid_state* state, const char* path, S
log_tag("content_info:block_unsynced:%u\n", count_unsynced);
log_tag("content_info:block_unscrubbed:%u\n", count_unscrubbed);
/* set the parity validity */
state->parity_is_invalid = count_unsynced != 0;
/* store the unsynced_blocks */
state->unsynced_blocks = count_unsynced;
}
struct state_write_thread_context {
@ -4020,8 +4020,8 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc)
log_tag("content_info:block_unsynced:%u\n", count_unsynced);
log_tag("content_info:block_unscrubbed:%u\n", count_unscrubbed);
/* set the parity validity */
state->parity_is_invalid = count_unsynced != 0;
/* store the unsynced_blocks */
state->unsynced_blocks = count_unsynced;
*out_crc = crc;
}

View file

@ -142,7 +142,7 @@ struct snapraid_state {
unsigned besthash; /**< Best hash suggested. */
const char* command; /**< Command running. */
int smartignore[SMART_IGNORE_MAX]; /**< Smart attributes to ignore for all devices. */
int parity_is_invalid; /**< If the parity is invalid, and a sync is needed. */
uint32_t unsynced_blocks; /**< If the parity is invalid, and a sync is needed. */
tommy_list contentlist; /**< List of content files. */
tommy_list disklist; /**< List of all the disks. */

View file

@ -72,7 +72,6 @@ int state_status(struct snapraid_state* state)
uint64_t file_block_count;
uint64_t file_block_free;
block_off_t parity_block_free;
unsigned unsynced_blocks;
unsigned unscrubbed_blocks;
uint64_t all_wasted;
int free_not_zero;
@ -297,7 +296,6 @@ int state_status(struct snapraid_state* state)
bad_last = 0;
count = 0;
rehash = 0;
unsynced_blocks = 0;
unscrubbed_blocks = 0;
log_tag("block_count:%u\n", blockmax);
for (i = 0; i < blockmax; ++i) {
@ -309,19 +307,17 @@ int state_status(struct snapraid_state* state)
/* for each disk */
one_invalid = 0;
one_valid = 0;
for (node_disk = state->disklist; node_disk != 0; node_disk = node_disk->next) {
struct snapraid_disk* disk = node_disk->data;
struct snapraid_block* block = fs_par2block_find(disk, i);
if (block_has_file(block))
one_valid = 1;
if (block_has_invalid_parity(block))
one_invalid = 1;
}
if (state->opt.gui_verbose) { /* avoid this time consuming operation if not needed */
for (node_disk = state->disklist; node_disk != 0; node_disk = node_disk->next) {
struct snapraid_disk* disk = node_disk->data;
struct snapraid_block* block = fs_par2block_find(disk, i);
/* if both valid and invalid, we need to update */
if (one_invalid && one_valid) {
++unsynced_blocks;
if (block_has_file(block))
one_valid = 1;
if (block_has_invalid_parity(block))
one_invalid = 1;
}
}
/* skip unused blocks */
@ -367,7 +363,7 @@ int state_status(struct snapraid_state* state)
}
/* sort the info to get the time info */
qsort(timemap, count, sizeof(time_t), time_compare);
sort_time(timemap, count);
/* output the info map */
i = 0;
@ -477,9 +473,9 @@ int state_status(struct snapraid_state* state)
printf("WARNING! You have scrub dates in the future! The next sync/scrub will truncate them!\n");
}
if (unsynced_blocks) {
if (state->unsynced_blocks) {
printf("WARNING! The array is NOT fully synced.\n");
printf("You have a sync in progress at %u%%.\n", muldiv(blockmax - unsynced_blocks, 100, blockmax));
printf("You have a sync in progress at %u%%.\n", muldiv(blockmax - state->unsynced_blocks, 100, blockmax));
} else {
printf("No sync is in progress.\n");
}
@ -573,7 +569,7 @@ int state_status(struct snapraid_state* state)
if (bad)
log_tag("summary:exit:bad\n");
else if (unsynced_blocks)
else if (state->unsynced_blocks != 0)
log_tag("summary:exit:unsynced\n");
else
log_tag("summary:exit:ok\n");

View file

@ -854,3 +854,99 @@ unsigned muldiv_upper(uint64_t v, uint64_t mul, uint64_t div)
return (uint32_t)((v * mul + div - 1) / div);
}
/****************************************************************************/
/* sort */
/**
* Three-way partition for quicksort
* Partitions array into three parts: < pivot, == pivot, > pivot
* Returns the boundaries of the equal section via lt and gt pointers
*/
static void partition3way(time_t *arr, size_t left, size_t right, size_t *lt, size_t *gt)
{
/* choose median-of-three as pivot to avoid worst case on sorted data */
size_t mid = left + (right - left) / 2;
time_t pivot;
/* sort left, mid, right and use median as pivot */
if (arr[left] > arr[mid]) {
uint64_t tmp = arr[left]; arr[left] = arr[mid]; arr[mid] = tmp;
}
if (arr[mid] > arr[right]) {
uint64_t tmp = arr[mid]; arr[mid] = arr[right]; arr[right] = tmp;
if (arr[left] > arr[mid]) {
tmp = arr[left]; arr[left] = arr[mid]; arr[mid] = tmp;
}
}
pivot = arr[mid];
// Dutch National Flag partition
size_t i = left;
size_t lt_idx = left;
size_t gt_idx = right;
while (i <= gt_idx) {
if (arr[i] < pivot) {
uint64_t tmp = arr[lt_idx];
arr[lt_idx] = arr[i];
arr[i] = tmp;
lt_idx++;
i++;
} else if (arr[i] > pivot) {
uint64_t tmp = arr[i];
arr[i] = arr[gt_idx];
arr[gt_idx] = tmp;
gt_idx--;
} else {
i++;
}
}
*lt = lt_idx;
*gt = gt_idx;
}
/**
* Recursive three-way quicksort
*/
static void quicksort3way_recursive(time_t *arr, size_t left, size_t right)
{
if (left >= right)
return;
/* use insertion sort for small subarrays (optimization) */
if (right - left < 16) {
for (size_t i = left + 1; i <= right; i++) {
time_t key = arr[i];
size_t j = i;
while (j > left && arr[j - 1] > key) {
arr[j] = arr[j - 1];
j--;
}
arr[j] = key;
}
return;
}
size_t lt, gt;
partition3way(arr, left, right, &lt, &gt);
/*
* Recursively sort elements less than and greater than pivot
* Elements equal to pivot are already in correct position
*/
if (lt > left) {
quicksort3way_recursive(arr, left, lt - 1);
}
if (gt < right) {
quicksort3way_recursive(arr, gt + 1, right);
}
}
void sort_time(time_t *arr, size_t n)
{
if (n <= 1)
return;
quicksort3way_recursive(arr, 0, n - 1);
}

View file

@ -273,5 +273,17 @@ static inline int bit_vect_test(bit_vect_t* bit_vect, size_t off)
unsigned muldiv(uint64_t v, uint64_t mul, uint64_t div);
unsigned muldiv_upper(uint64_t v, uint64_t mul, uint64_t div);
/****************************************************************************/
/* sort */
/**
* Sort an array of uint64_t integers in-place
* Optimized for arrays with many duplicate values
*
* @param arr Pointer to array of uint64_t
* @param n Number of elements in the array
*/
void sort_time(time_t* arr, size_t n);
#endif

View file

@ -484,6 +484,10 @@ The array is already synchronized.
.I diff
Indicates that differences were found.
The array needs a \`sync\` operation.
.HP 4
.I unsynced
The array has an interrupted sync.
The array needs another \`sync\` operation.
.PD
.RE
.SH GENERAL PROGRESS AND EXECUTION TAGS

View file

@ -330,6 +330,8 @@ Scan Tags
The array is already synchronized.
diff - Indicates that differences were found.
The array needs a `sync` operation.
unsynced - The array has an interrupted sync.
The array needs another `sync` operation.
General Progress and Execution Tags
These tags are used to report the runtime processing of the commands

View file

@ -346,6 +346,8 @@ These tags provide a final count of all detected changes.
The array is already synchronized.
diff - Indicates that differences were found.
The array needs a `sync` operation.
unsynced - The array has an interrupted sync.
The array needs another `sync` operation.
6 GENERAL PROGRESS AND EXECUTION TAGS