// ---------------------------------------------------------------------- //! @file: RoundRobinPlacementStrategy.hh //! @author: Abhishek Lekshmanan - CERN // ---------------------------------------------------------------------- /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2023 CERN/Switzerland * * * * This program 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 3 of the License, or * * (at your option) any later version. * * * * This program 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 this program. If not, see .* ************************************************************************/ #pragma once #include "common/Logging.hh" #include "mgm/placement/ClusterDataTypes.hh" #include "mgm/placement/PlacementStrategy.hh" #include "mgm/placement/RRSeed.hh" #include "mgm/placement/ThreadLocalRRSeed.hh" namespace eos::mgm::placement { struct RRSeeder { virtual ~RRSeeder() = default; virtual size_t get(size_t index, size_t num_items, size_t fid) = 0; virtual size_t getNumSeeds() = 0; }; struct GlobalRRSeeder : public RRSeeder { explicit GlobalRRSeeder(size_t max_buckets) : mSeed(max_buckets) {} size_t get(size_t index, size_t num_items, size_t) override { return mSeed.get(index, num_items); } size_t getNumSeeds() override { return mSeed.getNumSeeds(); } private: RRSeed mSeed; }; struct ThreadLocalRRSeeder : public RRSeeder { explicit ThreadLocalRRSeeder(size_t max_buckets) { ThreadLocalRRSeed::init(max_buckets); } size_t get(size_t index, size_t num_items, size_t) override { return ThreadLocalRRSeed::get(index, num_items); } size_t getNumSeeds() override { return ThreadLocalRRSeed::getNumSeeds(); } }; struct RandomSeeder: public RRSeeder { explicit RandomSeeder(size_t max_buckets) : rd(), random_gen(rd()), dist(0, max_buckets - 1), mMaxBuckets(max_buckets) {} size_t get(size_t index, size_t, size_t) override { if (index > mMaxBuckets) { eos_static_err("msg=\"RandomSeeder index > MaxBuckets\" index=%lu mMaxBuckets=%lu", index, mMaxBuckets); // This is a really bad random number, but this code should be unreachable return dist(random_gen) + index - mMaxBuckets; } return dist(random_gen); } size_t getNumSeeds() override { return mMaxBuckets; } private: std::random_device rd; std::mt19937 random_gen; std::uniform_int_distribution dist; size_t mMaxBuckets; }; struct FidSeeder: public RRSeeder { explicit FidSeeder(size_t _max_buckets) : max_buckets(_max_buckets) {} size_t get(size_t index, size_t replicas, size_t fid) { return index ^ replicas ^ fid; } size_t getNumSeeds() override { return max_buckets; } private: size_t max_buckets; }; std::unique_ptr makeRRSeeder(PlacementStrategyT strategy, size_t max_buckets); class RoundRobinPlacement : public PlacementStrategy { public: explicit RoundRobinPlacement(PlacementStrategyT strategy, size_t max_buckets) : mSeed(makeRRSeeder(strategy, max_buckets)) { } PlacementResult placeFiles(const ClusterData& cluster_data, Args args) override; private: std::unique_ptr mSeed; }; } // namespace eos::mgm::placementq