work.t.hh (fstransform-0.9.3-src) | : | work.t.hh (fstransform-0.9.4) | ||
---|---|---|---|---|
skipping to change at line 65 | skipping to change at line 65 | |||
FC_FREE_SPACE = FT_IO_NS fr_io_posix::FC_FREE_SPACE, | FC_FREE_SPACE = FT_IO_NS fr_io_posix::FC_FREE_SPACE, | |||
FC_STORAGE = FT_IO_NS fr_io_posix::FC_STORAGE, | FC_STORAGE = FT_IO_NS fr_io_posix::FC_STORAGE, | |||
FC_PRIMARY_STORAGE = FT_IO_NS fr_io_posix::FC_PRIMARY_STORAGE, | FC_PRIMARY_STORAGE = FT_IO_NS fr_io_posix::FC_PRIMARY_STORAGE, | |||
FC_SECONDARY_STORAGE = FT_IO_NS fr_io_posix::FC_SECONDARY_STORAGE, | FC_SECONDARY_STORAGE = FT_IO_NS fr_io_posix::FC_SECONDARY_STORAGE, | |||
}; | }; | |||
char const* const* const label = FT_IO_NS fr_io_posix::label; | char const* const* const label = FT_IO_NS fr_io_posix::label; | |||
char const* const label_LOOP_HOLES = "loop-holes"; | char const* const label_LOOP_HOLES = "loop-holes"; | |||
template<typename T> | ||||
void fr_work<T>::show(const char * label1, const char * label2, ft_uoff effectiv | ||||
e_block_size, | ||||
const fr_map<T> & map, ft_log_level level) | ||||
{ | ||||
ft_log_level header_level = level >= FC_DEBUG ? level : (ft_log_level)(level | ||||
+ 1); | ||||
if (!ff_log_is_enabled(header_level) && !ff_log_is_enabled(level)) | ||||
return; | ||||
map_const_iterator iter = map.begin(), end = map.end(); | ||||
ft_size n = map.size(); | ||||
if (iter != end) { | ||||
ff_log(header_level, 0, "# %4"FT_ULL" extent%s in %s%s", | ||||
(ft_ull) n, (n == 1 ? " " : "s"), label1, label2); | ||||
if (ff_log_is_enabled(level)) { | ||||
ff_log(level, 0, "# effective block size = %"FT_ULL, (ft_ull) effect | ||||
ive_block_size); | ||||
show(level); | ||||
for (ft_size i = 0; iter != end; ++iter, ++i) | ||||
show(i, *iter, level); | ||||
} | ||||
} else { | ||||
ff_log(header_level, 0, "# no extents in %s%s", label1, label2); | ||||
} | ||||
ff_log(level, 0, ""); | ||||
} | ||||
/** print extents header to log */ | ||||
template<typename T> | ||||
void fr_work<T>::show(ft_log_level level) | ||||
{ | ||||
ff_log(level, 0, "# extent physical logical length use | ||||
r_data"); | ||||
} | ||||
/** print extent contents to log */ | ||||
template<typename T> | ||||
void fr_work<T>::show(ft_size i, T physical, T logical, T length, ft_size user_d | ||||
ata, ft_log_level level) | ||||
{ | ||||
ff_log(level, 0, "#%8"FT_ULL"\t%12"FT_ULL"\t%12"FT_ULL"\t%8"FT_ULL"\t(%"FT_U | ||||
LL")", (ft_ull)i, | ||||
(ft_ull) physical, (ft_ull) logical, (ft_ull) length, (ft_ull) user_d | ||||
ata); | ||||
} | ||||
/** default constructor */ | /** default constructor */ | |||
template<typename T> | template<typename T> | |||
fr_work<T>::fr_work() | fr_work<T>::fr_work() | |||
: dev_map(), storage_map(), dev_free(), dev_transpose(), | : dev_map(), storage_map(), dev_free(), dev_transpose(), | |||
storage_free(), storage_transpose(), toclear_map(), | storage_free(), storage_transpose(), toclear_map(), | |||
eta(), work_total(0) | io(NULL), eta(), work_total(0) | |||
{ } | { } | |||
#ifdef FT_HAVE_EXTERNAL_TEMPLATE | #ifdef FT_HAVE_EXTERNAL_TEMPLATE | |||
/** | /** | |||
* copy constructor CANNOT be invoked, | * copy constructor CANNOT be invoked, | |||
* but some C++ compilers need it to be defined | * but some C++ compilers need it to be defined | |||
* if explicit template instantiation is used | * if explicit template instantiation is used | |||
*/ | */ | |||
template<typename T> | template<typename T> | |||
fr_work<T>::fr_work(const fr_work<T> & other) | fr_work<T>::fr_work(const fr_work<T> & other) | |||
skipping to change at line 165 | skipping to change at line 121 | |||
eta.clear(); | eta.clear(); | |||
work_total = 0; | work_total = 0; | |||
} | } | |||
/** | /** | |||
* high-level do-everything method. calls in sequence init(), run() and cleanup( ). | * high-level do-everything method. calls in sequence init(), run() and cleanup( ). | |||
* return 0 if success, else error. | * return 0 if success, else error. | |||
*/ | */ | |||
template<typename T> | template<typename T> | |||
int fr_work<T>::main(fr_vector<ft_uoff> & loop_file_extents, | int fr_work<T>::main(fr_vector<ft_uoff> & loop_file_extents, | |||
fr_vector<ft_uoff> & free_space_extents, FT_IO_NS fr_io & i | fr_vector<ft_uoff> & free_space_extents, | |||
o) | fr_vector<ft_uoff> & to_zero_extents, | |||
FT_IO_NS fr_io & io) | ||||
{ | { | |||
fr_work<T> worker; | fr_work<T> worker; | |||
return worker.run(loop_file_extents, free_space_extents, io); | return worker.run(loop_file_extents, free_space_extents, to_zero_extents, io ); | |||
// worker.cleanup() is called automatically by destructor, no need to call e xplicitly | // worker.cleanup() is called automatically by destructor, no need to call e xplicitly | |||
} | } | |||
/** full remapping algorithm */ | /** full remapping algorithm */ | |||
template<typename T> | template<typename T> | |||
int fr_work<T>::run(fr_vector<ft_uoff> & loop_file_extents, | int fr_work<T>::run(fr_vector<ft_uoff> & loop_file_extents, | |||
fr_vector<ft_uoff> & free_space_extents, FT_IO_NS fr_io & io | fr_vector<ft_uoff> & free_space_extents, | |||
) | fr_vector<ft_uoff> & to_zero_extents, | |||
FT_IO_NS fr_io & io) | ||||
{ | { | |||
int err; | int err; | |||
(err = init(io)) == 0 | if ((err = init(io)) == 0 | |||
&& (err = analyze(loop_file_extents, free_space_extents)) == 0 | && (err = analyze(loop_file_extents, free_space_extents, to_zero_extents | |||
)) == 0 | ||||
&& (err = create_storage()) == 0 | && (err = create_storage()) == 0 | |||
&& (err = start_ui()) == 0 | && (err = start_ui()) == 0 | |||
&& (err = relocate()) == 0 | && (err = relocate()) == 0 | |||
&& (err = clear_free_space()) == 0 | && (err = clear_free_space()) == 0 | |||
&& (err = close_storage_after_success()) == 0; | && (err = close_storage_after_success()) == 0) | |||
{ } | ||||
if (err == 0) { | if (err == 0) { | |||
ff_log(FC_NOTICE, 0, "%sjob completed.", io.simulate_run() ? "(simulated ) " : ""); | ff_log(FC_NOTICE, 0, "%sjob completed.", io.simulate_run() ? "(simulated ) " : ""); | |||
} else if (!ff_log_is_reported(err)) { | } else if (!ff_log_is_reported(err)) { | |||
/* | /* | |||
* note 1.2.2) fr_remap.main() and other high-level *.main() methods | * note 1.2.2) fr_remap.main() and other high-level *.main() methods | |||
* must check for unreported errors and log them them with message | * must check for unreported errors and log them them with message | |||
* "failed with unreported error" | * "failed with unreported error" | |||
*/ | */ | |||
skipping to change at line 304 | skipping to change at line 265 | |||
* assumes that vectors are ordered by extent->logical, and modifies them | * assumes that vectors are ordered by extent->logical, and modifies them | |||
* in place: vector contents will be UNDEFINED when this method returns. | * in place: vector contents will be UNDEFINED when this method returns. | |||
* | * | |||
* basic implementation idea: to compute this->dev_map, performs in-place the un ion of specified | * basic implementation idea: to compute this->dev_map, performs in-place the un ion of specified | |||
* loop_file_extents and free_space_extents, then sorts in-place and complements such union. | * loop_file_extents and free_space_extents, then sorts in-place and complements such union. | |||
* | * | |||
* detailed implementation is quite complicated... see the comments and the docu mentation | * detailed implementation is quite complicated... see the comments and the docu mentation | |||
*/ | */ | |||
template<typename T> | template<typename T> | |||
int fr_work<T>::analyze(fr_vector<ft_uoff> & loop_file_extents, | int fr_work<T>::analyze(fr_vector<ft_uoff> & loop_file_extents, | |||
fr_vector<ft_uoff> & free_space_extents) | fr_vector<ft_uoff> & free_space_extents, | |||
fr_vector<ft_uoff> & to_zero_extents) | ||||
{ | { | |||
// cleanup in case dev_map, storage_map or storage_map are not empty, or wor k_count != 0 | // cleanup in case dev_map, storage_map or storage_map are not empty, or wor k_count != 0 | |||
cleanup(); | cleanup(); | |||
map_type loop_map, loop_holes_map, renumbered_map; | map_type loop_map, loop_holes_map, renumbered_map; | |||
ft_uoff eff_block_size_log2 = io->effective_block_size_log2(); | ft_uoff eff_block_size_log2 = io->effective_block_size_log2(); | |||
ft_uoff eff_block_size = (ft_uoff)1 << eff_block_size_log2; | ft_uoff eff_block_size = (ft_uoff)1 << eff_block_size_log2; | |||
ft_uoff dev_length = io->dev_length(); | ft_uoff dev_length = io->dev_length(); | |||
/* | /* | |||
* algorithm: 1) find LOOP-FILE (logical) holes, i.e. LOOP-HOLES, | * algorithm: 1) find LOOP-FILE (logical) holes, i.e. LOOP-HOLES, | |||
* and store them in loop_holes_map | * and store them in loop_holes_map | |||
* note: all complement maps have physical == logical | * note: all complement maps have physical == logical | |||
*/ | */ | |||
loop_holes_map.complement0_logical_shift(loop_file_extents, eff_block_size_l og2, dev_length); | loop_holes_map.complement0_logical_shift(loop_file_extents, eff_block_size_l og2, dev_length); | |||
if (io->job_clear() == FC_CLEAR_ALL) | if (io->job_clear() == FC_CLEAR_ALL) | |||
toclear_map = loop_holes_map; | toclear_map = loop_holes_map; | |||
// merge to_zero_extents into toclear_map | ||||
toclear_map.merge_shift(to_zero_extents, eff_block_size_log2, FC_PHYSICAL1); | ||||
/* algorithm: 0) compute LOOP-FILE extents and store in loop_map, sorted by physical */ | /* algorithm: 0) compute LOOP-FILE extents and store in loop_map, sorted by physical */ | |||
loop_file_extents.sort_by_physical(); | loop_file_extents.sort_by_physical(); | |||
loop_map.append0_shift(loop_file_extents, eff_block_size_log2); | loop_map.append0_shift(loop_file_extents, eff_block_size_log2); | |||
/* show LOOP-FILE extents sorted by physical */ | /* show LOOP-FILE extents sorted by physical */ | |||
show(label[FC_LOOP_FILE], "", eff_block_size, loop_map); | loop_map.show(label[FC_LOOP_FILE], "", eff_block_size); | |||
/* algorithm: 0) compute FREE-SPACE extents and store in dev_free, sorted by physical | /* algorithm: 0) compute FREE-SPACE extents and store in dev_free, sorted by physical | |||
* | * | |||
* we must manually set ->logical = ->physical for all free_space_extents: | * we must manually set ->logical = ->physical for all free_space_extents: | |||
* here dev_free is just free space, but for I/O that computed it | * here dev_free is just free space, but for I/O that computed it | |||
* it could have been a ZERO-FILE with its own ->logical, | * it could have been a ZERO-FILE with its own ->logical, | |||
* | * | |||
* note: changing ->logical may also allow merging extents! | * note: changing ->logical may also allow merging extents! | |||
*/ | */ | |||
{ | { | |||
skipping to change at line 351 | skipping to change at line 316 | |||
physical = iter->first.physical >> eff_block_size_log2; | physical = iter->first.physical >> eff_block_size_log2; | |||
length = iter->second.length >> eff_block_size_log2; | length = iter->second.length >> eff_block_size_log2; | |||
dev_free.insert(physical, physical, length, FC_DEFAULT_USER_DATA); | dev_free.insert(physical, physical, length, FC_DEFAULT_USER_DATA); | |||
} | } | |||
} | } | |||
/* sanity check: LOOP-FILE and FREE-SPACE extents ->physical must NOT inters ect */ | /* sanity check: LOOP-FILE and FREE-SPACE extents ->physical must NOT inters ect */ | |||
renumbered_map.intersect_all_all(loop_map, dev_free, FC_PHYSICAL1); | renumbered_map.intersect_all_all(loop_map, dev_free, FC_PHYSICAL1); | |||
if (!renumbered_map.empty()) { | if (!renumbered_map.empty()) { | |||
ff_log(FC_FATAL, 0, "inconsistent %s and %s: they share common blocks on %s !", label[FC_LOOP_FILE], label[FC_FREE_SPACE], label[FC_DEVICE]); | ff_log(FC_FATAL, 0, "inconsistent %s and %s: they share common blocks on %s !", label[FC_LOOP_FILE], label[FC_FREE_SPACE], label[FC_DEVICE]); | |||
show(label[FC_LOOP_FILE], " intersection with free-space", eff_block_siz e, renumbered_map, FC_DEBUG); | renumbered_map.show(label[FC_LOOP_FILE], " intersection with free-space" , eff_block_size, FC_DEBUG); | |||
return -EFAULT; | return -EFAULT; | |||
} | } | |||
/* | /* | |||
* move from LOOP-FILE to DEV-FREE and to TO-CLEAR-MAP | * move from LOOP-FILE to DEV-FREE and to TO-CLEAR-MAP | |||
* the (physical) extents in LOOP-FILE that are full with zeros (UNWRITTEN). | * the (physical) extents in LOOP-FILE that are full with zeros (UNWRITTEN). | |||
* | * | |||
* this converts FC_EXTENT_ZEROED extents into free extents, | * this converts FC_EXTENT_ZEROED extents into free extents, | |||
* and will also mark them to be cleared after relocate() finishes. | * and will also mark them to be cleared after relocate() finishes. | |||
*/ | */ | |||
skipping to change at line 380 | skipping to change at line 345 | |||
/* extent must be inserted in toclear_map even if io->job_clear( ) == FC_CLEAR_ALL */ | /* extent must be inserted in toclear_map even if io->job_clear( ) == FC_CLEAR_ALL */ | |||
toclear_map.insert(physical, physical, length, FC_DEFAULT_USER_D ATA); | toclear_map.insert(physical, physical, length, FC_DEFAULT_USER_D ATA); | |||
dev_free.insert(physical, physical, length, FC_DEFAULT_USER_DATA ); | dev_free.insert(physical, physical, length, FC_DEFAULT_USER_DATA ); | |||
tmp = iter; | tmp = iter; | |||
++iter; | ++iter; | |||
loop_map.remove(tmp); | loop_map.remove(tmp); | |||
} else | } else | |||
++iter; | ++iter; | |||
} | } | |||
} | } | |||
show("to-clear", " (initial)", eff_block_size, toclear_map, FC_DEBUG); | toclear_map.show("to-clear", " (initial)", eff_block_size, FC_DEBUG); | |||
show(label[FC_FREE_SPACE], " (after to-clear)", eff_block_size, dev_free); | dev_free.show(label[FC_FREE_SPACE], " (after to-clear)", eff_block_size); | |||
/* algorithm: 0) compute DEVICE extents | /* algorithm: 0) compute DEVICE extents | |||
* | * | |||
* how: compute physical complement of all LOOP-FILE and FREE-SPACE extents | * how: compute physical complement of all LOOP-FILE and FREE-SPACE extents | |||
* and assume they are used by DEVICE for its file-system | * and assume they are used by DEVICE for its file-system | |||
*/ | */ | |||
/* compute in-place the union of LOOP-FILE extents and FREE-SPACE extents */ | /* compute in-place the union of LOOP-FILE extents and FREE-SPACE extents */ | |||
loop_file_extents.append_all(free_space_extents); | loop_file_extents.append_all(free_space_extents); | |||
/* sort the union by physical: needed by dev_map.complement0_physical_shift( ) immediately below */ | /* sort the union by physical: needed by dev_map.complement0_physical_shift( ) immediately below */ | |||
loop_file_extents.sort_by_physical(); | loop_file_extents.sort_by_physical(); | |||
dev_map.complement0_physical_shift(loop_file_extents, eff_block_size_log2, d ev_length); | dev_map.complement0_physical_shift(loop_file_extents, eff_block_size_log2, d ev_length); | |||
/* show DEVICE extents sorted by physical */ | /* show DEVICE extents sorted by physical */ | |||
show(label[FC_DEVICE], "", eff_block_size, dev_map); | dev_map.show(label[FC_DEVICE], "", eff_block_size); | |||
/* | /* | |||
* algorithm: 2), 3) allocate LOOP-HOLES for DEVICE extents logical destinat ion | * algorithm: 2), 3) allocate LOOP-HOLES for DEVICE extents logical destinat ion | |||
* and for LOOP-FILE invariant extents | * and for LOOP-FILE invariant extents | |||
*/ | */ | |||
/* show LOOP-HOLES extents before allocation, sorted by physical */ | /* show LOOP-HOLES extents before allocation, sorted by physical */ | |||
show(label_LOOP_HOLES, " (initial)", eff_block_size, loop_holes_map); | loop_holes_map.show(label_LOOP_HOLES, " (initial)", eff_block_size); | |||
/* algorithm: 2) re-number used DEVICE blocks, setting ->logical to values | /* algorithm: 2) re-number used DEVICE blocks, setting ->logical to values | |||
* from LOOP-HOLES. do not greedily use low hole numbers: | * from LOOP-HOLES. do not greedily use low hole numbers: | |||
* a) prefer holes with ->logical numbers equal to DEVICE ->physical block n umber: | * a) prefer holes with ->logical numbers equal to DEVICE ->physical block n umber: | |||
* they produce an INVARIANT block, already in its final destination | * they produce an INVARIANT block, already in its final destination | |||
* (marked with @@) | * (marked with @@) | |||
* b) spread the remaining ->logical across rest of holes (use best-fit allo cation) | * b) spread the remaining ->logical across rest of holes (use best-fit allo cation) | |||
*/ | */ | |||
/* how: intersect dev_map and loop_holes_map and put result into renumbered_ map */ | /* how: intersect dev_map and loop_holes_map and put result into renumbered_ map */ | |||
renumbered_map.intersect_all_all(dev_map, loop_holes_map, FC_BOTH); | renumbered_map.intersect_all_all(dev_map, loop_holes_map, FC_BOTH); | |||
/* show DEVICE INVARIANT extents (i.e. already in their final destination), sorted by physical */ | /* show DEVICE INVARIANT extents (i.e. already in their final destination), sorted by physical */ | |||
show(label[FC_DEVICE], " (invariant)", eff_block_size, renumbered_map); | renumbered_map.show(label[FC_DEVICE], " (invariant)", eff_block_size); | |||
/* remove from dev_map all the INVARIANT extents in renumbered_map */ | /* remove from dev_map all the INVARIANT extents in renumbered_map */ | |||
dev_map.remove_all(renumbered_map); | dev_map.remove_all(renumbered_map); | |||
/* | /* | |||
* also remove from loop_holes_map all extents in renumbered_map | * also remove from loop_holes_map all extents in renumbered_map | |||
* reason: they are no longer free (logical) holes, | * reason: they are no longer free (logical) holes, | |||
* since we allocated them for DEVICE INVARIANT extents | * since we allocated them for DEVICE INVARIANT extents | |||
*/ | */ | |||
loop_holes_map.remove_all(renumbered_map); | loop_holes_map.remove_all(renumbered_map); | |||
/* | /* | |||
* then clear renumbered_map: its extents are already in their final destina tion | * then clear renumbered_map: its extents are already in their final destina tion | |||
* (they are INVARIANT) -> no work on them | * (they are INVARIANT) -> no work on them | |||
*/ | */ | |||
renumbered_map.clear(); | renumbered_map.clear(); | |||
/* show LOOP-HOLES (sorted by physical) after allocating DEVICE-INVARIANT ex tents */ | /* show LOOP-HOLES (sorted by physical) after allocating DEVICE-INVARIANT ex tents */ | |||
show(label_LOOP_HOLES, " after device (invariant)", eff_block_size, loop_hol es_map); | loop_holes_map.show(label_LOOP_HOLES, " after device (invariant)", eff_block _size); | |||
/* | /* | |||
* algorithm: 2) b) spread the remaining DEVICE ->logical across rest of LOO P-HOLES | * algorithm: 2) b) spread the remaining DEVICE ->logical across rest of LOO P-HOLES | |||
* (use best-fit allocation) | * (use best-fit allocation) | |||
*/ | */ | |||
/* order loop_holes_map by length */ | /* order loop_holes_map by length */ | |||
fr_pool<T> loop_holes_pool(loop_holes_map); | fr_pool<T> loop_holes_pool(loop_holes_map); | |||
/* | /* | |||
* allocate LOOP-HOLES extents to store DEVICE extents using a best-fit stra tegy. | * allocate LOOP-HOLES extents to store DEVICE extents using a best-fit stra tegy. | |||
* move allocated extents from dev_map to renumbered_map | * move allocated extents from dev_map to renumbered_map | |||
*/ | */ | |||
loop_holes_pool.allocate_all(dev_map, renumbered_map); | loop_holes_pool.allocate_all(dev_map, renumbered_map); | |||
/* show DEVICE RENUMBERED extents sorted by physical */ | /* show DEVICE RENUMBERED extents sorted by physical */ | |||
show(label[FC_DEVICE], " (renumbered)", eff_block_size, renumbered_map); | renumbered_map.show(label[FC_DEVICE], " (renumbered)", eff_block_size); | |||
/* show LOOP-HOLES extents after allocation, sorted by physical */ | /* show LOOP-HOLES extents after allocation, sorted by physical */ | |||
show(label_LOOP_HOLES, " (final)", eff_block_size, loop_holes_map); | loop_holes_map.show(label_LOOP_HOLES, " (final)", eff_block_size); | |||
/* sanity check */ | /* sanity check */ | |||
if (!dev_map.empty()) { | if (!dev_map.empty()) { | |||
ff_log(FC_FATAL, 0, "internal error: there are extents in DEVICE not fit ting DEVICE. this is impossible! I give up"); | ff_log(FC_FATAL, 0, "internal error: there are extents in DEVICE not fit ting DEVICE. this is impossible! I give up"); | |||
/* show DEVICE-NOTFITTING extents sorted by physical */ | /* show DEVICE-NOTFITTING extents sorted by physical */ | |||
show(label[FC_DEVICE], " (not fitting)", eff_block_size, dev_map, FC_NOT ICE); | dev_map.show(label[FC_DEVICE], " (not fitting)", eff_block_size, FC_NOTI CE); | |||
return ENOSPC; | return ENOSPC; | |||
} | } | |||
/* move DEVICE (RENUMBERED) back into dev_map and clear renumbered_map */ | /* move DEVICE (RENUMBERED) back into dev_map and clear renumbered_map */ | |||
dev_map.swap(renumbered_map); | dev_map.swap(renumbered_map); | |||
if (io->job_clear() == FC_CLEAR_MINIMAL) { | if (io->job_clear() == FC_CLEAR_MINIMAL) { | |||
/* | /* | |||
* also add DEVICE (RENUMBERED) to TO-CLEAR-MAP: | * also add DEVICE (RENUMBERED) to TO-CLEAR-MAP: | |||
* we MUST clear it once remapping is finished, | * we MUST clear it once remapping is finished, | |||
* since it contains data from the original device, NOT from the loop-fi le | * since it contains data from the original device, NOT from the loop-fi le | |||
skipping to change at line 475 | skipping to change at line 440 | |||
renumbered_map.clear(); | renumbered_map.clear(); | |||
renumbered_map.intersect_all_all(dev_transpose, toclear_map, FC_PHYSICAL 2); | renumbered_map.intersect_all_all(dev_transpose, toclear_map, FC_PHYSICAL 2); | |||
toclear_map.remove_all(renumbered_map); | toclear_map.remove_all(renumbered_map); | |||
iter = dev_transpose.begin(); | iter = dev_transpose.begin(); | |||
end = dev_transpose.end(); | end = dev_transpose.end(); | |||
for (; iter != end; ++iter) { | for (; iter != end; ++iter) { | |||
const map_value_type & extent = *iter; | const map_value_type & extent = *iter; | |||
toclear_map.insert(extent.first.physical, extent.first.physical, ext ent.second.length, FC_DEFAULT_USER_DATA); | toclear_map.insert(extent.first.physical, extent.first.physical, ext ent.second.length, FC_DEFAULT_USER_DATA); | |||
} | } | |||
dev_transpose.clear(); | dev_transpose.clear(); | |||
show("to-clear", " (final)", eff_block_size, toclear_map, FC_DEBUG); | toclear_map.show("to-clear", " (final)", eff_block_size, FC_DEBUG); | |||
} | } | |||
/* | /* | |||
* 2.1) mark as INVARIANT (with @@) the (logical) extents in LOOP-FILE | * 2.1) mark as INVARIANT (with @@) the (logical) extents in LOOP-FILE | |||
* already in their final destination, and forget them (no work on those). | * already in their final destination, and forget them (no work on those). | |||
* also compute total length of extents remaining in LOOP-FILE and store in work_count. | * also compute total length of extents remaining in LOOP-FILE and store in work_count. | |||
*/ | */ | |||
iter = loop_map.begin(); | iter = loop_map.begin(); | |||
end = loop_map.end(); | end = loop_map.end(); | |||
T work_count = 0; /**< number of blocks to be relocated */ | T work_count = 0; /**< number of blocks to be relocated */ | |||
skipping to change at line 507 | skipping to change at line 472 | |||
work_count += iter->second.length; | work_count += iter->second.length; | |||
/* | /* | |||
* also prepare for item 3) "merge renumbered DEVICE extents with re maining LOOP-FILE extents" | * also prepare for item 3) "merge renumbered DEVICE extents with re maining LOOP-FILE extents" | |||
* i.e. remember who's who | * i.e. remember who's who | |||
*/ | */ | |||
iter->second.user_data = FC_LOOP_FILE; | iter->second.user_data = FC_LOOP_FILE; | |||
++iter; | ++iter; | |||
} | } | |||
} | } | |||
/* show LOOP-FILE (INVARIANT) blocks, sorted by physical */ | /* show LOOP-FILE (INVARIANT) blocks, sorted by physical */ | |||
show(label[FC_LOOP_FILE], " (invariant)", eff_block_size, renumbered_map); | renumbered_map.show(label[FC_LOOP_FILE], " (invariant)", eff_block_size); | |||
/* then forget them */ | /* then forget them */ | |||
renumbered_map.clear(); | renumbered_map.clear(); | |||
/* | /* | |||
* algorithm: 3) merge renumbered DEVICE extents with LOOP-FILE blocks (reme mber who's who) | * algorithm: 3) merge renumbered DEVICE extents with LOOP-FILE blocks (reme mber who's who) | |||
* also compute total length of extents remaining in DEVICE and add it to wo rk_count. | * also compute total length of extents remaining in DEVICE and add it to wo rk_count. | |||
*/ | */ | |||
iter = dev_map.begin(); | iter = dev_map.begin(); | |||
end = dev_map.end(); | end = dev_map.end(); | |||
for (; iter != end; ++iter) { | for (; iter != end; ++iter) { | |||
skipping to change at line 531 | skipping to change at line 496 | |||
} | } | |||
dev_map.clear(); | dev_map.clear(); | |||
/* | /* | |||
* from now on, we only need one of dev_map or loop_map, not both. | * from now on, we only need one of dev_map or loop_map, not both. | |||
* we choose dev_map: more intuitive name, and already stored in 'this' | * we choose dev_map: more intuitive name, and already stored in 'this' | |||
*/ | */ | |||
dev_map.swap(loop_map); | dev_map.swap(loop_map); | |||
dev_map.total_count(work_count); | dev_map.total_count(work_count); | |||
dev_map.used_count(work_count); | dev_map.used_count(work_count); | |||
/* show DEVICE + LOOP-FILE extents after merge, sorted by physical */ | /* show DEVICE + LOOP-FILE extents after merge, sorted by physical */ | |||
show("device + loop-file", " (merged)", eff_block_size, dev_map); | dev_map.show("device + loop-file", " (merged)", eff_block_size); | |||
double pretty_len = 0.0; | double pretty_len = 0.0; | |||
const char * pretty_unit = ff_pretty_size((ft_uoff) work_count << eff_block_ size_log2, & pretty_len); | const char * pretty_unit = ff_pretty_size((ft_uoff) work_count << eff_block_ size_log2, & pretty_len); | |||
ff_log(FC_NOTICE, 0, "analysis completed: %.2f %sbytes must be relocated", p retty_len, pretty_unit); | ff_log(FC_NOTICE, 0, "analysis completed: %.2f %sbytes must be relocated", p retty_len, pretty_unit); | |||
/* | /* | |||
* algorithm: 4) compute (physical) intersection of FREE-SPACE and LOOP-HOLE S, | * algorithm: 4) compute (physical) intersection of FREE-SPACE and LOOP-HOLE S, | |||
* and mark it as FREE-SPACE (INVARIANT) (with !!). | * and mark it as FREE-SPACE (INVARIANT) (with !!). | |||
* we can use these extents as partial or total replacement for STORAGE - se e 5) | * we can use these extents as partial or total replacement for STORAGE - se e 5) | |||
skipping to change at line 568 | skipping to change at line 533 | |||
/* | /* | |||
* consider for PRIMARY-STORAGE only "relatively large" blocks, i.e. | * consider for PRIMARY-STORAGE only "relatively large" blocks, i.e. | |||
* 1) at least 1024 * PAGE_SIZE bytes long, or at least work_count / 1024 bl ocks long | * 1) at least 1024 * PAGE_SIZE bytes long, or at least work_count / 1024 bl ocks long | |||
* 2) in any case, at least 1 * PAGE_SIZE bytes long | * 2) in any case, at least 1 * PAGE_SIZE bytes long | |||
*/ | */ | |||
ft_uoff hole_threshold = ff_max2((ft_uoff)page_size_blocks, ff_min2((ft_uoff ) work_count >> 10, (ft_uoff) page_size << 10 >> eff_block_size_log2)); | ft_uoff hole_threshold = ff_max2((ft_uoff)page_size_blocks, ff_min2((ft_uoff ) work_count >> 10, (ft_uoff) page_size << 10 >> eff_block_size_log2)); | |||
T hole_len, hole_total_len = 0; | T hole_len, hole_total_len = 0; | |||
iter = renumbered_map.begin(); | iter = renumbered_map.begin(); | |||
end = renumbered_map.end(); | end = renumbered_map.end(); | |||
show(label[FC_FREE_SPACE], " (invariant)", eff_block_size, renumbered_map); | renumbered_map.show(label[FC_FREE_SPACE], " (invariant)", eff_block_size); | |||
while (iter != end) { | while (iter != end) { | |||
map_value_type & extent = *iter; | map_value_type & extent = *iter; | |||
/* | /* | |||
* whether this hole (extent from dev_free) is large enough to be useful or not, | * whether this hole (extent from dev_free) is large enough to be useful or not, | |||
* it is invariant free space. the current remapping algorithm will neve r use it, | * it is invariant free space. the current remapping algorithm will neve r use it, | |||
* so remove it from free space to get accurate calculation of usable fr ee space. | * so remove it from free space to get accurate calculation of usable fr ee space. | |||
*/ | */ | |||
dev_free.remove(extent); | dev_free.remove(extent); | |||
if ((ft_uoff) (hole_len = iter->second.length) >= hole_threshold) { | if ((ft_uoff) (hole_len = iter->second.length) >= hole_threshold) { | |||
skipping to change at line 597 | skipping to change at line 562 | |||
tmp = iter; | tmp = iter; | |||
++iter; | ++iter; | |||
renumbered_map.remove(tmp); | renumbered_map.remove(tmp); | |||
} | } | |||
/* | /* | |||
* move FREE-SPACE (INVARIANT) extents into storage_map (i.e. PRIMARY-STORAG E), | * move FREE-SPACE (INVARIANT) extents into storage_map (i.e. PRIMARY-STORAG E), | |||
* as the latter is stored into 'this' | * as the latter is stored into 'this' | |||
*/ | */ | |||
storage_map.swap(renumbered_map); | storage_map.swap(renumbered_map); | |||
/* show PRIMARY-STORAGE extents, sorted by physical */ | /* show PRIMARY-STORAGE extents, sorted by physical */ | |||
show(label[FC_PRIMARY_STORAGE], " (= free-space, invariant, contiguous, alig ned)", eff_block_size, storage_map); | storage_map.show(label[FC_PRIMARY_STORAGE], " (= free-space, invariant, cont iguous, aligned)", eff_block_size); | |||
pretty_len = 0.0; | pretty_len = 0.0; | |||
pretty_unit = ff_pretty_size((ft_uoff) hole_total_len << eff_block_size_log2 , & pretty_len); | pretty_unit = ff_pretty_size((ft_uoff) hole_total_len << eff_block_size_log2 , & pretty_len); | |||
ft_size storage_map_n = storage_map.size(); | ft_size storage_map_n = storage_map.size(); | |||
ff_log(FC_INFO, 0, "%s: located %.2f %sbytes (%"FT_ULL" fragment%s) usable i n %s (free, invariant, contiguous and aligned)", | ff_log(FC_INFO, 0, "%s: located %.2f %sbytes (%" FT_ULL " fragment%s) usable in %s (free, invariant, contiguous and aligned)", | |||
label[FC_PRIMARY_STORAGE], pretty_len, pretty_unit, (ft_ull)storage_m ap_n, (storage_map_n == 1 ? "" : "s"), label[FC_DEVICE]); | label[FC_PRIMARY_STORAGE], pretty_len, pretty_unit, (ft_ull)storage_m ap_n, (storage_map_n == 1 ? "" : "s"), label[FC_DEVICE]); | |||
storage_map.total_count(hole_total_len); | storage_map.total_count(hole_total_len); | |||
/* all done */ | /* all done */ | |||
return 0; | return 0; | |||
} | } | |||
static int unusable_storage_size(const char * label, ft_uoff requested_len, cons t char * type_descr, ft_ull type_bytes) | static int unusable_storage_size(const char * label, ft_uoff requested_len, cons t char * type_descr, ft_ull type_bytes) | |||
{ | { | |||
ff_log(FC_FATAL, 0, "fatal error: cannot use job %s length = %"FT_ULL" bytes , it is incompatible with %s = %"FT_ULL" bytes," | ff_log(FC_FATAL, 0, "fatal error: cannot use job %s length = %" FT_ULL " byt es, it is incompatible with %s = %" FT_ULL " bytes," | |||
" original job was probably created on a platform with %s", | " original job was probably created on a platform with %s", | |||
label, (ft_ull) requested_len, type_descr, type_bytes); | label, (ft_ull) requested_len, type_descr, type_bytes); | |||
/* mark error as reported */ | /* mark error as reported */ | |||
return -EOVERFLOW; | return -EOVERFLOW; | |||
} | } | |||
/** | /** | |||
* creates on-disk secondary storage, used as (hopefully small) backup area duri ng relocate(). | * creates on-disk secondary storage, used as (hopefully small) backup area duri ng relocate(). | |||
* must be executed before relocate() | * must be executed before relocate() | |||
*/ | */ | |||
skipping to change at line 696 | skipping to change at line 661 | |||
const char * req_label = label[req_total_size_exact != 0 ? FC_STORAGE : FC_SECONDARY_STORAGE]; | const char * req_label = label[req_total_size_exact != 0 ? FC_STORAGE : FC_SECONDARY_STORAGE]; | |||
double req_pretty_len = 0.0; | double req_pretty_len = 0.0; | |||
const char * req_pretty_unit = ff_pretty_size(req_len, & req_pretty_len) ; | const char * req_pretty_unit = ff_pretty_size(req_len, & req_pretty_len) ; | |||
if (free_ram_or_0 == 0) { | if (free_ram_or_0 == 0) { | |||
ff_log(FC_WARN, 0, "no idea if the %.2f %sbytes requested for %s%s w ill fit into free RAM", | ff_log(FC_WARN, 0, "no idea if the %.2f %sbytes requested for %s%s w ill fit into free RAM", | |||
req_pretty_len, req_pretty_unit, "mmapped() ", req_label); | req_pretty_len, req_pretty_unit, "mmapped() ", req_label); | |||
ff_log(FC_WARN, 0, "continuing, but troubles (memory exhaustion) are possible"); | ff_log(FC_WARN, 0, "continuing, but troubles (memory exhaustion) are possible"); | |||
} else if ((ft_uoff) req_len >= free_ram_or_0 / 2) { | } else if ((ft_uoff) req_len >= free_ram_or_0 / 2) { | |||
ff_log(FC_WARN, 0, "using %.2f %sbytes as requested for %s, but only | ff_log(FC_WARN, 0, "using %.2f %sbytes as requested for %s%s, but on | |||
%.2f %sbytes RAM are free", | ly %.2f %sbytes RAM are free", | |||
req_pretty_len, req_pretty_unit, req_label, free_pretty_len, | req_pretty_len, req_pretty_unit, "mmapped() ", req_label, fr | |||
free_pretty_unit); | ee_pretty_len, free_pretty_unit); | |||
ff_log(FC_WARN, 0, "honoring the request, but expect troubles (memor y exhaustion)"); | ff_log(FC_WARN, 0, "honoring the request, but expect troubles (memor y exhaustion)"); | |||
} | } | |||
} | } | |||
if (req_total_size_exact == 0) { | if (req_total_size_exact == 0) { | |||
/* | /* | |||
* auto-detect total storage size to use: | * auto-detect total storage size to use: | |||
* we want it to be the smallest between | * we want it to be the smallest between | |||
* 50% of free RAM (if free RAM cannot be determined, use 16 MB on 32b it platforms, and 256MB on 64bit+ platforms) | * 50% of free RAM (if free RAM cannot be determined, use 16 MB on 32b it platforms, and 256MB on 64bit+ platforms) | |||
* 12.5% of bytes to relocate | * 12.5% of bytes to relocate | |||
*/ | */ | |||
skipping to change at line 808 | skipping to change at line 773 | |||
ff_log(FC_WARN, 0, "%s size to use would be 0 bytes, increasing to %.2f %sbytes", | ff_log(FC_WARN, 0, "%s size to use would be 0 bytes, increasing to %.2f %sbytes", | |||
"memory buffer", mem_pretty_len, mem_pretty_unit); | "memory buffer", mem_pretty_len, mem_pretty_unit); | |||
} | } | |||
ft_size primary_size; | ft_size primary_size; | |||
if (req_primary_size_exact > avail_primary_size) { | if (req_primary_size_exact > avail_primary_size) { | |||
double avail_pretty_len = 0.0, req_pretty_len = 0.0; | double avail_pretty_len = 0.0, req_pretty_len = 0.0; | |||
const char * avail_pretty_unit = ff_pretty_size(avail_primary_size, & av ail_pretty_len); | const char * avail_pretty_unit = ff_pretty_size(avail_primary_size, & av ail_pretty_len); | |||
const char * req_pretty_unit = ff_pretty_size(req_primary_size_exact, & req_pretty_len); | const char * req_pretty_unit = ff_pretty_size(req_primary_size_exact, & req_pretty_len); | |||
ff_log(FC_ERROR, 0, "available %s is only %"FT_ULL" bytes (%.2f %sbytes) | ff_log(FC_ERROR, 0, "available %s is only %" FT_ULL " bytes (%.2f %sbyte | |||
," | s)," | |||
" too small for requested %"FT_ULL" bytes (%.2f %sbytes)", label[ | " too small for requested %" FT_ULL " bytes (%.2f %sbytes)", labe | |||
FC_PRIMARY_STORAGE], | l[FC_PRIMARY_STORAGE], | |||
(ft_ull)avail_primary_size, avail_pretty_len, avail_pretty_unit, | (ft_ull)avail_primary_size, avail_pretty_len, avail_pretty_unit, | |||
(ft_ull) req_primary_size_exact, req_pretty_len, req_pretty_unit) ; | (ft_ull) req_primary_size_exact, req_pretty_len, req_pretty_unit) ; | |||
/* mark error as reported */ | /* mark error as reported */ | |||
return -ENOSPC; | return -ENOSPC; | |||
} else if (req_primary_size_exact != 0) | } else if (req_primary_size_exact != 0) | |||
primary_size = req_primary_size_exact; | primary_size = req_primary_size_exact; | |||
else | else | |||
primary_size = ff_min2(avail_primary_size, auto_total_size); | primary_size = ff_min2(avail_primary_size, auto_total_size); | |||
ft_size secondary_size; | ft_size secondary_size; | |||
skipping to change at line 921 | skipping to change at line 886 | |||
storage_map.clear(); | storage_map.clear(); | |||
storage_map.append0_shift(primary_storage, eff_block_size_log2); | storage_map.append0_shift(primary_storage, eff_block_size_log2); | |||
} | } | |||
storage_map.total_count((T)(primary_len >> eff_block_size_log2)); | storage_map.total_count((T)(primary_len >> eff_block_size_log2)); | |||
double pretty_len = 0.0; | double pretty_len = 0.0; | |||
const char * pretty_unit = ff_pretty_size(primary_len, & pretty_len); | const char * pretty_unit = ff_pretty_size(primary_len, & pretty_len); | |||
ft_size fragment_n = primary_storage.size(); | ft_size fragment_n = primary_storage.size(); | |||
ff_log(FC_INFO, 0, "%s: actually using %.2f %sbytes (%"FT_ULL" fragment%s) f rom %s", | ff_log(FC_INFO, 0, "%s: actually using %.2f %sbytes (%" FT_ULL " fragment%s) from %s", | |||
label[FC_PRIMARY_STORAGE], pretty_len, pretty_unit, | label[FC_PRIMARY_STORAGE], pretty_len, pretty_unit, | |||
(ft_ull)fragment_n, (fragment_n == 1 ? "" : "s"), label[FC_DEVICE]); | (ft_ull)fragment_n, (fragment_n == 1 ? "" : "s"), label[FC_DEVICE]); | |||
show(label[FC_PRIMARY_STORAGE], " (actually used)", (ft_uoff) 1 << eff_block _size_log2, storage_map); | storage_map.show(label[FC_PRIMARY_STORAGE], " (actually used)", (ft_uoff) 1 << eff_block_size_log2); | |||
} | } | |||
/** start UI, passing I/O object to it. requires I/O to know device length and s torage size */ | /** start UI, passing I/O object to it. requires I/O to know device length and s torage size */ | |||
template<typename T> | template<typename T> | |||
int fr_work<T>::start_ui() | int fr_work<T>::start_ui() | |||
{ | { | |||
FT_UI_NS fr_ui * ui = io->ui(); | FT_UI_NS fr_ui * ui = io->ui(); | |||
int err = 0; | int err = 0; | |||
if (ui != NULL) | if (ui != NULL) | |||
err = ui->start(io); | err = ui->start(io); | |||
skipping to change at line 1073 | skipping to change at line 1038 | |||
const ft_uoff eff_block_size_log2 = io->effective_block_size_log2(); | const ft_uoff eff_block_size_log2 = io->effective_block_size_log2(); | |||
T dev_used = dev_map.used_count(), storage_used = storage_map.used_count(); | T dev_used = dev_map.used_count(), storage_used = storage_map.used_count(); | |||
ft_uoff total_len = ((ft_uoff)dev_used + (ft_uoff)storage_used) << eff_block _size_log2; | ft_uoff total_len = ((ft_uoff)dev_used + (ft_uoff)storage_used) << eff_block _size_log2; | |||
double percentage = 0.0, time_left = -1.0; | double percentage = 0.0, time_left = -1.0; | |||
if (work_total != 0) { | if (work_total != 0) { | |||
percentage = 1.0 - ((double)dev_used + 0.5 * (double)storage_used) / (do uble)work_total; | percentage = 1.0 - ((double)dev_used + 0.5 * (double)storage_used) / (do uble)work_total; | |||
if (simul_msg[0] == '\0') | /* underestimate the progress percentage: algorithm slows down near the | |||
time_left = eta.add(percentage); | end */ | |||
else | /* time_left = eta.add(percentage); */ | |||
eta.clear(); | double x = percentage; | |||
time_left = eta.add(0.5*x + 0.5*x*x); | ||||
percentage *= 100.0; | percentage *= 100.0; | |||
} | } | |||
ff_show_progress(log_level, simul_msg, percentage, total_len, " still to rel ocate", time_left); | ff_show_progress(log_level, simul_msg, percentage, total_len, " still to rem ap", time_left); | |||
const ft_uoff eff_block_size = (ft_uoff)1 << eff_block_size_log2; | const ft_uoff eff_block_size = (ft_uoff)1 << eff_block_size_log2; | |||
show(label[FC_DEVICE], "", eff_block_size, dev_map, FC_DUMP); | dev_map.show(label[FC_DEVICE], "", eff_block_size, FC_DUMP); | |||
show(label[FC_DEVICE], " free space", eff_block_size, dev_free, FC_DUMP); | dev_free.show(label[FC_DEVICE], " free space", eff_block_size, FC_DUMP); | |||
show(label[FC_STORAGE], "", eff_block_size, storage_map, FC_DUMP); | storage_map.show(label[FC_STORAGE], "", eff_block_size, FC_DUMP); | |||
show(label[FC_STORAGE], " free space", eff_block_size, storage_free, FC_DUMP | storage_free.show(label[FC_STORAGE], " free space", eff_block_size, FC_DUMP) | |||
); | ; | |||
} | } | |||
/** | /** | |||
* called once by relocate() immediately before starting the remapping phase. | * called once by relocate() immediately before starting the remapping phase. | |||
* | * | |||
* 1) check that last device block to be written is actually writable. | * 1) check that last device block to be written is actually writable. | |||
* Reason: at least on Linux, if a filesystems is smaller than its containing device, | * Reason: at least on Linux, if a filesystems is smaller than its containing device, | |||
* it often limits to its length the writable blocks in the device. | * it often limits to its length the writable blocks in the device. | |||
* | * | |||
* 2) check for corner care where we have an odd-sized (i.e. smaller than effect ive block size) last device block, | * 2) check for corner care where we have an odd-sized (i.e. smaller than effect ive block size) last device block, | |||
skipping to change at line 1122 | skipping to change at line 1088 | |||
ft_uoff dev_len = io->dev_length(), loop_file_len = io->loop_file_length(); | ft_uoff dev_len = io->dev_length(), loop_file_len = io->loop_file_length(); | |||
dev_len &= ~(eff_block_size - 1); | dev_len &= ~(eff_block_size - 1); | |||
if (loop_file_len <= dev_len) | if (loop_file_len <= dev_len) | |||
return io->check_last_block(); | return io->check_last_block(); | |||
ft_uoff odd_block_len = loop_file_len & (eff_block_size - 1); | ft_uoff odd_block_len = loop_file_len & (eff_block_size - 1); | |||
const char * simul_msg = io->simulate_run() ? "(simulated) " : ""; | const char * simul_msg = io->simulate_run() ? "(simulated) " : ""; | |||
ff_log(FC_ERROR, 0, "%s%s has an odd-sized last block (%"FT_ULL" bytes long) that exceeds device rounded length.", | ff_log(FC_ERROR, 0, "%s%s has an odd-sized last block (%" FT_ULL " bytes lon g) that exceeds device rounded length.", | |||
simul_msg, label[FC_LOOP_FILE], (ft_ull) odd_block_len); | simul_msg, label[FC_LOOP_FILE], (ft_ull) odd_block_len); | |||
ff_log(FC_ERROR, 0, "%sExiting, please shrink %s to %"FT_ULL" bytes or less before running fsremap again.", | ff_log(FC_ERROR, 0, "%sExiting, please shrink %s to %" FT_ULL " bytes or les s before running fsremap again.", | |||
simul_msg, label[FC_LOOP_FILE], (ft_ull) dev_len); | simul_msg, label[FC_LOOP_FILE], (ft_ull) dev_len); | |||
return -EFBIG; | return -EFBIG; | |||
} | } | |||
/** called by relocate(). move as many extents as possible from DEVICE to STORAG E */ | /** called by relocate(). move as many extents as possible from DEVICE to STORAG E */ | |||
template<typename T> | template<typename T> | |||
int fr_work<T>::fill_storage() | int fr_work<T>::fill_storage() | |||
{ | { | |||
map_iterator from_iter = dev_map.begin(), from_pos, from_end = dev_map.end() ; | map_iterator from_iter = dev_map.begin(), from_pos, from_end = dev_map.end() ; | |||
T moved = 0, from_used_count = dev_map.used_count(), to_free_count = storage _map.free_count(); | T moved = 0, from_used_count = dev_map.used_count(), to_free_count = storage _map.free_count(); | |||
const bool simulated = io->simulate_run(); | const bool simulated = io->simulate_run(); | |||
const bool replaying = io->is_replaying(); | const bool replaying = io->is_replaying(); | |||
const char * simul_msg = simulated ? "(simulated) " : replaying ? "(replayin g) " : ""; | const char * simul_msg = simulated ? "(simulated) " : replaying ? "(replayin g) " : ""; | |||
double pretty_len = 0.0; | double pretty_len = 0.0; | |||
const char * pretty_label = ff_pretty_size((ft_uoff)ff_min2<T>(from_used_cou nt, to_free_count) | const char * pretty_label = ff_pretty_size((ft_uoff)ff_min2<T>(from_used_cou nt, to_free_count) | |||
<< io->effective_block_size_log2( ), & pretty_len); | << io->effective_block_size_log2( ), & pretty_len); | |||
ff_log(FC_INFO, 0, "%sfilling %s by moving %.2f %sbytes from %s ...", | ff_log(FC_INFO, 0, "%sfilling %s by moving %.2f %sbytes from %s ...", | |||
simul_msg, label[FC_STORAGE], pretty_len, pretty_label, label[FC_DEVI CE]); | simul_msg, label[FC_STORAGE], pretty_len, pretty_label, label[FC_DEVI CE]); | |||
show(); /* show extents header */ | fr_extent<T>::show(); /* show extents header */ | |||
ft_size counter = 0; | ft_size counter = 0; | |||
int err = 0; | int err = 0; | |||
while (err == 0 && moved < to_free_count && from_iter != from_end) { | while (err == 0 && moved < to_free_count && from_iter != from_end) { | |||
/* fully or partially move this extent to STORAGE */ | /* fully or partially move this extent to STORAGE */ | |||
from_pos = from_iter; | from_pos = from_iter; | |||
++from_iter; | ++from_iter; | |||
/* note: some blocks may have been moved even in case of errors! */ | /* note: some blocks may have been moved even in case of errors! */ | |||
err = move(counter++, from_pos, FC_DEV2STORAGE, moved); | err = move(counter++, from_pos, FC_DEV2STORAGE, moved); | |||
} | } | |||
skipping to change at line 1184 | skipping to change at line 1150 | |||
int fr_work<T>::move(ft_size counter, map_iterator from_iter, fr_dir dir, T & re t_moved) | int fr_work<T>::move(ft_size counter, map_iterator from_iter, fr_dir dir, T & re t_moved) | |||
{ | { | |||
T moved, length = from_iter->second.length; | T moved, length = from_iter->second.length; | |||
const bool is_to_dev = ff_is_to_dev(dir); | const bool is_to_dev = ff_is_to_dev(dir); | |||
map_stat_type & to_map = is_to_dev ? dev_map : storage_map; | map_stat_type & to_map = is_to_dev ? dev_map : storage_map; | |||
map_type & to_free_map = is_to_dev ? dev_free : storage_free; | map_type & to_free_map = is_to_dev ? dev_free : storage_free; | |||
map_iterator to_free_iter = to_free_map.begin(), to_free_pos, to_free_end = to_free_map.end(); | map_iterator to_free_iter = to_free_map.begin(), to_free_pos, to_free_end = to_free_map.end(); | |||
int err = 0; | int err = 0; | |||
if (ff_log_is_enabled((ft_log_level)FC_SHOW_DEFAULT_LEVEL)) { | if (ff_logl_is_enabled("extent", 6/*strlen("extent")*/, FC_SHOW_DEFAULT_LEVE L)) { | |||
const map_value_type & extent = *from_iter; | const map_value_type & extent = *from_iter; | |||
show(counter, extent.first.physical, extent.second.logical, | fr_extent<T>::show(counter, extent.first.physical, extent.second.logical | |||
ff_min2(extent.second.length, to_map.free_count()), | , | |||
extent.second.user_data); | ff_min2(extent.second.length, to_map.free_count()), | |||
extent.second.user_data); | ||||
} | } | |||
while (err == 0 && length != 0 && to_free_iter != to_free_end) { | while (err == 0 && length != 0 && to_free_iter != to_free_end) { | |||
to_free_pos = to_free_iter; | to_free_pos = to_free_iter; | |||
++to_free_iter; | ++to_free_iter; | |||
moved = 0; | moved = 0; | |||
err = move_fragment(from_iter, to_free_pos, dir, moved); | err = move_fragment(from_iter, to_free_pos, dir, moved); | |||
length -= moved; | length -= moved; | |||
ret_moved += moved; | ret_moved += moved; | |||
} | } | |||
skipping to change at line 1297 | skipping to change at line 1263 | |||
int err = 0; | int err = 0; | |||
const bool simulated = io->simulate_run(); | const bool simulated = io->simulate_run(); | |||
const char * simul_msg = simulated ? "(simulated) " : io->is_replaying() ? " (replaying) " : ""; | const char * simul_msg = simulated ? "(simulated) " : io->is_replaying() ? " (replaying) " : ""; | |||
/* find all DEVICE or STORAGE extents that can be moved to their final desti nation into DEVICE free space */ | /* find all DEVICE or STORAGE extents that can be moved to their final desti nation into DEVICE free space */ | |||
movable.intersect_all_all(from_transpose, dev_free, FC_PHYSICAL1); | movable.intersect_all_all(from_transpose, dev_free, FC_PHYSICAL1); | |||
if (movable.empty()) { | if (movable.empty()) { | |||
ff_log(FC_INFO, 0, "%smoved 0 bytes from %s to target (not so useful)", simul_msg, label_from); | ff_log(FC_INFO, 0, "%smoved 0 bytes from %s to target (not so useful)", simul_msg, label_from); | |||
ft_uoff eff_block_size = (ft_uoff)1 << io->effective_block_size_log2(); | ft_uoff eff_block_size = (ft_uoff)1 << io->effective_block_size_log2(); | |||
show(label_from, " transposed", eff_block_size, from_transpose, FC_DEBUG | from_transpose.show(label_from, " transposed", eff_block_size); | |||
); | dev_free.show(label[FC_DEVICE], " free space", eff_block_size); | |||
show(label[FC_DEVICE], " free space", eff_block_size, dev_free, FC_DEBUG | ||||
); | ||||
return err; | return err; | |||
} | } | |||
if (ff_log_is_enabled(FC_INFO)) { | if (ff_log_is_enabled(FC_INFO)) { | |||
map_const_iterator iter = movable.begin(), end = movable.end(); | map_const_iterator iter = movable.begin(), end = movable.end(); | |||
ft_uoff movable_length = 0; | ft_uoff movable_length = 0; | |||
for (; iter != end; ++iter) | for (; iter != end; ++iter) | |||
movable_length += iter->second.length; | movable_length += iter->second.length; | |||
movable_length <<= io->effective_block_size_log2(); | movable_length <<= io->effective_block_size_log2(); | |||
double pretty_len = 0.0; | double pretty_len = 0.0; | |||
const char * pretty_label = ff_pretty_size(movable_length, & pretty_len) ; | const char * pretty_label = ff_pretty_size(movable_length, & pretty_len) ; | |||
ff_log(FC_INFO, 0, "%smoving %.2f %sbytes from %s to target ...", | ff_log(FC_INFO, 0, "%smoving %.2f %sbytes from %s to target ...", | |||
simul_msg, pretty_len, pretty_label, label_from); | simul_msg, pretty_len, pretty_label, label_from); | |||
show(); /* show extents header */ | fr_extent<T>::show(); /* show extents header */ | |||
} | } | |||
/* move them */ | /* move them */ | |||
map_const_iterator iter = movable.begin(), end = movable.end(); | map_const_iterator iter = movable.begin(), end = movable.end(); | |||
T from_physical, to_physical, length; | T from_physical, to_physical, length; | |||
ft_size counter = 0; | ft_size counter = 0; | |||
for (; iter != end; ++iter) { | for (; iter != end; ++iter) { | |||
const map_value_type & extent = *iter; | const map_value_type & extent = *iter; | |||
from_physical = extent.second.logical; | from_physical = extent.second.logical; | |||
to_physical = extent.first.physical; | to_physical = extent.first.physical; | |||
length = extent.second.length; | length = extent.second.length; | |||
/* sequential disk access: consecutive calls to io->copy() are sorted by to_physical, i.e. device to_offset */ | /* sequential disk access: consecutive calls to io->copy() are sorted by to_physical, i.e. device to_offset */ | |||
err = io->copy(dir, from_physical, to_physical, length); | err = io->copy(dir, from_physical, to_physical, length); | |||
show(counter++, from_physical, to_physical, length, extent.second.user_d ata); | fr_extent<T>::show(counter++, from_physical, to_physical, length, extent .second.user_data); | |||
if (err != 0) | if (err != 0) | |||
return err; | return err; | |||
from_transpose.remove(extent); | from_transpose.remove(extent); | |||
from_map.stat_remove(from_physical, to_physical, length); | from_map.stat_remove(from_physical, to_physical, length); | |||
from_free.insert(from_physical, from_physical, length, FC_DEFAULT_USER_D ATA); | from_free.insert(from_physical, from_physical, length, FC_DEFAULT_USER_D ATA); | |||
/* | /* | |||
* forget final destination extent: it's NOT free anymore, but nothing t o do there. | * forget final destination extent: it's NOT free anymore, but nothing t o do there. | |||
* actually, if it is DEVICE-RENUMBERED, it will likely be cleared after relocate() finishes, | * actually, if it is DEVICE-RENUMBERED, it will likely be cleared after relocate() finishes, | |||
* but in such case it is supposed to be ALREADY in toclear_map | * but in such case it is supposed to be ALREADY in toclear_map | |||
*/ | */ | |||
skipping to change at line 1373 | skipping to change at line 1339 | |||
int err = 0; | int err = 0; | |||
fr_clear_free_space job_clear = io->job_clear(); | fr_clear_free_space job_clear = io->job_clear(); | |||
do { | do { | |||
ft_uoff toclear_len = 0; | ft_uoff toclear_len = 0; | |||
if (job_clear == FC_CLEAR_MINIMAL) | if (job_clear == FC_CLEAR_MINIMAL) | |||
toclear_len += (ft_uoff) io->job_storage_size(FC_PRIMARY_STORAGE_EXA CT_SIZE); | toclear_len += (ft_uoff) io->job_storage_size(FC_PRIMARY_STORAGE_EXA CT_SIZE); | |||
map_const_iterator iter = toclear_map.begin(), end = toclear_map.end(); | map_const_iterator iter = toclear_map.begin(), end = toclear_map.end(); | |||
for (; iter != end; ++iter) | for (; iter != end; ++iter) | |||
toclear_len += iter->second.length << io->effective_block_size_log2( ); | toclear_len += (ft_uoff) iter->second.length << io->effective_block_ size_log2(); | |||
double pretty_len = 0.0; | double pretty_len = 0.0; | |||
const char * pretty_label = ff_pretty_size(toclear_len, & pretty_len); | const char * pretty_label = ff_pretty_size(toclear_len, & pretty_len); | |||
switch (job_clear) { | switch (job_clear) { | |||
case FC_CLEAR_MINIMAL: | case FC_CLEAR_MINIMAL: | |||
ff_log(FC_NOTICE, 0, "%sclearing %.2f %sbytes free space from %s to remove temporary data (%s and %s backup)...", | ff_log(FC_NOTICE, 0, "%sclearing %.2f %sbytes free space from %s to remove temporary data (%s and %s backup)...", | |||
sim_msg, pretty_len, pretty_label, label[FC_DEVICE], labe l[FC_PRIMARY_STORAGE], label[FC_DEVICE]); | sim_msg, pretty_len, pretty_label, label[FC_DEVICE], labe l[FC_PRIMARY_STORAGE], label[FC_DEVICE]); | |||
err = io->zero_primary_storage(); | err = io->zero_primary_storage(); | |||
break; | break; | |||
default: | default: | |||
End of changes. 43 change blocks. | ||||
113 lines changed or deleted | 71 lines changed or added |