Reallocates files after a failed sync.

This commit is contained in:
Andrea Mazzoleni 2013-12-24 21:46:27 +01:00
parent e55723ecdd
commit bbe151792c
3 changed files with 70 additions and 4 deletions

View file

@ -9,6 +9,9 @@ SnapRAID HISTORY
positive when searching for inode/timestamp/size.
* Allow to run a fix command with disks that doesn't need to be
fixed mounted as read-only.
* After a failed sync, always reallocates new files with a not
yet computed parity to ensure to minimize the parity usage,
if some other file is deleted in the meantime.
* Doesn't count empty dirs as files in the diff counters.
* Added a new "share" configuration option to allow to share
in the network the pool directory also in Windows.

2
elem.h
View file

@ -70,8 +70,6 @@ struct snapraid_filter {
/**
* The block has both the hash and the parity computed.
* This is the normal state of a saved block.
* Note that if exists at least one BLOCK_STATE_BLK in a disk, all the other
* blocks at the same address in other disks can be only BLOCK_STATE_EMPTY or BLOCK_STATE_BLK.
*
* The block hash field IS set.
* The parity for this disk is updated.

69
scan.c
View file

@ -140,9 +140,9 @@ static void scan_link(struct snapraid_scan* scan, struct snapraid_state* state,
}
/**
* Removes the specified file from the data set.
* Removes the specified file from the parity.
*/
static void scan_file_remove(struct snapraid_state* state, struct snapraid_disk* disk, struct snapraid_file* file)
static void scan_file_deallocate(struct snapraid_state* state, struct snapraid_disk* disk, struct snapraid_file* file)
{
block_off_t i;
@ -202,6 +202,65 @@ static void scan_file_remove(struct snapraid_state* state, struct snapraid_disk*
/* set the deleted block in the block array */
tommy_arrayblk_set(&disk->blockarr, block_pos, &deleted->block);
}
}
/**
* Checks if a file is completely formed of NEW or CHG blocks,
* and if it has at least one block.
*/
static int file_is_full_invalid(struct snapraid_file* file)
{
block_off_t i;
/* if no block, the file is valid */
if (file->blockmax == 0)
return 0;
/* check all blocks */
/* it should be enough to check only the first one */
/* because updates are always in forward direction, */
/* but we check all just to be sure */
for(i=0;i<file->blockmax;++i) {
struct snapraid_block* block = &file->blockvec[i];
unsigned block_state;
block_state = block_state_get(block);
if (block_state != BLOCK_STATE_NEW && block_state != BLOCK_STATE_CHG)
return 0;
}
return 1;
}
/**
* Keeps the file as it's (or with only a name/inode modification).
* If a file contains only NEW blocks, it's reallocated to ensure
* to always minimize the space used in the parity.
* This could happen after a failed sync, when some other file is deleted,
* and then new ones can be moved to fill the hole created.
*/
static void scan_file_keep(struct snapraid_scan* scan, struct snapraid_state* state, struct snapraid_disk* disk, struct snapraid_file* file)
{
if (file_is_full_invalid(file)) {
/* deallocate the file from the parity */
scan_file_deallocate(state, disk, file);
/* remove the file from the list */
tommy_list_remove_existing(&disk->filelist, &file->nodelist);
/* insert the file in the delayed block allocation */
tommy_list_insert_tail(&scan->file_insert_list, &file->nodelist, file);
}
}
/**
* Removes the specified file from the data set.
*/
static void scan_file_remove(struct snapraid_state* state, struct snapraid_disk* disk, struct snapraid_file* file)
{
/* deallocate the file from the parity */
scan_file_deallocate(state, disk, file);
/* remove the file from the file containers */
if (!file_flag_has(file, FILE_IS_WITHOUT_INODE)) {
@ -391,6 +450,9 @@ static void scan_file(struct snapraid_scan* scan, struct snapraid_state* state,
}
}
/* mark the file as kept */
scan_file_keep(scan, state, disk, file);
/* nothing more to do */
return;
}
@ -514,6 +576,9 @@ static void scan_file(struct snapraid_scan* scan, struct snapraid_state* state,
}
}
/* mark the file as kept */
scan_file_keep(scan, state, disk, file);
/* nothing more to do */
return;
}