Use a single scheduling point for sync

This commit is contained in:
Andrea Mazzoleni 2016-01-31 18:55:09 +01:00
parent d2bad33af8
commit 541665db46
3 changed files with 56 additions and 3 deletions

View file

@ -489,7 +489,7 @@ static void io_write_next_outside(struct snapraid_io* io)
* *
* It must be called inside the lock. * It must be called inside the lock.
*/ */
static void io_write_next_inside(struct snapraid_io* io, unsigned blockcur, int skip, int* writer_error) static void io_write_next_inside(struct snapraid_io* io, block_off_t blockcur, int skip, int* writer_error)
{ {
unsigned i; unsigned i;
@ -537,6 +537,38 @@ void io_write_next(struct snapraid_io* io, unsigned blockcur, int skip, int* wri
#endif #endif
} }
block_off_t io_write_and_read_next(struct snapraid_io* io, block_off_t blockcur, int skip, int* writer_error, void*** buffer)
{
block_off_t blockcur_schedule;
block_off_t blockcur_caller;
io_write_next_outside(io);
blockcur_schedule = io_read_next_outside(io);
/* the synchronization is protected by the io mutex */
pthread_mutex_lock(&io->mutex);
io_write_next_inside(io, blockcur, skip, writer_error);
blockcur_caller = io_read_next_inside(io, blockcur_schedule, buffer);
#ifndef CHECKER
/* without the thread checker unlock before signaling, */
/* this reduces the number of context switches */
pthread_mutex_unlock(&io->mutex);
#endif
/* signal all the workers that there is a new pending task */
pthread_cond_broadcast(&io->write_sched);
pthread_cond_broadcast(&io->read_sched);
#ifdef CHECKER
pthread_mutex_unlock(&io->mutex);
#endif
return blockcur_caller;
}
void io_refresh(struct snapraid_io* io) void io_refresh(struct snapraid_io* io)
{ {
unsigned i; unsigned i;

View file

@ -365,6 +365,14 @@ void io_parity_write(struct snapraid_io* io, unsigned* levcur, unsigned* waiting
*/ */
void io_write_next(struct snapraid_io* io, block_off_t blockcur, int skip, int* writer_error); void io_write_next(struct snapraid_io* io, block_off_t blockcur, int skip, int* writer_error);
/**
* Next write and read position.
*
* It's a combination of io_write_next() and io_read_next() that
* locks only one time the scheduling mutex.
*/
block_off_t io_write_and_read_next(struct snapraid_io* io, block_off_t blockcur, int skip, int* writer_error, void*** buffer);
/** /**
* Refresh the number of cached blocks for all data and parity disks. * Refresh the number of cached blocks for all data and parity disks.
*/ */

View file

@ -686,6 +686,8 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
unsigned l; unsigned l;
unsigned* waiting_map; unsigned* waiting_map;
unsigned waiting_mac; unsigned waiting_mac;
block_off_t blocknext;
void** buffernext;
/* the sync process assumes that all the hashes are correct */ /* the sync process assumes that all the hashes are correct */
/* including the ones from CHG and DELETED blocks */ /* including the ones from CHG and DELETED blocks */
@ -754,6 +756,10 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
if (!state_progress_begin(state, blockstart, blockmax, countmax)) if (!state_progress_begin(state, blockstart, blockmax, countmax))
goto end; goto end;
/* scheduling helper */
buffernext = 0;
blocknext = 0;
while (1) { while (1) {
unsigned failed_count; unsigned failed_count;
int error_on_this_block; int error_on_this_block;
@ -768,7 +774,14 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
int writer_error[IO_WRITER_ERROR_MAX]; int writer_error[IO_WRITER_ERROR_MAX];
/* go to the next block */ /* go to the next block */
blockcur = io_read_next(&io, &buffer); if (buffernext != 0) {
/* if already computed, use it */
buffer = buffernext;
blockcur = blocknext;
} else {
/* otherwise do it now */
blockcur = io_read_next(&io, &buffer);
}
if (blockcur >= blockmax) if (blockcur >= blockmax)
break; break;
@ -1227,7 +1240,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
} }
/* write finished */ /* write finished */
io_write_next(&io, blockcur, !parity_going_to_be_updated, writer_error); blocknext = io_write_and_read_next(&io, blockcur, !parity_going_to_be_updated, writer_error, &buffernext);
/* handle errors reported */ /* handle errors reported */
for (j = 0; j < IO_WRITER_ERROR_MAX; ++j) { for (j = 0; j < IO_WRITER_ERROR_MAX; ++j) {