/* ---- This file is part of SECONDO. Copyright (C) 2020, Faculty of Mathematics and Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- This files realizes a balanced dsitribution of slots to workers. */ #include "BalancedCollect.h" #include #include #include #include #include #include #include using namespace std; namespace distributed2 { namespace loadbalance { /* ~class Slot~ A slot is represented by its number and the size. */ class Slot{ public: Slot(size_t _no, double _size): no(_no), size(_size) {} size_t getNo() const { return no; } double getSize() const { return size;} string toString() const{ stringstream ss; ss << no <<"(" << size << ")"; return ss.str(); } static bool sizeGreater(const Slot& s1, const Slot& s2) { return s1.size > s2.size; } private: size_t no; double size; }; std::ostream& operator<<(ostream& o, const Slot& s){ return o << s.toString(); } /* Class representing a DWorker. A DWorker is represented as a vector of Slots contained by this worker. */ class DWorker{ public: DWorker(int _no) : no(_no),size(0) {} void add (Slot slot){ slots.push_back(slot); size += slot.getSize(); } Slot removeTop(){ if(slots.empty()) return Slot(-1,-1); Slot res = slots.back(); slots.pop_back(); size -= res.getSize(); return res; } string toString() const{ stringstream ss; for(size_t i=0;i 0) ss << " + " ; ss << slots[i].toString(); } ss << " => " << size ; return ss.str(); } string sizeString() const{ stringstream ss; for(size_t i=0;i 0) ss << " + " ; ss << slots[i].getSize(); } ss << " => " << size ; return ss.str(); } size_t getNoSlots() const { return slots.size(); } double getNoElements() const { return size; } size_t getId () const{ return no; } const vector& getSlots() const { return slots; } private: size_t no; // identifikator of this worker double size; // summarized size of all slots vector slots; }; /* ~wless~ Comparator for DWorkers. Returns true if the left DWorker has more elements than the right one. */ class wless { public: bool operator()(const DWorker& left, const DWorker& right){ return left.getNoElements()< right.getNoElements(); } }; class wgreater{ public: bool operator()(const DWorker& left, const DWorker& right){ return left.getNoElements() > right.getNoElements(); } }; /* ~SimpleDist~ Implementation of a Distributor. Slots are sorted by decreasinge size. Then it iteratet over the sorted slots. The next slot is assigned to that DWorker having the smallest amount of elements. */ class Distributor{ public: vector distributeSimple(vector& slots, int noDWorkers) { return distribute(slots, noDWorkers, 0); } vector distributeComplete(vector& slots, int noDWorkers){ return distribute(slots, noDWorkers, getNoReserve(noDWorkers)); } private : virtual vector distribute(vector& slots, int noDWorkers, int noReserve) { // sort slots in descending order sort(slots.begin(), slots.end(), Slot::sizeGreater); // create completely empty dworkers (full set) DWorkers.clear(); for(int i=0;i, wgreater> q; for(size_t i=0;i 0){ reDistribute(noReserve); } return DWorkers; }; vector DWorkers; // the workers double completeSize; // size of the whole relation // 5 percent uint32_t getNoReserve(int noWorkers){ if(noWorkers < 4){ return 0; } return ((uint32_t) ((noWorkers-1)*0.05))+1; } void reDistribute(uint32_t noReserve){ double avgSize = completeSize / DWorkers.size(); double maxSize = 1.03 * avgSize; priority_queue, wgreater> qreserve; for(size_t i=DWorkers.size()-noReserve; i< DWorkers.size();i++){ DWorker w = DWorkers[i]; qreserve.push(w); } priority_queue, wless> qbase; for(size_t i=0;i qbase; for(size_t i=0;i maxSize){ source.add(slot); return false; } else { target.add(slot); return true; } } }; /* Returns a vektor having the size slotsizes. The content of each field is the assigned worker. */ vector getMapping(const vector& slotsizes, uint32_t noWorkers, bool simple) { vector slots; vector result; for(size_t i=0;i worker = simple ? dist.distributeSimple(slots,noWorkers) : dist.distributeComplete(slots,noWorkers); for(auto w : worker){ size_t wn = w.getId(); for(auto& s : w.getSlots()){ result[s.getNo()] = wn; } } return result; } } // end of namespace loadbalance }