Commit 7c2a9b97 authored by David Auer's avatar David Auer
Browse files

Add remove function to random slicing

parent 48f239a7
Loading
Loading
Loading
Loading
+27 −14
Original line number Diff line number Diff line
@@ -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.
@@ -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
@@ -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,
@@ -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;

@@ -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;

@@ -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;

+148 −18
Original line number Diff line number Diff line
@@ -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) {

@@ -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
@@ -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;
}

@@ -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;

@@ -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;
    }
@@ -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
@@ -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;
    }

@@ -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

@@ -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
    }
@@ -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";
@@ -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";
@@ -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);