Loading include/global/random_slicing/DistRandSlice.hpp +27 −14 Original line number Diff line number Diff line Loading @@ -42,19 +42,17 @@ namespace VDRIVE { */ class DistRandSlice { public: static bool constexpr DEBUG_VSPACE = false; // constants declaring the min and max values for the // virtual allocation space. // right now, it spans from 0 to 2^64-1 blocks/files/whatever static const uint64_t VSPACE_MIN = 0; static const uint64_t VSPACE_MAX = UINT64_MAX; static uint64_t constexpr VSPACE_MIN = 0; static uint64_t constexpr VSPACE_MAX = DEBUG_VSPACE ? 1000000 : UINT64_MAX; // HARD DEBUG TODO(dauer) UINT64_MAX; /** * Create a new instance from the data in the given XML Element. * * @param data An XML-Element containing the description of a DistRandSlice. */ // DistRandSlice(xercesc::DOMElement* data); static double constexpr DOUBLE_ALLOWED_ERROR = DEBUG_VSPACE ? 1.0e-5 : 1.0e-14; /** * generate a new, uninitialized Rand Slice Implementation. Loading Loading @@ -87,10 +85,18 @@ public: int32_t copies); /** * @see Distributor::setDisks * @see Distributor::addDisks */ virtual void setDisks(std::list<Disk*>* disks); addDisks(std::list<Disk*>* disks); /** * Added for GekkoFS - Remove the Disks given by their IDs * from the distribution. * TODO(dauer): Decide & document freeing of memory */ void removeDisks(std::vector<int64_t> disk_ids); /** * @see Distributor::getDisks Loading Loading @@ -160,6 +166,12 @@ private: void add_partitions(std::list<Disk*>* disks); uint64_t partition_capacity(uint64_t part_id, uint64_t new_total_capacity); uint64_t partition_capacity(Disk* disk, uint64_t new_total_capacity); void redistribute( std::unordered_map<uint64_t, uint64_t>& old_partitions, Loading Loading @@ -207,7 +219,7 @@ private: int32_t m_copies; /** * the disks as given to setDisks (or setConfiguration) * the disks as given to addDisks (or setConfiguration) */ std::unordered_map<uint64_t, Disk*>* m_disks; Loading @@ -217,7 +229,8 @@ private: uint64_t m_num_disks; /** * partition info: id -> capacity * partition info: id -> capacity (Scaled relative to VSPACE_MAX. This * unit is also referred to as blocks.) */ std::unordered_map<uint64_t, uint64_t>* m_partitions; Loading @@ -233,7 +246,7 @@ private: flat_segment_tree* m_interval_tree; /** * capacity of the system * capacity of the system (absolute i.e. sum of disk capacities) */ uint64_t m_capacity; Loading src/global/random_slicing/DistRandSlice.cpp +148 −18 Original line number Diff line number Diff line Loading @@ -97,11 +97,11 @@ DistRandSlice::setConfiguration(std::list<Disk*>* disks, int64_t extentsize, m_copies = copies; setDisks(disks); addDisks(disks); } void DistRandSlice::setDisks(std::list<Disk*>* disks) { DistRandSlice::addDisks(std::list<Disk*>* disks) { if(this->m_disks == NULL) { Loading @@ -122,6 +122,129 @@ DistRandSlice::setDisks(std::list<Disk*>* disks) { } } // Added for GekkoFS void DistRandSlice::removeDisks(std::vector<int64_t> disk_ids) { // part id -> num blocks to remove std::unordered_map<uint64_t, uint64_t> old_partitions; for(const auto partition : *m_partitions) { // initialize with 0 blocks to remove old_partitions[partition.first] = 0; } uint64_t capacity_to_remove = 0; for(const auto id : disk_ids) { old_partitions[id] = UINT64_MAX; // remove all blocks capacity_to_remove += m_disks->at(id)->getCapacity(); } uint64_t new_capacity = m_capacity - capacity_to_remove; std::list<std::pair<uint64_t, uint64_t>> free_space; collect_free_space(old_partitions, free_space); uint64_t num_blocks_to_remove = 0; for(const auto start_end : free_space) { num_blocks_to_remove += start_end.second - start_end.first; } #if defined DEBUG std::cout << "DEBUG: Removing " << disk_ids.size() << " disks: "; for(const auto id : disk_ids) { std::cout << id << " "; } std::cout << "\n" << "DEBUG: capacity_to_remove: " << capacity_to_remove << "\n" << "DEBUG: m_capacity: " << m_capacity << "\n" << "DEBUG: new_capacity: " << new_capacity << "\n" << "DEBUG: num_blocks_to_remove: " << num_blocks_to_remove << "\n"; #endif // remove those disks and their corresponding partitions // we don't need those any more and must not add the partitions to be // deleted to num_blocks_to_add in the next step for(const auto id : disk_ids) { delete m_disks->at(id); m_disks->erase(id); m_partitions->erase(id); } m_num_disks -= disk_ids.size(); m_num_partitions -= disk_ids.size(); // partition_id -> number of blocks to add std::list<std::pair<uint64_t, uint64_t>> updated_partitions; uint64_t num_blocks_to_add = 0; // adapted from add_partitions // recalculate partition sizes for remaining partitions for(const auto& partition : *m_partitions) { auto part_id = partition.first; auto old_part_capacity = partition.second; // in blocks uint64_t new_part_capacity = partition_capacity(part_id, new_capacity); assert(new_part_capacity >= old_part_capacity); // division flipped compared to add updated_partitions.push_back( std::make_pair(part_id, new_part_capacity - old_part_capacity)); num_blocks_to_add += new_part_capacity - old_part_capacity; // !!! CAUTION: m_partitions map is not used again in computations, // therefore it is safe to update partition sizes here. If this ever // changes, take it into account (*m_partitions)[part_id] = new_part_capacity; } // XXX: ideally, num_blocks_to_add should equal num_blocks_to_remove, but // due to rounding errors, this is not always the case. Add/remove the // difference to/from the last partition. // // NOTE: We could distribute the remainder proportionally among the new // partitions, but this way is faster and the remainder is neglectable if(num_blocks_to_remove != num_blocks_to_add) { uint64_t r = num_blocks_to_remove - num_blocks_to_add; #if defined DEBUG cout << "remove " << num_blocks_to_remove << "\n" << "add " << num_blocks_to_add << "\n" << "diff " << r << "\n"; #endif updated_partitions.back().second += r; } // compute the free space as list of pairs (start block - end block) // std::list<std::pair<uint64_t, uint64_t>> free_space; redistribute(old_partitions, updated_partitions); m_capacity = new_capacity; #if defined DEBUG dump_intervals(); verify_partitions(); #endif // TODO(dauer): what about segment_tree: defaultvalue? } /** * Private function to get disk capacity and compute the new partition capacity * according to it and the new capacity of the system. * @return calculated capacity in blocks */ uint64_t DistRandSlice::partition_capacity(uint64_t part_id, uint64_t new_total_capacity) { return partition_capacity(m_disks->at(part_id), new_total_capacity); } uint64_t DistRandSlice::partition_capacity(Disk* disk, uint64_t new_total_capacity) { uint64_t disk_capacity = disk->getCapacity(); double p = disk_capacity * 1.0 / new_total_capacity; return (uint64_t) floor(p * VSPACE_MAX); } /** * 64 bit Integer Hash Function Loading @@ -138,6 +261,14 @@ my_hash(int64_t i) { i ^= (i >> 28); i += (i << 31); // For debugging with smaller VSPACE_MAX. if(DistRandSlice::VSPACE_MAX != UINT64_MAX) { #ifndef DEBUG assert(!"Running with VSPACE_MAX != UINT64_MAX but no DEBUG"); #endif i = i % DistRandSlice::VSPACE_MAX; } return i; } Loading Loading @@ -401,15 +532,9 @@ DistRandSlice::add_partitions(std::list<Disk*>* new_disks) { it != m_partitions->end(); ++it) { uint64_t part_id = it->first; uint64_t old_part_capacity = it->second; uint64_t old_part_capacity = it->second; // in blocks // get disk capacity and compute the new partition capacity according to // it and the new capacity of the system uint64_t disk_capacity = m_disks->find(part_id)->second->getCapacity(); double p = disk_capacity * 1.0 / new_capacity; uint64_t new_part_capacity = (uint64_t) floor(p * VSPACE_MAX); uint64_t new_part_capacity = partition_capacity(part_id, new_capacity); old_partitions[it->first] = old_part_capacity - new_part_capacity; Loading @@ -423,8 +548,7 @@ DistRandSlice::add_partitions(std::list<Disk*>* new_disks) { #endif // !!! CAUTION: m_partitions map is not used again in computations, // therefore it is // safe to update partition sizes here. If this ever // therefore it is safe to update partition sizes here. If this ever // changes, take it into account (*m_partitions)[part_id] = new_part_capacity; } Loading @@ -444,8 +568,7 @@ DistRandSlice::add_partitions(std::list<Disk*>* new_disks) { it != new_disks->end(); ++it) { uint64_t part_id = (*it)->getId(); double p = (*it)->getCapacity() * 1.0 / new_capacity; uint64_t new_part_capacity = (uint64_t) floor(p * VSPACE_MAX); uint64_t new_part_capacity = partition_capacity(*it, new_capacity); num_blocks_to_add += new_part_capacity; // XXX ATM partition_id == disk_id Loading @@ -472,6 +595,11 @@ DistRandSlice::add_partitions(std::list<Disk*>* new_disks) { // partitions, but this way is faster and the remainder is neglectable if(num_blocks_to_remove != num_blocks_to_add) { uint64_t r = num_blocks_to_remove - num_blocks_to_add; #if defined DEBUG cout << "remove " << num_blocks_to_remove << "\n" << "add " << num_blocks_to_add << "\n" << "diff " << r << "\n"; #endif new_partitions.back().second += r; } Loading Loading @@ -528,6 +656,7 @@ DistRandSlice::redistribute( } #if defined DEBUG && defined DUMP_FREE_SPACE std::cout << "\n\nDEBUG: redistribute after collecting free space"; dump_free_space(free_space); #endif Loading Loading @@ -850,6 +979,7 @@ DistRandSlice::reuse_free_space_sort( } #if defined DEBUG && defined DUMP_FREE_SPACE std::cout << "\n\nDEBUG: in reuse_free_space_sort"; dump_free_space(free_space); #endif } Loading Loading @@ -964,7 +1094,7 @@ DistRandSlice::verify_partitions(void) { // we can't use == here :P double e = fabs(dp - pp); if(e > 1.0e-14) { if(e > DistRandSlice::DOUBLE_ALLOWED_ERROR) { cerr.precision(100); cerr << "1: error in double comparison: " << dp << " vs. " << pp << " e=" << e << "\n"; Loading @@ -973,7 +1103,7 @@ DistRandSlice::verify_partitions(void) { e = fabs(pp - ip); if(e > 1.0e-14) { if(e > DistRandSlice::DOUBLE_ALLOWED_ERROR) { cerr.precision(100); cerr << "2: error in double comparison: " << pp << " vs. " << ip << " e=" << e << "\n"; Loading Loading @@ -1015,7 +1145,7 @@ DistRandSlice::compute_interval_sizes(void) { i_high = it->first; i_pid = last_pid; // check for illegal memory access // at: check for illegal memory access result.at(i_pid) += (i_high - i_low); // result[i_pid] += (i_high - i_low); Loading Loading
include/global/random_slicing/DistRandSlice.hpp +27 −14 Original line number Diff line number Diff line Loading @@ -42,19 +42,17 @@ namespace VDRIVE { */ class DistRandSlice { public: static bool constexpr DEBUG_VSPACE = false; // constants declaring the min and max values for the // virtual allocation space. // right now, it spans from 0 to 2^64-1 blocks/files/whatever static const uint64_t VSPACE_MIN = 0; static const uint64_t VSPACE_MAX = UINT64_MAX; static uint64_t constexpr VSPACE_MIN = 0; static uint64_t constexpr VSPACE_MAX = DEBUG_VSPACE ? 1000000 : UINT64_MAX; // HARD DEBUG TODO(dauer) UINT64_MAX; /** * Create a new instance from the data in the given XML Element. * * @param data An XML-Element containing the description of a DistRandSlice. */ // DistRandSlice(xercesc::DOMElement* data); static double constexpr DOUBLE_ALLOWED_ERROR = DEBUG_VSPACE ? 1.0e-5 : 1.0e-14; /** * generate a new, uninitialized Rand Slice Implementation. Loading Loading @@ -87,10 +85,18 @@ public: int32_t copies); /** * @see Distributor::setDisks * @see Distributor::addDisks */ virtual void setDisks(std::list<Disk*>* disks); addDisks(std::list<Disk*>* disks); /** * Added for GekkoFS - Remove the Disks given by their IDs * from the distribution. * TODO(dauer): Decide & document freeing of memory */ void removeDisks(std::vector<int64_t> disk_ids); /** * @see Distributor::getDisks Loading Loading @@ -160,6 +166,12 @@ private: void add_partitions(std::list<Disk*>* disks); uint64_t partition_capacity(uint64_t part_id, uint64_t new_total_capacity); uint64_t partition_capacity(Disk* disk, uint64_t new_total_capacity); void redistribute( std::unordered_map<uint64_t, uint64_t>& old_partitions, Loading Loading @@ -207,7 +219,7 @@ private: int32_t m_copies; /** * the disks as given to setDisks (or setConfiguration) * the disks as given to addDisks (or setConfiguration) */ std::unordered_map<uint64_t, Disk*>* m_disks; Loading @@ -217,7 +229,8 @@ private: uint64_t m_num_disks; /** * partition info: id -> capacity * partition info: id -> capacity (Scaled relative to VSPACE_MAX. This * unit is also referred to as blocks.) */ std::unordered_map<uint64_t, uint64_t>* m_partitions; Loading @@ -233,7 +246,7 @@ private: flat_segment_tree* m_interval_tree; /** * capacity of the system * capacity of the system (absolute i.e. sum of disk capacities) */ uint64_t m_capacity; Loading
src/global/random_slicing/DistRandSlice.cpp +148 −18 Original line number Diff line number Diff line Loading @@ -97,11 +97,11 @@ DistRandSlice::setConfiguration(std::list<Disk*>* disks, int64_t extentsize, m_copies = copies; setDisks(disks); addDisks(disks); } void DistRandSlice::setDisks(std::list<Disk*>* disks) { DistRandSlice::addDisks(std::list<Disk*>* disks) { if(this->m_disks == NULL) { Loading @@ -122,6 +122,129 @@ DistRandSlice::setDisks(std::list<Disk*>* disks) { } } // Added for GekkoFS void DistRandSlice::removeDisks(std::vector<int64_t> disk_ids) { // part id -> num blocks to remove std::unordered_map<uint64_t, uint64_t> old_partitions; for(const auto partition : *m_partitions) { // initialize with 0 blocks to remove old_partitions[partition.first] = 0; } uint64_t capacity_to_remove = 0; for(const auto id : disk_ids) { old_partitions[id] = UINT64_MAX; // remove all blocks capacity_to_remove += m_disks->at(id)->getCapacity(); } uint64_t new_capacity = m_capacity - capacity_to_remove; std::list<std::pair<uint64_t, uint64_t>> free_space; collect_free_space(old_partitions, free_space); uint64_t num_blocks_to_remove = 0; for(const auto start_end : free_space) { num_blocks_to_remove += start_end.second - start_end.first; } #if defined DEBUG std::cout << "DEBUG: Removing " << disk_ids.size() << " disks: "; for(const auto id : disk_ids) { std::cout << id << " "; } std::cout << "\n" << "DEBUG: capacity_to_remove: " << capacity_to_remove << "\n" << "DEBUG: m_capacity: " << m_capacity << "\n" << "DEBUG: new_capacity: " << new_capacity << "\n" << "DEBUG: num_blocks_to_remove: " << num_blocks_to_remove << "\n"; #endif // remove those disks and their corresponding partitions // we don't need those any more and must not add the partitions to be // deleted to num_blocks_to_add in the next step for(const auto id : disk_ids) { delete m_disks->at(id); m_disks->erase(id); m_partitions->erase(id); } m_num_disks -= disk_ids.size(); m_num_partitions -= disk_ids.size(); // partition_id -> number of blocks to add std::list<std::pair<uint64_t, uint64_t>> updated_partitions; uint64_t num_blocks_to_add = 0; // adapted from add_partitions // recalculate partition sizes for remaining partitions for(const auto& partition : *m_partitions) { auto part_id = partition.first; auto old_part_capacity = partition.second; // in blocks uint64_t new_part_capacity = partition_capacity(part_id, new_capacity); assert(new_part_capacity >= old_part_capacity); // division flipped compared to add updated_partitions.push_back( std::make_pair(part_id, new_part_capacity - old_part_capacity)); num_blocks_to_add += new_part_capacity - old_part_capacity; // !!! CAUTION: m_partitions map is not used again in computations, // therefore it is safe to update partition sizes here. If this ever // changes, take it into account (*m_partitions)[part_id] = new_part_capacity; } // XXX: ideally, num_blocks_to_add should equal num_blocks_to_remove, but // due to rounding errors, this is not always the case. Add/remove the // difference to/from the last partition. // // NOTE: We could distribute the remainder proportionally among the new // partitions, but this way is faster and the remainder is neglectable if(num_blocks_to_remove != num_blocks_to_add) { uint64_t r = num_blocks_to_remove - num_blocks_to_add; #if defined DEBUG cout << "remove " << num_blocks_to_remove << "\n" << "add " << num_blocks_to_add << "\n" << "diff " << r << "\n"; #endif updated_partitions.back().second += r; } // compute the free space as list of pairs (start block - end block) // std::list<std::pair<uint64_t, uint64_t>> free_space; redistribute(old_partitions, updated_partitions); m_capacity = new_capacity; #if defined DEBUG dump_intervals(); verify_partitions(); #endif // TODO(dauer): what about segment_tree: defaultvalue? } /** * Private function to get disk capacity and compute the new partition capacity * according to it and the new capacity of the system. * @return calculated capacity in blocks */ uint64_t DistRandSlice::partition_capacity(uint64_t part_id, uint64_t new_total_capacity) { return partition_capacity(m_disks->at(part_id), new_total_capacity); } uint64_t DistRandSlice::partition_capacity(Disk* disk, uint64_t new_total_capacity) { uint64_t disk_capacity = disk->getCapacity(); double p = disk_capacity * 1.0 / new_total_capacity; return (uint64_t) floor(p * VSPACE_MAX); } /** * 64 bit Integer Hash Function Loading @@ -138,6 +261,14 @@ my_hash(int64_t i) { i ^= (i >> 28); i += (i << 31); // For debugging with smaller VSPACE_MAX. if(DistRandSlice::VSPACE_MAX != UINT64_MAX) { #ifndef DEBUG assert(!"Running with VSPACE_MAX != UINT64_MAX but no DEBUG"); #endif i = i % DistRandSlice::VSPACE_MAX; } return i; } Loading Loading @@ -401,15 +532,9 @@ DistRandSlice::add_partitions(std::list<Disk*>* new_disks) { it != m_partitions->end(); ++it) { uint64_t part_id = it->first; uint64_t old_part_capacity = it->second; uint64_t old_part_capacity = it->second; // in blocks // get disk capacity and compute the new partition capacity according to // it and the new capacity of the system uint64_t disk_capacity = m_disks->find(part_id)->second->getCapacity(); double p = disk_capacity * 1.0 / new_capacity; uint64_t new_part_capacity = (uint64_t) floor(p * VSPACE_MAX); uint64_t new_part_capacity = partition_capacity(part_id, new_capacity); old_partitions[it->first] = old_part_capacity - new_part_capacity; Loading @@ -423,8 +548,7 @@ DistRandSlice::add_partitions(std::list<Disk*>* new_disks) { #endif // !!! CAUTION: m_partitions map is not used again in computations, // therefore it is // safe to update partition sizes here. If this ever // therefore it is safe to update partition sizes here. If this ever // changes, take it into account (*m_partitions)[part_id] = new_part_capacity; } Loading @@ -444,8 +568,7 @@ DistRandSlice::add_partitions(std::list<Disk*>* new_disks) { it != new_disks->end(); ++it) { uint64_t part_id = (*it)->getId(); double p = (*it)->getCapacity() * 1.0 / new_capacity; uint64_t new_part_capacity = (uint64_t) floor(p * VSPACE_MAX); uint64_t new_part_capacity = partition_capacity(*it, new_capacity); num_blocks_to_add += new_part_capacity; // XXX ATM partition_id == disk_id Loading @@ -472,6 +595,11 @@ DistRandSlice::add_partitions(std::list<Disk*>* new_disks) { // partitions, but this way is faster and the remainder is neglectable if(num_blocks_to_remove != num_blocks_to_add) { uint64_t r = num_blocks_to_remove - num_blocks_to_add; #if defined DEBUG cout << "remove " << num_blocks_to_remove << "\n" << "add " << num_blocks_to_add << "\n" << "diff " << r << "\n"; #endif new_partitions.back().second += r; } Loading Loading @@ -528,6 +656,7 @@ DistRandSlice::redistribute( } #if defined DEBUG && defined DUMP_FREE_SPACE std::cout << "\n\nDEBUG: redistribute after collecting free space"; dump_free_space(free_space); #endif Loading Loading @@ -850,6 +979,7 @@ DistRandSlice::reuse_free_space_sort( } #if defined DEBUG && defined DUMP_FREE_SPACE std::cout << "\n\nDEBUG: in reuse_free_space_sort"; dump_free_space(free_space); #endif } Loading Loading @@ -964,7 +1094,7 @@ DistRandSlice::verify_partitions(void) { // we can't use == here :P double e = fabs(dp - pp); if(e > 1.0e-14) { if(e > DistRandSlice::DOUBLE_ALLOWED_ERROR) { cerr.precision(100); cerr << "1: error in double comparison: " << dp << " vs. " << pp << " e=" << e << "\n"; Loading @@ -973,7 +1103,7 @@ DistRandSlice::verify_partitions(void) { e = fabs(pp - ip); if(e > 1.0e-14) { if(e > DistRandSlice::DOUBLE_ALLOWED_ERROR) { cerr.precision(100); cerr << "2: error in double comparison: " << pp << " vs. " << ip << " e=" << e << "\n"; Loading Loading @@ -1015,7 +1145,7 @@ DistRandSlice::compute_interval_sizes(void) { i_high = it->first; i_pid = last_pid; // check for illegal memory access // at: check for illegal memory access result.at(i_pid) += (i_high - i_low); // result[i_pid] += (i_high - i_low); Loading