From 1f2f51ac2bd2ee8d598ba7fb9a7b6696c193372f Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Tue, 18 Oct 2022 06:01:39 -0500 Subject: [PATCH 001/511] Add prefetcher --- src/CMakeLists.txt | 5 +- src/api/hermes.cc | 2 + src/hermes_types.h | 24 +++++ src/prefetcher.cc | 12 +++ src/prefetcher.h | 180 ++++++++++++++++++++++++++++++++++ src/prefetcher_factory.h | 39 ++++++++ src/prefetchers/apriori.cc | 5 + src/prefetchers/apriori.h | 20 ++++ src/prefetchers/sequential.cc | 5 + src/prefetchers/sequential.h | 20 ++++ src/rpc.h | 2 + src/rpc_thallium.cc | 47 +++++++++ src/rpc_thallium.h | 1 + 13 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 src/prefetcher.cc create mode 100644 src/prefetcher.h create mode 100644 src/prefetcher_factory.h create mode 100644 src/prefetchers/apriori.cc create mode 100644 src/prefetchers/apriori.h create mode 100644 src/prefetchers/sequential.cc create mode 100644 src/prefetchers/sequential.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 552b7cc03..52e2c057d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,11 +26,14 @@ set(HERMES_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/api/hermes.cc ${CMAKE_CURRENT_SOURCE_DIR}/api/vbucket.cc ${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cc + ${CMAKE_CURRENT_SOURCE_DIR}/prefetcher.cc + ${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/sequential.cc + ${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/apriori.cc ${CMAKE_CURRENT_SOURCE_DIR}/data_placement_engine.cc ${CMAKE_CURRENT_SOURCE_DIR}/dpe/random.cc ${CMAKE_CURRENT_SOURCE_DIR}/dpe/round_robin.cc ${CMAKE_CURRENT_SOURCE_DIR}/dpe/minimize_io_time.cc - ) +) #------------------------------------------------------------------------------ # Libraries diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 6ff7bcbb5..df77ecca6 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -375,6 +375,8 @@ std::shared_ptr InitHermes(Config *config, bool is_daemon, &result->trans_arena_, bo_address.c_str(), config->bo_num_threads, config->buffer_organizer_port); + StartPrefetcher(&result->context_, &result->rpc_, 10); + double sleep_ms = config->system_view_state_update_interval_ms; StartGlobalSystemViewStateUpdateThread(&result->context_, &result->rpc_, &result->trans_arena_, sleep_ms); diff --git a/src/hermes_types.h b/src/hermes_types.h index e42584101..b6a3c0ee3 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -387,6 +387,7 @@ union BlobID { u64 as_int; }; + /** Trait ID type */ typedef u64 TraitID; @@ -403,4 +404,27 @@ enum class TraitType : u8 { } // namespace api } // namespace hermes + +namespace std { +template <> +struct hash { + std::size_t operator()(const hermes::BlobID &key) const { + return std::hash{}(key.as_int); + } +}; + +template <> +struct hash { + std::size_t operator()(const hermes::BucketID &key) const { + return std::hash{}(key.as_int); + } +}; + +template <> +struct hash { + std::size_t operator()(const hermes::VBucketID &key) const { + return std::hash{}(key.as_int); + } +}; +} // namespace std #endif // HERMES_TYPES_H_ diff --git a/src/prefetcher.cc b/src/prefetcher.cc new file mode 100644 index 000000000..7b6d49c6e --- /dev/null +++ b/src/prefetcher.cc @@ -0,0 +1,12 @@ +// +// Created by lukemartinlogan on 10/18/22. +// + +#include "prefetcher.h" + +namespace hermes { + +void Prefetcher::Process() { +} + +} // namespace hermes \ No newline at end of file diff --git a/src/prefetcher.h b/src/prefetcher.h new file mode 100644 index 000000000..dc50c291c --- /dev/null +++ b/src/prefetcher.h @@ -0,0 +1,180 @@ +// +// Created by lukemartinlogan on 10/18/22. +// + +#ifndef HERMES_SRC_PREFETCHER_H_ +#define HERMES_SRC_PREFETCHER_H_ + +#include "hermes.h" +#include "hermes_types.h" +#include "rpc_thallium.h" +#include +#include +#include +#include +#include + +namespace hermes { + +/* Equal operators */ +static bool operator==(const BlobID& first, const BlobID& second) { + return first.as_int == second.as_int; +} +static bool operator==(const BucketID& first, const BucketID& second) { + return first.as_int == second.as_int; +} +static bool operator==(const VBucketID& first, const VBucketID& second) { + return first.as_int == second.as_int; +} + +enum class PrefetchHint { + kNone, + kNoPrefetch, + kFileSequential, + kFileStrided, + kMachineLearning +}; + +enum class IoType { + kNone, kPut, kGet +}; + +struct PrefetchContext { + PrefetchHint hint_; + int read_ahead_; + PrefetchContext() : hint_(PrefetchHint::kNone) {} +}; + +struct GlobalThreadID { + int rank_; + int tid_; + GlobalThreadID() : rank_(0), tid_(0) {} + GlobalThreadID(int rank, int tid) : rank_(rank), tid_(tid) {} +}; + +struct IoLogEntry { + VBucketID vbkt_id_; + BucketID bkt_id_; + BlobID blob_id_; + IoType type_; + off_t off_; + size_t size_; + PrefetchContext pctx_; + GlobalThreadID tid_; + struct timespec timestamp_; + bool historical_; +}; + +class Prefetcher { + private: + uint32_t max_length_; + std::list log_; + thallium::mutex lock_; + public: + Prefetcher() : max_length_(4096) {} + void SetLogLength(uint32_t max_length); + void Log(IoLogEntry &entry) { + lock_.lock(); + if (log_.size() == max_length_) { + log_.pop_front(); + } + log_.emplace_back(entry); + lock_.unlock(); + } + static void LogIoStat(IoLogEntry &entry) { + } + void Process(); +}; + +struct PrefetchDecision { + BlobID blob_id; + std::list access_times_; + float updated_score_; +}; + +class PrefetchSchema { + private: + std::unordered_map schema_; + + public: + void emplace(PrefetchDecision &decision) { + schema_.emplace(decision.blob_id, decision); + } +}; + +class PrefetchAlgorithm { + public: + virtual void Process(std::list &log, + PrefetchSchema &schema) = 0; +}; + +/** RPC SERIALIZERS */ + +// PrefetchHint +template +void save(A &ar, PrefetchHint &hint) { + ar << static_cast(hint); +} +template +void load(A &ar, PrefetchHint &hint) { + int hint_i; + ar >> hint_i; + hint = static_cast(hint_i); +} + +// IoType +template +void save(A &ar, IoType &hint) { + ar << static_cast(hint); +} +template +void load(A &ar, IoType &hint) { + int hint_i; + ar >> hint_i; + hint = static_cast(hint_i); +} + +// struct timespec +template +void save(A &ar, struct timespec &ts) { + ar << ts.tv_sec; + ar << ts.tv_nsec; +} +template +void load(A &ar, struct timespec &ts) { + ar >> ts.tv_sec; + ar >> ts.tv_nsec; +} + +// PrefetchContext +template +void serialize(A &ar, PrefetchContext &pctx) { + ar & pctx.hint_; + ar & pctx.read_ahead_; +} + +// GlobalThreadID +template +void serialize(A &ar, GlobalThreadID &tid) { + ar & tid.rank_; + ar & tid.tid_; +} + +// IoLogEntry +template +void serialize(A &ar, IoLogEntry &entry) { + ar & entry.vbkt_id_; + ar & entry.bkt_id_; + ar & entry.blob_id_; + ar & entry.type_; + ar & entry.off_; + ar & entry.size_; + ar & entry.pctx_; + ar & entry.tid_; + // ar & entry.timestamp_; + ar & entry.historical_; +} + +} + +#endif // HERMES_SRC_PREFETCHER_H_ diff --git a/src/prefetcher_factory.h b/src/prefetcher_factory.h new file mode 100644 index 000000000..f641a22d7 --- /dev/null +++ b/src/prefetcher_factory.h @@ -0,0 +1,39 @@ +// +// Created by lukemartinlogan on 10/18/22. +// + +#ifndef HERMES_SRC_PREFETCHER_FACTORY_H_ +#define HERMES_SRC_PREFETCHER_FACTORY_H_ + +#include "prefetcher.h" +#include + +#include "prefetchers/sequential.h" +#include "prefetchers/apriori.h" + +namespace hermes { + +class PrefetcherFactory { + public: + /** + * Return the instance of mapper given a type. Uses factory pattern. + * + * @param type, MapperType, type of mapper to be used by the STDIO adapter. + * @return Instance of mapper given a type. + */ + static std::unique_ptr Get(const PrefetchHint &type) { + switch (type) { + case PrefetchHint::kSequential: { + return std::make_unique(); + } + case PrefetchHint::kApriori: { + return std::make_unique(); + } + default: return nullptr; + } + } +}; + +} + +#endif // HERMES_SRC_PREFETCHER_FACTORY_H_ diff --git a/src/prefetchers/apriori.cc b/src/prefetchers/apriori.cc new file mode 100644 index 000000000..6e57fd92d --- /dev/null +++ b/src/prefetchers/apriori.cc @@ -0,0 +1,5 @@ +// +// Created by lukemartinlogan on 10/18/22. +// + +#include "apriori.h" diff --git a/src/prefetchers/apriori.h b/src/prefetchers/apriori.h new file mode 100644 index 000000000..44a715723 --- /dev/null +++ b/src/prefetchers/apriori.h @@ -0,0 +1,20 @@ +// +// Created by lukemartinlogan on 10/18/22. +// + +#ifndef HERMES_SRC_PREFETCHERS_APRIORI_H_ +#define HERMES_SRC_PREFETCHERS_APRIORI_H_ + +#include "prefetcher.h" + +namespace hermes { + +class AprioriPrefetcher : public PrefetchAlgorithm { + public: + void Process(std::list &log, + PrefetchSchema &schema) {} +}; + +} + +#endif // HERMES_SRC_PREFETCHERS_APRIORI_H_ diff --git a/src/prefetchers/sequential.cc b/src/prefetchers/sequential.cc new file mode 100644 index 000000000..94b6e4a4f --- /dev/null +++ b/src/prefetchers/sequential.cc @@ -0,0 +1,5 @@ +// +// Created by lukemartinlogan on 10/18/22. +// + +#include "sequential.h" diff --git a/src/prefetchers/sequential.h b/src/prefetchers/sequential.h new file mode 100644 index 000000000..7725a68e0 --- /dev/null +++ b/src/prefetchers/sequential.h @@ -0,0 +1,20 @@ +// +// Created by lukemartinlogan on 10/18/22. +// + +#ifndef HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ +#define HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ + +#include "prefetcher.h" + +namespace hermes { + +class SequentialPrefetcher : public PrefetchAlgorithm { + public: + void Process(std::list &log, + PrefetchSchema &schema) {} +}; + +} + +#endif // HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ diff --git a/src/rpc.h b/src/rpc.h index 70e9797ec..85de47532 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -73,6 +73,8 @@ std::string GetProtocol(RpcContext *rpc); void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, Arena *arena, const char *addr, int num_threads, int port); +void StartPrefetcher(SharedMemoryContext *context, RpcContext *rpc, + double sleep_ms); } // namespace hermes // TODO(chogan): I don't like that code similar to this is in buffer_pool.cc. diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 9650d8226..13f5f2d30 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -15,6 +15,8 @@ #include "rpc.h" #include "buffer_organizer.h" #include "metadata_management_internal.h" +#include "prefetcher.h" +#include "singleton.h" namespace tl = thallium; @@ -597,6 +599,51 @@ void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, rpc_server->define("OrganizeBlob", rpc_organize_blob); } +void StartPrefetcher(SharedMemoryContext *context, RpcContext *rpc, + double sleep_ms) { + ThalliumState *state = GetThalliumState(rpc); + tl::engine *rpc_server = state->engine; + using tl::request; + + // Create the LogIoStat RPC + auto rpc_log_io_stat = [context](const request &req, IoLogEntry &entry) { + (void) context; + auto prefetcher = Singleton::GetInstance(); + prefetcher->Log(entry); + req.respond(true); + }; + rpc_server->define("LogIoStat", rpc_log_io_stat); + + // Prefetcher thread args + struct PrefetcherThreadArgs { + SharedMemoryContext *context; + RpcContext *rpc; + double sleep_ms; + }; + + // Create the prefetcher thread lambda + auto prefetch = [](void *args) { + PrefetcherThreadArgs targs = *((PrefetcherThreadArgs*)args); + ThalliumState *state = GetThalliumState(targs.rpc); + auto prefetcher = Singleton::GetInstance(); + while (!state->kill_requested.load()) { + prefetcher->Process(); + tl::thread::self().sleep(*state->engine, targs.sleep_ms); + } + }; + + // Create prefetcher thread + PrefetcherThreadArgs args; + args.context = context; + args.rpc = rpc; + args.sleep_ms = sleep_ms; + + ABT_xstream_create(ABT_SCHED_NULL, &state->execution_stream); + ABT_thread_create_on_xstream(state->prefetch_stream, + prefetch, &args, + ABT_THREAD_ATTR_NULL, NULL); +} + void StartGlobalSystemViewStateUpdateThread(SharedMemoryContext *context, RpcContext *rpc, Arena *arena, double sleep_ms) { diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index 6a2aeb700..e2930076a 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -42,6 +42,7 @@ struct ThalliumState { tl::engine *engine; tl::engine *bo_engine; ABT_xstream execution_stream; + ABT_xstream prefetch_stream; }; struct ClientThalliumState { From dd116f35a390b513e586630ebebfbe21aa6b2927 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Tue, 18 Oct 2022 06:33:03 -0500 Subject: [PATCH 002/511] Add log to prefetcher --- src/prefetcher.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/prefetcher.cc b/src/prefetcher.cc index 7b6d49c6e..00b0d9c6b 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -7,6 +7,7 @@ namespace hermes { void Prefetcher::Process() { + LOG(INFO) << "In prefetcher!!!" << std::endl; } } // namespace hermes \ No newline at end of file From 36c055a9bca2967c769ef00c5e56f4feeb3b4a8e Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 19 Oct 2022 06:10:16 -0500 Subject: [PATCH 003/511] Prefetcher thread starts --- src/api/hermes.cc | 3 ++- src/prefetcher.cc | 35 ++++++++++++++++++++++++++++++++++- src/prefetcher.h | 21 +++++++++------------ src/rpc.h | 2 +- src/rpc_thallium.cc | 19 +++++++++++-------- src/rpc_thallium.h | 1 - 6 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/api/hermes.cc b/src/api/hermes.cc index df77ecca6..af808bca4 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -375,7 +375,8 @@ std::shared_ptr InitHermes(Config *config, bool is_daemon, &result->trans_arena_, bo_address.c_str(), config->bo_num_threads, config->buffer_organizer_port); - StartPrefetcher(&result->context_, &result->rpc_, 10); + StartPrefetcher(&result->context_, &result->rpc_, + &result->trans_arena_, 10); double sleep_ms = config->system_view_state_update_interval_ms; StartGlobalSystemViewStateUpdateThread(&result->context_, &result->rpc_, diff --git a/src/prefetcher.cc b/src/prefetcher.cc index 00b0d9c6b..928b82984 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -3,11 +3,44 @@ // #include "prefetcher.h" +#include "metadata_management.h" +#include "singleton.h" + +using hermes::api::Hermes; namespace hermes { +bool Prefetcher::LogIoStat(Hermes *hermes, IoLogEntry &entry) { + RpcContext *rpc = &hermes->rpc_; + u32 target_node = HashToNode(hermes, entry); + bool result = false; + if (target_node == rpc->node_id) { + auto prefetcher = Singleton::GetInstance(); + prefetcher->Log(entry); + } else { + result = RpcCall(rpc, target_node, "LogIoStat", entry); + } + return result; +} + +size_t Prefetcher::HashToNode(Hermes *hermes, IoLogEntry &entry) { + CommunicationContext *comm = &hermes->comm_; + size_t h1 = std::hash{}(entry.vbkt_id_.as_int); + size_t h2 = std::hash{}(entry.bkt_id_.as_int); + size_t hash = h1 ^ h2; + return (hash % comm->num_nodes) + 1; +} + +void Prefetcher::Log(IoLogEntry &entry) { + lock_.lock(); + if (log_.size() == max_length_) { + log_.pop_front(); + } + log_.emplace_back(entry); + lock_.unlock(); +} + void Prefetcher::Process() { - LOG(INFO) << "In prefetcher!!!" << std::endl; } } // namespace hermes \ No newline at end of file diff --git a/src/prefetcher.h b/src/prefetcher.h index dc50c291c..a66e00a5f 100644 --- a/src/prefetcher.h +++ b/src/prefetcher.h @@ -20,12 +20,13 @@ namespace hermes { static bool operator==(const BlobID& first, const BlobID& second) { return first.as_int == second.as_int; } +/* static bool operator==(const BucketID& first, const BucketID& second) { return first.as_int == second.as_int; } static bool operator==(const VBucketID& first, const VBucketID& second) { return first.as_int == second.as_int; -} +}*/ enum class PrefetchHint { kNone, @@ -70,20 +71,16 @@ class Prefetcher { uint32_t max_length_; std::list log_; thallium::mutex lock_; + public: Prefetcher() : max_length_(4096) {} - void SetLogLength(uint32_t max_length); - void Log(IoLogEntry &entry) { - lock_.lock(); - if (log_.size() == max_length_) { - log_.pop_front(); - } - log_.emplace_back(entry); - lock_.unlock(); - } - static void LogIoStat(IoLogEntry &entry) { - } + void SetLogLength(uint32_t max_length) { max_length_ = max_length; } + void Log(IoLogEntry &entry); + static bool LogIoStat(api::Hermes *hermes, IoLogEntry &entry); void Process(); + + private: + static size_t HashToNode(api::Hermes *hermes, IoLogEntry &entry); }; struct PrefetchDecision { diff --git a/src/rpc.h b/src/rpc.h index 85de47532..4041c5f60 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -74,7 +74,7 @@ void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, Arena *arena, const char *addr, int num_threads, int port); void StartPrefetcher(SharedMemoryContext *context, RpcContext *rpc, - double sleep_ms); + Arena *arena, double sleep_ms); } // namespace hermes // TODO(chogan): I don't like that code similar to this is in buffer_pool.cc. diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 13f5f2d30..93cc22667 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -600,7 +600,7 @@ void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, } void StartPrefetcher(SharedMemoryContext *context, RpcContext *rpc, - double sleep_ms) { + Arena *arena, double sleep_ms) { ThalliumState *state = GetThalliumState(rpc); tl::engine *rpc_server = state->engine; using tl::request; @@ -619,12 +619,14 @@ void StartPrefetcher(SharedMemoryContext *context, RpcContext *rpc, SharedMemoryContext *context; RpcContext *rpc; double sleep_ms; + bool init_; }; // Create the prefetcher thread lambda auto prefetch = [](void *args) { PrefetcherThreadArgs targs = *((PrefetcherThreadArgs*)args); ThalliumState *state = GetThalliumState(targs.rpc); + LOG(INFO) << "Prefetching thread started" << std::endl; auto prefetcher = Singleton::GetInstance(); while (!state->kill_requested.load()) { prefetcher->Process(); @@ -633,14 +635,15 @@ void StartPrefetcher(SharedMemoryContext *context, RpcContext *rpc, }; // Create prefetcher thread - PrefetcherThreadArgs args; - args.context = context; - args.rpc = rpc; - args.sleep_ms = sleep_ms; + PrefetcherThreadArgs *args = PushStruct(arena); + args->context = context; + args->rpc = rpc; + args->sleep_ms = sleep_ms; + args->init_ = false; ABT_xstream_create(ABT_SCHED_NULL, &state->execution_stream); - ABT_thread_create_on_xstream(state->prefetch_stream, - prefetch, &args, + ABT_thread_create_on_xstream(state->execution_stream, + prefetch, args, ABT_THREAD_ATTR_NULL, NULL); } @@ -656,6 +659,7 @@ void StartGlobalSystemViewStateUpdateThread(SharedMemoryContext *context, auto update_global_system_view_state = [](void *args) { ThreadArgs *targs = (ThreadArgs *)args; ThalliumState *state = GetThalliumState(targs->rpc); + LOG(INFO) << "Update global system view state start" << std::endl; while (!state->kill_requested.load()) { UpdateGlobalSystemViewState(targs->context, targs->rpc); tl::thread::self().sleep(*state->engine, targs->sleep_ms); @@ -668,7 +672,6 @@ void StartGlobalSystemViewStateUpdateThread(SharedMemoryContext *context, args->sleep_ms = sleep_ms; ThalliumState *state = GetThalliumState(rpc); - ABT_xstream_create(ABT_SCHED_NULL, &state->execution_stream); ABT_thread_create_on_xstream(state->execution_stream, update_global_system_view_state, args, ABT_THREAD_ATTR_NULL, NULL); diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index e2930076a..6a2aeb700 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -42,7 +42,6 @@ struct ThalliumState { tl::engine *engine; tl::engine *bo_engine; ABT_xstream execution_stream; - ABT_xstream prefetch_stream; }; struct ClientThalliumState { From 06571b91fd97f3101de1dd3d1dc95a747ec82098 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 19 Oct 2022 12:05:14 -0500 Subject: [PATCH 004/511] Prefetcher frontend nearly complete --- src/api/hermes.cc | 4 ++ src/prefetcher.cc | 106 +++++++++++++++++++++++++++++++++++++-- src/prefetcher.h | 99 +++++++++++++++++++++++++++++------- src/prefetcher_factory.h | 9 ++-- src/rpc.h | 4 +- src/rpc_thallium.cc | 4 +- 6 files changed, 196 insertions(+), 30 deletions(-) diff --git a/src/api/hermes.cc b/src/api/hermes.cc index af808bca4..9b39bdf88 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -24,6 +24,8 @@ #include "buffer_pool_internal.h" #include "metadata_management_internal.h" #include "config_parser.h" +#include "prefetcher.h" +#include "singleton.h" namespace hermes { @@ -375,6 +377,8 @@ std::shared_ptr InitHermes(Config *config, bool is_daemon, &result->trans_arena_, bo_address.c_str(), config->bo_num_threads, config->buffer_organizer_port); + auto prefetcher = Singleton::GetInstance(); + prefetcher->SetHermes(result); StartPrefetcher(&result->context_, &result->rpc_, &result->trans_arena_, 10); diff --git a/src/prefetcher.cc b/src/prefetcher.cc index 928b82984..101d5b4c1 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -2,7 +2,7 @@ // Created by lukemartinlogan on 10/18/22. // -#include "prefetcher.h" +#include "prefetcher_factory.h" #include "metadata_management.h" #include "singleton.h" @@ -18,16 +18,27 @@ bool Prefetcher::LogIoStat(Hermes *hermes, IoLogEntry &entry) { auto prefetcher = Singleton::GetInstance(); prefetcher->Log(entry); } else { - result = RpcCall(rpc, target_node, "LogIoStat", entry); + result = RpcCall(rpc, target_node, + "LogIoStat", entry); } return result; } +/** + * HashToNode + * + * Determines which node an IoLogEntry should be keyed to. + * We hash IoLogEntries to nodes using only the BucketID. + * This way, IoLogEntries regarding a particular blob are + * always placed on the same node. + * + * This approach assumes that prefetching decisions are based + * solely on the bucket's access pattern, not patterns across-buckets. + * */ + size_t Prefetcher::HashToNode(Hermes *hermes, IoLogEntry &entry) { CommunicationContext *comm = &hermes->comm_; - size_t h1 = std::hash{}(entry.vbkt_id_.as_int); - size_t h2 = std::hash{}(entry.bkt_id_.as_int); - size_t hash = h1 ^ h2; + size_t hash = std::hash{}(entry.bkt_id_.as_int); return (hash % comm->num_nodes) + 1; } @@ -40,7 +51,92 @@ void Prefetcher::Log(IoLogEntry &entry) { lock_.unlock(); } +float Prefetcher::EstimateBlobMovementTime(BlobID blob_id) { + Arena arena = InitArenaAndAllocate(8192); + u32 *buffer_sizes = 0; + BufferIdArray id_array = GetBufferIdsFromBlobId(&arena, + &hermes_->context_, + &hermes_->rpc_, + blob_id, + &buffer_sizes); + std::vector buffer_ids(id_array.ids, + id_array.ids + id_array.length); + DestroyArena(&arena); + std::vector buffer_info = GetBufferInfo( + &hermes_->context_, &hermes_->rpc_, buffer_ids); + + float xfer_time = 0; + for (auto &info : buffer_info) { + xfer_time += static_cast(info.size) / + (MEGABYTES(1) * info.bandwidth_mbps); + } + xfer_time *= 2; // x2 because movement reads, and then writes data + return xfer_time; +} + +void Prefetcher::CalculateBlobScore(PrefetchDecision &decision) { + float est_xfer_time = decision.est_xfer_time_; + float max_wait_xfer = 10; + float max_wait_sec = 60; + decision.new_score_ = -1; + decision.queue_later_ = false; + for (auto &access_time_struct : decision.access_times_) { + float next_access_sec = + if (next_access_sec < est_xfer_time) continue; + float max_access_wait = std::max(max_wait_xfer*est_xfer_time, + max_wait_sec); + float est_wait = (next_access_sec - est_xfer_time); + if (est_wait > max_access_wait) { + decision.queue_later_ = true; + continue; + } + float score = (max_access_wait - est_wait) / max_access_wait; + if (score > decision.new_score_) { + decision.new_score_ = score; + } + } +} + void Prefetcher::Process() { + // Group log by I/O hint + lock_.lock(); + std::unordered_map> hint_logs; + for (auto &entry : log_) { + hint_logs[entry.pctx_.hint_].emplace_back(entry); + } + log_.erase(log_.begin(), log_.end()); + lock_.unlock(); + + // Based on the current log, determine what blobs to prefetch + PrefetchSchema schema; + for (auto &[hint, hint_log] : hint_logs) { + auto algorithm= PrefetcherFactory::Get(hint); + algorithm->Process(hint_log, schema); + } + schema.SetCurrentTime(); + + // Merge old prefetching decisions with the new ones + for (auto &[blob_id, decision] : queue_later_) { + schema.emplace(decision); + } + queue_later_.erase(queue_later_.begin(), queue_later_.end()); + + // Calculate new blob scores + for (auto &[blob_id, decision] : schema) { + if (decision.est_xfer_time_ == -1) { + decision.est_xfer_time_ = EstimateBlobMovementTime(blob_id); + } + CalculateBlobScore(decision); + if (decision.new_score_ < 0) { + queue_later_.emplace(blob_id, decision); + continue; + } + OrganizeBlob(&hermes_->context_, &hermes_->rpc_, + decision.bkt_id_, decision.blob_id_, + epsilon_, decision.new_score_); + } + + // } } // namespace hermes \ No newline at end of file diff --git a/src/prefetcher.h b/src/prefetcher.h index a66e00a5f..7ddcf7deb 100644 --- a/src/prefetcher.h +++ b/src/prefetcher.h @@ -30,8 +30,9 @@ static bool operator==(const VBucketID& first, const VBucketID& second) { enum class PrefetchHint { kNone, - kNoPrefetch, kFileSequential, + kApriori, + kFileStrided, kMachineLearning }; @@ -66,27 +67,39 @@ struct IoLogEntry { bool historical_; }; -class Prefetcher { - private: - uint32_t max_length_; - std::list log_; - thallium::mutex lock_; +struct PrefetchStat { + float max_time_; + struct timespec start_; - public: - Prefetcher() : max_length_(4096) {} - void SetLogLength(uint32_t max_length) { max_length_ = max_length; } - void Log(IoLogEntry &entry); - static bool LogIoStat(api::Hermes *hermes, IoLogEntry &entry); - void Process(); + explicit PrefetchStat(float max_time) : max_time_(max_time) {} + + float GetRemainingTime(const struct timespec *cur) { + float diff = DiffTimespec(cur, &start_); + return max_time_ - diff; + } private: - static size_t HashToNode(api::Hermes *hermes, IoLogEntry &entry); + static float DiffTimespec(const struct timespec *left, + const struct timespec *right) { + return (left->tv_sec - right->tv_sec) + + (left->tv_nsec - right->tv_nsec) / 1000000000.0; + } }; struct PrefetchDecision { - BlobID blob_id; - std::list access_times_; - float updated_score_; + BucketID bkt_id_; + BlobID blob_id_; + std::list stats_; + bool queue_later_; + float est_xfer_time_; + float new_score_; + + PrefetchDecision() : est_xfer_time_(-1), new_score_(-1) {} + void SetCurrentTime(struct timespec &ts) { + for (auto &access_time : stats_) { + access_time.start_ = ts; + } + } }; class PrefetchSchema { @@ -94,8 +107,37 @@ class PrefetchSchema { std::unordered_map schema_; public: + void emplace(BlobID blob_id, float access_time) { + + } + void emplace(PrefetchDecision &decision) { - schema_.emplace(decision.blob_id, decision); + auto prior_decision_iter = schema_.find(decision.blob_id_); + if (prior_decision_iter == schema_.end()) { + schema_.emplace(decision.blob_id_, decision); + return; + } + auto &[blob_id, prior_decision] = (*prior_decision_iter); + prior_decision.est_xfer_time_ = decision.est_xfer_time_; + prior_decision.stats_.splice( + prior_decision.stats_.end(), + decision.stats_); + } + + void SetCurrentTime() { + struct timespec ts; + timespec_get(&ts, TIME_UTC); + for (auto &[blob_id, decision] : schema_) { + decision.SetCurrentTime(ts); + } + } + + std::unordered_map::iterator begin() { + return schema_.begin(); + } + + std::unordered_map::iterator end() { + return schema_.end(); } }; @@ -105,6 +147,29 @@ class PrefetchAlgorithm { PrefetchSchema &schema) = 0; }; +class Prefetcher { + private: + uint32_t max_length_; + thallium::mutex lock_; + std::list log_; + std::unordered_map queue_later_; + std::shared_ptr hermes_; + float epsilon_; + + public: + explicit Prefetcher() : max_length_(4096), epsilon_(.05) {} + void SetHermes(std::shared_ptr &hermes) { hermes_ = hermes; } + void SetLogLength(uint32_t max_length) { max_length_ = max_length; } + void Log(IoLogEntry &entry); + static bool LogIoStat(api::Hermes *hermes, IoLogEntry &entry); + void Process(); + + private: + static size_t HashToNode(api::Hermes *hermes, IoLogEntry &entry); + float EstimateBlobMovementTime(BlobID blob_id); + void CalculateBlobScore(PrefetchDecision &decision); +}; + /** RPC SERIALIZERS */ // PrefetchHint diff --git a/src/prefetcher_factory.h b/src/prefetcher_factory.h index f641a22d7..7e6475294 100644 --- a/src/prefetcher_factory.h +++ b/src/prefetcher_factory.h @@ -10,6 +10,7 @@ #include "prefetchers/sequential.h" #include "prefetchers/apriori.h" +#include "singleton.h" namespace hermes { @@ -21,13 +22,13 @@ class PrefetcherFactory { * @param type, MapperType, type of mapper to be used by the STDIO adapter. * @return Instance of mapper given a type. */ - static std::unique_ptr Get(const PrefetchHint &type) { + static PrefetchAlgorithm* Get(const PrefetchHint &type) { switch (type) { - case PrefetchHint::kSequential: { - return std::make_unique(); + case PrefetchHint::kFileSequential: { + return Singleton::GetInstance(); } case PrefetchHint::kApriori: { - return std::make_unique(); + return Singleton::GetInstance(); } default: return nullptr; } diff --git a/src/rpc.h b/src/rpc.h index 4041c5f60..743ca8e93 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -73,8 +73,8 @@ std::string GetProtocol(RpcContext *rpc); void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, Arena *arena, const char *addr, int num_threads, int port); -void StartPrefetcher(SharedMemoryContext *context, RpcContext *rpc, - Arena *arena, double sleep_ms); +void StartPrefetcher(SharedMemoryContext *context, + RpcContext *rpc, Arena *arena, double sleep_ms); } // namespace hermes // TODO(chogan): I don't like that code similar to this is in buffer_pool.cc. diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 93cc22667..e7912e76d 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -599,8 +599,8 @@ void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, rpc_server->define("OrganizeBlob", rpc_organize_blob); } -void StartPrefetcher(SharedMemoryContext *context, RpcContext *rpc, - Arena *arena, double sleep_ms) { +void StartPrefetcher(SharedMemoryContext *context, + RpcContext *rpc, Arena *arena, double sleep_ms) { ThalliumState *state = GetThalliumState(rpc); tl::engine *rpc_server = state->engine; using tl::request; From 11dfd252d4d834ee67822920d03c248bcc887c00 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 19 Oct 2022 12:32:09 -0500 Subject: [PATCH 005/511] Add Prefetcher to Context --- src/hermes_types.h | 18 +++++++++++ src/prefetcher.cc | 22 ++++++++------ src/prefetcher.h | 74 ++++++++-------------------------------------- src/rpc_thallium.h | 20 +++++++++++++ 4 files changed, 64 insertions(+), 70 deletions(-) diff --git a/src/hermes_types.h b/src/hermes_types.h index b6a3c0ee3..736bd7d20 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -124,6 +124,21 @@ struct MinimizeIoTimeOptions { } }; +enum class PrefetchHint { + kNone, + kFileSequential, + kApriori, + + kFileStrided, + kMachineLearning +}; + +struct PrefetchContext { + PrefetchHint hint_; + int read_ahead_; + PrefetchContext() : hint_(PrefetchHint::kNone) {} +}; + /** Hermes API call context */ struct Context { /** The default maximum number of buffer organizer retries */ @@ -155,6 +170,9 @@ struct Context { /** Whether swapping is disabled */ bool disable_swap; + /** Prefetching hints */ + PrefetchContext pctx_; + Context() : policy(default_placement_policy), buffer_organizer_retries(default_buffer_organizer_retries), rr_split(default_rr_split), diff --git a/src/prefetcher.cc b/src/prefetcher.cc index 101d5b4c1..5fda6dc40 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -17,6 +17,7 @@ bool Prefetcher::LogIoStat(Hermes *hermes, IoLogEntry &entry) { if (target_node == rpc->node_id) { auto prefetcher = Singleton::GetInstance(); prefetcher->Log(entry); + result = true; } else { result = RpcCall(rpc, target_node, "LogIoStat", entry); @@ -47,6 +48,7 @@ void Prefetcher::Log(IoLogEntry &entry) { if (log_.size() == max_length_) { log_.pop_front(); } + timespec_get(&entry.timestamp_, TIME_UTC); log_.emplace_back(entry); lock_.unlock(); } @@ -74,14 +76,15 @@ float Prefetcher::EstimateBlobMovementTime(BlobID blob_id) { return xfer_time; } -void Prefetcher::CalculateBlobScore(PrefetchDecision &decision) { +void Prefetcher::CalculateBlobScore(struct timespec &ts, + PrefetchDecision &decision) { float est_xfer_time = decision.est_xfer_time_; float max_wait_xfer = 10; float max_wait_sec = 60; decision.new_score_ = -1; decision.queue_later_ = false; - for (auto &access_time_struct : decision.access_times_) { - float next_access_sec = + for (auto &access_time_struct : decision.stats_) { + float next_access_sec = access_time_struct.GetRemainingTime(&ts); if (next_access_sec < est_xfer_time) continue; float max_access_wait = std::max(max_wait_xfer*est_xfer_time, max_wait_sec); @@ -113,30 +116,31 @@ void Prefetcher::Process() { auto algorithm= PrefetcherFactory::Get(hint); algorithm->Process(hint_log, schema); } - schema.SetCurrentTime(); - // Merge old prefetching decisions with the new ones + // Take into consideration old prefetching decisions for (auto &[blob_id, decision] : queue_later_) { schema.emplace(decision); } queue_later_.erase(queue_later_.begin(), queue_later_.end()); + //Get the current time + struct timespec ts; + timespec_get(&ts, TIME_UTC); + // Calculate new blob scores for (auto &[blob_id, decision] : schema) { if (decision.est_xfer_time_ == -1) { decision.est_xfer_time_ = EstimateBlobMovementTime(blob_id); } - CalculateBlobScore(decision); + CalculateBlobScore(ts, decision); if (decision.new_score_ < 0) { queue_later_.emplace(blob_id, decision); continue; } OrganizeBlob(&hermes_->context_, &hermes_->rpc_, - decision.bkt_id_, decision.blob_id_, + decision.bkt_id_, decision.blob_name_, epsilon_, decision.new_score_); } - - // } } // namespace hermes \ No newline at end of file diff --git a/src/prefetcher.h b/src/prefetcher.h index 7ddcf7deb..484d16d0c 100644 --- a/src/prefetcher.h +++ b/src/prefetcher.h @@ -16,37 +16,17 @@ namespace hermes { -/* Equal operators */ +using hermes::api::PrefetchContext; +using hermes::api::PrefetchHint; + static bool operator==(const BlobID& first, const BlobID& second) { return first.as_int == second.as_int; } -/* -static bool operator==(const BucketID& first, const BucketID& second) { - return first.as_int == second.as_int; -} -static bool operator==(const VBucketID& first, const VBucketID& second) { - return first.as_int == second.as_int; -}*/ - -enum class PrefetchHint { - kNone, - kFileSequential, - kApriori, - - kFileStrided, - kMachineLearning -}; enum class IoType { kNone, kPut, kGet }; -struct PrefetchContext { - PrefetchHint hint_; - int read_ahead_; - PrefetchContext() : hint_(PrefetchHint::kNone) {} -}; - struct GlobalThreadID { int rank_; int tid_; @@ -58,6 +38,7 @@ struct IoLogEntry { VBucketID vbkt_id_; BucketID bkt_id_; BlobID blob_id_; + std::string blob_name_; IoType type_; off_t off_; size_t size_; @@ -71,7 +52,8 @@ struct PrefetchStat { float max_time_; struct timespec start_; - explicit PrefetchStat(float max_time) : max_time_(max_time) {} + explicit PrefetchStat(float max_time, struct timespec &start) : + max_time_(max_time), start_(start) {} float GetRemainingTime(const struct timespec *cur) { float diff = DiffTimespec(cur, &start_); @@ -89,16 +71,15 @@ struct PrefetchStat { struct PrefetchDecision { BucketID bkt_id_; BlobID blob_id_; + std::string blob_name_; std::list stats_; bool queue_later_; float est_xfer_time_; float new_score_; PrefetchDecision() : est_xfer_time_(-1), new_score_(-1) {} - void SetCurrentTime(struct timespec &ts) { - for (auto &access_time : stats_) { - access_time.start_ = ts; - } + void AddStat(float est_access_time, struct timespec &start) { + stats_.emplace_back(est_access_time, start); } }; @@ -107,10 +88,6 @@ class PrefetchSchema { std::unordered_map schema_; public: - void emplace(BlobID blob_id, float access_time) { - - } - void emplace(PrefetchDecision &decision) { auto prior_decision_iter = schema_.find(decision.blob_id_); if (prior_decision_iter == schema_.end()) { @@ -124,14 +101,6 @@ class PrefetchSchema { decision.stats_); } - void SetCurrentTime() { - struct timespec ts; - timespec_get(&ts, TIME_UTC); - for (auto &[blob_id, decision] : schema_) { - decision.SetCurrentTime(ts); - } - } - std::unordered_map::iterator begin() { return schema_.begin(); } @@ -167,23 +136,12 @@ class Prefetcher { private: static size_t HashToNode(api::Hermes *hermes, IoLogEntry &entry); float EstimateBlobMovementTime(BlobID blob_id); - void CalculateBlobScore(PrefetchDecision &decision); + void CalculateBlobScore(struct timespec &ts, + PrefetchDecision &decision); }; /** RPC SERIALIZERS */ -// PrefetchHint -template -void save(A &ar, PrefetchHint &hint) { - ar << static_cast(hint); -} -template -void load(A &ar, PrefetchHint &hint) { - int hint_i; - ar >> hint_i; - hint = static_cast(hint_i); -} - // IoType template void save(A &ar, IoType &hint) { @@ -208,13 +166,6 @@ void load(A &ar, struct timespec &ts) { ar >> ts.tv_nsec; } -// PrefetchContext -template -void serialize(A &ar, PrefetchContext &pctx) { - ar & pctx.hint_; - ar & pctx.read_ahead_; -} - // GlobalThreadID template void serialize(A &ar, GlobalThreadID &tid) { @@ -228,6 +179,7 @@ void serialize(A &ar, IoLogEntry &entry) { ar & entry.vbkt_id_; ar & entry.bkt_id_; ar & entry.blob_id_; + ar & entry.blob_name_; ar & entry.type_; ar & entry.off_; ar & entry.size_; @@ -237,6 +189,6 @@ void serialize(A &ar, IoLogEntry &entry) { ar & entry.historical_; } -} +} // namespace hermes #endif // HERMES_SRC_PREFETCHER_H_ diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index 6a2aeb700..5889f2087 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -224,6 +224,26 @@ void serialize(A &ar, ViolationInfo &info) { } namespace api { + +// PrefetchHint +template +void save(A &ar, PrefetchHint &hint) { + ar << static_cast(hint); +} +template +void load(A &ar, PrefetchHint &hint) { + int hint_i; + ar >> hint_i; + hint = static_cast(hint_i); +} + +// PrefetchContext +template +void serialize(A &ar, PrefetchContext &pctx) { + ar & pctx.hint_; + ar & pctx.read_ahead_; +} + template #ifndef THALLIUM_USE_CEREAL void save(A &ar, api::Context &ctx) { From 708f5640abacd3bf3cece2d017e496dba6c54820 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 19 Oct 2022 14:00:01 -0500 Subject: [PATCH 006/511] Add LogIoStat to all bucket types --- src/api/bucket.cc | 17 ++++++ src/api/vbucket.cc | 6 +- src/api/vbucket.h | 4 +- src/hermes_types.h | 109 +++++++++++++++++++------------------ src/metadata_management.cc | 7 --- src/prefetcher.h | 8 ++- 6 files changed, 85 insertions(+), 66 deletions(-) diff --git a/src/api/bucket.cc b/src/api/bucket.cc index f358f51a2..d77cab751 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -11,6 +11,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "bucket.h" +#include "prefetcher.h" #include #include @@ -153,6 +154,22 @@ size_t Bucket::Get(const std::string &name, void *user_blob, size_t blob_size, LOG(INFO) << "Getting Blob " << name << " from bucket " << name_ << '\n'; BlobID blob_id = GetBlobId(&hermes_->context_, &hermes_->rpc_, name, id_); + + // Upload statistic to prefetcher + if (ctx.pctx_.hint_ != PrefetchHint::kNone) { + IoLogEntry entry; + entry.vbkt_id_ = ctx.vbkt_id_; + entry.bkt_id_ = id_; + entry.blob_id_ = blob_id; + entry.blob_name_ = name; + entry.type_ = IoType::kGet; + entry.off_ = 0; + entry.size_ = blob_size; + entry.pctx_ = ctx.pctx_; + entry.tid_ = GlobalThreadID(hermes_->comm_.world_proc_id); + entry.historical_ = false; + Prefetcher::LogIoStat(hermes_.get(), entry); + } ret = ReadBlobById(&hermes_->context_, &hermes_->rpc_, &hermes_->trans_arena_, blob, blob_id); } else { diff --git a/src/api/vbucket.cc b/src/api/vbucket.cc index ea6e16ea6..6474d4b78 100644 --- a/src/api/vbucket.cc +++ b/src/api/vbucket.cc @@ -18,6 +18,7 @@ #include #include "bucket.h" +#include "prefetcher.h" namespace hermes { @@ -167,7 +168,7 @@ bool VBucket::ContainsBlob(std::string blob_name, std::string bucket_name) { } size_t VBucket::Get(const std::string &name, Bucket &bkt, Blob &user_blob, - const Context &ctx) { + Context &ctx) { size_t ret = Get(name, bkt, user_blob.data(), user_blob.size(), ctx); return ret; @@ -180,12 +181,13 @@ size_t VBucket::Get(const std::string &name, Bucket &bkt, Blob &user_blob) { } size_t VBucket::Get(const std::string &name, Bucket &bkt, void *user_blob, - size_t blob_size, const Context &ctx) { + size_t blob_size, Context &ctx) { bool is_size_query = false; if (blob_size != 0) { is_size_query = true; } + ctx.vbkt_id_ = id_; size_t result = bkt.Get(name, user_blob, blob_size, ctx); if (!is_size_query) { diff --git a/src/api/vbucket.h b/src/api/vbucket.h index f3e19aa28..f7a479ba2 100644 --- a/src/api/vbucket.h +++ b/src/api/vbucket.h @@ -131,10 +131,10 @@ class VBucket { * of any attached Traits. */ size_t Get(const std::string &name, Bucket &bkt, Blob &user_blob, - const Context &ctx); + Context &ctx); size_t Get(const std::string &name, Bucket &bkt, Blob &user_blob); size_t Get(const std::string &name, Bucket &bkt, void *user_blob, - size_t blob_size, const Context &ctx); + size_t blob_size, Context &ctx); /** retrieves the subset of blob links satisfying pred */ /** could return iterator */ diff --git a/src/hermes_types.h b/src/hermes_types.h index 736bd7d20..5a7b25bc2 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -57,6 +57,58 @@ struct ChunkedIdList { u32 capacity; }; +union BucketID { + /** The Bucket ID as bitfield */ + struct { + /** The index into the Target array starting at BufferPool::targets_offset + * (on the node with ID node_id). */ + u32 index; + /** The ID of the node in charge of this bucket. */ + u32 node_id; + } bits; + + /** The BucketID as a unsigned 64-bit integer */ + u64 as_int; +}; + +// NOTE(chogan): We reserve sizeof(BucketID) * 2 bytes in order to embed the +// BucketID into the Blob name. See MakeInternalBlobName() for a description of +// why we need double the bytes of a BucketID. +constexpr int kBucketIdStringSize = sizeof(BucketID) * 2; +/** + * The maximum size in bytes allowed for Blob names. + */ +constexpr int kMaxBlobNameSize = 64 - kBucketIdStringSize; + +union VBucketID { + /** The VBucket ID as bitfield */ + struct { + /** The index into the Target array starting at BufferPool::targets_offset + * (on the node with ID node_id). */ + u32 index; + /** The ID of the node in charge of this vbucket. */ + u32 node_id; + } bits; + + /** The VBucketID as a unsigned 64-bit integer */ + u64 as_int; +}; + +union BlobID { + /** The Blob ID as bitfield */ + struct { + /** The index into the Target array starting at BufferPool::targets_offset + * (on the node with ID node_id). */ + u32 buffer_ids_offset; + /** The ID of the node in charge of this bucket. (Negative when in swap + space.) */ + i32 node_id; + } bits; + + /** The BlobID as an unsigned 64-bit integer */ + u64 as_int; +}; + /** * \namespace api */ @@ -67,6 +119,7 @@ namespace api { */ typedef std::vector Blob; + /** Supported data placement policies */ enum class PlacementPolicy { kRandom, /**< Random blob placement */ @@ -171,13 +224,15 @@ struct Context { bool disable_swap; /** Prefetching hints */ + VBucketID vbkt_id_; PrefetchContext pctx_; Context() : policy(default_placement_policy), buffer_organizer_retries(default_buffer_organizer_retries), rr_split(default_rr_split), rr_retry(false), - disable_swap(false) {} + disable_swap(false), + vbkt_id_({0,0}) {} }; } // namespace api @@ -353,58 +408,6 @@ struct Config { std::vector path_inclusions; }; -union BucketID { - /** The Bucket ID as bitfield */ - struct { - /** The index into the Target array starting at BufferPool::targets_offset - * (on the node with ID node_id). */ - u32 index; - /** The ID of the node in charge of this bucket. */ - u32 node_id; - } bits; - - /** The BucketID as a unsigned 64-bit integer */ - u64 as_int; -}; - -// NOTE(chogan): We reserve sizeof(BucketID) * 2 bytes in order to embed the -// BucketID into the Blob name. See MakeInternalBlobName() for a description of -// why we need double the bytes of a BucketID. -constexpr int kBucketIdStringSize = sizeof(BucketID) * 2; -/** - * The maximum size in bytes allowed for Blob names. - */ -constexpr int kMaxBlobNameSize = 64 - kBucketIdStringSize; - -union VBucketID { - /** The VBucket ID as bitfield */ - struct { - /** The index into the Target array starting at BufferPool::targets_offset - * (on the node with ID node_id). */ - u32 index; - /** The ID of the node in charge of this vbucket. */ - u32 node_id; - } bits; - - /** The VBucketID as a unsigned 64-bit integer */ - u64 as_int; -}; - -union BlobID { - /** The Blob ID as bitfield */ - struct { - /** The index into the Target array starting at BufferPool::targets_offset - * (on the node with ID node_id). */ - u32 buffer_ids_offset; - /** The ID of the node in charge of this bucket. (Negative when in swap - space.) */ - i32 node_id; - } bits; - - /** The BlobID as an unsigned 64-bit integer */ - u64 as_int; -}; - /** Trait ID type */ typedef u64 TraitID; diff --git a/src/metadata_management.cc b/src/metadata_management.cc index 583e2b0b9..42c866d8c 100644 --- a/src/metadata_management.cc +++ b/src/metadata_management.cc @@ -1561,13 +1561,6 @@ bool LocalUnlockBlob(SharedMemoryContext *context, BlobID blob_id) { return result; } -void GetPidTid(u32 &pid, u32 &tid) { - pid = getpid(); - ABT_unit_id tid_argo; - ABT_thread_self_id(&tid_argo); - tid = tid_argo; -} - bool LockBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id) { u32 target_node = GetBlobNodeId(blob_id); bool result = false; diff --git a/src/prefetcher.h b/src/prefetcher.h index 484d16d0c..ef0afa49d 100644 --- a/src/prefetcher.h +++ b/src/prefetcher.h @@ -31,7 +31,11 @@ struct GlobalThreadID { int rank_; int tid_; GlobalThreadID() : rank_(0), tid_(0) {} - GlobalThreadID(int rank, int tid) : rank_(rank), tid_(tid) {} + GlobalThreadID(int rank) : rank_(rank) { + ABT_unit_id tid_argo; + ABT_thread_self_id(&tid_argo); + tid_ = tid_argo; + } }; struct IoLogEntry { @@ -44,8 +48,8 @@ struct IoLogEntry { size_t size_; PrefetchContext pctx_; GlobalThreadID tid_; - struct timespec timestamp_; bool historical_; + struct timespec timestamp_; }; struct PrefetchStat { From 0c203ac876703499a8499b191d33adf577b4d769 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 19 Oct 2022 14:04:59 -0500 Subject: [PATCH 007/511] Fix lint issues --- src/hermes_types.h | 2 +- src/prefetcher.cc | 20 ++++++++++++++------ src/prefetcher.h | 18 +++++++++++++----- src/prefetcher_factory.h | 16 ++++++++++++---- src/prefetchers/apriori.cc | 14 +++++++++++--- src/prefetchers/apriori.h | 14 +++++++++++--- src/prefetchers/sequential.cc | 14 +++++++++++--- src/prefetchers/sequential.h | 14 +++++++++++--- 8 files changed, 84 insertions(+), 28 deletions(-) diff --git a/src/hermes_types.h b/src/hermes_types.h index 5a7b25bc2..1f9863638 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -232,7 +232,7 @@ struct Context { rr_split(default_rr_split), rr_retry(false), disable_swap(false), - vbkt_id_({0,0}) {} + vbkt_id_({0, 0}) {} }; } // namespace api diff --git a/src/prefetcher.cc b/src/prefetcher.cc index 5fda6dc40..95859dc2f 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 10/18/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "prefetcher_factory.h" #include "metadata_management.h" @@ -113,7 +121,7 @@ void Prefetcher::Process() { // Based on the current log, determine what blobs to prefetch PrefetchSchema schema; for (auto &[hint, hint_log] : hint_logs) { - auto algorithm= PrefetcherFactory::Get(hint); + auto algorithm = PrefetcherFactory::Get(hint); algorithm->Process(hint_log, schema); } @@ -123,7 +131,7 @@ void Prefetcher::Process() { } queue_later_.erase(queue_later_.begin(), queue_later_.end()); - //Get the current time + // Get the current time struct timespec ts; timespec_get(&ts, TIME_UTC); @@ -143,4 +151,4 @@ void Prefetcher::Process() { } } -} // namespace hermes \ No newline at end of file +} // namespace hermes diff --git a/src/prefetcher.h b/src/prefetcher.h index ef0afa49d..e3fc79ffd 100644 --- a/src/prefetcher.h +++ b/src/prefetcher.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 10/18/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_PREFETCHER_H_ #define HERMES_SRC_PREFETCHER_H_ @@ -31,7 +39,7 @@ struct GlobalThreadID { int rank_; int tid_; GlobalThreadID() : rank_(0), tid_(0) {} - GlobalThreadID(int rank) : rank_(rank) { + explicit GlobalThreadID(int rank) : rank_(rank) { ABT_unit_id tid_argo; ABT_thread_self_id(&tid_argo); tid_ = tid_argo; @@ -130,7 +138,7 @@ class Prefetcher { float epsilon_; public: - explicit Prefetcher() : max_length_(4096), epsilon_(.05) {} + Prefetcher() : max_length_(4096), epsilon_(.05) {} void SetHermes(std::shared_ptr &hermes) { hermes_ = hermes; } void SetLogLength(uint32_t max_length) { max_length_ = max_length; } void Log(IoLogEntry &entry); diff --git a/src/prefetcher_factory.h b/src/prefetcher_factory.h index 7e6475294..ecb138f2b 100644 --- a/src/prefetcher_factory.h +++ b/src/prefetcher_factory.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 10/18/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_PREFETCHER_FACTORY_H_ #define HERMES_SRC_PREFETCHER_FACTORY_H_ @@ -35,6 +43,6 @@ class PrefetcherFactory { } }; -} +} // namespace hermes #endif // HERMES_SRC_PREFETCHER_FACTORY_H_ diff --git a/src/prefetchers/apriori.cc b/src/prefetchers/apriori.cc index 6e57fd92d..88f58be94 100644 --- a/src/prefetchers/apriori.cc +++ b/src/prefetchers/apriori.cc @@ -1,5 +1,13 @@ -// -// Created by lukemartinlogan on 10/18/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "apriori.h" diff --git a/src/prefetchers/apriori.h b/src/prefetchers/apriori.h index 44a715723..c217ede59 100644 --- a/src/prefetchers/apriori.h +++ b/src/prefetchers/apriori.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 10/18/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_PREFETCHERS_APRIORI_H_ #define HERMES_SRC_PREFETCHERS_APRIORI_H_ diff --git a/src/prefetchers/sequential.cc b/src/prefetchers/sequential.cc index 94b6e4a4f..fc8d7d5cf 100644 --- a/src/prefetchers/sequential.cc +++ b/src/prefetchers/sequential.cc @@ -1,5 +1,13 @@ -// -// Created by lukemartinlogan on 10/18/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "sequential.h" diff --git a/src/prefetchers/sequential.h b/src/prefetchers/sequential.h index 7725a68e0..5d69613f0 100644 --- a/src/prefetchers/sequential.h +++ b/src/prefetchers/sequential.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 10/18/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ #define HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ From 40031e7d6853127b4fa5460f3b0d2019ccdddcaf Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 19 Oct 2022 14:26:33 -0500 Subject: [PATCH 008/511] Sequential prefetcher state --- src/prefetcher.h | 36 +++++++++++++++++++++++++++++++++++ src/prefetchers/sequential.cc | 16 ++++++++++++++++ src/prefetchers/sequential.h | 12 +++++++++++- 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/prefetcher.h b/src/prefetcher.h index e3fc79ffd..ec253769b 100644 --- a/src/prefetcher.h +++ b/src/prefetcher.h @@ -44,6 +44,20 @@ struct GlobalThreadID { ABT_thread_self_id(&tid_argo); tid_ = tid_argo; } + + bool operator==(const GlobalThreadID &other) { + return (rank_ == other.rank_ && tid_ == other.tid_); + } +}; + +struct UniqueBucket { + VBucketID vbkt_id_; + BucketID bkt_id_; + + bool operator==(const UniqueBucket &other) { + return (vbkt_id_.as_int == other.vbkt_id_.as_int && + bkt_id_.as_int == other.bkt_id_.as_int); + } }; struct IoLogEntry { @@ -203,4 +217,26 @@ void serialize(A &ar, IoLogEntry &entry) { } // namespace hermes +namespace std { +template <> +struct hash { + std::size_t operator()(const hermes::GlobalThreadID &key) const { + size_t h1 = std::hash{}(key.rank_); + size_t h2 = std::hash{}(key.tid_); + size_t hash = h1^h2; + return hash; + } +}; + +template <> +struct hash { + std::size_t operator()(const hermes::UniqueBucket &key) const { + size_t h1 = std::hash{}(key.vbkt_id_); + size_t h2 = std::hash{}(key.bkt_id_); + size_t hash = h1^h2; + return hash; + } +}; +} // namespace std + #endif // HERMES_SRC_PREFETCHER_H_ diff --git a/src/prefetchers/sequential.cc b/src/prefetchers/sequential.cc index fc8d7d5cf..b3fae34e1 100644 --- a/src/prefetchers/sequential.cc +++ b/src/prefetchers/sequential.cc @@ -11,3 +11,19 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "sequential.h" + +namespace hermes { + +void SequentialPrefetcher::Process(std::list &log, + PrefetchSchema &schema) { + // Group by tid + std::unordered_map> per_thread_log; + for (auto &entry : log) { + per_thread_log[entry.tid_].emplace_back(entry); + } + + // Estimate the time until next access + +} + +} // namespace hermes \ No newline at end of file diff --git a/src/prefetchers/sequential.h b/src/prefetchers/sequential.h index 5d69613f0..bf6e2c77d 100644 --- a/src/prefetchers/sequential.h +++ b/src/prefetchers/sequential.h @@ -17,10 +17,20 @@ namespace hermes { +struct SequentialState { + struct timespec prior_access_; + float total_access_time_; + u32 count_; + + SequentialState() : total_access_time_(0), count_(0) {} +}; + class SequentialPrefetcher : public PrefetchAlgorithm { + private: + std::unordered_map state_; public: void Process(std::list &log, - PrefetchSchema &schema) {} + PrefetchSchema &schema); }; } From 69cea99b7a609bb2c8ebd890c4a7da86a6725edf Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 20 Oct 2022 05:57:47 -0500 Subject: [PATCH 009/511] Initial SequentialPrefetch impl --- src/CMakeLists.txt | 1 + src/api/bucket.cc | 1 - src/prefetcher.h | 18 ++++++---- src/prefetchers/sequential.cc | 65 ++++++++++++++++++++++++++++++++--- src/prefetchers/sequential.h | 14 ++++++-- 5 files changed, 84 insertions(+), 15 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 52e2c057d..6c51d8a5c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,4 @@ +include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/adapter) configure_file(hermes_version.h.in hermes_version.h) diff --git a/src/api/bucket.cc b/src/api/bucket.cc index d77cab751..41cfbb52e 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -161,7 +161,6 @@ size_t Bucket::Get(const std::string &name, void *user_blob, size_t blob_size, entry.vbkt_id_ = ctx.vbkt_id_; entry.bkt_id_ = id_; entry.blob_id_ = blob_id; - entry.blob_name_ = name; entry.type_ = IoType::kGet; entry.off_ = 0; entry.size_ = blob_size; diff --git a/src/prefetcher.h b/src/prefetcher.h index ec253769b..1a30e77bd 100644 --- a/src/prefetcher.h +++ b/src/prefetcher.h @@ -45,7 +45,7 @@ struct GlobalThreadID { tid_ = tid_argo; } - bool operator==(const GlobalThreadID &other) { + bool operator==(const GlobalThreadID &other) const { return (rank_ == other.rank_ && tid_ == other.tid_); } }; @@ -54,7 +54,11 @@ struct UniqueBucket { VBucketID vbkt_id_; BucketID bkt_id_; - bool operator==(const UniqueBucket &other) { + UniqueBucket() = default; + UniqueBucket(VBucketID vbkt_id, BucketID bkt_id) : + vbkt_id_(vbkt_id), bkt_id_(bkt_id) {} + + bool operator==(const UniqueBucket &other) const { return (vbkt_id_.as_int == other.vbkt_id_.as_int && bkt_id_.as_int == other.bkt_id_.as_int); } @@ -64,7 +68,6 @@ struct IoLogEntry { VBucketID vbkt_id_; BucketID bkt_id_; BlobID blob_id_; - std::string blob_name_; IoType type_; off_t off_; size_t size_; @@ -86,7 +89,6 @@ struct PrefetchStat { return max_time_ - diff; } - private: static float DiffTimespec(const struct timespec *left, const struct timespec *right) { return (left->tv_sec - right->tv_sec) @@ -103,7 +105,9 @@ struct PrefetchDecision { float est_xfer_time_; float new_score_; - PrefetchDecision() : est_xfer_time_(-1), new_score_(-1) {} + PrefetchDecision() : queue_later_(false), + est_xfer_time_(-1), + new_score_(-1) {} void AddStat(float est_access_time, struct timespec &start) { stats_.emplace_back(est_access_time, start); } @@ -148,10 +152,11 @@ class Prefetcher { thallium::mutex lock_; std::list log_; std::unordered_map queue_later_; - std::shared_ptr hermes_; float epsilon_; public: + std::shared_ptr hermes_; + Prefetcher() : max_length_(4096), epsilon_(.05) {} void SetHermes(std::shared_ptr &hermes) { hermes_ = hermes; } void SetLogLength(uint32_t max_length) { max_length_ = max_length; } @@ -205,7 +210,6 @@ void serialize(A &ar, IoLogEntry &entry) { ar & entry.vbkt_id_; ar & entry.bkt_id_; ar & entry.blob_id_; - ar & entry.blob_name_; ar & entry.type_; ar & entry.off_; ar & entry.size_; diff --git a/src/prefetchers/sequential.cc b/src/prefetchers/sequential.cc index b3fae34e1..3355a2499 100644 --- a/src/prefetchers/sequential.cc +++ b/src/prefetchers/sequential.cc @@ -11,19 +11,76 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "sequential.h" +#include "singleton.h" +#include "api/bucket.h" +#include + +using hermes::adapter::BlobPlacement; namespace hermes { void SequentialPrefetcher::Process(std::list &log, PrefetchSchema &schema) { - // Group by tid - std::unordered_map> per_thread_log; + // Increase each unique_bucket access count for (auto &entry : log) { - per_thread_log[entry.tid_].emplace_back(entry); + UniqueBucket id(entry.vbkt_id_, entry.bkt_id_); + ++state_[id].count_; } - // Estimate the time until next access + // Append time estimates and read-aheads to the schema + for (auto &entry : log) { + UniqueBucket id(entry.vbkt_id_, entry.bkt_id_); + auto &state = state_[id]; + float cur_runtime = PrefetchStat::DiffTimespec(&entry.timestamp_, + &state.first_access_); + float avg_time = cur_runtime / state.count_; + + // Read-ahead the next few blobs + BlobID cur_id = entry.blob_id_; + for (int i = 0; i < entry.pctx_.read_ahead_; ++i) { + PrefetchDecision decision; + decision.bkt_id_ = entry.bkt_id_; + if (IsNullVBucketId(entry.vbkt_id_)) { + GetNextBucket(entry, decision, cur_id); + } else { + GetNextVbucket(entry, decision, cur_id); + } + if (IsNullBlobId(decision.blob_id_)) { + break; + } + decision.AddStat(avg_time, entry.timestamp_); + schema.emplace(decision); + cur_id = decision.blob_id_; + } + } +} + +void SequentialPrefetcher::GetNextBucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobID &cur_id) { + // Get current blob name + auto prefetcher = Singleton::GetInstance(); + auto hermes = prefetcher->hermes_; + std::string blob_name = GetBlobNameFromId(&hermes->context_, + &hermes->rpc_, + cur_id); + + // Get next blob name + BlobPlacement p; + p.DecodeBlobName(blob_name); + p.page_ += 1; + std::string next_blob_name = p.CreateBlobName(); + + // Get the next blob ID from the bucket + decision.blob_id_ = GetBlobId(&hermes->context_, &hermes->rpc_, + next_blob_name, entry.bkt_id_, + false); +} +void SequentialPrefetcher::GetNextVbucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobID &cur_id) { + // TODO(llogan): Not implemented for now. } } // namespace hermes \ No newline at end of file diff --git a/src/prefetchers/sequential.h b/src/prefetchers/sequential.h index bf6e2c77d..2016b0a3f 100644 --- a/src/prefetchers/sequential.h +++ b/src/prefetchers/sequential.h @@ -18,19 +18,27 @@ namespace hermes { struct SequentialState { - struct timespec prior_access_; - float total_access_time_; + struct timespec first_access_; u32 count_; - SequentialState() : total_access_time_(0), count_(0) {} + SequentialState() : count_(0) {} }; class SequentialPrefetcher : public PrefetchAlgorithm { private: std::unordered_map state_; + public: void Process(std::list &log, PrefetchSchema &schema); + + private: + void GetNextBucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobID &cur_id); + void GetNextVbucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobID &cur_id); }; } From 74a0690981cb86f0abf2b78fdf89e985cb79aab1 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 20 Oct 2022 05:58:50 -0500 Subject: [PATCH 010/511] Fix lint issues --- src/prefetchers/apriori.h | 2 +- src/prefetchers/sequential.cc | 2 +- src/prefetchers/sequential.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/prefetchers/apriori.h b/src/prefetchers/apriori.h index c217ede59..666c5d0e9 100644 --- a/src/prefetchers/apriori.h +++ b/src/prefetchers/apriori.h @@ -23,6 +23,6 @@ class AprioriPrefetcher : public PrefetchAlgorithm { PrefetchSchema &schema) {} }; -} +} // namespace hermes #endif // HERMES_SRC_PREFETCHERS_APRIORI_H_ diff --git a/src/prefetchers/sequential.cc b/src/prefetchers/sequential.cc index 3355a2499..8810b3d6e 100644 --- a/src/prefetchers/sequential.cc +++ b/src/prefetchers/sequential.cc @@ -83,4 +83,4 @@ void SequentialPrefetcher::GetNextVbucket(IoLogEntry &entry, // TODO(llogan): Not implemented for now. } -} // namespace hermes \ No newline at end of file +} // namespace hermes diff --git a/src/prefetchers/sequential.h b/src/prefetchers/sequential.h index 2016b0a3f..93b62d182 100644 --- a/src/prefetchers/sequential.h +++ b/src/prefetchers/sequential.h @@ -41,6 +41,6 @@ class SequentialPrefetcher : public PrefetchAlgorithm { BlobID &cur_id); }; -} +} // namespace hermes #endif // HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ From 020699ab06859a8e8f83a50d23fed6c2bb29ec1d Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 20 Oct 2022 06:29:03 -0500 Subject: [PATCH 011/511] Prefetcher unit test --- adapter/mapper/abstract_mapper.h | 4 +- test/CMakeLists.txt | 9 ++++- test/prefetch_test.cc | 64 ++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 test/prefetch_test.cc diff --git a/adapter/mapper/abstract_mapper.h b/adapter/mapper/abstract_mapper.h index fe29921f1..ab6c13abe 100644 --- a/adapter/mapper/abstract_mapper.h +++ b/adapter/mapper/abstract_mapper.h @@ -55,14 +55,14 @@ struct BlobPlacement { return ss.str(); } - void DecodeBlobNamePerProc(const std::string &blob_name) { + void DecodeBlobNameLogEntry(const std::string &blob_name) { auto str_split = hermes::adapter::StringSplit(blob_name.data(), '#'); std::stringstream(str_split[0]) >> page_; std::stringstream(str_split[1]) >> blob_off_; std::stringstream(str_split[2]) >> blob_size_; std::stringstream(str_split[3]) >> rank_; - std::stringstream(str_split[4]) >> rank_; + std::stringstream(str_split[4]) >> time_; } }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3a90c4740..cafe28135 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -163,4 +163,11 @@ if(HERMES_INSTALL_TESTS) RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} ) endforeach() -endif() \ No newline at end of file +endif() + +include_directories(${CMAKE_SOURCE_DIR}/adapter) +add_executable(prefetch_test prefetch_test.cc) +target_compile_definitions(prefetch_test + PRIVATE $<$:HERMES_RPC_THALLIUM>) +add_dependencies(prefetch_test hermes) +target_link_libraries(prefetch_test hermes MPI::MPI_CXX glog::glog) \ No newline at end of file diff --git a/test/prefetch_test.cc b/test/prefetch_test.cc new file mode 100644 index 000000000..eaedcd49b --- /dev/null +++ b/test/prefetch_test.cc @@ -0,0 +1,64 @@ +// +// Created by lukemartinlogan on 10/20/22. +// + +#include +#include "hermes.h" +#include "bucket.h" +#include "vbucket.h" +#include +#include + +namespace hapi = hermes::api; + +bool VerifyBlob(hapi::Blob &blob, int nonce, size_t ret_size) { + if (ret_size != blob.size()) { + LOG(INFO) << "The blob get did not get full blob" << std::endl; + return false; + } + for (auto &c : blob) { + if (c != static_cast(nonce)) { + LOG(INFO) << "The blob get was not successful" << std::endl; + return false; + } + } + return true; +} + +int main(int argc, char **argv) { + std::shared_ptr hermes = + hapi::InitHermes(getenv("HERMES_CONF")); + + if (hermes->IsApplicationCore()) { + hapi::Context ctx; + ctx.pctx_.hint_ = hapi::PrefetchHint::kFileSequential; + ctx.pctx_.read_ahead_ = 1; + std::string bkt_name = "PREFETCH"; + auto bkt = std::make_shared( + bkt_name, hermes, ctx); + + // Place 100 1MB blobs + for (int i = 0; i < 100; ++i) { + hapi::Blob blob; + blob.resize(MEGABYTES(1), i); + hermes::adapter::BlobPlacement p; + p.page_ = i; + std::string blob_name = p.CreateBlobName(); + bkt->Put(blob_name, blob); + } + + // Get 100 1MB blobs (sequentially) + for (int i = 0; i < 100; ++i) { + hapi::Blob blob; + blob.resize(MEGABYTES(1), -1); + hermes::adapter::BlobPlacement p; + p.page_ = i; + std::string blob_name = p.CreateBlobName(); + size_t ret = bkt->Get(blob_name, blob); + assert(VerifyBlob(blob, i, ret)); + usleep(50000); + } + } + + hermes->Finalize(); +} \ No newline at end of file From 3a3891e2ef646a7dcdcb5ae254e05b36e8ade3ab Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 20 Oct 2022 08:16:38 -0500 Subject: [PATCH 012/511] Prefetcher will cause prefetching on sequential in basic cases --- .../adapter_generator/create_interceptor.py | 2 +- adapter/mpiio/real_api.h | 56 ++++++++--------- adapter/posix/real_api.h | 55 +++++++---------- adapter/stdio/real_api.h | 56 ++++++++--------- src/buffer_pool.cc | 3 +- src/prefetcher.cc | 17 ++++-- src/prefetcher.h | 15 +++-- src/prefetchers/sequential.cc | 19 ++++-- src/rpc_thallium.cc | 10 ++++ test/prefetch_test.cc | 60 ++++++++++--------- 10 files changed, 161 insertions(+), 132 deletions(-) diff --git a/adapter/adapter_generator/adapter_generator/create_interceptor.py b/adapter/adapter_generator/adapter_generator/create_interceptor.py index fc0251fef..ccec0809a 100644 --- a/adapter/adapter_generator/adapter_generator/create_interceptor.py +++ b/adapter/adapter_generator/adapter_generator/create_interceptor.py @@ -192,7 +192,7 @@ def add_typedef(self, api): self.h_lines.append(f"typedef {api.ret} (*{api.type})({api.get_args()});") def add_intercept_api(self, api): - self.h_lines.append(f" {api.ret} (*{api.real_name})({api.get_args()}) = nullptr;") + self.h_lines.append(f" {api.type} {api.real_name} = nullptr;") def init_api(self, api): self.h_lines.append(f" if (is_intercepted) {{") diff --git a/adapter/mpiio/real_api.h b/adapter/mpiio/real_api.h index 58e21a15a..46076b083 100644 --- a/adapter/mpiio/real_api.h +++ b/adapter/mpiio/real_api.h @@ -63,34 +63,34 @@ namespace hermes::adapter::mpiio { class API { public: - int (*MPI_Init)(int * argc, char *** argv) = nullptr; - int (*MPI_Finalize)( void) = nullptr; - int (*MPI_Wait)(MPI_Request * req, MPI_Status * status) = nullptr; - int (*MPI_Waitall)(int count, MPI_Request * req, MPI_Status * status) = nullptr; - int (*MPI_File_open)(MPI_Comm comm, const char * filename, int amode, MPI_Info info, MPI_File * fh) = nullptr; - int (*MPI_File_close)(MPI_File * fh) = nullptr; - int (*MPI_File_seek_shared)(MPI_File fh, MPI_Offset offset, int whence) = nullptr; - int (*MPI_File_seek)(MPI_File fh, MPI_Offset offset, int whence) = nullptr; - int (*MPI_File_get_position)(MPI_File fh, MPI_Offset * offset) = nullptr; - int (*MPI_File_read_all)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Status * status) = nullptr; - int (*MPI_File_read_at_all)(MPI_File fh, MPI_Offset offset, void * buf, int count, MPI_Datatype datatype, MPI_Status * status) = nullptr; - int (*MPI_File_read_at)(MPI_File fh, MPI_Offset offset, void * buf, int count, MPI_Datatype datatype, MPI_Status * status) = nullptr; - int (*MPI_File_read)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Status * status) = nullptr; - int (*MPI_File_read_ordered)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Status * status) = nullptr; - int (*MPI_File_read_shared)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Status * status) = nullptr; - int (*MPI_File_write_all)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status) = nullptr; - int (*MPI_File_write_at_all)(MPI_File fh, MPI_Offset offset, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status) = nullptr; - int (*MPI_File_write_at)(MPI_File fh, MPI_Offset offset, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status) = nullptr; - int (*MPI_File_write)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status) = nullptr; - int (*MPI_File_write_ordered)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status) = nullptr; - int (*MPI_File_write_shared)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status) = nullptr; - int (*MPI_File_iread_at)(MPI_File fh, MPI_Offset offset, void * buf, int count, MPI_Datatype datatype, MPI_Request * request) = nullptr; - int (*MPI_File_iread)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Request * request) = nullptr; - int (*MPI_File_iread_shared)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Request * request) = nullptr; - int (*MPI_File_iwrite_at)(MPI_File fh, MPI_Offset offset, const void * buf, int count, MPI_Datatype datatype, MPI_Request * request) = nullptr; - int (*MPI_File_iwrite)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Request * request) = nullptr; - int (*MPI_File_iwrite_shared)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Request * request) = nullptr; - int (*MPI_File_sync)(MPI_File fh) = nullptr; + MPI_Init_t MPI_Init = nullptr; + MPI_Finalize_t MPI_Finalize = nullptr; + MPI_Wait_t MPI_Wait = nullptr; + MPI_Waitall_t MPI_Waitall = nullptr; + MPI_File_open_t MPI_File_open = nullptr; + MPI_File_close_t MPI_File_close = nullptr; + MPI_File_seek_shared_t MPI_File_seek_shared = nullptr; + MPI_File_seek_t MPI_File_seek = nullptr; + MPI_File_get_position_t MPI_File_get_position = nullptr; + MPI_File_read_all_t MPI_File_read_all = nullptr; + MPI_File_read_at_all_t MPI_File_read_at_all = nullptr; + MPI_File_read_at_t MPI_File_read_at = nullptr; + MPI_File_read_t MPI_File_read = nullptr; + MPI_File_read_ordered_t MPI_File_read_ordered = nullptr; + MPI_File_read_shared_t MPI_File_read_shared = nullptr; + MPI_File_write_all_t MPI_File_write_all = nullptr; + MPI_File_write_at_all_t MPI_File_write_at_all = nullptr; + MPI_File_write_at_t MPI_File_write_at = nullptr; + MPI_File_write_t MPI_File_write = nullptr; + MPI_File_write_ordered_t MPI_File_write_ordered = nullptr; + MPI_File_write_shared_t MPI_File_write_shared = nullptr; + MPI_File_iread_at_t MPI_File_iread_at = nullptr; + MPI_File_iread_t MPI_File_iread = nullptr; + MPI_File_iread_shared_t MPI_File_iread_shared = nullptr; + MPI_File_iwrite_at_t MPI_File_iwrite_at = nullptr; + MPI_File_iwrite_t MPI_File_iwrite = nullptr; + MPI_File_iwrite_shared_t MPI_File_iwrite_shared = nullptr; + MPI_File_sync_t MPI_File_sync = nullptr; API() { void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, "mpiio_intercepted"); diff --git a/adapter/posix/real_api.h b/adapter/posix/real_api.h index ac2e64c3e..54a71c05b 100644 --- a/adapter/posix/real_api.h +++ b/adapter/posix/real_api.h @@ -39,11 +39,9 @@ typedef int (*creat64_t)(const char * path, mode_t mode); typedef ssize_t (*read_t)(int fd, void * buf, size_t count); typedef ssize_t (*write_t)(int fd, const void * buf, size_t count); typedef ssize_t (*pread_t)(int fd, void * buf, size_t count, off_t offset); -typedef ssize_t (*pwrite_t)(int fd, const void * buf, - size_t count, off_t offset); +typedef ssize_t (*pwrite_t)(int fd, const void * buf, size_t count, off_t offset); typedef ssize_t (*pread64_t)(int fd, void * buf, size_t count, off64_t offset); -typedef ssize_t (*pwrite64_t)(int fd, const void * buf, - size_t count, off64_t offset); +typedef ssize_t (*pwrite64_t)(int fd, const void * buf, size_t count, off64_t offset); typedef off_t (*lseek_t)(int fd, off_t offset, int whence); typedef off64_t (*lseek64_t)(int fd, off64_t offset, int whence); typedef int (*__fxstat_t)(int version, int fd, struct stat * buf); @@ -55,43 +53,36 @@ namespace hermes::adapter::posix { class API { public: - int (*MPI_Init)(int * argc, char *** argv) = nullptr; - int (*MPI_Finalize)( void) = nullptr; - int (*open)(const char * path, int flags, ...) = nullptr; - int (*open64)(const char * path, int flags, ...) = nullptr; - int (*__open_2)(const char * path, int oflag) = nullptr; - int (*creat)(const char * path, mode_t mode) = nullptr; - int (*creat64)(const char * path, mode_t mode) = nullptr; - ssize_t (*read)(int fd, void * buf, size_t count) = nullptr; - ssize_t (*write)(int fd, const void * buf, size_t count) = nullptr; - ssize_t (*pread)(int fd, void * buf, - size_t count, off_t offset) = nullptr; - ssize_t (*pwrite)(int fd, const void * buf, - size_t count, off_t offset) = nullptr; - ssize_t (*pread64)(int fd, void * buf, - size_t count, off64_t offset) = nullptr; - ssize_t (*pwrite64)(int fd, const void * buf, - size_t count, off64_t offset) = nullptr; - off_t (*lseek)(int fd, off_t offset, int whence) = nullptr; - off64_t (*lseek64)(int fd, off64_t offset, int whence) = nullptr; - int (*__fxstat)(int version, int fd, struct stat * buf) = nullptr; - int (*fsync)(int fd) = nullptr; - int (*close)(int fd) = nullptr; + MPI_Init_t MPI_Init = nullptr; + MPI_Finalize_t MPI_Finalize = nullptr; + open_t open = nullptr; + open64_t open64 = nullptr; + __open_2_t __open_2 = nullptr; + creat_t creat = nullptr; + creat64_t creat64 = nullptr; + read_t read = nullptr; + write_t write = nullptr; + pread_t pread = nullptr; + pwrite_t pwrite = nullptr; + pread64_t pread64 = nullptr; + pwrite64_t pwrite64 = nullptr; + lseek_t lseek = nullptr; + lseek64_t lseek64 = nullptr; + __fxstat_t __fxstat = nullptr; + fsync_t fsync = nullptr; + close_t close = nullptr; API() { - void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, - "posix_intercepted"); + void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, "posix_intercepted"); if (is_intercepted) { MPI_Init = (MPI_Init_t)dlsym(RTLD_NEXT, "MPI_Init"); } else { MPI_Init = (MPI_Init_t)dlsym(RTLD_DEFAULT, "MPI_Init"); } if (is_intercepted) { - MPI_Finalize = (MPI_Finalize_t)dlsym( - RTLD_NEXT, "MPI_Finalize"); + MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_NEXT, "MPI_Finalize"); } else { - MPI_Finalize = (MPI_Finalize_t)dlsym( - RTLD_DEFAULT, "MPI_Finalize"); + MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_DEFAULT, "MPI_Finalize"); } if (is_intercepted) { open = (open_t)dlsym(RTLD_NEXT, "open"); diff --git a/adapter/stdio/real_api.h b/adapter/stdio/real_api.h index 4ff3ae343..e21cad6cb 100644 --- a/adapter/stdio/real_api.h +++ b/adapter/stdio/real_api.h @@ -62,34 +62,34 @@ namespace hermes::adapter::stdio { class API { public: - int (*MPI_Init)(int * argc, char *** argv) = nullptr; - int (*MPI_Finalize)( void) = nullptr; - FILE * (*fopen)(const char * path, const char * mode) = nullptr; - FILE * (*fopen64)(const char * path, const char * mode) = nullptr; - FILE * (*fdopen)(int fd, const char * mode) = nullptr; - FILE * (*freopen)(const char * path, const char * mode, FILE * stream) = nullptr; - FILE * (*freopen64)(const char * path, const char * mode, FILE * stream) = nullptr; - int (*fflush)(FILE * fp) = nullptr; - int (*fclose)(FILE * fp) = nullptr; - size_t (*fwrite)(const void * ptr, size_t size, size_t nmemb, FILE * fp) = nullptr; - int (*fputc)(int c, FILE * fp) = nullptr; - int (*fgetpos)(FILE * fp, fpos_t * pos) = nullptr; - int (*fgetpos64)(FILE * fp, fpos64_t * pos) = nullptr; - int (*putc)(int c, FILE * fp) = nullptr; - int (*putw)(int w, FILE * fp) = nullptr; - int (*fputs)(const char * s, FILE * stream) = nullptr; - size_t (*fread)(void * ptr, size_t size, size_t nmemb, FILE * stream) = nullptr; - int (*fgetc)(FILE * stream) = nullptr; - int (*getc)(FILE * stream) = nullptr; - int (*getw)(FILE * stream) = nullptr; - char * (*fgets)(char * s, int size, FILE * stream) = nullptr; - void (*rewind)(FILE * stream) = nullptr; - int (*fseek)(FILE * stream, long offset, int whence) = nullptr; - int (*fseeko)(FILE * stream, off_t offset, int whence) = nullptr; - int (*fseeko64)(FILE * stream, off64_t offset, int whence) = nullptr; - int (*fsetpos)(FILE * stream, const fpos_t * pos) = nullptr; - int (*fsetpos64)(FILE * stream, const fpos64_t * pos) = nullptr; - long int (*ftell)(FILE * fp) = nullptr; + MPI_Init_t MPI_Init = nullptr; + MPI_Finalize_t MPI_Finalize = nullptr; + fopen_t fopen = nullptr; + fopen64_t fopen64 = nullptr; + fdopen_t fdopen = nullptr; + freopen_t freopen = nullptr; + freopen64_t freopen64 = nullptr; + fflush_t fflush = nullptr; + fclose_t fclose = nullptr; + fwrite_t fwrite = nullptr; + fputc_t fputc = nullptr; + fgetpos_t fgetpos = nullptr; + fgetpos64_t fgetpos64 = nullptr; + putc_t putc = nullptr; + putw_t putw = nullptr; + fputs_t fputs = nullptr; + fread_t fread = nullptr; + fgetc_t fgetc = nullptr; + getc_t getc = nullptr; + getw_t getw = nullptr; + fgets_t fgets = nullptr; + rewind_t rewind = nullptr; + fseek_t fseek = nullptr; + fseeko_t fseeko = nullptr; + fseeko64_t fseeko64 = nullptr; + fsetpos_t fsetpos = nullptr; + fsetpos64_t fsetpos64 = nullptr; + ftell_t ftell = nullptr; API() { void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, "stdio_intercepted"); diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 1df4c85e1..dadd4df89 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -90,7 +90,8 @@ void Finalize(SharedMemoryContext *context, CommunicationContext *comm, bool is_application_core, bool force_rpc_shutdown) { WorldBarrier(comm); if (!is_application_core && comm->first_on_node) { - StopGlobalSystemViewStateUpdateThread(rpc); + StopPrefetcher(rpc); + StopGlobalSystemViewStateUpdateThread(rpc); } WorldBarrier(comm); ShutdownRpcClients(rpc); diff --git a/src/prefetcher.cc b/src/prefetcher.cc index 95859dc2f..4566e5e9b 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -52,6 +52,7 @@ size_t Prefetcher::HashToNode(Hermes *hermes, IoLogEntry &entry) { } void Prefetcher::Log(IoLogEntry &entry) { + LOG(INFO) << "Logging I/O stat" << std::endl; lock_.lock(); if (log_.size() == max_length_) { log_.pop_front(); @@ -87,15 +88,13 @@ float Prefetcher::EstimateBlobMovementTime(BlobID blob_id) { void Prefetcher::CalculateBlobScore(struct timespec &ts, PrefetchDecision &decision) { float est_xfer_time = decision.est_xfer_time_; - float max_wait_xfer = 10; - float max_wait_sec = 60; decision.new_score_ = -1; decision.queue_later_ = false; for (auto &access_time_struct : decision.stats_) { float next_access_sec = access_time_struct.GetRemainingTime(&ts); if (next_access_sec < est_xfer_time) continue; - float max_access_wait = std::max(max_wait_xfer*est_xfer_time, - max_wait_sec); + float max_access_wait = std::max(max_wait_xfer_*est_xfer_time, + max_wait_sec_); float est_wait = (next_access_sec - est_xfer_time); if (est_wait > max_access_wait) { decision.queue_later_ = true; @@ -117,6 +116,9 @@ void Prefetcher::Process() { } log_.erase(log_.begin(), log_.end()); lock_.unlock(); + if (hint_logs.size() == 0) { + return; + } // Based on the current log, determine what blobs to prefetch PrefetchSchema schema; @@ -142,9 +144,14 @@ void Prefetcher::Process() { } CalculateBlobScore(ts, decision); if (decision.new_score_ < 0) { - queue_later_.emplace(blob_id, decision); + if (decision.queue_later_) { + queue_later_.emplace(blob_id, decision); + } continue; } + LOG(INFO) << "Prefetching bkt_id: " << decision.bkt_id_.as_int + << " blob_id: " << decision.blob_name_ + << " score: " << decision.new_score_ << std::endl; OrganizeBlob(&hermes_->context_, &hermes_->rpc_, decision.bkt_id_, decision.blob_name_, epsilon_, decision.new_score_); diff --git a/src/prefetcher.h b/src/prefetcher.h index 1a30e77bd..2eb1135f4 100644 --- a/src/prefetcher.h +++ b/src/prefetcher.h @@ -78,15 +78,15 @@ struct IoLogEntry { }; struct PrefetchStat { - float max_time_; + float est_next_time_; struct timespec start_; - explicit PrefetchStat(float max_time, struct timespec &start) : - max_time_(max_time), start_(start) {} + explicit PrefetchStat(float est_next_time, struct timespec &start) : + est_next_time_(est_next_time), start_(start) {} float GetRemainingTime(const struct timespec *cur) { float diff = DiffTimespec(cur, &start_); - return max_time_ - diff; + return est_next_time_ - diff; } static float DiffTimespec(const struct timespec *left, @@ -152,12 +152,17 @@ class Prefetcher { thallium::mutex lock_; std::list log_; std::unordered_map queue_later_; + + public: + float max_wait_xfer_; + float max_wait_sec_; float epsilon_; public: std::shared_ptr hermes_; - Prefetcher() : max_length_(4096), epsilon_(.05) {} + Prefetcher() : max_length_(4096), max_wait_xfer_(10), max_wait_sec_(60), + epsilon_(.05) {} void SetHermes(std::shared_ptr &hermes) { hermes_ = hermes; } void SetLogLength(uint32_t max_length) { max_length_ = max_length; } void Log(IoLogEntry &entry); diff --git a/src/prefetchers/sequential.cc b/src/prefetchers/sequential.cc index 8810b3d6e..1b64039d0 100644 --- a/src/prefetchers/sequential.cc +++ b/src/prefetchers/sequential.cc @@ -21,10 +21,16 @@ namespace hermes { void SequentialPrefetcher::Process(std::list &log, PrefetchSchema &schema) { + auto prefetcher = Singleton::GetInstance(); + // Increase each unique_bucket access count for (auto &entry : log) { UniqueBucket id(entry.vbkt_id_, entry.bkt_id_); - ++state_[id].count_; + auto &state = state_[id]; + if (state.count_ == 0) { + state.first_access_ = entry.timestamp_; + } + ++state.count_; } // Append time estimates and read-aheads to the schema @@ -34,6 +40,9 @@ void SequentialPrefetcher::Process(std::list &log, float cur_runtime = PrefetchStat::DiffTimespec(&entry.timestamp_, &state.first_access_); float avg_time = cur_runtime / state.count_; + if (avg_time == 0) { + avg_time = prefetcher->max_wait_sec_ / 2.0; + } // Read-ahead the next few blobs BlobID cur_id = entry.blob_id_; @@ -48,7 +57,7 @@ void SequentialPrefetcher::Process(std::list &log, if (IsNullBlobId(decision.blob_id_)) { break; } - decision.AddStat(avg_time, entry.timestamp_); + decision.AddStat((i+1)*avg_time, entry.timestamp_); schema.emplace(decision); cur_id = decision.blob_id_; } @@ -69,12 +78,12 @@ void SequentialPrefetcher::GetNextBucket(IoLogEntry &entry, BlobPlacement p; p.DecodeBlobName(blob_name); p.page_ += 1; - std::string next_blob_name = p.CreateBlobName(); + decision.blob_name_ = p.CreateBlobName(); // Get the next blob ID from the bucket decision.blob_id_ = GetBlobId(&hermes->context_, &hermes->rpc_, - next_blob_name, entry.bkt_id_, - false); + decision.blob_name_, entry.bkt_id_, + false); } void SequentialPrefetcher::GetNextVbucket(IoLogEntry &entry, diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index e7912e76d..4157ca07c 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -632,6 +632,7 @@ void StartPrefetcher(SharedMemoryContext *context, prefetcher->Process(); tl::thread::self().sleep(*state->engine, targs.sleep_ms); } + LOG(INFO) << "Finished prefetcher" << std::endl; }; // Create prefetcher thread @@ -647,6 +648,13 @@ void StartPrefetcher(SharedMemoryContext *context, ABT_THREAD_ATTR_NULL, NULL); } +void StopPrefetcher(RpcContext *rpc) { + ThalliumState *state = GetThalliumState(rpc); + state->kill_requested.store(true); + ABT_xstream_join(state->execution_stream); + ABT_xstream_free(&state->execution_stream); +} + void StartGlobalSystemViewStateUpdateThread(SharedMemoryContext *context, RpcContext *rpc, Arena *arena, double sleep_ms) { @@ -664,6 +672,7 @@ void StartGlobalSystemViewStateUpdateThread(SharedMemoryContext *context, UpdateGlobalSystemViewState(targs->context, targs->rpc); tl::thread::self().sleep(*state->engine, targs->sleep_ms); } + LOG(INFO) << "Finished global system view update thread" << std::endl; }; ThreadArgs *args = PushStruct(arena); @@ -764,6 +773,7 @@ void RunDaemon(SharedMemoryContext *context, RpcContext *rpc, auto prefinalize_callback = [rpc, comm]() { SubBarrier(comm); + StopPrefetcher(rpc); StopGlobalSystemViewStateUpdateThread(rpc); SubBarrier(comm); ShutdownRpcClients(rpc); diff --git a/test/prefetch_test.cc b/test/prefetch_test.cc index eaedcd49b..69f54efb9 100644 --- a/test/prefetch_test.cc +++ b/test/prefetch_test.cc @@ -26,39 +26,45 @@ bool VerifyBlob(hapi::Blob &blob, int nonce, size_t ret_size) { } int main(int argc, char **argv) { + MPI_Init(&argc, &argv); std::shared_ptr hermes = - hapi::InitHermes(getenv("HERMES_CONF")); + hermes::InitHermesDaemon(getenv("HERMES_CONF")); - if (hermes->IsApplicationCore()) { - hapi::Context ctx; + bool with_prefetch = atoi(argv[1]); + + hapi::Context ctx; + if (with_prefetch) { ctx.pctx_.hint_ = hapi::PrefetchHint::kFileSequential; ctx.pctx_.read_ahead_ = 1; - std::string bkt_name = "PREFETCH"; - auto bkt = std::make_shared( - bkt_name, hermes, ctx); + } + std::string bkt_name = "PREFETCH"; + auto bkt = std::make_shared( + bkt_name, hermes, ctx); - // Place 100 1MB blobs - for (int i = 0; i < 100; ++i) { - hapi::Blob blob; - blob.resize(MEGABYTES(1), i); - hermes::adapter::BlobPlacement p; - p.page_ = i; - std::string blob_name = p.CreateBlobName(); - bkt->Put(blob_name, blob); - } + // Place 100 1MB blobs + for (int i = 0; i < 100; ++i) { + hapi::Blob blob; + blob.resize(MEGABYTES(1), i); + hermes::adapter::BlobPlacement p; + p.page_ = i; + std::string blob_name = p.CreateBlobName(); + bkt->Put(blob_name, blob); + } + LOG(INFO) << "FINISHED PUTTING ALL BLOBS" << std::endl; - // Get 100 1MB blobs (sequentially) - for (int i = 0; i < 100; ++i) { - hapi::Blob blob; - blob.resize(MEGABYTES(1), -1); - hermes::adapter::BlobPlacement p; - p.page_ = i; - std::string blob_name = p.CreateBlobName(); - size_t ret = bkt->Get(blob_name, blob); - assert(VerifyBlob(blob, i, ret)); - usleep(50000); - } + // Get 100 1MB blobs (sequentially) + for (int i = 0; i < 100; ++i) { + hapi::Blob blob; + blob.resize(MEGABYTES(1), -1); + hermes::adapter::BlobPlacement p; + p.page_ = i; + std::string blob_name = p.CreateBlobName(); + size_t ret = bkt->Get(blob_name, blob); + assert(VerifyBlob(blob, i, ret)); + usleep(500000); } + LOG(INFO) << "FINISHED GETTING ALL BLOBS" << std::endl; - hermes->Finalize(); + hermes->Finalize(true); + MPI_Finalize(); } \ No newline at end of file From b0fbcef18712acb033e3d6c29ba1cc3ad3d4daf6 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 20 Oct 2022 09:13:40 -0500 Subject: [PATCH 013/511] Add prefetcher test --- test/data/prefetch.yaml | 134 ++++++++++++++++++++++++++++++++++++++++ test/prefetch_test.cc | 18 ++++-- 2 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 test/data/prefetch.yaml diff --git a/test/data/prefetch.yaml b/test/data/prefetch.yaml new file mode 100644 index 000000000..a60228a04 --- /dev/null +++ b/test/data/prefetch.yaml @@ -0,0 +1,134 @@ +# Example Hermes configuration file + +# The number of buffering tiers available. For example, RAM, NVMe, burst +# buffer, and parallel file system would be 4 tiers. +num_devices: 2 +# For now this should be the same as num_devices. +num_targets: 2 + +# The maximum buffering capacity in MiB of each device. Here we say that all 4 +# devices get 50 MiB of buffering capacity. +capacities_mb: [100, 10000] + +# The size of the smallest available buffer in KiB. In general this should be +# the page size of your system for byte addressable storage, and the block size +# of the storage device for block addressable storage. +block_sizes_kb: [4, 4] + +# The nummber of size categories for each device. Here we say that each of our 4 +# devices should have 4 different sizes of buffers. +num_slabs: [4, 4] + +# The number of blocks (the size of which is chosen in block_sizes_kb) that each +# device should contain for each slab (controlled by num_slabs). This allows for +# precise control of the distibution of buffer sizes. +slab_unit_sizes: [ + [1, 4, 16, 32], + [1, 4, 16, 32] +] + +# The percentage of buffering capacity per device to allocate for each slab. +# Each row should add up to 1. In this example, we have 2 devices, each with 4 +# slabs, and each slab is allotted 25% of the device's total buffering capacity. +desired_slab_percentages: [ + [0.25, 0.25, 0.25, 0.25], + [0.25, 0.25, 0.25, 0.25] +] + +# The maximum theoretical bandwidth (as advertised by the manufacturer) in +# MiB/sec. of each device. +bandwidth_mbps: [6000, 500] +# The latency in microseconds of each device (as advertised by the manufacturer). +latencies_us: [10, 100] + +# Hermes memory management. The following 4 values should add up to 1. +# The percentage of Hermes memory to reserve for RAM buffers. +buffer_pool_arena_percentage: 0.85 +# The percentage of Hermes memory to reserve for metadata. +metadata_arena_percentage: 0.04 +# The percentage of Hermes memory to reserve for short term storage. +transient_arena_percentage: 0.11 + +# The maxiumum number of buckets that can be created. +max_buckets_per_node: 16 +# The maxiumum number of virtual buckets that can be created. +max_vbuckets_per_node: 8 +# The interval in milliseconds at which to update the global system view. +system_view_state_update_interval_ms: 1000 + +# The mount point of each device. RAM should be the empty string. For block +# devices, this is the directory where Hermes will create buffering files. For +# object storage or cloud targets, this will be a url. +mount_points: ["", "./"] +# For each device, indicate '1' if it is shared among nodes (e.g., burst +# buffers), or '0' if it is per node (e.g., local NVMe). +is_shared_device: [0, 0] +# The mount point of a PFS or object store for swap space, in the event that +# Hermes buffers become full. +swap_mount: "./" +# The number of times the buffer organizer will attempt to place a blob from +# swap space into the hierarchy before giving up. +num_buffer_organizer_retries: 3 + +# A path to a file containing a list of server names, 1 per line. If your +# servers are named according to a pattern (e.g., server-1, server-2, etc.), +# prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this +# option is not empty, it will override anything in `rpc_server_base_name`. +rpc_server_host_file: "" +# Base hostname for the RPC servers. +rpc_server_base_name: "localhost" +# RPC server name suffix. This is appended to the the base name plus host +# number. +rpc_server_suffix: "" +# The RPC protocol. This must come from the documentation of the specific RPC +# library in use. +rpc_protocol: "ofi+sockets" +# RPC domain name for verbs transport. Blank for tcp. +rpc_domain: "" +# Desired RPC port number. +rpc_port: 8080 +# Desired RPC port number for buffer organizer. +buffer_organizer_port: 8081 +# A list of host numbers. Host names are constructed as "rpc_server_base_name + +# host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list +# can be either a single number, or a range, which is 2 numbers separated by a +# hyphen (-). For example the list {1, 3-5, 7, 8-10} will be expanded to +# {1, 3, 4, 5, 7, 8, 9, 10}. +rpc_host_number_range: [] +# The number of handler threads for each RPC server. +rpc_num_threads: 1 +# The number of threads used in the background organization of internal Hermes buffers. +buffer_organizer_num_threads: 4 +# The shared memory prefix for the hermes shared memory segment. A user name +# will be automatically appended. +buffer_pool_shmem_name: "/hermes_buffer_pool_" +# Choose Random, RoundRobin, or MinimizeIoTime +default_placement_policy: "MinimizeIoTime" +# If true (1) the RoundRobin placement policy algorithm will split each Blob +# into a random number of smaller Blobs. +default_rr_split: 0 + +# For each device, the minimum and maximum percent capacity threshold at which +# the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause +# the BufferOrganizer to move data to lower devices, making more room in faster +# devices (ideal for write-heavy workloads). Conversely, increasing the minimum +# threshold will cause data to be moved from slower devices into faster devices +# (ideal for read-heavy workloads). For example, a maximum capacity threshold of +# 0.8 would have the effect of always keeping 20% of the device's space free for +# incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure +# that the device is always at least 30% occupied. +bo_capacity_thresholds: [ + [0.0, 1.0], + [0.0, 1.0] +] + +#Paths which are ignored when buffering data +path_exclusions: [ + "/bin/", "/boot/", "/dev/", "/etc/", + "/lib/", "/opt/", "/proc/", "/sbin/", + "/sys/", "/usr/", "/var/", "/run/", + "pipe", "socket:", "anon_inode:" +] +#Paths which are never ignored when buffering data +path_inclusions: ["/var/opt/cray/dws/mounts/"] + diff --git a/test/prefetch_test.cc b/test/prefetch_test.cc index 69f54efb9..e9eadf03e 100644 --- a/test/prefetch_test.cc +++ b/test/prefetch_test.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 10/20/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "hermes.h" @@ -61,10 +69,10 @@ int main(int argc, char **argv) { std::string blob_name = p.CreateBlobName(); size_t ret = bkt->Get(blob_name, blob); assert(VerifyBlob(blob, i, ret)); - usleep(500000); + // usleep(50000); } LOG(INFO) << "FINISHED GETTING ALL BLOBS" << std::endl; hermes->Finalize(true); MPI_Finalize(); -} \ No newline at end of file +} From a1fd47ccceaf2e34f61871253dabf892535c058b Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 26 Oct 2022 11:33:37 -0500 Subject: [PATCH 014/511] Unbalanced slab sizes work now --- src/buffer_organizer.cc | 7 +++++-- src/buffer_pool.cc | 43 +++++++++++++++++++++++++++-------------- test/data/prefetch.yaml | 6 +++--- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 798daa1b1..23ebe6a02 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -76,8 +76,11 @@ f32 NormalizeAccessScore(SharedMemoryContext *context, f32 raw_score, f32 range = max_seconds - min_seconds; f32 adjusted_score = raw_score - min_seconds; f32 result = 1.0 - (adjusted_score / range); - assert(result >= 0.0 && result <= 1.0); - + if (result <= 1.0 && result <= 1.01) { result = 1.0; } + if (result <= 0.0 && result <= 1.0) { + LOG(FATAL) << "NormalizeAccessScore must be 0 <= score <= 1, but was: " + << result << std::endl; + } return result; } diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 9be720e75..baa9d6dfc 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -1013,16 +1013,18 @@ void SplitRamBufferFreeList(SharedMemoryContext *context, int slab_index) { EndTicketMutex(&pool->ticket_mutex); } -ptrdiff_t InitBufferPool(u8 *shmem_base, Arena *buffer_pool_arena, - Arena *scratch_arena, i32 node_id, Config *config) { - ScopedTemporaryMemory scratch(scratch_arena); - - i32 **buffer_counts = PushArray(scratch, config->num_devices); - i32 **slab_buffer_sizes = PushArray(scratch, config->num_devices); - i32 *header_counts = PushArray(scratch, config->num_devices); - - size_t total_ram_bytes = 0; - +/** + * GetBufferSlabInfo + * + * @scratch temporary memory (avoids using new/malloc) + * @config the shared-memory hermes config + * @slab_buffer_sizes the size (bytes) of each buffer in a particular device + * @buffer_counts the number of slabs in a particular device + * */ + +void GetBufferSlabInfo(ScopedTemporaryMemory &scratch, Config *config, + i32 **slab_buffer_sizes, i32 **buffer_counts, + size_t &total_ram_bytes) { for (int device = 0; device < config->num_devices; ++device) { slab_buffer_sizes[device] = PushArray(scratch, config->num_slabs[device]); @@ -1030,17 +1032,31 @@ ptrdiff_t InitBufferPool(u8 *shmem_base, Arena *buffer_pool_arena, for (int slab = 0; slab < config->num_slabs[device]; ++slab) { slab_buffer_sizes[device][slab] = (config->block_sizes[device] * - config->slab_unit_sizes[device][slab]); + config->slab_unit_sizes[device][slab]); f32 slab_percentage = config->desired_slab_percentages[device][slab]; - size_t bytes_for_slab = (size_t)((f32)config->capacities[device] * + f32 device_capacity = config->capacities[device]; + size_t bytes_for_slab = (size_t)((f32)device_capacity * slab_percentage); buffer_counts[device][slab] = (bytes_for_slab / - slab_buffer_sizes[device][slab]); + slab_buffer_sizes[device][slab]); if (device == 0) { total_ram_bytes += bytes_for_slab; } } } +} +ptrdiff_t InitBufferPool(u8 *shmem_base, Arena *buffer_pool_arena, + Arena *scratch_arena, i32 node_id, Config *config) { + ScopedTemporaryMemory scratch(scratch_arena); + + i32 **buffer_counts = PushArray(scratch, config->num_devices); + i32 **slab_buffer_sizes = PushArray(scratch, config->num_devices); + i32 *header_counts = PushArray(scratch, config->num_devices); + size_t total_ram_bytes = 0; + + // Determine the number and size of buffers + GetBufferSlabInfo(scratch, config, slab_buffer_sizes, buffer_counts, + total_ram_bytes); // TODO(chogan): @configuration Assumes first Device is RAM // TODO(chogan): Allow splitting and merging for every Device @@ -1048,7 +1064,6 @@ ptrdiff_t InitBufferPool(u8 *shmem_base, Arena *buffer_pool_arena, // NOTE(chogan): We need one header per RAM block to allow for splitting and // merging header_counts[0] = total_ram_bytes / config->block_sizes[0]; - for (int device = 1; device < config->num_devices; ++device) { header_counts[device] = 0; for (int slab = 0; slab < config->num_slabs[device]; ++slab) { diff --git a/test/data/prefetch.yaml b/test/data/prefetch.yaml index a60228a04..41b017fba 100644 --- a/test/data/prefetch.yaml +++ b/test/data/prefetch.yaml @@ -8,7 +8,7 @@ num_targets: 2 # The maximum buffering capacity in MiB of each device. Here we say that all 4 # devices get 50 MiB of buffering capacity. -capacities_mb: [100, 10000] +capacities_mb: [50, 10000] # The size of the smallest available buffer in KiB. In general this should be # the page size of your system for byte addressable storage, and the block size @@ -24,7 +24,7 @@ num_slabs: [4, 4] # precise control of the distibution of buffer sizes. slab_unit_sizes: [ [1, 4, 16, 32], - [1, 4, 16, 32] + [256] ] # The percentage of buffering capacity per device to allocate for each slab. @@ -32,7 +32,7 @@ slab_unit_sizes: [ # slabs, and each slab is allotted 25% of the device's total buffering capacity. desired_slab_percentages: [ [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25] + [1.0, 0.0, 0.0, 0.0] ] # The maximum theoretical bandwidth (as advertised by the manufacturer) in From 47608c4a20840603d09106ab98390c9b6f52bf93 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 31 Oct 2022 08:40:29 -0500 Subject: [PATCH 015/511] Add timer to prefetcher --- src/prefetcher.cc | 5 +- test/data/prefetch.yaml | 12 +-- test/prefetch_test.cc | 53 ++++++++--- test/timer.h | 201 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 253 insertions(+), 18 deletions(-) create mode 100644 test/timer.h diff --git a/src/prefetcher.cc b/src/prefetcher.cc index 4566e5e9b..337337e13 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -63,7 +63,7 @@ void Prefetcher::Log(IoLogEntry &entry) { } float Prefetcher::EstimateBlobMovementTime(BlobID blob_id) { - Arena arena = InitArenaAndAllocate(8192); + Arena arena = InitArenaAndAllocate(MEGABYTES(1)); u32 *buffer_sizes = 0; BufferIdArray id_array = GetBufferIdsFromBlobId(&arena, &hermes_->context_, @@ -147,6 +147,9 @@ void Prefetcher::Process() { if (decision.queue_later_) { queue_later_.emplace(blob_id, decision); } + /*LOG(INFO) << "Not prefetching bkt_id: " << decision.bkt_id_.as_int + << " blob_id: " << decision.blob_name_ + << " score: " << decision.new_score_ << std::endl;*/ continue; } LOG(INFO) << "Prefetching bkt_id: " << decision.bkt_id_.as_int diff --git a/test/data/prefetch.yaml b/test/data/prefetch.yaml index 41b017fba..4da7db5ab 100644 --- a/test/data/prefetch.yaml +++ b/test/data/prefetch.yaml @@ -8,7 +8,7 @@ num_targets: 2 # The maximum buffering capacity in MiB of each device. Here we say that all 4 # devices get 50 MiB of buffering capacity. -capacities_mb: [50, 10000] +capacities_mb: [1000, 10000] # The size of the smallest available buffer in KiB. In general this should be # the page size of your system for byte addressable storage, and the block size @@ -23,7 +23,7 @@ num_slabs: [4, 4] # device should contain for each slab (controlled by num_slabs). This allows for # precise control of the distibution of buffer sizes. slab_unit_sizes: [ - [1, 4, 16, 32], + [1, 256], [256] ] @@ -31,7 +31,7 @@ slab_unit_sizes: [ # Each row should add up to 1. In this example, we have 2 devices, each with 4 # slabs, and each slab is allotted 25% of the device's total buffering capacity. desired_slab_percentages: [ - [0.25, 0.25, 0.25, 0.25], + [0.5, 0.5, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0] ] @@ -43,11 +43,11 @@ latencies_us: [10, 100] # Hermes memory management. The following 4 values should add up to 1. # The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage: 0.85 +buffer_pool_arena_percentage: 0.6 # The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage: 0.04 +metadata_arena_percentage: 0.2 # The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage: 0.11 +transient_arena_percentage: 0.2 # The maxiumum number of buckets that can be created. max_buckets_per_node: 16 diff --git a/test/prefetch_test.cc b/test/prefetch_test.cc index e9eadf03e..1eb7e42eb 100644 --- a/test/prefetch_test.cc +++ b/test/prefetch_test.cc @@ -16,17 +16,22 @@ #include "vbucket.h" #include #include +#include "timer.h" namespace hapi = hermes::api; bool VerifyBlob(hapi::Blob &blob, int nonce, size_t ret_size) { if (ret_size != blob.size()) { - LOG(INFO) << "The blob get did not get full blob" << std::endl; + LOG(INFO) << "The blob get did not get full blob: " + << " ret_size: " << ret_size + << " blob_size: " << std::endl; return false; } for (auto &c : blob) { - if (c != static_cast(nonce)) { - LOG(INFO) << "The blob get was not successful" << std::endl; + if (c != static_cast(nonce)) { + LOG(INFO) << "The blob get was not successful" + << " nonce: " << (int)nonce + << " ret: " << (int)c; return false; } } @@ -38,21 +43,37 @@ int main(int argc, char **argv) { std::shared_ptr hermes = hermes::InitHermesDaemon(getenv("HERMES_CONF")); + if (argc != 6) { + std::cout << "USAGE: ./prefetch_test" + << "[with_prefetch] [dataset_mb] [blob_size_mb]" + << "[read_ahead] [phase]" << std::endl; + } + bool with_prefetch = atoi(argv[1]); + size_t dataset_size = MEGABYTES(atoi(argv[2])); + size_t blob_size = MEGABYTES(atoi(argv[3])); + size_t blob_count = dataset_size / blob_size; + int read_ahead = atoi(argv[4]); + int phase = atoi(argv[5]); + + std::cout << "Dataset Size: " << dataset_size / MEGABYTES(1) + << " Blob Size: " << blob_size / MEGABYTES(1) + << " Blob Count: " << blob_count << std::endl; hapi::Context ctx; if (with_prefetch) { ctx.pctx_.hint_ = hapi::PrefetchHint::kFileSequential; - ctx.pctx_.read_ahead_ = 1; + ctx.pctx_.read_ahead_ = read_ahead; + printf("Prefetch is enabled\n"); } std::string bkt_name = "PREFETCH"; auto bkt = std::make_shared( bkt_name, hermes, ctx); - // Place 100 1MB blobs - for (int i = 0; i < 100; ++i) { + // Place blobs + for (int i = 0; i < blob_count; ++i) { hapi::Blob blob; - blob.resize(MEGABYTES(1), i); + blob.resize(blob_size, i); hermes::adapter::BlobPlacement p; p.page_ = i; std::string blob_name = p.CreateBlobName(); @@ -60,18 +81,28 @@ int main(int argc, char **argv) { } LOG(INFO) << "FINISHED PUTTING ALL BLOBS" << std::endl; - // Get 100 1MB blobs (sequentially) - for (int i = 0; i < 100; ++i) { + // Get blobs (sequentially) + hermes::HighResMonotonicTimer t; + t.Resume(); + for (int i = 0; i < blob_count; ++i) { hapi::Blob blob; - blob.resize(MEGABYTES(1), -1); + blob.resize(blob_size, -1); hermes::adapter::BlobPlacement p; p.page_ = i; std::string blob_name = p.CreateBlobName(); size_t ret = bkt->Get(blob_name, blob); assert(VerifyBlob(blob, i, ret)); - // usleep(50000); + if (phase > 0 && ((i+1) % phase) == 0) { + hermes::HighResMonotonicTimer t2; + t2.Resume(); + while(t2.GetMsecFromStart() < 100) { + ABT_thread_yield(); + } + } } + t.Pause(); LOG(INFO) << "FINISHED GETTING ALL BLOBS" << std::endl; + std::cout <<"TIME: " << t.GetMsec() << std::endl; hermes->Finalize(true); MPI_Finalize(); diff --git a/test/timer.h b/test/timer.h new file mode 100644 index 000000000..4df1ebd2f --- /dev/null +++ b/test/timer.h @@ -0,0 +1,201 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_TIMER_H +#define HERMES_TIMER_H + +#include +#include +#include + +namespace hermes { + +template +class Timer { + private: + std::chrono::time_point start_, end_; + double time_ns_; + + public: + Timer() : time_ns_(0) {} + + void Resume() { + start_ = T::now(); + } + double Pause() { + time_ns_ += GetNsecFromStart(); + return time_ns_; + } + double Pause(double &dt) { + dt = GetNsecFromStart(); + time_ns_ += dt; + return time_ns_; + } + void Reset() { + time_ns_ = 0; + } + + double GetNsecFromStart() { + end_ = T::now(); + double elapsed = std::chrono::duration_cast( + end_ - start_).count(); + return elapsed; + } + double GetUsecFromStart() { + end_ = T::now(); + return std::chrono::duration_cast( + end_ - start_).count(); + } + double GetMsecFromStart() { + end_ = T::now(); + return std::chrono::duration_cast( + end_ - start_).count(); + } + double GetSecFromStart() { + end_ = T::now(); + return std::chrono::duration_cast( + end_ - start_).count(); + } + + double GetNsec() const { + return time_ns_; + } + double GetUsec() const { + return time_ns_/1000; + } + double GetMsec() const { + return time_ns_/1000000; + } + double GetSec() const { + return time_ns_/1000000000; + } + + double GetUsFromEpoch() const { + std::chrono::time_point point = + std::chrono::system_clock::now(); + return std::chrono::duration_cast( + point.time_since_epoch()).count(); + } +}; + +template +class ThreadedTimer { + private: + std::vector> timers_; + + public: + ThreadedTimer() = default; + + void Resume(int tid) { + MinimumTID(tid); + timers_[tid].Resume(); + } + double Pause(int tid) { + MinimumTID(tid); + return timers_[tid].Pause(); + } + double Pause(int tid, double &dt) { + MinimumTID(tid); + return timers_[tid].Pause(dt); + } + void Reset(int tid) { + MinimumTID(tid); + timers_[tid].Reset(); + } + + double GetMsecFromStart(int tid) { + MinimumTID(tid); + return timers_[tid].GetMsecFromStart(); + } + + double GetNsec(int tid) { + MinimumTID(tid); + return timers_[tid].GetNsec(); + } + double GetUsec(int tid) { + MinimumTID(tid); + return timers_[tid].GetUsec(); + } + double GetMsec(int tid) { + MinimumTID(tid); + return timers_[tid].GetMsec(); + } + double GetSec(int tid) { + MinimumTID(tid); + return timers_[tid].GetSec(); + } + double GetUsFromEpoch(int tid) { + MinimumTID(tid); + return timers_[tid].GetUsFromEpoch(); + } + + double GetMsecFromStart() const { + auto iter = std::max_element(timers_.begin(), timers_.end(), + [] (Timer const& lhs, Timer const& rhs) { + return lhs.GetMsecFromStart() < rhs.GetMsecFromStart(); + }); + return iter->GetMsecFromStart(); + } + double GetNsec() const { + auto iter = std::max_element(timers_.begin(), timers_.end(), + [] (Timer const& lhs, Timer const& rhs) { + return lhs.GetNsec() < rhs.GetNsec(); + }); + return iter->GetNsec(); + } + double GetUsec() const { + auto iter = std::max_element(timers_.begin(), timers_.end(), + [] (Timer const& lhs, Timer const& rhs) { + return lhs.GetUsec() < rhs.GetUsec(); + }); + return iter->GetUsec(); + } + double GetMsec() const { + auto iter = std::max_element(timers_.begin(), timers_.end(), + [] (Timer const& lhs, Timer const& rhs) { + return lhs.GetMsec() < rhs.GetMsec(); + }); + return iter->GetMsec(); + } + double GetSec() const { + auto iter = std::max_element(timers_.begin(), timers_.end(), + [] (Timer const& lhs, Timer const& rhs) { + return lhs.GetSec() < rhs.GetSec(); + }); + return iter->GetSec(); + } + double GetUsFromEpoch() const { + auto iter = std::max_element(timers_.begin(), timers_.end(), + [] (Timer const& lhs, Timer const& rhs) { + return lhs.GetUsFromEpoch() < rhs.GetUsFromEpoch(); + }); + return iter->GetUsFromEpoch(); + } + + private: + void MinimumTID(int tid) { + if ((size_t)tid >= timers_.size()) { + timers_.resize(tid+1); + } + } +}; + +typedef Timer HighResCpuTimer; +typedef Timer HighResMonotonicTimer; +typedef ThreadedTimer + ThreadedHighResCpuTimer; +typedef ThreadedTimer + ThreadedHighResMonotonicTimer; + +} // namespace labstor + +#endif // HERMES_TIMER_H From 4570f9b5a60a64c1099527d6b6eac58dc830f78b Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 31 Oct 2022 18:37:10 -0500 Subject: [PATCH 016/511] Add more log info to prefetcher and borg. Make stage-in use 5 inputs --- data_stager/stage_in.cc | 2 +- src/buffer_organizer.cc | 20 ++++++++++++++++++-- src/config_parser.cc | 6 +++--- src/prefetcher.cc | 25 ++++++++++++++++++++----- src/prefetcher.h | 9 ++++++++- src/prefetchers/sequential.cc | 1 + test/data/prefetch.yaml | 10 +++++----- test/prefetch_test.cc | 4 ++-- 8 files changed, 58 insertions(+), 19 deletions(-) diff --git a/data_stager/stage_in.cc b/data_stager/stage_in.cc index 226142c90..49a47062f 100644 --- a/data_stager/stage_in.cc +++ b/data_stager/stage_in.cc @@ -22,7 +22,7 @@ using hermes::DataStager; using hermes::DataStagerFactory; int main(int argc, char **argv) { - if (argc != 4) { + if (argc != 5) { std::cout << "Usage: mpirun -n [nprocs]" << " ./stage_in [url] [offset] [size] [dpe]" << std::endl; exit(1); diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 23ebe6a02..cd2596fbb 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -178,7 +178,8 @@ void LocalEnqueueBoMove(SharedMemoryContext *context, RpcContext *rpc, BoPriority priority) { ThreadPool *pool = &context->bo->pool; bool is_high_priority = priority == BoPriority::kHigh; - VLOG(1) << "BufferOrganizer queuing Blob " << blob_id.as_int; + // NOTE(llogan): VLOG(1) -> LOG(INFO) + LOG(INFO) << "BufferOrganizer queuing Blob " << blob_id.as_int; pool->run(std::bind(BoMove, context, rpc, moves, blob_id, bucket_id, internal_blob_name), is_high_priority); @@ -190,7 +191,8 @@ void LocalEnqueueBoMove(SharedMemoryContext *context, RpcContext *rpc, void BoMove(SharedMemoryContext *context, RpcContext *rpc, const BoMoveList &moves, BlobID blob_id, BucketID bucket_id, const std::string &internal_blob_name) { - VLOG(1) << "Moving blob " + // NOTE(llogan): VLOG(1) -> LOG(INFO) + LOG(INFO) << "Moving blob " << internal_blob_name.substr(kBucketIdStringSize, std::string::npos) << std::endl; MetadataManager *mdm = GetMetadataManagerFromContext(context); @@ -414,6 +416,20 @@ void LocalOrganizeBlob(SharedMemoryContext *context, RpcContext *rpc, break; } } + + for (auto &src_dest_pair : src_dest) { + auto &src = src_dest_pair.first; + for (auto &dst : src_dest_pair.second) { + LOG(INFO) << "Moving " + << LocalGetBufferInfo(context, src).size / MEGABYTES(1) << " mb " + << " of " << blob_id.as_int << "" + << " from " + << LocalGetBufferInfo(context, src).bandwidth_mbps + << " into " + << LocalGetBufferInfo(context, dst).bandwidth_mbps + << std::endl; + } + } EnqueueBoMove(rpc, src_dest, blob_id, bucket_id, internal_blob_name, BoPriority::kLow); } diff --git a/src/config_parser.cc b/src/config_parser.cc index 4d9efcbf5..fa07f178c 100644 --- a/src/config_parser.cc +++ b/src/config_parser.cc @@ -376,10 +376,10 @@ void ParseConfigYAML(YAML::Node &yaml_conf, Config *config) { reinterpret_cast(config->desired_slab_percentages), kMaxDevices, kMaxBufferPoolSlabs, config->num_slabs); } - if (yaml_conf["bandwidths_mbps"]) { + if (yaml_conf["bandwidth_mbps"]) { RequireNumDevices(config); - ParseArray(yaml_conf["bandwidths_mbps"], - "bandwidths_mbps", + ParseArray(yaml_conf["bandwidth_mbps"], + "bandwidth_mbps", config->bandwidths, config->num_devices); } if (yaml_conf["latencies"]) { diff --git a/src/prefetcher.cc b/src/prefetcher.cc index 337337e13..ec9fa09cb 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -78,8 +78,10 @@ float Prefetcher::EstimateBlobMovementTime(BlobID blob_id) { float xfer_time = 0; for (auto &info : buffer_info) { - xfer_time += static_cast(info.size) / - (MEGABYTES(1) * info.bandwidth_mbps); + xfer_time += static_cast(info.size) / MEGABYTES(info.bandwidth_mbps); + /*LOG(INFO) << "size: " << info.size / MEGABYTES(1) + << " bw: " << info.bandwidth_mbps + << " current total: " << xfer_time << std::endl;*/ } xfer_time *= 2; // x2 because movement reads, and then writes data return xfer_time; @@ -91,10 +93,23 @@ void Prefetcher::CalculateBlobScore(struct timespec &ts, decision.new_score_ = -1; decision.queue_later_ = false; for (auto &access_time_struct : decision.stats_) { - float next_access_sec = access_time_struct.GetRemainingTime(&ts); + // Wait until the I/O for this Get seems to have completed + float time_left_on_io = access_time_struct.TimeLeftOnIo( + est_xfer_time, &ts); + /*LOG(INFO) << "Blob id: " << decision.blob_id_.as_int + << " Time left before starting prefetch: " + << time_left_on_io << std::endl;*/ + if (time_left_on_io > 0) { + decision.queue_later_ = true; + continue; + } + float next_access_sec = access_time_struct.TimeToNextIo(&ts); + LOG(INFO) << "Next access sec: " << next_access_sec << std::endl; + LOG(INFO) << "Est xfer time : " << est_xfer_time << std::endl; if (next_access_sec < est_xfer_time) continue; float max_access_wait = std::max(max_wait_xfer_*est_xfer_time, max_wait_sec_); + LOG(INFO) << "Max access wait: " << max_access_wait << std::endl; float est_wait = (next_access_sec - est_xfer_time); if (est_wait > max_access_wait) { decision.queue_later_ = true; @@ -116,7 +131,7 @@ void Prefetcher::Process() { } log_.erase(log_.begin(), log_.end()); lock_.unlock(); - if (hint_logs.size() == 0) { + if (hint_logs.size() == 0 && queue_later_.size() == 0) { return; } @@ -157,7 +172,7 @@ void Prefetcher::Process() { << " score: " << decision.new_score_ << std::endl; OrganizeBlob(&hermes_->context_, &hermes_->rpc_, decision.bkt_id_, decision.blob_name_, - epsilon_, decision.new_score_); + epsilon_, 1.0); } } diff --git a/src/prefetcher.h b/src/prefetcher.h index 2eb1135f4..9eeee6c2c 100644 --- a/src/prefetcher.h +++ b/src/prefetcher.h @@ -84,7 +84,14 @@ struct PrefetchStat { explicit PrefetchStat(float est_next_time, struct timespec &start) : est_next_time_(est_next_time), start_(start) {} - float GetRemainingTime(const struct timespec *cur) { + float TimeLeftOnIo(float est_xfer_time, const struct timespec *cur) { + float diff = DiffTimespec(cur, &start_); + /*LOG(INFO) << "Time since I/O submitted: " << diff << std::endl; + LOG(INFO) << "Est I/O time: " << est_xfer_time << std::endl;*/ + return est_xfer_time - diff; + } + + float TimeToNextIo(const struct timespec *cur) { float diff = DiffTimespec(cur, &start_); return est_next_time_ - diff; } diff --git a/src/prefetchers/sequential.cc b/src/prefetchers/sequential.cc index 1b64039d0..8e14d561f 100644 --- a/src/prefetchers/sequential.cc +++ b/src/prefetchers/sequential.cc @@ -43,6 +43,7 @@ void SequentialPrefetcher::Process(std::list &log, if (avg_time == 0) { avg_time = prefetcher->max_wait_sec_ / 2.0; } + LOG(INFO) << "Avg time: " << avg_time << std::endl; // Read-ahead the next few blobs BlobID cur_id = entry.blob_id_; diff --git a/test/data/prefetch.yaml b/test/data/prefetch.yaml index 4da7db5ab..211a2d5eb 100644 --- a/test/data/prefetch.yaml +++ b/test/data/prefetch.yaml @@ -8,7 +8,7 @@ num_targets: 2 # The maximum buffering capacity in MiB of each device. Here we say that all 4 # devices get 50 MiB of buffering capacity. -capacities_mb: [1000, 10000] +capacities_mb: [2000, 10000] # The size of the smallest available buffer in KiB. In general this should be # the page size of your system for byte addressable storage, and the block size @@ -17,7 +17,7 @@ block_sizes_kb: [4, 4] # The nummber of size categories for each device. Here we say that each of our 4 # devices should have 4 different sizes of buffers. -num_slabs: [4, 4] +num_slabs: [2, 1] # The number of blocks (the size of which is chosen in block_sizes_kb) that each # device should contain for each slab (controlled by num_slabs). This allows for @@ -31,13 +31,13 @@ slab_unit_sizes: [ # Each row should add up to 1. In this example, we have 2 devices, each with 4 # slabs, and each slab is allotted 25% of the device's total buffering capacity. desired_slab_percentages: [ - [0.5, 0.5, 0.0, 0.0], - [1.0, 0.0, 0.0, 0.0] + [0.1, 0.9], + [1.0] ] # The maximum theoretical bandwidth (as advertised by the manufacturer) in # MiB/sec. of each device. -bandwidth_mbps: [6000, 500] +bandwidth_mbps: [4000, 500] # The latency in microseconds of each device (as advertised by the manufacturer). latencies_us: [10, 100] diff --git a/test/prefetch_test.cc b/test/prefetch_test.cc index 1eb7e42eb..cdff063dd 100644 --- a/test/prefetch_test.cc +++ b/test/prefetch_test.cc @@ -92,10 +92,10 @@ int main(int argc, char **argv) { std::string blob_name = p.CreateBlobName(); size_t ret = bkt->Get(blob_name, blob); assert(VerifyBlob(blob, i, ret)); - if (phase > 0 && ((i+1) % phase) == 0) { + if (phase > 0) { hermes::HighResMonotonicTimer t2; t2.Resume(); - while(t2.GetMsecFromStart() < 100) { + while(t2.GetMsecFromStart() < phase) { ABT_thread_yield(); } } From 64595f715de13ab128325e7449b578312f2e65a2 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 31 Oct 2022 20:05:46 -0500 Subject: [PATCH 017/511] prefetch_ares + staging --- data_stager/stage_in.cc | 2 +- data_stager/stagers/unix_stager.cc | 2 +- test/data/prefetch_ares.yaml | 140 +++++++++++++++++++++++++++++ test/data/staging.yaml | 134 +++++++++++++++++++++++++++ 4 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 test/data/prefetch_ares.yaml create mode 100644 test/data/staging.yaml diff --git a/data_stager/stage_in.cc b/data_stager/stage_in.cc index 49a47062f..a1f79fdcf 100644 --- a/data_stager/stage_in.cc +++ b/data_stager/stage_in.cc @@ -37,7 +37,7 @@ int main(int argc, char **argv) { std::stringstream(argv[3]) >> size; PlacementPolicy dpe = PlacementPolicyConv::to_enum(argv[4]); auto stager = DataStagerFactory::Get(url); - stager->StageIn(url, dpe); + stager->StageIn(url, off, size, dpe); mdm->FinalizeHermes(); MPI_Finalize(); } diff --git a/data_stager/stagers/unix_stager.cc b/data_stager/stagers/unix_stager.cc index e383956f8..e96c28ef0 100644 --- a/data_stager/stagers/unix_stager.cc +++ b/data_stager/stagers/unix_stager.cc @@ -63,7 +63,7 @@ void UnixStager::FileStageIn(std::string path, bool stat_exists; IoStatus io_status; File f = fs_api.Open(stat, path); - fs_api.Read(f, stat, buf.data(), off, size, + fs_api.Read(f, stat_exists, buf.data(), off, size, io_status, IoOptions::WithParallelDpe(dpe)); fs_api.Close(f, stat_exists, false); } diff --git a/test/data/prefetch_ares.yaml b/test/data/prefetch_ares.yaml new file mode 100644 index 000000000..395d7e76b --- /dev/null +++ b/test/data/prefetch_ares.yaml @@ -0,0 +1,140 @@ +# Example Hermes configuration file + +# The number of buffering tiers available. For example, RAM, NVMe, burst +# buffer, and parallel file system would be 4 tiers. +num_devices: 2 +# For now this should be the same as num_devices. +num_targets: 2 + +# The maximum buffering capacity in MiB of each device. Here we say that all 4 +# devices get 50 MiB of buffering capacity. +capacities_mb: [2000, 2000, 2000, 10000] + +# The size of the smallest available buffer in KiB. In general this should be +# the page size of your system for byte addressable storage, and the block size +# of the storage device for block addressable storage. +block_sizes_kb: [4, 4, 4, 4] + +# The nummber of size categories for each device. Here we say that each of our 4 +# devices should have 4 different sizes of buffers. +num_slabs: [2, 1, 1, 1] + +# The number of blocks (the size of which is chosen in block_sizes_kb) that each +# device should contain for each slab (controlled by num_slabs). This allows for +# precise control of the distibution of buffer sizes. +slab_unit_sizes: [ + [1, 256], + [256], + [256], + [256] +] + +# The percentage of buffering capacity per device to allocate for each slab. +# Each row should add up to 1. In this example, we have 2 devices, each with 4 +# slabs, and each slab is allotted 25% of the device's total buffering capacity. +desired_slab_percentages: [ + [0.1, 0.9], + [1.0], + [1.0], + [1.0] +] + +# The maximum theoretical bandwidth (as advertised by the manufacturer) in +# MiB/sec. of each device. +bandwidth_mbps: [4000, 1000, 500, 150] +# The latency in microseconds of each device (as advertised by the manufacturer). +latencies_us: [10, 100, 800, 10000] + +# Hermes memory management. The following 4 values should add up to 1. +# The percentage of Hermes memory to reserve for RAM buffers. +buffer_pool_arena_percentage: 0.6 +# The percentage of Hermes memory to reserve for metadata. +metadata_arena_percentage: 0.2 +# The percentage of Hermes memory to reserve for short term storage. +transient_arena_percentage: 0.2 + +# The maxiumum number of buckets that can be created. +max_buckets_per_node: 16 +# The maxiumum number of virtual buckets that can be created. +max_vbuckets_per_node: 8 +# The interval in milliseconds at which to update the global system view. +system_view_state_update_interval_ms: 1000 + +# The mount point of each device. RAM should be the empty string. For block +# devices, this is the directory where Hermes will create buffering files. For +# object storage or cloud targets, this will be a url. +mount_points: ["", "/mnt/nvme/llogan/borg", "/mnt/ssd/llogan/ssd", "/mnt/hdd/llogan/borg"] +# For each device, indicate '1' if it is shared among nodes (e.g., burst +# buffers), or '0' if it is per node (e.g., local NVMe). +is_shared_device: [0, 0, 0, 0] +# The mount point of a PFS or object store for swap space, in the event that +# Hermes buffers become full. +swap_mount: "./" +# The number of times the buffer organizer will attempt to place a blob from +# swap space into the hierarchy before giving up. +num_buffer_organizer_retries: 3 + +# A path to a file containing a list of server names, 1 per line. If your +# servers are named according to a pattern (e.g., server-1, server-2, etc.), +# prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this +# option is not empty, it will override anything in `rpc_server_base_name`. +rpc_server_host_file: "" +# Base hostname for the RPC servers. +rpc_server_base_name: "localhost" +# RPC server name suffix. This is appended to the the base name plus host +# number. +rpc_server_suffix: "" +# The RPC protocol. This must come from the documentation of the specific RPC +# library in use. +rpc_protocol: "ofi+sockets" +# RPC domain name for verbs transport. Blank for tcp. +rpc_domain: "" +# Desired RPC port number. +rpc_port: 8080 +# Desired RPC port number for buffer organizer. +buffer_organizer_port: 8081 +# A list of host numbers. Host names are constructed as "rpc_server_base_name + +# host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list +# can be either a single number, or a range, which is 2 numbers separated by a +# hyphen (-). For example the list {1, 3-5, 7, 8-10} will be expanded to +# {1, 3, 4, 5, 7, 8, 9, 10}. +rpc_host_number_range: [] +# The number of handler threads for each RPC server. +rpc_num_threads: 1 +# The number of threads used in the background organization of internal Hermes buffers. +buffer_organizer_num_threads: 4 +# The shared memory prefix for the hermes shared memory segment. A user name +# will be automatically appended. +buffer_pool_shmem_name: "/hermes_buffer_pool_" +# Choose Random, RoundRobin, or MinimizeIoTime +default_placement_policy: "MinimizeIoTime" +# If true (1) the RoundRobin placement policy algorithm will split each Blob +# into a random number of smaller Blobs. +default_rr_split: 0 + +# For each device, the minimum and maximum percent capacity threshold at which +# the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause +# the BufferOrganizer to move data to lower devices, making more room in faster +# devices (ideal for write-heavy workloads). Conversely, increasing the minimum +# threshold will cause data to be moved from slower devices into faster devices +# (ideal for read-heavy workloads). For example, a maximum capacity threshold of +# 0.8 would have the effect of always keeping 20% of the device's space free for +# incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure +# that the device is always at least 30% occupied. +bo_capacity_thresholds: [ + [0.0, 1.0], + [0.0, 1.0], + [0.0, 1.0], + [0.0, 1.0] +] + +#Paths which are ignored when buffering data +path_exclusions: [ + "/bin/", "/boot/", "/dev/", "/etc/", + "/lib/", "/opt/", "/proc/", "/sbin/", + "/sys/", "/usr/", "/var/", "/run/", + "pipe", "socket:", "anon_inode:" +] +#Paths which are never ignored when buffering data +path_inclusions: ["/var/opt/cray/dws/mounts/"] + diff --git a/test/data/staging.yaml b/test/data/staging.yaml new file mode 100644 index 000000000..cb21092ad --- /dev/null +++ b/test/data/staging.yaml @@ -0,0 +1,134 @@ +# Example Hermes configuration file + +# The number of buffering tiers available. For example, RAM, NVMe, burst +# buffer, and parallel file system would be 4 tiers. +num_devices: 2 +# For now this should be the same as num_devices. +num_targets: 2 + +# The maximum buffering capacity in MiB of each device. Here we say that all 4 +# devices get 50 MiB of buffering capacity. +capacities_mb: [2000, 18000] + +# The size of the smallest available buffer in KiB. In general this should be +# the page size of your system for byte addressable storage, and the block size +# of the storage device for block addressable storage. +block_sizes_kb: [4, 4] + +# The nummber of size categories for each device. Here we say that each of our 4 +# devices should have 4 different sizes of buffers. +num_slabs: [2, 1] + +# The number of blocks (the size of which is chosen in block_sizes_kb) that each +# device should contain for each slab (controlled by num_slabs). This allows for +# precise control of the distibution of buffer sizes. +slab_unit_sizes: [ + [1, 256], + [256] +] + +# The percentage of buffering capacity per device to allocate for each slab. +# Each row should add up to 1. In this example, we have 2 devices, each with 4 +# slabs, and each slab is allotted 25% of the device's total buffering capacity. +desired_slab_percentages: [ + [0.1, 0.9], + [1.0] +] + +# The maximum theoretical bandwidth (as advertised by the manufacturer) in +# MiB/sec. of each device. +bandwidth_mbps: [4000, 500] +# The latency in microseconds of each device (as advertised by the manufacturer). +latencies_us: [10, 100] + +# Hermes memory management. The following 4 values should add up to 1. +# The percentage of Hermes memory to reserve for RAM buffers. +buffer_pool_arena_percentage: 0.6 +# The percentage of Hermes memory to reserve for metadata. +metadata_arena_percentage: 0.2 +# The percentage of Hermes memory to reserve for short term storage. +transient_arena_percentage: 0.2 + +# The maxiumum number of buckets that can be created. +max_buckets_per_node: 16 +# The maxiumum number of virtual buckets that can be created. +max_vbuckets_per_node: 8 +# The interval in milliseconds at which to update the global system view. +system_view_state_update_interval_ms: 1000 + +# The mount point of each device. RAM should be the empty string. For block +# devices, this is the directory where Hermes will create buffering files. For +# object storage or cloud targets, this will be a url. +mount_points: ["", "./"] +# For each device, indicate '1' if it is shared among nodes (e.g., burst +# buffers), or '0' if it is per node (e.g., local NVMe). +is_shared_device: [0, 0] +# The mount point of a PFS or object store for swap space, in the event that +# Hermes buffers become full. +swap_mount: "./" +# The number of times the buffer organizer will attempt to place a blob from +# swap space into the hierarchy before giving up. +num_buffer_organizer_retries: 3 + +# A path to a file containing a list of server names, 1 per line. If your +# servers are named according to a pattern (e.g., server-1, server-2, etc.), +# prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this +# option is not empty, it will override anything in `rpc_server_base_name`. +rpc_server_host_file: "" +# Base hostname for the RPC servers. +rpc_server_base_name: "localhost" +# RPC server name suffix. This is appended to the the base name plus host +# number. +rpc_server_suffix: "" +# The RPC protocol. This must come from the documentation of the specific RPC +# library in use. +rpc_protocol: "ofi+sockets" +# RPC domain name for verbs transport. Blank for tcp. +rpc_domain: "" +# Desired RPC port number. +rpc_port: 8080 +# Desired RPC port number for buffer organizer. +buffer_organizer_port: 8081 +# A list of host numbers. Host names are constructed as "rpc_server_base_name + +# host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list +# can be either a single number, or a range, which is 2 numbers separated by a +# hyphen (-). For example the list {1, 3-5, 7, 8-10} will be expanded to +# {1, 3, 4, 5, 7, 8, 9, 10}. +rpc_host_number_range: [] +# The number of handler threads for each RPC server. +rpc_num_threads: 1 +# The number of threads used in the background organization of internal Hermes buffers. +buffer_organizer_num_threads: 4 +# The shared memory prefix for the hermes shared memory segment. A user name +# will be automatically appended. +buffer_pool_shmem_name: "/hermes_buffer_pool_" +# Choose Random, RoundRobin, or MinimizeIoTime +default_placement_policy: "MinimizeIoTime" +# If true (1) the RoundRobin placement policy algorithm will split each Blob +# into a random number of smaller Blobs. +default_rr_split: 0 + +# For each device, the minimum and maximum percent capacity threshold at which +# the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause +# the BufferOrganizer to move data to lower devices, making more room in faster +# devices (ideal for write-heavy workloads). Conversely, increasing the minimum +# threshold will cause data to be moved from slower devices into faster devices +# (ideal for read-heavy workloads). For example, a maximum capacity threshold of +# 0.8 would have the effect of always keeping 20% of the device's space free for +# incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure +# that the device is always at least 30% occupied. +bo_capacity_thresholds: [ + [0.0, 1.0], + [0.0, 1.0] +] + +#Paths which are ignored when buffering data +path_exclusions: [ + "/bin/", "/boot/", "/dev/", "/etc/", + "/lib/", "/opt/", "/proc/", "/sbin/", + "/sys/", "/usr/", "/var/", "/run/", + "pipe", "socket:", "anon_inode:" +] +#Paths which are never ignored when buffering data +path_inclusions: ["/var/opt/cray/dws/mounts/"] + From 2cdd64a41e124bf2744715a6c5764474f810023c Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 31 Oct 2022 20:08:34 -0500 Subject: [PATCH 018/511] prefetch_ares + staging --- test/data/prefetch_ares.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/data/prefetch_ares.yaml b/test/data/prefetch_ares.yaml index 395d7e76b..ad3d06f83 100644 --- a/test/data/prefetch_ares.yaml +++ b/test/data/prefetch_ares.yaml @@ -2,9 +2,9 @@ # The number of buffering tiers available. For example, RAM, NVMe, burst # buffer, and parallel file system would be 4 tiers. -num_devices: 2 +num_devices: 4 # For now this should be the same as num_devices. -num_targets: 2 +num_targets: 4 # The maximum buffering capacity in MiB of each device. Here we say that all 4 # devices get 50 MiB of buffering capacity. From fc73d182fb00044dd1216d6eabb7927d58d89d23 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 31 Oct 2022 20:08:59 -0500 Subject: [PATCH 019/511] prefetch_ares + staging --- test/data/prefetch_ares.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data/prefetch_ares.yaml b/test/data/prefetch_ares.yaml index ad3d06f83..9821af2bf 100644 --- a/test/data/prefetch_ares.yaml +++ b/test/data/prefetch_ares.yaml @@ -63,7 +63,7 @@ system_view_state_update_interval_ms: 1000 # The mount point of each device. RAM should be the empty string. For block # devices, this is the directory where Hermes will create buffering files. For # object storage or cloud targets, this will be a url. -mount_points: ["", "/mnt/nvme/llogan/borg", "/mnt/ssd/llogan/ssd", "/mnt/hdd/llogan/borg"] +mount_points: ["", "/mnt/nvme/llogan/borg", "/mnt/ssd/llogan/borg", "/mnt/hdd/llogan/borg"] # For each device, indicate '1' if it is shared among nodes (e.g., burst # buffers), or '0' if it is per node (e.g., local NVMe). is_shared_device: [0, 0, 0, 0] From f1c2fc4a04881f452478d6d32bfcccad92b3441d Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 31 Oct 2022 20:09:51 -0500 Subject: [PATCH 020/511] prefetch_ares + staging --- test/data/prefetch_ares.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data/prefetch_ares.yaml b/test/data/prefetch_ares.yaml index 9821af2bf..38ea3580c 100644 --- a/test/data/prefetch_ares.yaml +++ b/test/data/prefetch_ares.yaml @@ -8,7 +8,7 @@ num_targets: 4 # The maximum buffering capacity in MiB of each device. Here we say that all 4 # devices get 50 MiB of buffering capacity. -capacities_mb: [2000, 2000, 2000, 10000] +capacities_mb: [2000, 2000, 2000, 16000] # The size of the smallest available buffer in KiB. In general this should be # the page size of your system for byte addressable storage, and the block size From c38762839ad984a881c8fcbe9aa59c8166e0448f Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 31 Oct 2022 20:15:17 -0500 Subject: [PATCH 021/511] Remove wait for transfer --- src/prefetcher.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/prefetcher.cc b/src/prefetcher.cc index ec9fa09cb..da13b2953 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -94,15 +94,15 @@ void Prefetcher::CalculateBlobScore(struct timespec &ts, decision.queue_later_ = false; for (auto &access_time_struct : decision.stats_) { // Wait until the I/O for this Get seems to have completed - float time_left_on_io = access_time_struct.TimeLeftOnIo( + /*float time_left_on_io = access_time_struct.TimeLeftOnIo( est_xfer_time, &ts); - /*LOG(INFO) << "Blob id: " << decision.blob_id_.as_int + LOG(INFO) << "Blob id: " << decision.blob_id_.as_int << " Time left before starting prefetch: " - << time_left_on_io << std::endl;*/ + << time_left_on_io << std::endl; if (time_left_on_io > 0) { decision.queue_later_ = true; continue; - } + }*/ float next_access_sec = access_time_struct.TimeToNextIo(&ts); LOG(INFO) << "Next access sec: " << next_access_sec << std::endl; LOG(INFO) << "Est xfer time : " << est_xfer_time << std::endl; From bcebec42132f3982fee21ee59acab3e15baab920 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 31 Oct 2022 20:22:35 -0500 Subject: [PATCH 022/511] Remove next_access check --- src/prefetcher.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prefetcher.cc b/src/prefetcher.cc index da13b2953..7c752ae61 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -106,7 +106,7 @@ void Prefetcher::CalculateBlobScore(struct timespec &ts, float next_access_sec = access_time_struct.TimeToNextIo(&ts); LOG(INFO) << "Next access sec: " << next_access_sec << std::endl; LOG(INFO) << "Est xfer time : " << est_xfer_time << std::endl; - if (next_access_sec < est_xfer_time) continue; + // if (next_access_sec < est_xfer_time) continue; float max_access_wait = std::max(max_wait_xfer_*est_xfer_time, max_wait_sec_); LOG(INFO) << "Max access wait: " << max_access_wait << std::endl; From 0c29e8e529a58e9bfb2a6e6dc70fed62f130bc85 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sat, 5 Nov 2022 14:22:55 -0500 Subject: [PATCH 023/511] BORG again --- Testing/Temporary/CTestCostData.txt | 1 + Testing/Temporary/LastTest.log | 3 + .../Testing/Temporary/LastTest.log | 3 + src/api/bucket.cc | 2 + src/buffer_organizer.cc | 7 +- src/buffer_pool.cc | 6 + src/hermes_types.h | 3 +- src/metadata_management_internal.h | 2 + src/prefetcher.cc | 61 +++++++- src/prefetcher.h | 14 +- src/prefetchers/sequential.cc | 65 +++++++- src/prefetchers/sequential.h | 18 ++- test/clear_cache.sh | 3 + test/data/prefetch.yaml | 14 +- test/data/prefetch_ares.yaml | 30 ++-- test/data/prefetch_ares_ram.yaml | 140 ++++++++++++++++++ test/data/prefetch_ram.yaml | 131 ++++++++++++++++ test/prefetch_test.cc | 10 +- 18 files changed, 458 insertions(+), 55 deletions(-) create mode 100644 Testing/Temporary/CTestCostData.txt create mode 100644 Testing/Temporary/LastTest.log create mode 100644 adapter/adapter_generator/Testing/Temporary/LastTest.log create mode 100644 test/clear_cache.sh create mode 100644 test/data/prefetch_ares_ram.yaml create mode 100644 test/data/prefetch_ram.yaml diff --git a/Testing/Temporary/CTestCostData.txt b/Testing/Temporary/CTestCostData.txt new file mode 100644 index 000000000..ed97d539c --- /dev/null +++ b/Testing/Temporary/CTestCostData.txt @@ -0,0 +1 @@ +--- diff --git a/Testing/Temporary/LastTest.log b/Testing/Temporary/LastTest.log new file mode 100644 index 000000000..c72e2e752 --- /dev/null +++ b/Testing/Temporary/LastTest.log @@ -0,0 +1,3 @@ +Start testing: Oct 13 05:01 CDT +---------------------------------------------------------- +End testing: Oct 13 05:01 CDT diff --git a/adapter/adapter_generator/Testing/Temporary/LastTest.log b/adapter/adapter_generator/Testing/Temporary/LastTest.log new file mode 100644 index 000000000..f9dee83b3 --- /dev/null +++ b/adapter/adapter_generator/Testing/Temporary/LastTest.log @@ -0,0 +1,3 @@ +Start testing: Oct 21 10:03 CDT +---------------------------------------------------------- +End testing: Oct 21 10:03 CDT diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 41cfbb52e..377c4fc26 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -169,8 +169,10 @@ size_t Bucket::Get(const std::string &name, void *user_blob, size_t blob_size, entry.historical_ = false; Prefetcher::LogIoStat(hermes_.get(), entry); } + LockBlob(&hermes_->context_, &hermes_->rpc_, blob_id); ret = ReadBlobById(&hermes_->context_, &hermes_->rpc_, &hermes_->trans_arena_, blob, blob_id); + UnlockBlob(&hermes_->context_, &hermes_->rpc_, blob_id); } else { ret = GetBlobSize(scratch, name, ctx); } diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index cd2596fbb..870d196d8 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -76,11 +76,8 @@ f32 NormalizeAccessScore(SharedMemoryContext *context, f32 raw_score, f32 range = max_seconds - min_seconds; f32 adjusted_score = raw_score - min_seconds; f32 result = 1.0 - (adjusted_score / range); - if (result <= 1.0 && result <= 1.01) { result = 1.0; } - if (result <= 0.0 && result <= 1.0) { - LOG(FATAL) << "NormalizeAccessScore must be 0 <= score <= 1, but was: " - << result << std::endl; - } + if (result < 0.0) result = 0.0; + if (result > 1.0) result = 1.0; return result; } diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index baa9d6dfc..71926e363 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -678,6 +678,9 @@ ptrdiff_t GetBufferOffset(SharedMemoryContext *context, BufferID id) { u8 *GetRamBufferPtr(SharedMemoryContext *context, BufferID buffer_id) { ptrdiff_t data_offset = GetBufferOffset(context, buffer_id); + if (data_offset > context->shm_size) { + LOG(FATAL) << "Buffer pointer outside of SHM region" << std::endl; + } u8 *result = context->shm_base + data_offset; return result; @@ -1037,6 +1040,9 @@ void GetBufferSlabInfo(ScopedTemporaryMemory &scratch, Config *config, f32 device_capacity = config->capacities[device]; size_t bytes_for_slab = (size_t)((f32)device_capacity * slab_percentage); + if (device == 0) { + bytes_for_slab *= .6; // TODO(llogan): this is a temporary hack + } buffer_counts[device][slab] = (bytes_for_slab / slab_buffer_sizes[device][slab]); if (device == 0) { diff --git a/src/hermes_types.h b/src/hermes_types.h index 1f9863638..ca6d976e9 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -189,7 +189,8 @@ enum class PrefetchHint { struct PrefetchContext { PrefetchHint hint_; int read_ahead_; - PrefetchContext() : hint_(PrefetchHint::kNone) {} + float decay_; + PrefetchContext() : hint_(PrefetchHint::kNone), read_ahead_(1), decay_(.5) {} }; /** Hermes API call context */ diff --git a/src/metadata_management_internal.h b/src/metadata_management_internal.h index 18add4dc4..4fdafcc12 100644 --- a/src/metadata_management_internal.h +++ b/src/metadata_management_internal.h @@ -106,6 +106,8 @@ BucketID LocalGetOrCreateBucketId(SharedMemoryContext *context, VBucketID LocalGetOrCreateVBucketId(SharedMemoryContext *context, const std::string &name); f32 LocalGetBlobImportanceScore(SharedMemoryContext *context, BlobID blob_id); +f32 GetBlobImportanceScore(SharedMemoryContext *context, RpcContext *rpc, + BlobID blob_id); /** * Faster version of std::stoull. diff --git a/src/prefetcher.cc b/src/prefetcher.cc index 7c752ae61..9f8d0bce1 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -13,6 +13,7 @@ #include "prefetcher_factory.h" #include "metadata_management.h" #include "singleton.h" +#include "metadata_management_internal.h" using hermes::api::Hermes; @@ -87,14 +88,41 @@ float Prefetcher::EstimateBlobMovementTime(BlobID blob_id) { return xfer_time; } +bool HasOnlyDemotions(PrefetchDecision &decision, float &decay) { + decay = std::numeric_limits::infinity(); + if (decision.stats_.size() == 0) return false; + for (auto &prefetch_stat : decision.stats_) { + if (prefetch_stat.decay_ < 0) { + return false; + } + decay = std::min(decay, prefetch_stat.decay_); + } + return true; +}; + void Prefetcher::CalculateBlobScore(struct timespec &ts, PrefetchDecision &decision) { float est_xfer_time = decision.est_xfer_time_; decision.new_score_ = -1; decision.queue_later_ = false; - for (auto &access_time_struct : decision.stats_) { + + float decay; + if (HasOnlyDemotions(decision, decay)) { + decision.new_score_ = GetBlobImportanceScore(&hermes_->context_, + &hermes_->rpc_, + decision.blob_id_); + decision.new_score_ *= decay; + if (decision.new_score_ < 0) { + decision.new_score_ = 0; + } + decision.decay_ = true; + return; + } + + for (auto &prefetch_stat : decision.stats_) { + if (prefetch_stat.decay_ >= 0) continue; // Wait until the I/O for this Get seems to have completed - /*float time_left_on_io = access_time_struct.TimeLeftOnIo( + /*float time_left_on_io = prefetch_stat.TimeLeftOnIo( est_xfer_time, &ts); LOG(INFO) << "Blob id: " << decision.blob_id_.as_int << " Time left before starting prefetch: " @@ -103,7 +131,7 @@ void Prefetcher::CalculateBlobScore(struct timespec &ts, decision.queue_later_ = true; continue; }*/ - float next_access_sec = access_time_struct.TimeToNextIo(&ts); + float next_access_sec = prefetch_stat.TimeToNextIo(&ts); LOG(INFO) << "Next access sec: " << next_access_sec << std::endl; LOG(INFO) << "Est xfer time : " << est_xfer_time << std::endl; // if (next_access_sec < est_xfer_time) continue; @@ -162,11 +190,30 @@ void Prefetcher::Process() { if (decision.queue_later_) { queue_later_.emplace(blob_id, decision); } - /*LOG(INFO) << "Not prefetching bkt_id: " << decision.bkt_id_.as_int - << " blob_id: " << decision.blob_name_ - << " score: " << decision.new_score_ << std::endl;*/ - continue; } + } + + // Process decay blobs first (make room) + for (auto &[blob_id, decision] : schema) { + if (!decision.decay_) { continue; } + LOG(INFO) << "Decaying Blob: " << blob_id.as_int + << " to score: " << decision.new_score_ << std::endl; + OrganizeBlob(&hermes_->context_, &hermes_->rpc_, + decision.bkt_id_, decision.blob_name_, + epsilon_, decision.new_score_); + } + + // TODO(llogan): a hack to help BORG shuffle data + struct timespec ts2; + while(PrefetchStat::DiffTimespec(&ts2, &ts) < 1) { + timespec_get(&ts2, TIME_UTC); + ABT_thread_yield(); + } + + // Calculate new blob scores + for (auto &[blob_id, decision] : schema) { + if (decision.decay_) { continue; } + if (decision.new_score_ < 0) { continue; } LOG(INFO) << "Prefetching bkt_id: " << decision.bkt_id_.as_int << " blob_id: " << decision.blob_name_ << " score: " << decision.new_score_ << std::endl; diff --git a/src/prefetcher.h b/src/prefetcher.h index 9eeee6c2c..315e6fa1c 100644 --- a/src/prefetcher.h +++ b/src/prefetcher.h @@ -80,9 +80,14 @@ struct IoLogEntry { struct PrefetchStat { float est_next_time_; struct timespec start_; + float decay_; + + PrefetchStat() : est_next_time_(0), decay_(-1) {} explicit PrefetchStat(float est_next_time, struct timespec &start) : - est_next_time_(est_next_time), start_(start) {} + est_next_time_(est_next_time), start_(start), decay_(-1) {} + + explicit PrefetchStat(float decay) : decay_(decay) {} float TimeLeftOnIo(float est_xfer_time, const struct timespec *cur) { float diff = DiffTimespec(cur, &start_); @@ -111,13 +116,18 @@ struct PrefetchDecision { bool queue_later_; float est_xfer_time_; float new_score_; + bool decay_; PrefetchDecision() : queue_later_(false), est_xfer_time_(-1), - new_score_(-1) {} + new_score_(-1), + decay_(false) {} void AddStat(float est_access_time, struct timespec &start) { stats_.emplace_back(est_access_time, start); } + void AddStat(float decay) { + stats_.emplace_back(decay); + } }; class PrefetchSchema { diff --git a/src/prefetchers/sequential.cc b/src/prefetchers/sequential.cc index 8e14d561f..d2131960d 100644 --- a/src/prefetchers/sequential.cc +++ b/src/prefetchers/sequential.cc @@ -51,9 +51,9 @@ void SequentialPrefetcher::Process(std::list &log, PrefetchDecision decision; decision.bkt_id_ = entry.bkt_id_; if (IsNullVBucketId(entry.vbkt_id_)) { - GetNextBucket(entry, decision, cur_id); + GetNextFromBucket(entry, decision, cur_id); } else { - GetNextVbucket(entry, decision, cur_id); + GetNextFromVbucket(entry, decision, cur_id); } if (IsNullBlobId(decision.blob_id_)) { break; @@ -62,12 +62,29 @@ void SequentialPrefetcher::Process(std::list &log, schema.emplace(decision); cur_id = decision.blob_id_; } + + // Demote the previous blobs + cur_id = entry.blob_id_; + for (int i = 0; i < entry.pctx_.read_ahead_; ++i) { + PrefetchDecision decision; + if (IsNullVBucketId(entry.vbkt_id_)) { + GetPriorFromBucket(entry, decision, cur_id); + } else { + GetPriorFromVbucket(entry, decision, cur_id); + } + if (IsNullBlobId(decision.blob_id_)) { + break; + } + decision.AddStat(entry.pctx_.decay_); + schema.emplace(decision); + cur_id = decision.blob_id_; + } } } -void SequentialPrefetcher::GetNextBucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobID &cur_id) { +void SequentialPrefetcher::GetNextFromBucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobID &cur_id) { // Get current blob name auto prefetcher = Singleton::GetInstance(); auto hermes = prefetcher->hermes_; @@ -87,9 +104,41 @@ void SequentialPrefetcher::GetNextBucket(IoLogEntry &entry, false); } -void SequentialPrefetcher::GetNextVbucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobID &cur_id) { +void SequentialPrefetcher::GetNextFromVbucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobID &cur_id) { + // TODO(llogan): Not implemented for now. +} + +void SequentialPrefetcher::GetPriorFromBucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobID &cur_id) { + // Get current blob name + auto prefetcher = Singleton::GetInstance(); + auto hermes = prefetcher->hermes_; + std::string blob_name = GetBlobNameFromId(&hermes->context_, + &hermes->rpc_, + cur_id); + + // Get prior blob name + BlobPlacement p; + p.DecodeBlobName(blob_name); + if (p.page_ == 0) { + cur_id.as_int = 0; + return; + } + p.page_ -= 1; + decision.blob_name_ = p.CreateBlobName(); + + // Get the prior blob ID from the bucket + decision.blob_id_ = GetBlobId(&hermes->context_, &hermes->rpc_, + decision.blob_name_, entry.bkt_id_, + false); +} + +void SequentialPrefetcher::GetPriorFromVbucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobID &cur_id) { // TODO(llogan): Not implemented for now. } diff --git a/src/prefetchers/sequential.h b/src/prefetchers/sequential.h index 93b62d182..b27328db8 100644 --- a/src/prefetchers/sequential.h +++ b/src/prefetchers/sequential.h @@ -33,12 +33,18 @@ class SequentialPrefetcher : public PrefetchAlgorithm { PrefetchSchema &schema); private: - void GetNextBucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobID &cur_id); - void GetNextVbucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobID &cur_id); + void GetNextFromBucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobID &cur_id); + void GetNextFromVbucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobID &cur_id); + void GetPriorFromBucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobID &cur_id); + void GetPriorFromVbucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobID &cur_id); }; } // namespace hermes diff --git a/test/clear_cache.sh b/test/clear_cache.sh new file mode 100644 index 000000000..6bfd1dc55 --- /dev/null +++ b/test/clear_cache.sh @@ -0,0 +1,3 @@ +#!/bin/bash +sync +echo 3 > /proc/sys/vm/drop_caches \ No newline at end of file diff --git a/test/data/prefetch.yaml b/test/data/prefetch.yaml index 211a2d5eb..0e24e682e 100644 --- a/test/data/prefetch.yaml +++ b/test/data/prefetch.yaml @@ -8,7 +8,7 @@ num_targets: 2 # The maximum buffering capacity in MiB of each device. Here we say that all 4 # devices get 50 MiB of buffering capacity. -capacities_mb: [2000, 10000] +capacities_mb: [4000, 16000] # The size of the smallest available buffer in KiB. In general this should be # the page size of your system for byte addressable storage, and the block size @@ -43,11 +43,11 @@ latencies_us: [10, 100] # Hermes memory management. The following 4 values should add up to 1. # The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage: 0.6 +buffer_pool_arena_percentage: 0.8 # The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage: 0.2 +metadata_arena_percentage: 0.1 # The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage: 0.2 +transient_arena_percentage: 0.1 # The maxiumum number of buckets that can be created. max_buckets_per_node: 16 @@ -59,10 +59,10 @@ system_view_state_update_interval_ms: 1000 # The mount point of each device. RAM should be the empty string. For block # devices, this is the directory where Hermes will create buffering files. For # object storage or cloud targets, this will be a url. -mount_points: ["", "./"] +mount_points: [""] # For each device, indicate '1' if it is shared among nodes (e.g., burst # buffers), or '0' if it is per node (e.g., local NVMe). -is_shared_device: [0, 0] +is_shared_device: [0,0] # The mount point of a PFS or object store for swap space, in the event that # Hermes buffers become full. swap_mount: "./" @@ -98,7 +98,7 @@ rpc_host_number_range: [] # The number of handler threads for each RPC server. rpc_num_threads: 1 # The number of threads used in the background organization of internal Hermes buffers. -buffer_organizer_num_threads: 4 +buffer_organizer_num_threads: 1 # The shared memory prefix for the hermes shared memory segment. A user name # will be automatically appended. buffer_pool_shmem_name: "/hermes_buffer_pool_" diff --git a/test/data/prefetch_ares.yaml b/test/data/prefetch_ares.yaml index 38ea3580c..6b56e7c90 100644 --- a/test/data/prefetch_ares.yaml +++ b/test/data/prefetch_ares.yaml @@ -2,30 +2,28 @@ # The number of buffering tiers available. For example, RAM, NVMe, burst # buffer, and parallel file system would be 4 tiers. -num_devices: 4 +num_devices: 2 # For now this should be the same as num_devices. -num_targets: 4 +num_targets: 2 # The maximum buffering capacity in MiB of each device. Here we say that all 4 # devices get 50 MiB of buffering capacity. -capacities_mb: [2000, 2000, 2000, 16000] +capacities_mb: [2000, 16000] # The size of the smallest available buffer in KiB. In general this should be # the page size of your system for byte addressable storage, and the block size # of the storage device for block addressable storage. -block_sizes_kb: [4, 4, 4, 4] +block_sizes_kb: [4, 4] # The nummber of size categories for each device. Here we say that each of our 4 # devices should have 4 different sizes of buffers. -num_slabs: [2, 1, 1, 1] +num_slabs: [2, 1] # The number of blocks (the size of which is chosen in block_sizes_kb) that each # device should contain for each slab (controlled by num_slabs). This allows for # precise control of the distibution of buffer sizes. slab_unit_sizes: [ [1, 256], - [256], - [256], [256] ] @@ -34,24 +32,22 @@ slab_unit_sizes: [ # slabs, and each slab is allotted 25% of the device's total buffering capacity. desired_slab_percentages: [ [0.1, 0.9], - [1.0], - [1.0], [1.0] ] # The maximum theoretical bandwidth (as advertised by the manufacturer) in # MiB/sec. of each device. -bandwidth_mbps: [4000, 1000, 500, 150] +bandwidth_mbps: [4000, 150] # The latency in microseconds of each device (as advertised by the manufacturer). -latencies_us: [10, 100, 800, 10000] +latencies_us: [10, 10000] # Hermes memory management. The following 4 values should add up to 1. # The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage: 0.6 +buffer_pool_arena_percentage: 0.8 # The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage: 0.2 +metadata_arena_percentage: 0.1 # The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage: 0.2 +transient_arena_percentage: 0.1 # The maxiumum number of buckets that can be created. max_buckets_per_node: 16 @@ -63,10 +59,10 @@ system_view_state_update_interval_ms: 1000 # The mount point of each device. RAM should be the empty string. For block # devices, this is the directory where Hermes will create buffering files. For # object storage or cloud targets, this will be a url. -mount_points: ["", "/mnt/nvme/llogan/borg", "/mnt/ssd/llogan/borg", "/mnt/hdd/llogan/borg"] +mount_points: ["", "/mnt/hdd/llogan/borg"] # For each device, indicate '1' if it is shared among nodes (e.g., burst # buffers), or '0' if it is per node (e.g., local NVMe). -is_shared_device: [0, 0, 0, 0] +is_shared_device: [0, 0] # The mount point of a PFS or object store for swap space, in the event that # Hermes buffers become full. swap_mount: "./" @@ -122,8 +118,6 @@ default_rr_split: 0 # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure # that the device is always at least 30% occupied. bo_capacity_thresholds: [ - [0.0, 1.0], - [0.0, 1.0], [0.0, 1.0], [0.0, 1.0] ] diff --git a/test/data/prefetch_ares_ram.yaml b/test/data/prefetch_ares_ram.yaml new file mode 100644 index 000000000..38ea3580c --- /dev/null +++ b/test/data/prefetch_ares_ram.yaml @@ -0,0 +1,140 @@ +# Example Hermes configuration file + +# The number of buffering tiers available. For example, RAM, NVMe, burst +# buffer, and parallel file system would be 4 tiers. +num_devices: 4 +# For now this should be the same as num_devices. +num_targets: 4 + +# The maximum buffering capacity in MiB of each device. Here we say that all 4 +# devices get 50 MiB of buffering capacity. +capacities_mb: [2000, 2000, 2000, 16000] + +# The size of the smallest available buffer in KiB. In general this should be +# the page size of your system for byte addressable storage, and the block size +# of the storage device for block addressable storage. +block_sizes_kb: [4, 4, 4, 4] + +# The nummber of size categories for each device. Here we say that each of our 4 +# devices should have 4 different sizes of buffers. +num_slabs: [2, 1, 1, 1] + +# The number of blocks (the size of which is chosen in block_sizes_kb) that each +# device should contain for each slab (controlled by num_slabs). This allows for +# precise control of the distibution of buffer sizes. +slab_unit_sizes: [ + [1, 256], + [256], + [256], + [256] +] + +# The percentage of buffering capacity per device to allocate for each slab. +# Each row should add up to 1. In this example, we have 2 devices, each with 4 +# slabs, and each slab is allotted 25% of the device's total buffering capacity. +desired_slab_percentages: [ + [0.1, 0.9], + [1.0], + [1.0], + [1.0] +] + +# The maximum theoretical bandwidth (as advertised by the manufacturer) in +# MiB/sec. of each device. +bandwidth_mbps: [4000, 1000, 500, 150] +# The latency in microseconds of each device (as advertised by the manufacturer). +latencies_us: [10, 100, 800, 10000] + +# Hermes memory management. The following 4 values should add up to 1. +# The percentage of Hermes memory to reserve for RAM buffers. +buffer_pool_arena_percentage: 0.6 +# The percentage of Hermes memory to reserve for metadata. +metadata_arena_percentage: 0.2 +# The percentage of Hermes memory to reserve for short term storage. +transient_arena_percentage: 0.2 + +# The maxiumum number of buckets that can be created. +max_buckets_per_node: 16 +# The maxiumum number of virtual buckets that can be created. +max_vbuckets_per_node: 8 +# The interval in milliseconds at which to update the global system view. +system_view_state_update_interval_ms: 1000 + +# The mount point of each device. RAM should be the empty string. For block +# devices, this is the directory where Hermes will create buffering files. For +# object storage or cloud targets, this will be a url. +mount_points: ["", "/mnt/nvme/llogan/borg", "/mnt/ssd/llogan/borg", "/mnt/hdd/llogan/borg"] +# For each device, indicate '1' if it is shared among nodes (e.g., burst +# buffers), or '0' if it is per node (e.g., local NVMe). +is_shared_device: [0, 0, 0, 0] +# The mount point of a PFS or object store for swap space, in the event that +# Hermes buffers become full. +swap_mount: "./" +# The number of times the buffer organizer will attempt to place a blob from +# swap space into the hierarchy before giving up. +num_buffer_organizer_retries: 3 + +# A path to a file containing a list of server names, 1 per line. If your +# servers are named according to a pattern (e.g., server-1, server-2, etc.), +# prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this +# option is not empty, it will override anything in `rpc_server_base_name`. +rpc_server_host_file: "" +# Base hostname for the RPC servers. +rpc_server_base_name: "localhost" +# RPC server name suffix. This is appended to the the base name plus host +# number. +rpc_server_suffix: "" +# The RPC protocol. This must come from the documentation of the specific RPC +# library in use. +rpc_protocol: "ofi+sockets" +# RPC domain name for verbs transport. Blank for tcp. +rpc_domain: "" +# Desired RPC port number. +rpc_port: 8080 +# Desired RPC port number for buffer organizer. +buffer_organizer_port: 8081 +# A list of host numbers. Host names are constructed as "rpc_server_base_name + +# host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list +# can be either a single number, or a range, which is 2 numbers separated by a +# hyphen (-). For example the list {1, 3-5, 7, 8-10} will be expanded to +# {1, 3, 4, 5, 7, 8, 9, 10}. +rpc_host_number_range: [] +# The number of handler threads for each RPC server. +rpc_num_threads: 1 +# The number of threads used in the background organization of internal Hermes buffers. +buffer_organizer_num_threads: 4 +# The shared memory prefix for the hermes shared memory segment. A user name +# will be automatically appended. +buffer_pool_shmem_name: "/hermes_buffer_pool_" +# Choose Random, RoundRobin, or MinimizeIoTime +default_placement_policy: "MinimizeIoTime" +# If true (1) the RoundRobin placement policy algorithm will split each Blob +# into a random number of smaller Blobs. +default_rr_split: 0 + +# For each device, the minimum and maximum percent capacity threshold at which +# the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause +# the BufferOrganizer to move data to lower devices, making more room in faster +# devices (ideal for write-heavy workloads). Conversely, increasing the minimum +# threshold will cause data to be moved from slower devices into faster devices +# (ideal for read-heavy workloads). For example, a maximum capacity threshold of +# 0.8 would have the effect of always keeping 20% of the device's space free for +# incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure +# that the device is always at least 30% occupied. +bo_capacity_thresholds: [ + [0.0, 1.0], + [0.0, 1.0], + [0.0, 1.0], + [0.0, 1.0] +] + +#Paths which are ignored when buffering data +path_exclusions: [ + "/bin/", "/boot/", "/dev/", "/etc/", + "/lib/", "/opt/", "/proc/", "/sbin/", + "/sys/", "/usr/", "/var/", "/run/", + "pipe", "socket:", "anon_inode:" +] +#Paths which are never ignored when buffering data +path_inclusions: ["/var/opt/cray/dws/mounts/"] + diff --git a/test/data/prefetch_ram.yaml b/test/data/prefetch_ram.yaml new file mode 100644 index 000000000..f698056c0 --- /dev/null +++ b/test/data/prefetch_ram.yaml @@ -0,0 +1,131 @@ +# Example Hermes configuration file + +# The number of buffering tiers available. For example, RAM, NVMe, burst +# buffer, and parallel file system would be 4 tiers. +num_devices: 1 +# For now this should be the same as num_devices. +num_targets: 1 + +# The maximum buffering capacity in MiB of each device. Here we say that all 4 +# devices get 50 MiB of buffering capacity. +capacities_mb: [18000] + +# The size of the smallest available buffer in KiB. In general this should be +# the page size of your system for byte addressable storage, and the block size +# of the storage device for block addressable storage. +block_sizes_kb: [4] + +# The nummber of size categories for each device. Here we say that each of our 4 +# devices should have 4 different sizes of buffers. +num_slabs: [2] + +# The number of blocks (the size of which is chosen in block_sizes_kb) that each +# device should contain for each slab (controlled by num_slabs). This allows for +# precise control of the distibution of buffer sizes. +slab_unit_sizes: [ + [1, 256] +] + +# The percentage of buffering capacity per device to allocate for each slab. +# Each row should add up to 1. In this example, we have 2 devices, each with 4 +# slabs, and each slab is allotted 25% of the device's total buffering capacity. +desired_slab_percentages: [ + [0.1, 0.9] +] + +# The maximum theoretical bandwidth (as advertised by the manufacturer) in +# MiB/sec. of each device. +bandwidth_mbps: [4000] +# The latency in microseconds of each device (as advertised by the manufacturer). +latencies_us: [10] + +# Hermes memory management. The following 4 values should add up to 1. +# The percentage of Hermes memory to reserve for RAM buffers. +buffer_pool_arena_percentage: 0.8 +# The percentage of Hermes memory to reserve for metadata. +metadata_arena_percentage: 0.1 +# The percentage of Hermes memory to reserve for short term storage. +transient_arena_percentage: 0.1 + +# The maxiumum number of buckets that can be created. +max_buckets_per_node: 16 +# The maxiumum number of virtual buckets that can be created. +max_vbuckets_per_node: 8 +# The interval in milliseconds at which to update the global system view. +system_view_state_update_interval_ms: 1000 + +# The mount point of each device. RAM should be the empty string. For block +# devices, this is the directory where Hermes will create buffering files. For +# object storage or cloud targets, this will be a url. +mount_points: [""] +# For each device, indicate '1' if it is shared among nodes (e.g., burst +# buffers), or '0' if it is per node (e.g., local NVMe). +is_shared_device: [0] +# The mount point of a PFS or object store for swap space, in the event that +# Hermes buffers become full. +swap_mount: "./" +# The number of times the buffer organizer will attempt to place a blob from +# swap space into the hierarchy before giving up. +num_buffer_organizer_retries: 3 + +# A path to a file containing a list of server names, 1 per line. If your +# servers are named according to a pattern (e.g., server-1, server-2, etc.), +# prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this +# option is not empty, it will override anything in `rpc_server_base_name`. +rpc_server_host_file: "" +# Base hostname for the RPC servers. +rpc_server_base_name: "localhost" +# RPC server name suffix. This is appended to the the base name plus host +# number. +rpc_server_suffix: "" +# The RPC protocol. This must come from the documentation of the specific RPC +# library in use. +rpc_protocol: "ofi+sockets" +# RPC domain name for verbs transport. Blank for tcp. +rpc_domain: "" +# Desired RPC port number. +rpc_port: 8080 +# Desired RPC port number for buffer organizer. +buffer_organizer_port: 8081 +# A list of host numbers. Host names are constructed as "rpc_server_base_name + +# host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list +# can be either a single number, or a range, which is 2 numbers separated by a +# hyphen (-). For example the list {1, 3-5, 7, 8-10} will be expanded to +# {1, 3, 4, 5, 7, 8, 9, 10}. +rpc_host_number_range: [] +# The number of handler threads for each RPC server. +rpc_num_threads: 1 +# The number of threads used in the background organization of internal Hermes buffers. +buffer_organizer_num_threads: 1 +# The shared memory prefix for the hermes shared memory segment. A user name +# will be automatically appended. +buffer_pool_shmem_name: "/hermes_buffer_pool_" +# Choose Random, RoundRobin, or MinimizeIoTime +default_placement_policy: "MinimizeIoTime" +# If true (1) the RoundRobin placement policy algorithm will split each Blob +# into a random number of smaller Blobs. +default_rr_split: 0 + +# For each device, the minimum and maximum percent capacity threshold at which +# the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause +# the BufferOrganizer to move data to lower devices, making more room in faster +# devices (ideal for write-heavy workloads). Conversely, increasing the minimum +# threshold will cause data to be moved from slower devices into faster devices +# (ideal for read-heavy workloads). For example, a maximum capacity threshold of +# 0.8 would have the effect of always keeping 20% of the device's space free for +# incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure +# that the device is always at least 30% occupied. +bo_capacity_thresholds: [ + [0.0, 1.0] +] + +#Paths which are ignored when buffering data +path_exclusions: [ + "/bin/", "/boot/", "/dev/", "/etc/", + "/lib/", "/opt/", "/proc/", "/sbin/", + "/sys/", "/usr/", "/var/", "/run/", + "pipe", "socket:", "anon_inode:" +] +#Paths which are never ignored when buffering data +path_inclusions: ["/var/opt/cray/dws/mounts/"] + diff --git a/test/prefetch_test.cc b/test/prefetch_test.cc index cdff063dd..089ca0a1a 100644 --- a/test/prefetch_test.cc +++ b/test/prefetch_test.cc @@ -46,7 +46,7 @@ int main(int argc, char **argv) { if (argc != 6) { std::cout << "USAGE: ./prefetch_test" << "[with_prefetch] [dataset_mb] [blob_size_mb]" - << "[read_ahead] [phase]" << std::endl; + << "[read_ahead] [phase] [clear_cache_path]" << std::endl; } bool with_prefetch = atoi(argv[1]); @@ -55,6 +55,11 @@ int main(int argc, char **argv) { size_t blob_count = dataset_size / blob_size; int read_ahead = atoi(argv[4]); int phase = atoi(argv[5]); + std::string clear_cache = argv[6]; + std::string clear_cache_script = ("bash " + clear_cache); + + std::cout << clear_cache_script << std::endl; + system(clear_cache_script.c_str()); std::cout << "Dataset Size: " << dataset_size / MEGABYTES(1) << " Blob Size: " << blob_size / MEGABYTES(1) @@ -81,6 +86,9 @@ int main(int argc, char **argv) { } LOG(INFO) << "FINISHED PUTTING ALL BLOBS" << std::endl; + std::cout << clear_cache_script << std::endl; + system(clear_cache_script.c_str()); + // Get blobs (sequentially) hermes::HighResMonotonicTimer t; t.Resume(); From 861ddb8a4458c82b8f4a4fd5a068eb054ee16fb9 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sat, 5 Nov 2022 14:31:30 -0500 Subject: [PATCH 024/511] prefetch ram --- test/data/prefetch_ares_ram.yaml | 35 ++++++++++++-------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/test/data/prefetch_ares_ram.yaml b/test/data/prefetch_ares_ram.yaml index 38ea3580c..40a0a3c9e 100644 --- a/test/data/prefetch_ares_ram.yaml +++ b/test/data/prefetch_ares_ram.yaml @@ -2,56 +2,50 @@ # The number of buffering tiers available. For example, RAM, NVMe, burst # buffer, and parallel file system would be 4 tiers. -num_devices: 4 +num_devices: 1 # For now this should be the same as num_devices. -num_targets: 4 +num_targets: 1 # The maximum buffering capacity in MiB of each device. Here we say that all 4 # devices get 50 MiB of buffering capacity. -capacities_mb: [2000, 2000, 2000, 16000] +capacities_mb: [18000] # The size of the smallest available buffer in KiB. In general this should be # the page size of your system for byte addressable storage, and the block size # of the storage device for block addressable storage. -block_sizes_kb: [4, 4, 4, 4] +block_sizes_kb: [4] # The nummber of size categories for each device. Here we say that each of our 4 # devices should have 4 different sizes of buffers. -num_slabs: [2, 1, 1, 1] +num_slabs: [2] # The number of blocks (the size of which is chosen in block_sizes_kb) that each # device should contain for each slab (controlled by num_slabs). This allows for # precise control of the distibution of buffer sizes. slab_unit_sizes: [ - [1, 256], - [256], - [256], - [256] + [1,256], ] # The percentage of buffering capacity per device to allocate for each slab. # Each row should add up to 1. In this example, we have 2 devices, each with 4 # slabs, and each slab is allotted 25% of the device's total buffering capacity. desired_slab_percentages: [ - [0.1, 0.9], - [1.0], - [1.0], - [1.0] + [0.1, 0.9] ] # The maximum theoretical bandwidth (as advertised by the manufacturer) in # MiB/sec. of each device. -bandwidth_mbps: [4000, 1000, 500, 150] +bandwidth_mbps: [4000] # The latency in microseconds of each device (as advertised by the manufacturer). -latencies_us: [10, 100, 800, 10000] +latencies_us: [10] # Hermes memory management. The following 4 values should add up to 1. # The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage: 0.6 +buffer_pool_arena_percentage: 0.8 # The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage: 0.2 +metadata_arena_percentage: 0.1 # The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage: 0.2 +transient_arena_percentage: 0.1 # The maxiumum number of buckets that can be created. max_buckets_per_node: 16 @@ -66,7 +60,7 @@ system_view_state_update_interval_ms: 1000 mount_points: ["", "/mnt/nvme/llogan/borg", "/mnt/ssd/llogan/borg", "/mnt/hdd/llogan/borg"] # For each device, indicate '1' if it is shared among nodes (e.g., burst # buffers), or '0' if it is per node (e.g., local NVMe). -is_shared_device: [0, 0, 0, 0] +is_shared_device: [0] # The mount point of a PFS or object store for swap space, in the event that # Hermes buffers become full. swap_mount: "./" @@ -122,9 +116,6 @@ default_rr_split: 0 # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure # that the device is always at least 30% occupied. bo_capacity_thresholds: [ - [0.0, 1.0], - [0.0, 1.0], - [0.0, 1.0], [0.0, 1.0] ] From a8bfb6a64382635dabfc73b8719dc7869d0f105a Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 7 Nov 2022 03:39:53 -0600 Subject: [PATCH 025/511] Add system() --- test/prefetch_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/prefetch_test.cc b/test/prefetch_test.cc index 089ca0a1a..0db1ae882 100644 --- a/test/prefetch_test.cc +++ b/test/prefetch_test.cc @@ -86,8 +86,8 @@ int main(int argc, char **argv) { } LOG(INFO) << "FINISHED PUTTING ALL BLOBS" << std::endl; - std::cout << clear_cache_script << std::endl; - system(clear_cache_script.c_str()); + //std::cout << clear_cache_script << std::endl; + //system(clear_cache_script.c_str()); // Get blobs (sequentially) hermes::HighResMonotonicTimer t; From c086ef3b473de486bd3f57aee7747e1c82011a35 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Tue, 29 Nov 2022 17:23:33 -0600 Subject: [PATCH 026/511] Add FindLabStor.cmake. Arena move --- CMake/FindLabStor.cmake | 43 ++ CMakeLists.txt | 7 + Testing/Temporary/CTestCostData.txt | 1 - Testing/Temporary/LastTest.log | 3 - src/api/bucket.cc | 2 +- src/api/bucket.h | 2 +- src/buffer_pool.cc | 14 +- src/buffer_pool.h | 9 +- src/buffer_pool_internal.h | 5 +- src/communication.h | 1 - src/config_parser.cc | 4 +- src/config_parser.h | 5 +- src/memory_management.cc | 623 ---------------------------- src/memory_management.h | 416 ------------------- src/metadata_management.cc | 4 +- src/metadata_management.h | 2 +- src/metadata_management_internal.h | 4 +- src/metadata_storage_stb_ds.cc | 6 +- src/rpc.h | 4 +- src/rpc_thallium.cc | 6 +- test/config_parser_test.cc | 10 +- 21 files changed, 88 insertions(+), 1083 deletions(-) create mode 100644 CMake/FindLabStor.cmake delete mode 100644 Testing/Temporary/CTestCostData.txt delete mode 100644 Testing/Temporary/LastTest.log delete mode 100644 src/memory_management.cc delete mode 100644 src/memory_management.h diff --git a/CMake/FindLabStor.cmake b/CMake/FindLabStor.cmake new file mode 100644 index 000000000..1b08efa2a --- /dev/null +++ b/CMake/FindLabStor.cmake @@ -0,0 +1,43 @@ +# Find labstor header and library. +# + +# This module defines the following uncached variables: +# LabStor_FOUND, if false, do not try to use labstor. +# LabStor_INCLUDE_DIRS, where to find labstor.h. +# LabStor_LIBRARIES, the libraries to link against to use the labstor library +# LabStor_LIBRARY_DIRS, the directory where the labstor library is found. + +find_path( + LabStor_INCLUDE_DIR + labstor/labstor.h +) + +if( LabStor_INCLUDE_DIR ) + get_filename_component(LabStor_DIR ${LabStor_INCLUDE_DIR} PATH) + + find_library( + LabStor_LIBRARY + NAMES labstor_data_structures + ) + + if( LabStor_LIBRARY ) + set(LabStor_LIBRARY_DIR "") + get_filename_component(LabStor_LIBRARY_DIRS ${LabStor_LIBRARY} PATH) + # Set uncached variables as per standard. + set(LabStor_FOUND ON) + set(LabStor_INCLUDE_DIRS ${LabStor_INCLUDE_DIR}) + set(LabStor_LIBRARIES ${LabStor_LIBRARY}) + endif(LabStor_LIBRARY) +else(LabStor_INCLUDE_DIR) + message(STATUS "Findlabstor: Could not find labstor.h") +endif(LabStor_INCLUDE_DIR) + +if(LabStor_FOUND) + if(NOT LabStor_FIND_QUIETLY) + message(STATUS "Findlabstor: Found both labstor.h and liblabstor.a") + endif(NOT LabStor_FIND_QUIETLY) +else(LabStor_FOUND) + if(LabStor_FIND_REQUIRED) + message(STATUS "Findlabstor: Could not find labstor.h and/or liblabstor.a") + endif(LabStor_FIND_REQUIRED) +endif(LabStor_FOUND) diff --git a/CMakeLists.txt b/CMakeLists.txt index 121ec0ca5..161a0b995 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,6 +285,13 @@ endif() find_path(GLOG_INCLUDE_DIRS NAME glog PATH_SUFFIXES include/) include_directories(${GLOG_INCLUDE_DIRS}) +# LabStor +find_package(LabStor REQUIRED) +if(LabStor_FOUND) + message(STATUS "found Labstor at ${LabStor_DIR}") +endif() +include_directories(${LabStor_INCLUDE_DIR}) + # GFLAGS if(HERMES_ENABLE_GFLAGS) find_package(gflags REQUIRED) diff --git a/Testing/Temporary/CTestCostData.txt b/Testing/Temporary/CTestCostData.txt deleted file mode 100644 index ed97d539c..000000000 --- a/Testing/Temporary/CTestCostData.txt +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/Testing/Temporary/LastTest.log b/Testing/Temporary/LastTest.log deleted file mode 100644 index c72e2e752..000000000 --- a/Testing/Temporary/LastTest.log +++ /dev/null @@ -1,3 +0,0 @@ -Start testing: Oct 13 05:01 CDT ----------------------------------------------------------- -End testing: Oct 13 05:01 CDT diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 377c4fc26..ea7a8c32d 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -105,7 +105,7 @@ size_t Bucket::GetBlobSize(const std::string &name, const Context &ctx) { return result; } -size_t Bucket::GetBlobSize(Arena *arena, const std::string &name, +size_t Bucket::GetBlobSize(const std::string &name, const Context &ctx) { (void)ctx; size_t result = 0; diff --git a/src/api/bucket.h b/src/api/bucket.h index a40a48410..c4ee0bc63 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -192,7 +192,7 @@ class Bucket { * \param name The name of the Blob to query. * \param ctx context */ - size_t GetBlobSize(Arena *arena, const std::string &name, const Context &ctx); + size_t GetBlobSize(const std::string &name, const Context &ctx); /** \brief Get a blob from this Bucket. * diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index e4c52e4dc..45289f52f 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -761,7 +761,7 @@ size_t GetBlobSize(SharedMemoryContext *context, RpcContext *rpc, \a rpc RpcContext, \a arena Arena, and \a blob_id BlobID. */ size_t GetBlobSizeById(SharedMemoryContext *context, RpcContext *rpc, - Arena *arena, BlobID blob_id) { + BlobID blob_id) { size_t result = 0; BufferIdArray buffer_ids = GetBufferIdsFromBlobId(arena, context, rpc, blob_id, NULL); @@ -813,7 +813,7 @@ BufferID MakeBufferId(u32 node_id, u32 header_index) { Partition RAM buffers by \a block_size for \a buffer_count buffers with \a buffer_size size in \a arena Arena. */ -void PartitionRamBuffers(Arena *arena, i32 buffer_size, i32 buffer_count, +void PartitionRamBuffers(i32 buffer_size, i32 buffer_count, int block_size) { for (int i = 0; i < buffer_count; ++i) { int num_blocks_needed = buffer_size / block_size; @@ -836,7 +836,7 @@ void PartitionRamBuffers(Arena *arena, i32 buffer_size, i32 buffer_count, /** Make \a end_index - \a start_index amount of BufferHeaders. */ -BufferID MakeBufferHeaders(Arena *arena, int buffer_size, u32 start_index, +BufferID MakeBufferHeaders(int buffer_size, u32 start_index, u32 end_index, int node_id, DeviceID device_id, ptrdiff_t initial_offset, u8 **header_begin) { BufferHeader dummy = {}; @@ -868,7 +868,7 @@ BufferID MakeBufferHeaders(Arena *arena, int buffer_size, u32 start_index, /** Initialize devices. */ -Device *InitDevices(Arena *arena, Config *config, f32 &min_bw, f32 &max_bw) { +Device *InitDevices(Config *config, f32 &min_bw, f32 &max_bw) { min_bw = FLT_MAX; max_bw = 0; @@ -909,7 +909,7 @@ Device *InitDevices(Arena *arena, Config *config, f32 &min_bw, f32 &max_bw) { } /** Initialize targets. */ -Target *InitTargets(Arena *arena, Config *config, Device *devices, +Target *InitTargets(Config *config, Device *devices, int node_id) { Target *result = PushClearedArray(arena, config->num_targets); @@ -1974,7 +1974,7 @@ api::Status PlaceBlob(SharedMemoryContext *context, RpcContext *rpc, /** Persist Bucket using stdio. */ api::Status StdIoPersistBucket(SharedMemoryContext *context, RpcContext *rpc, - Arena *arena, BucketID bucket_id, + BucketID bucket_id, const std::string &file_name, const std::string &open_mode) { api::Status result; @@ -2023,7 +2023,7 @@ api::Status StdIoPersistBucket(SharedMemoryContext *context, RpcContext *rpc, /** Persist BLOB using stdio. */ api::Status StdIoPersistBlob(SharedMemoryContext *context, RpcContext *rpc, - Arena *arena, BlobID blob_id, int fd, + BlobID blob_id, int fd, const i32 &offset) { api::Status result; diff --git a/src/buffer_pool.h b/src/buffer_pool.h index 9f7f77437..fad6d77f5 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -25,7 +25,8 @@ #include "communication.h" #include "hermes_status.h" #include "hermes_types.h" -#include "memory_management.h" + +#include /** @file buffer_pool.h * @@ -303,7 +304,7 @@ size_t GetBlobSize(SharedMemoryContext *context, RpcContext *rpc, * */ size_t GetBlobSizeById(SharedMemoryContext *context, RpcContext *rpc, - Arena *arena, BlobID blob_id); + BlobID blob_id); f32 GetBlobImportanceScore(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id); @@ -562,12 +563,12 @@ api::Status PlaceBlob(SharedMemoryContext *context, RpcContext *rpc, const api::Context &ctx, bool called_from_buffer_organizer = false); api::Status StdIoPersistBucket(SharedMemoryContext *context, RpcContext *rpc, - Arena *arena, BucketID bucket_id, + BucketID bucket_id, const std::string &file_name, const std::string &open_mode); api::Status StdIoPersistBlob(SharedMemoryContext *context, RpcContext *rpc, - Arena *arena, BlobID blob_id, int fd, + BlobID blob_id, int fd, const i32 &offset); Device *GetDeviceFromHeader(SharedMemoryContext *context, BufferHeader *header); diff --git a/src/buffer_pool_internal.h b/src/buffer_pool_internal.h index b4c54b44c..3a0df58a6 100644 --- a/src/buffer_pool_internal.h +++ b/src/buffer_pool_internal.h @@ -54,8 +54,7 @@ namespace hermes { * @return The offset of the beginning of the BufferPool from the beginning of * shared memory. */ -ptrdiff_t InitBufferPool(u8 *hermes_memory, Arena *buffer_pool_arena, - Arena *scratch_arena, i32 node_id, Config *config); +ptrdiff_t InitBufferPool(u8 *hermes_memory, i32 node_id, Config *config); /** * Obtains a pointer to the BufferPool constructed in shared memory. @@ -191,7 +190,7 @@ void SerializeBufferPoolToFile(SharedMemoryContext *context, FILE *file); /** * */ -void ParseConfig(Arena *arena, const char *path, Config *config); +void ParseConfig(const char *path, Config *config); /** * diff --git a/src/communication.h b/src/communication.h index 4c42cf203..0f00a33e3 100644 --- a/src/communication.h +++ b/src/communication.h @@ -14,7 +14,6 @@ #define HERMES_COMMUNICATION_H_ #include "hermes_types.h" -#include "memory_management.h" /** * @file communication.h diff --git a/src/config_parser.cc b/src/config_parser.cc index 3dcb341a6..70e9ad942 100644 --- a/src/config_parser.cc +++ b/src/config_parser.cc @@ -521,7 +521,7 @@ void ParseConfigYAML(YAML::Node &yaml_conf, Config *config) { /** parse YAML configuration file */ -void ParseConfig(Arena *arena, const char *path, Config *config) { +void ParseConfig(const char *path, Config *config) { ScopedTemporaryMemory scratch(arena); InitDefaultConfig(config); LOG(INFO) << "ParseConfig-LoadFile" << std::endl; @@ -534,7 +534,7 @@ void ParseConfig(Arena *arena, const char *path, Config *config) { parse configuration string */ void ParseConfigString( - Arena *arena, const std::string &config_string, Config *config) { + const std::string &config_string, Config *config) { ScopedTemporaryMemory scratch(arena); InitDefaultConfig(config); YAML::Node yaml_conf = YAML::Load(config_string); diff --git a/src/config_parser.h b/src/config_parser.h index 6335bfd3f..981fe41a8 100644 --- a/src/config_parser.h +++ b/src/config_parser.h @@ -16,12 +16,11 @@ #include #include "hermes_types.h" -#include "memory_management.h" namespace hermes { -void ParseConfig(Arena *arena, const char *path, Config *config); -void ParseConfigString(Arena *arena, const std::string &config_string, +void ParseConfig(const char *path, Config *config); +void ParseConfigString(const std::string &config_string, Config *config); void InitConfig(hermes::Config *config, const char *config_file); /** create configuration file */ diff --git a/src/memory_management.cc b/src/memory_management.cc deleted file mode 100644 index 852dc3502..000000000 --- a/src/memory_management.cc +++ /dev/null @@ -1,623 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "memory_management.h" - -#include - -/** - * @file memory_management.cc - * - * Basic Arena implementation. - */ - -namespace hermes { - -/** Check if \a val number is a power of 2 or not. - Use a bitwise operator instead of log_2(n) math function. - */ -bool IsPowerOfTwo(size_t val) { - bool result = (val & (val - 1)) == 0; - - return result; -} - -/** - align \a addr forward by \a alignment. - */ -uintptr_t AlignForward(uintptr_t addr, size_t alignment) { - assert(IsPowerOfTwo(alignment)); - - uintptr_t result = addr; - uintptr_t a = (uintptr_t)alignment; - uintptr_t remainder = addr & (a - 1); - - if (remainder != 0) { - result += a - remainder; - } - - return result; -} - -/** - align \a addr backward by \a alignment. - */ -uintptr_t AlignBackward(uintptr_t addr, size_t alignment) { - assert(IsPowerOfTwo(alignment)); - - uintptr_t result = addr; - uintptr_t a = (uintptr_t)alignment; - uintptr_t remainder = addr & (a - 1); - - if (remainder != 0) { - result -= remainder; - } - - return result; -} - -/** - initialize \a arena Arena with \a bytes capacity and \a base address - */ -void InitArena(Arena *arena, size_t bytes, u8 *base) { - arena->base = base; - arena->used = 0; - arena->capacity = bytes; - arena->temp_count = 0; -} - -/** - initialize arena by allocating \a bytes memory - */ -Arena InitArenaAndAllocate(size_t bytes) { - Arena result = {}; - result.base = (u8 *)malloc(bytes); - result.capacity = bytes; - - return result; -} - -/** - free \a arena Arena memory and reset its members to 0. - */ -void DestroyArena(Arena *arena) { - // TODO(chogan): Check for temp count? - free(arena->base); - arena->base = 0; - arena->used = 0; - arena->capacity = 0; -} - -/** - get the remaining capacity of \a arena Arena - */ -size_t GetRemainingCapacity(Arena *arena) { - size_t result = arena->capacity - arena->used; - - return result; -} - -/** - * \brief The maximum capacity of \p arena becomes \p new_size - */ -void GrowArena(Arena *arena, size_t new_size) { - if (new_size > arena->capacity) { - void *new_base = (u8 *)realloc(arena->base, new_size); - if (new_base) { - arena->base = (u8 *)new_base; - arena->capacity = new_size; - } else { - LOG(FATAL) << "realloc failed in " << __func__ << std::endl; - } - } else { - LOG(WARNING) << __func__ << ": Not growing arena. " - << "Only accepts a size greater than the current arena " - << "capacity." << std::endl; - } -} - -TemporaryMemory BeginTemporaryMemory(Arena *arena) { - TemporaryMemory result = {}; - result.arena = arena; - result.used = arena->used; - if (++arena->temp_count > 1) { - HERMES_NOT_IMPLEMENTED_YET; - } - - return result; -} - -void EndTemporaryMemory(TemporaryMemory *temp_memory) { - temp_memory->arena->used = temp_memory->used; - temp_memory->arena->temp_count--; - assert(temp_memory->arena->temp_count >= 0); -} - -u8 *PushSize(Arena *arena, size_t size, size_t alignment) { - // TODO(chogan): Account for possible size increase due to alignment - // bool can_fit = GetAlignedSize(arena, size, alignment); - bool can_fit = size + arena->used <= arena->capacity; - - if (!can_fit && arena->error_handler) { - arena->error_handler(); - } - - assert(can_fit); - - u8 *base_result = arena->base + arena->used; - u8 *result = (u8 *)AlignForward((uintptr_t)base_result, alignment); - - if (base_result != result) { - ptrdiff_t alignment_size = result - base_result; - arena->used += alignment_size; - DLOG(INFO) << "PushSize added " << alignment_size - << " bytes of padding for alignment" << std::endl; - } - arena->used += size; - - return result; -} - -u8 *PushSizeAndClear(Arena *arena, size_t size, size_t alignment) { - size_t previously_used = arena->used; - u8 *result = PushSize(arena, size, alignment); - // NOTE(chogan): Account for case when `size` is increased for alignment - size_t bytes_to_clear = arena->used - previously_used; - - if (result) { - memset(result, 0, bytes_to_clear); - } - - return result; -} - -/** - get \a heap memory address - */ -u8 *GetHeapMemory(Heap *heap) { - u8 *result = (u8 *)heap + heap->base_offset; - - return result; -} - -/** - get \a heap free block pointer - */ -FreeBlock *GetHeapFreeList(Heap *heap) { - FreeBlock *result = 0; - if (heap->free_list_offset) { - if (heap->grows_up) { - result = (FreeBlock *)(GetHeapMemory(heap) + heap->free_list_offset); - } else { - result = (FreeBlock *)(GetHeapMemory(heap) - heap->free_list_offset); - } - } - - return result; -} - -/** - get \a heap's next free block from \a block. - */ -FreeBlock *NextFreeBlock(Heap *heap, FreeBlock *block) { - FreeBlock *result = 0; - - if (block->next_offset) { - if (heap->grows_up) { - result = (FreeBlock *)(GetHeapMemory(heap) + block->next_offset); - } else { - result = (FreeBlock *)(GetHeapMemory(heap) - block->next_offset); - } - } - - return result; -} - -/** - get \a pointer to heap's memory from \a offset. - */ -u8 *HeapOffsetToPtr(Heap *heap, u32 offset) { - u8 *result = 0; - if (heap->grows_up) { - result = GetHeapMemory(heap) + offset; - } else { - result = GetHeapMemory(heap) - offset; - } - - return result; -} - -/** - get \a pointer to heap's memory from \a offset. - */ -u32 GetHeapOffset(Heap *heap, u8 *ptr) { - ptrdiff_t signed_result = (u8 *)ptr - GetHeapMemory(heap); - u32 result = (u32)std::abs(signed_result); - - return result; -} - -/** - print a fatal out-of-memory error message. - */ -void HeapErrorHandler() { - LOG(FATAL) << "Heap out of memory. Increase metadata_arena_percentage " - << "in Hermes configuration." << std::endl; -} - -/** - compute \a heap's extent - */ -u32 ComputeHeapExtent(Heap *heap, void *item, u32 size) { - u32 result = 0; - if (heap->grows_up) { - result = ((u8 *)item + size) - GetHeapMemory(heap); - } else { - result = GetHeapMemory(heap) - (u8 *)item; - } - - return result; -} - -/** - return a pointer to \a heap's extent - */ -u8 *HeapExtentToPtr(Heap *heap) { - u8 *result = 0; - BeginTicketMutex(&heap->mutex); - if (heap->grows_up) { - result = GetHeapMemory(heap) + heap->extent; - } else { - result = GetHeapMemory(heap) - heap->extent; - } - EndTicketMutex(&heap->mutex); - - return result; -} - -/** - initialize heap in \a arena with 4G capacity. - */ -Heap *InitHeapInArena(Arena *arena, bool grows_up, u16 alignment) { - Heap *result = 0; - - if (arena->capacity >= 4UL * 1024UL * 1024UL * 1024UL) { - LOG(FATAL) << "Metadata heap cannot be larger than 4GB. Decrease " - << "metadata_arena_percentage in the Hermes configuration." - << std::endl; - } - - size_t heap_size = 0; - if (grows_up) { - result = PushClearedStruct(arena); - heap_size = GetRemainingCapacity(arena); - } else { - result = (Heap *)((arena->base + arena->capacity) - sizeof(Heap)); - heap_size = GetRemainingCapacity(arena) - sizeof(Heap); - memset((void *)result, 0, sizeof(Heap)); - } - - HERMES_DEBUG_SERVER_INIT(grows_up); - - result->base_offset = grows_up ? (u8 *)(result + 1) - (u8 *)result : 0; - result->error_handler = HeapErrorHandler; - result->alignment = alignment; - // NOTE(chogan): We reserve the first `alignment` sized block as the NULL - // block, so the free list starts after that. - result->free_list_offset = alignment + (grows_up ? 0 : sizeof(FreeBlock)); - result->grows_up = grows_up; - - FreeBlock *first_free_block = GetHeapFreeList(result); - - // NOTE(chogan): offset 0 represents NULL - first_free_block->next_offset = 0; - // NOTE(chogan): Subtract alignment since we're using the first `alignment` - // sized block as the NULL block. - first_free_block->size = heap_size - alignment; - - result->extent = ComputeHeapExtent(result, first_free_block, - sizeof(*first_free_block)); - - return result; -} - -/** - get the pointer to first free block from \a heap that has \a desired_size. - */ -FreeBlock *FindFirstFit(Heap *heap, u32 desired_size) { - const u32 min_free_block_size = 8 + sizeof(FreeBlock); - FreeBlock *result = 0; - FreeBlock *prev = 0; - FreeBlock *head = GetHeapFreeList(heap); - - while (head) { - if (head->size >= desired_size) { - result = head; - u32 remaining_size = head->size - desired_size; - result->size = desired_size; - u32 next_offset = 0; - - if (remaining_size >= min_free_block_size) { - // NOTE(chogan): Split the remaining size off into a new FreeBlock - FreeBlock *split_block = 0; - if (heap->grows_up) { - split_block = (FreeBlock *)((u8 *)result + desired_size); - } else { - split_block = (FreeBlock *)((u8 *)result - desired_size); - } - split_block->size = remaining_size; - split_block->next_offset = result->next_offset; - u32 split_block_offset = GetHeapOffset(heap, (u8 *)split_block); - next_offset = split_block_offset; - } else { - next_offset = result->next_offset; - result->size += remaining_size; - } - - if (prev) { - prev->next_offset = next_offset; - } else { - heap->free_list_offset = next_offset; - } - - break; - } - prev = head; - head = NextFreeBlock(heap, head); - } - - if (!result && heap->error_handler) { - heap->error_handler(); - } - - return result; -} - -#if 0 -FreeBlock *FindBestFit(FreeBlock *head, size_t desired_size, - u32 threshold = 0) { - FreeBlock *result = 0; - FreeBlock *prev = head; - FreeBlock *smallest_prev = head; - u32 smallest_wasted = 0xFFFFFFFF; - - while (head && smallest_wasted > threshold) { - if (head->size >= desired_size) { - u32 wasted_space = head->size - desired_size; - if (wasted_space < smallest_wasted) { - smallest_wasted = wasted_space; - result = head; - smallest_prev = prev; - } - } - prev = head; - head = head->next; - } - - if (result) { - smallest_prev->next = result->next; - } - - return result; -} -#endif - -u8 *HeapPushSize(Heap *heap, u32 size) { - u8 *result = 0; - - HERMES_DEBUG_CLIENT_INIT(); - - if (size) { - BeginTicketMutex(&heap->mutex); - // TODO(chogan): Respect heap->alignment - FreeBlock *first_fit = FindFirstFit(heap, size + sizeof(FreeBlockHeader)); - - if (first_fit) { - u32 actual_size = first_fit->size - sizeof(FreeBlockHeader); - FreeBlockHeader *header = 0; - if (heap->grows_up) { - header = (FreeBlockHeader *)first_fit; - } else { - header = (FreeBlockHeader *)((u8 *)first_fit - actual_size); - } - header->size = actual_size; - result = (u8 *)(header + 1); - - HERMES_DEBUG_TRACK_ALLOCATION(header, - header->size + sizeof(FreeBlockHeader), - heap->grows_up); - - u32 extent_adjustment = heap->grows_up ? 0 : sizeof(FreeBlock); - - u32 this_extent = - ComputeHeapExtent(heap, header, header->size + sizeof(FreeBlockHeader)); - heap->extent = std::max(heap->extent, this_extent); - if (heap->extent == heap->free_list_offset - extent_adjustment) { - heap->extent += sizeof(FreeBlock); - } - EndTicketMutex(&heap->mutex); - } else { - EndTicketMutex(&heap->mutex); - heap->error_handler(); - } - } - - return result; -} - -/** - free heap -*/ -void HeapFree(Heap *heap, void *ptr) { - if (heap && ptr) { - BeginTicketMutex(&heap->mutex); - FreeBlockHeader *header = (FreeBlockHeader *)ptr - 1; - u32 size = header->size; - FreeBlock *new_block = 0; - if (heap->grows_up) { - new_block = (FreeBlock *)header; - } else { - new_block = - (FreeBlock *)((u8 *)(header + 1) + header->size - sizeof(FreeBlock)); - } - - memset(ptr, 0, size); - new_block->size = size + sizeof(FreeBlockHeader); - - HERMES_DEBUG_TRACK_FREE(header, new_block->size, heap->grows_up); - - u32 extent = ComputeHeapExtent(heap, ptr, size); - if (extent == heap->extent) { - assert(new_block->size < heap->extent); - heap->extent -= new_block->size; - } - - new_block->next_offset = heap->free_list_offset; - heap->free_list_offset = GetHeapOffset(heap, (u8 *)new_block); - EndTicketMutex(&heap->mutex); - } -} - -/** - reallocate heap -*/ -void *HeapRealloc(Heap *heap, void *ptr, size_t size) { - if (ptr) { - // NOTE(chogan): We only support malloc behavior for now. The stb_ds.h hash - // map uses STBDS_REALLOC for its malloc style allocations. We just give the - // initial map a large enough size so that it never needs to realloc. - - HERMES_NOT_IMPLEMENTED_YET; - } - - void *result = HeapPushSize(heap, size); - - return result; -} - - -/** coalesce free blocks from \a heap */ -void CoalesceFreeBlocks(Heap *heap) { - (void)heap; - // TODO(chogan): This will run as a deferred coalesce. How often? - // Test case: Lots of blocks are free but none of the pointers are adjacent - // X: A used block - // n: A link to free block with index n - // /: End of the free list - - // 0 1 2 3 4 5 6 7 8 - // |2|/|4|1|6|3|8|X|5| -} - -/** - acquire ticket from \a existing_ticket or new one from \a mutex -*/ -Ticket TryBeginTicketMutex(TicketMutex *mutex, Ticket *existing_ticket) { - Ticket result = {}; - result.ticket = - existing_ticket ? existing_ticket->ticket : mutex->ticket.fetch_add(1); - - if (result.ticket == mutex->serving.load()) { - result.acquired = true; - } - - return result; -} - -/** - begin ticket mutex - */ -void BeginTicketMutex(TicketMutex *mutex) { - u32 ticket = mutex->ticket.fetch_add(1); - while (ticket != mutex->serving.load()) { - // TODO(chogan): @optimization This seems to be necessary if we expect - // oversubscription. As soon as we have more MPI ranks than logical - // cores, the performance of the ticket mutex drops dramatically. We - // lose about 8% when yielding and not oversubscribed, but without - // yielding, it is unusable when oversubscribed. I want to implement a - // ticket mutex with a waiting array at some point: - // https://arxiv.org/pdf/1810.01573.pdf. It looks like that should give - // us the best of both worlds. - sched_yield(); - } -} - -/** - end ticket mutex - */ -void EndTicketMutex(TicketMutex *mutex) { - mutex->serving.fetch_add(1); -} - -/** A constant value for maximum attempts for ticket lock */ -const int kAttemptsBeforeYield = 100; - -/** - begin reader lock by incrementing \a lock's readers. - */ -bool BeginReaderLock(RwLock *lock) { - bool result = false; - if (!lock->writer_waiting.load()) { - lock->readers++; - result = true; - } - - return result; -} - -/** - end reader lock - */ -void EndReaderLock(RwLock *lock) { - u32 readers = lock->readers.load(); - - int retry = 0; - while (true) { - if (readers > 0) { - if (lock->readers.compare_exchange_weak(readers, readers - 1)) { - break; - } - } - retry++; - if (retry > kAttemptsBeforeYield) { - retry = 0; - sched_yield(); - } - } -} - -/** - begin writer lock - */ -void BeginWriterLock(RwLock *lock) { - lock->writer_waiting.store(true); - - int retry = 0; - while (lock->readers.load() > 0) { - retry++; - if (retry > kAttemptsBeforeYield) { - retry = 0; - sched_yield(); - } - } - BeginTicketMutex(&lock->mutex); -} - -/** - end writer lock - */ -void EndWriterLock(RwLock *lock) { - EndTicketMutex(&lock->mutex); - lock->writer_waiting.store(false); -} - -} // namespace hermes diff --git a/src/memory_management.h b/src/memory_management.h deleted file mode 100644 index 2f41369e7..000000000 --- a/src/memory_management.h +++ /dev/null @@ -1,416 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_MEMORY_MANAGEMENT_H_ -#define HERMES_MEMORY_MANAGEMENT_H_ - -#include - -#include - -#include "hermes_types.h" - -/** - * @file memory_management.h - * - * Structures for memory management. - */ - -namespace hermes { - -typedef void(ArenaErrorFunc)(); /**< Arena error function */ - -/** - * Implements a ticket lock as described at - * https://en.wikipedia.org/wiki/Ticket_lock. - */ -struct TicketMutex { - std::atomic ticket; /**< ticket number */ - std::atomic serving; /**< ticket number being served */ -}; - -/** - A structure to represent ticket -*/ -struct Ticket { - u32 ticket; /**< ticket number */ - bool acquired; /**< is ticket acquired? */ - Ticket() : ticket(-1), acquired(false) {} /**< constructor */ -}; - -/** - A structure to represent read-write lock -*/ -struct RwLock { - TicketMutex mutex; /**< mutex is a lock for shared resource. */ - std::atomic readers; /**< number of readers */ - std::atomic writer_waiting; /**< is writer waiting for the lock? */ -}; - -/** - A structure to represent arena information -*/ -struct ArenaInfo { - size_t sizes[kArenaType_Count]; /**< array of sizes for each arena type */ - size_t total; /**< total number of arena */ -}; - -/** - * A block of memory that can be divided up dynamically. - * - * An Arena must be initialized from a contiguous block of allocated memory. - * After it's initialized, you can use it like `new` via the PushStruct and - * PushArray calls. Note that this Arena is designed to persist for the - * application lifetime, so we don't have a need to free anything out of it. - * - * Example: - * ```cpp - * size_t arena_size = 4 * 1024; - * void *block_base = malloc(arena_size); - * Arena arena = {}; - * InitArena(&arena, arena_size, block_base); - * MyStruct *s = PushStruct(&arena); - * ``` - */ -struct Arena { - /** The beginning of the memory block tracked by this Arena */ - u8 *base; - /** Number of bytes currently in use */ - size_t used; - /** Total number of bytes in the block tracked by this Arena */ - size_t capacity; - /** Per-arena error handling function */ - ArenaErrorFunc *error_handler; - /** The number of ScopedTemporaryMemory instances that are using this Arena */ - i32 temp_count; -}; - -/** - A structure to represent heap -*/ -struct Heap { - /** Function called when this Heap encounters and error */ - ArenaErrorFunc *error_handler; - /** Mutex for multi-threaded access to this Heap's members */ - TicketMutex mutex; - /** Offset of the beginning of this heap's memory, relative to the Heap */ - u32 base_offset; - /** Offset of the head of the free list, relative to base_offset */ - u32 free_list_offset; - /** The highest (if Heap::grows_up == 1) or lowest (if Heap::grows_up == 0) - * used memory address of this Heap, stored as an offset from - * Heap::base_offset. This value is used to make sure two heaps growing in - * opposite directions don't overlap each other. */ - u32 extent; - /** Every allocation from this Heap will result in an address aligned to this - * value */ - u16 alignment; - /** 1 if allocating new memory returns higher memory addresses, else 0 */ - bool grows_up; -}; - -/** - A structure to represent free block header -*/ -struct FreeBlockHeader { - size_t size; /**< size of free block header */ -}; - -/** - A structure to represent free block -*/ -struct FreeBlock { - /** The offset of the next FreeBlock in the list. Offset 0 represents NULL. */ - u32 next_offset; - /** The size of the next FreeBlock in the list */ - u32 size; -}; - -/** - A structure to represent a temporary memory -*/ -struct TemporaryMemory { - Arena *arena; /**< pointer to arena */ - size_t used; /**< temporary memory used */ -}; - -/** - * A block of memory that can be used dynamically, but is deleted when exiting - * the current scope. - * - * ScopedTemporaryMemory wraps an existing Arena. You can pass an instance of it - * as you would normally pass an Arena instance to PushSize and PushArray. The - * difference is that the memory is reclaimed once the scope in which - * ScopedTemporaryMemory is declared is exited. Note that there is no actual - * `free` happening. Rather, the existing Arena's `used` parameter is reset to - * where it was before the ScopedTemporaryMemory was created. - * - * Example: - * ```cpp - * { - * ScopedTemporaryMemory temp_memory(existing_arena_ptr); - * MyStruct *scoped_array = PushArray(temp_memory, num_elements); - * for (int i = 0; i < num_elements; ++i) { - * // ... - * } - * } // scoped_array memory is reclaimed here - * ``` - */ -struct ScopedTemporaryMemory { - /** An existing, backing Arena */ - Arena *arena; - /** The stored number of bytes in use by the backing Arena */ - size_t used; - - ScopedTemporaryMemory() = delete; - ScopedTemporaryMemory(const ScopedTemporaryMemory &) = delete; - ScopedTemporaryMemory &operator=(const ScopedTemporaryMemory &) = delete; - - /** - * Creates a ScopedTemporaryMemory from an existing, backing Arena. - * - * @param backing_arena The existing Arena backing the temporary memory. - */ - explicit ScopedTemporaryMemory(Arena *backing_arena) - : arena(backing_arena), used(backing_arena->used) { - // TODO(chogan): Currently not threadsafe unless each thread has a different - // `backing_arena` - if (++backing_arena->temp_count > 1) { - HERMES_NOT_IMPLEMENTED_YET; - } - } - - /** - * Destructor. Restores the backing Arena's bytes in use to the saved `used` - * value, effectively reclaiming the memory that was used in this scope. - */ - ~ScopedTemporaryMemory() { - assert(arena->used >= used); - arena->used = used; - assert(arena->temp_count > 0); - arena->temp_count--; - } - - /** - * Allows passing a ScopedTemporaryMemory to functions that take an Arena - * without an explicit cast. - */ - operator Arena *() { return arena; } -}; - -/** - return a temporary memory that points to \a arena Arena - */ -TemporaryMemory BeginTemporaryMemory(Arena *arena); - -/** - copy \a temp_memory usage information back to its arena. - */ -void EndTemporaryMemory(TemporaryMemory *temp_memory); - -/** - * Initializes an Arena with a starting size and base pointer. The @p base - * parameter must point to a contiguous region of allocated memory of at least - * @p bytes bytes. - * - * @param[in,out] arena The Arena to initialize. - * @param[in] bytes The desired size in bytes of the Arena's backing memory. - * @param[in] base A pointer to the beginning of the Arena's backing memory. - */ -void InitArena(Arena *arena, size_t bytes, u8 *base); - -/** - * Initializes an Arena with a starting size. This function uses malloc to - * allocate a contiguous region of length @p bytes for the arena. - * - * @param[in] bytes The desired size in bytes to allocate. - * - * @return An arena with capacity @p bytes. - */ -Arena InitArenaAndAllocate(size_t bytes); - -/** - * Frees the memory backing the Arena, and zeros out all its fields. - * - * Only Arenas whose backing memory was created by malloc should be destroyed - * with this function. Arenas using shared memory as the backing store should - * not be destroyed. The backing memory is reclaimed when the shared memory is - * unlinked. - * - * @param[in,out] arena The Arena to destroy. - */ -void DestroyArena(Arena *arena); - -/** - * Returns the amount of free space left in an Arena. - * - * @param[in] arena The Arena to query. - * - * @return The number of free bytes remaining - */ -size_t GetRemainingCapacity(Arena *arena); - -/** - * Expands the backing memory for an arena to be `new_size` bytes. - * - * Becuase this function uses `realloc`, it will only work for Arenas whose - * backing store was created with malloc. It cannot be used with Arenas whose - * backing store is shared memory (e.g., the BufferPool arena). - * - * @param arena The arena to expand. - * @param new_size The new (larger) size that the Arena should occupy. - */ -void GrowArena(Arena *arena, size_t new_size); - -/** - * Returns a pointer to a raw region of @p size bytes. - * - * This is the lower level Arena allocation function. The higher level - * PushStruct and PushArray should be used by clients. - * - * @param[in,out] arena The Arena to allocate from. - * @param[in] size The requested memory size in bytes. - * @param[in] alignment Align the result to a desired multiple. - * - * @return A pointer to the beginning of a contiguous region of @p size bytes. - */ -u8 *PushSize(Arena *arena, size_t size, size_t alignment = 8); - -/** - * Returns a pointer to a raw region of bytes that are cleared to zero. - * - * Like PushSize, but clears the requested region to zero. - * - * @param[in,out] arena The Arena to allocate from. - * @param[in] size The requested memory size in bytes. - * @param[in] alignment Align the result to a desired multiple. - * - * @return A pointer to the beginning of a contiguous region of @p size zeros. - */ -u8 *PushSizeAndClear(Arena *arena, size_t size, size_t alignment = 8); - -/** - * Reserves space for and returns a pointer to a T instance. - * - * Note that the T instance will be uninitialized. The caller is responsible for - * any initialization. - * - * @param[in,out] arena The backing Arena from which to reserve space. - * @param[in] alignment Align the result to a desired multiple. - * - * @return A pointer to an uninitialized `T` instance. - */ -template -inline T *PushStruct(Arena *arena, size_t alignment = 8) { - T *result = reinterpret_cast(PushSize(arena, sizeof(T), alignment)); - - return result; -} - -/** - * Reserves space for, clears to zero, and returns a pointer to a T instance. - * - * Like PushStruct, but all the object's members are initialized to zero. - * Note: assumes 0/NULL is a valid value for all the object's members. - * - * @param[in,out] arena The backing Arena from which to reserve space. - * @param[in] alignment Align the result to a desired multiple. - * - * @return A pointer to a `T` instance with all members initialized to zero. - */ -template -inline T *PushClearedStruct(Arena *arena, size_t alignment = 8) { - T *result = - reinterpret_cast(PushSizeAndClear(arena, sizeof(T), alignment)); - - return result; -} - -/** - * Reserves space for @p count `T` objects and returns a pointer to the first - * one. - * - * The objects will be uninitialized. - * - * @param[in,out] arena The backing Arena from which to reserve space. - * @param[in] count The number of objects to allocate. - * @param[in] alignment Align the result to a desired multiple. - * - * @return A pointer to the first `T` instance in the uninitialized array. - */ -template -inline T *PushArray(Arena *arena, int count, size_t alignment = 8) { - T *result = - reinterpret_cast(PushSize(arena, sizeof(T) * count, alignment)); - - return result; -} - -/** - * Reserves space for @p count `T` objects, clears them to zero, and returns a - * pointer to the first one. - * - * @param[in,out] arena The backing Arena from which to reserve space. - * @param[in] count The number of objects to allocate. - * @param[in] alignment Align the result to a desired multiple. - * - * @return A pointer to the first `T` instance in the array. - */ -template -inline T *PushClearedArray(Arena *arena, int count, size_t alignment = 8) { - T *result = reinterpret_cast( - PushSizeAndClear(arena, sizeof(T) * count, alignment)); - - return result; -} -u8 *HeapPushSize(Heap *heap, u32 size); /**< push \a size to \a heap */ - -/** - A template for pushing structure to \a heap. -*/ -template -inline T *HeapPushStruct(Heap *heap) { - T *result = reinterpret_cast(HeapPushSize(heap, sizeof(T))); - - return result; -} - -/** - A template for pushing array of \a count size to \a heap. -*/ -template -inline T *HeapPushArray(Heap *heap, u32 count) { - T *result = reinterpret_cast(HeapPushSize(heap, count * sizeof(T))); - - return result; -} - -Heap *InitHeapInArena(Arena *arena, bool grows_up = true, u16 alignment = 8); -void HeapFree(Heap *heap, void *ptr); -void *HeapRealloc(Heap *heap, void *ptr, size_t size); -u32 GetHeapOffset(Heap *heap, u8 *ptr); -FreeBlock *NextFreeBlock(Heap *heap, FreeBlock *block); -FreeBlock *GetHeapFreeList(Heap *heap); -u8 *HeapOffsetToPtr(Heap *heap, u32 offset); -u8 *HeapExtentToPtr(Heap *heap); - -void BeginTicketMutex(TicketMutex *mutex); -void EndTicketMutex(TicketMutex *mutex); - -bool BeginReaderLock(RwLock *lock); -void EndReaderLock(RwLock *lock); -void BeginWriterLock(RwLock *lock); -void EndWriterLock(RwLock *lock); - -} // namespace hermes - -#endif // HERMES_MEMORY_MANAGEMENT_H_ diff --git a/src/metadata_management.cc b/src/metadata_management.cc index fb62c7d46..f26d81059 100644 --- a/src/metadata_management.cc +++ b/src/metadata_management.cc @@ -656,7 +656,7 @@ bool BlobIsInSwap(BlobID id) { } /** get buffer ID list */ -void GetBufferIdList(Arena *arena, SharedMemoryContext *context, +void GetBufferIdList(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id, BufferIdArray *buffer_ids) { MetadataManager *mdm = GetMetadataManagerFromContext(context); @@ -1185,7 +1185,7 @@ static ptrdiff_t GetOffsetFromMdm(MetadataManager *mdm, void *ptr) { } /** create system view state */ -SystemViewState *CreateSystemViewState(Arena *arena, Config *config) { +SystemViewState *CreateSystemViewState(Config *config) { SystemViewState *result = PushClearedStruct(arena); result->num_devices = config->num_devices; for (int i = 0; i < result->num_devices; ++i) { diff --git a/src/metadata_management.h b/src/metadata_management.h index 82bf738ca..61510bc5a 100644 --- a/src/metadata_management.h +++ b/src/metadata_management.h @@ -318,7 +318,7 @@ bool ContainsBlob(SharedMemoryContext *context, RpcContext *rpc, /** * */ -BufferIdArray GetBufferIdsFromBlobId(Arena *arena, SharedMemoryContext *context, +BufferIdArray GetBufferIdsFromBlobId(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id, u32 **sizes); diff --git a/src/metadata_management_internal.h b/src/metadata_management_internal.h index aa8a68d92..5387cb39a 100644 --- a/src/metadata_management_internal.h +++ b/src/metadata_management_internal.h @@ -42,7 +42,7 @@ void LocalAddBlobIdToVBucket(MetadataManager *mdm, VBucketID vbucket_id, BlobID blob_id); std::vector LocalGetBufferIdList(MetadataManager *mdm, BlobID blob_id); -void LocalGetBufferIdList(Arena *arena, MetadataManager *mdm, BlobID blob_id, +void LocalGetBufferIdList(MetadataManager *mdm, BlobID blob_id, BufferIdArray *buffer_ids); void LocalFreeBufferIdList(SharedMemoryContext *context, BlobID blob_id); bool LocalDestroyBucket(SharedMemoryContext *context, RpcContext *rpc, @@ -88,7 +88,7 @@ void StartGlobalSystemViewStateUpdateThread(SharedMemoryContext *context, double sleep_ms); void InitMetadataStorage(SharedMemoryContext *context, MetadataManager *mdm, - Arena *arena, Config *config); + Config *config); std::string GetSwapFilename(MetadataManager *mdm, u32 node_id); std::vector LocalGetBlobIds(SharedMemoryContext *context, diff --git a/src/metadata_storage_stb_ds.cc b/src/metadata_storage_stb_ds.cc index 947abfe32..8810697fe 100644 --- a/src/metadata_storage_stb_ds.cc +++ b/src/metadata_storage_stb_ds.cc @@ -601,7 +601,7 @@ std::vector LocalGetBufferIdList(MetadataManager *mdm, } /** get buffer ID list into \a buffer_ids locally */ -void LocalGetBufferIdList(Arena *arena, MetadataManager *mdm, BlobID blob_id, +void LocalGetBufferIdList(MetadataManager *mdm, BlobID blob_id, BufferIdArray *buffer_ids) { size_t length = 0; BufferID *ids = GetBufferIdsPtrFromBlobId(mdm, blob_id, length); @@ -925,7 +925,7 @@ void SeedHashForStorage(size_t seed) { } /** initialize swap space file name */ -void InitSwapSpaceFilename(MetadataManager *mdm, Arena *arena, Config *config) { +void InitSwapSpaceFilename(MetadataManager *mdm, Config *config) { std::string swap_filename_prefix("swap"); size_t swap_mount_length = config->swap_mount.size(); bool ends_in_slash = config->swap_mount[swap_mount_length - 1] == '/'; @@ -966,7 +966,7 @@ void InitNeighborhoodTargets(SharedMemoryContext *context, RpcContext *rpc) { /** initialize metadata storage */ void InitMetadataStorage(SharedMemoryContext *context, MetadataManager *mdm, - Arena *arena, Config *config) { + Config *config) { InitSwapSpaceFilename(mdm, arena, config); // Heaps diff --git a/src/rpc.h b/src/rpc.h index 679bdfcfa..0c3ca3bb1 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -77,10 +77,10 @@ std::string GetServerName(RpcContext *rpc, u32 node_id, bool is_buffer_organizer = false); std::string GetProtocol(RpcContext *rpc); void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, - Arena *arena, const char *addr, int num_threads, + const char *addr, int num_threads, int port); void StartPrefetcher(SharedMemoryContext *context, - RpcContext *rpc, Arena *arena, double sleep_ms); + RpcContext *rpc, double sleep_ms); } // namespace hermes // TODO(chogan): I don't like that code similar to this is in buffer_pool.cc. diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 03a46ea79..a0b7ddf20 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -36,7 +36,7 @@ void CopyStringToCharArray(const std::string &src, char *dest, size_t max) { /** start Thallium RPC server */ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, - Arena *arena, const char *addr, + const char *addr, i32 num_rpc_threads) { ThalliumState *state = GetThalliumState(rpc); state->engine = new tl::engine(addr, THALLIUM_SERVER_MODE, true, @@ -504,7 +504,7 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, /** start buffer organizer */ void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, - Arena *arena, const char *addr, int num_threads, + const char *addr, int num_threads, int port) { context->bo = PushStruct(arena); new(context->bo) BufferOrganizer(num_threads); @@ -604,7 +604,7 @@ void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, /** start prefetcher */ void StartPrefetcher(SharedMemoryContext *context, - RpcContext *rpc, Arena *arena, double sleep_ms) { + RpcContext *rpc, double sleep_ms) { ThalliumState *state = GetThalliumState(rpc); tl::engine *rpc_server = state->engine; using tl::request; diff --git a/test/config_parser_test.cc b/test/config_parser_test.cc index 633dfa7e3..eb0e45fba 100644 --- a/test/config_parser_test.cc +++ b/test/config_parser_test.cc @@ -28,13 +28,13 @@ using hermes::Config; namespace hermes { namespace testing { -Config ParseConfigStringTest(Arena *arena, const std::string &config_string) { +Config ParseConfigStringTest(const std::string &config_string) { Config config = {}; ParseConfigString(arena, config_string, &config); return config; } -void RunHostNumbersTest(Arena *arena, const std::string &config_string, +void RunHostNumbersTest(const std::string &config_string, const std::vector &expected) { Config config = ParseConfigStringTest(arena, config_string); Assert(config.host_names == expected); @@ -81,7 +81,7 @@ void TestParseRangeList(Arena *arena) { } } -void RunCapacityValuesTest(Arena *arena, const std::string &config_string, +void RunCapacityValuesTest(const std::string &config_string, const std::vector &expected) { Config config = ParseConfigStringTest(arena, config_string); Assert((size_t)config.num_devices == expected.size()); @@ -140,7 +140,7 @@ void TestCapacityValues(Arena *arena) { } } -void RunBlockSizesTest(Arena *arena, const std::string &config_string, +void RunBlockSizesTest(const std::string &config_string, const std::vector &expected) { Config config = ParseConfigStringTest(arena, config_string); Assert((size_t)config.num_devices == expected.size()); @@ -177,7 +177,7 @@ void TestBlockSizes(Arena *arena) { } } -void TestDefaultConfig(Arena *arena, const char *config_file) { +void TestDefaultConfig(const char *config_file) { hermes::Config config = {}; hermes::ParseConfig(arena, config_file, &config); From 83d6b4766e677030aa9225adcbbaeda4cd833858 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Tue, 29 Nov 2022 21:20:22 -0600 Subject: [PATCH 027/511] Remove most of Arenas. Rename some TicketMutexes. Remove debug_state.h/cc --- src/buffer_organizer.cc | 12 +- src/buffer_pool.cc | 17 ++- src/buffer_pool.h | 2 +- src/buffer_pool_internal.h | 1 - .../buffer_pool_visualizer.cc | 43 ++---- src/communication.h | 2 +- src/communication_mpi.cc | 1 - src/debug_state.cc | 108 ---------------- src/debug_state.h | 48 ------- src/metadata_management.cc | 122 +++++------------- src/metadata_management.h | 4 +- src/metadata_management_internal.h | 5 +- src/metadata_storage_stb_ds.cc | 109 +++++++--------- src/rpc.h | 11 +- test/config_parser_test.cc | 62 ++++----- test/memory_test.cc | 1 - test/stb_map_test.cc | 1 - 17 files changed, 146 insertions(+), 403 deletions(-) delete mode 100644 src/debug_state.cc delete mode 100644 src/debug_state.h diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 760f5804b..9e6ebb112 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -483,10 +483,10 @@ void LocalEnforceCapacityThresholds(SharedMemoryContext *context, }; Target *src_target = GetTargetFromId(context, src_target_id); - BeginTicketMutex(&src_target->effective_blobs_lock); + src_target->effective_blobs_lock.Lock(); std::vector blob_ids = GetChunkedIdList(mdm, src_target->effective_blobs); - EndTicketMutex(&src_target->effective_blobs_lock); + src_target->effective_blobs_lock.Unlock(); auto compare_importance = [context](const u64 lhs, const u64 rhs) { BlobID lhs_blob_id = {}; @@ -576,10 +576,10 @@ void LocalEnforceCapacityThresholds(SharedMemoryContext *context, f32 min_importance = FLT_MAX; BlobID least_important_blob = {}; - BeginTicketMutex(&target->effective_blobs_lock); + target->effective_blobs_lock.Lock(); std::vector blob_ids = GetChunkedIdList(mdm, target->effective_blobs); - EndTicketMutex(&target->effective_blobs_lock); + target->effective_blobs_lock.Unlock(); // Find least important blob in violated Target for (size_t i = 0; i < blob_ids.size(); ++i) { @@ -790,7 +790,7 @@ void LocalAdjustFlushCount(SharedMemoryContext *context, const std::string &vbkt_name, int adjustment) { MetadataManager *mdm = GetMetadataManagerFromContext(context); VBucketID id = LocalGetVBucketId(context, vbkt_name.c_str()); - BeginTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Lock(); VBucketInfo *info = LocalGetVBucketInfoById(mdm, id); if (info) { int flush_count = info->async_flush_count.fetch_add(adjustment); @@ -798,7 +798,7 @@ void LocalAdjustFlushCount(SharedMemoryContext *context, << (adjustment > 0 ? "incremented" : "decremented") << " to " << flush_count + adjustment << "\n"; } - EndTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Unlock(); } void LocalIncrementFlushCount(SharedMemoryContext *context, diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 45289f52f..bf497c4aa 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -40,7 +40,6 @@ #include "rpc.h" #include "debug_state.cc" -#include "memory_management.cc" #include "config_parser.cc" #include "utils.cc" #include "traits.cc" @@ -579,7 +578,7 @@ void LocalReleaseBuffer(SharedMemoryContext *context, BufferID buffer_id) { BufferHeader *header_to_free = GetHeaderByIndex(context, buffer_id.bits.header_index); if (header_to_free) { - BeginTicketMutex(&pool->ticket_mutex); + pool->ticket_mutex.Lock(); header_to_free->used = 0; header_to_free->in_use = false; int slab_index = GetSlabIndexFromHeader(context, header_to_free); @@ -592,7 +591,7 @@ void LocalReleaseBuffer(SharedMemoryContext *context, BufferID buffer_id) { i64 capacity_adjustment = header_to_free->capacity; UpdateBufferingCapacities(context, capacity_adjustment, device_id); - EndTicketMutex(&pool->ticket_mutex); + pool->ticket_mutex.Unlock(); } } @@ -640,7 +639,7 @@ BufferID GetFreeBuffer(SharedMemoryContext *context, DeviceID device_id, BufferPool *pool = GetBufferPoolFromContext(context); BufferID result = {}; - BeginTicketMutex(&pool->ticket_mutex); + pool->ticket_mutex.Lock(); BufferID id = PeekFirstFreeBufferId(context, device_id, slab_index); if (!IsNullBufferId(id)) { u32 header_index = id.bits.header_index; @@ -653,7 +652,7 @@ BufferID GetFreeBuffer(SharedMemoryContext *context, DeviceID device_id, i64 capacity_adjustment = -(i64)header->capacity; UpdateBufferingCapacities(context, capacity_adjustment, device_id); } - EndTicketMutex(&pool->ticket_mutex); + pool->ticket_mutex.Unlock(); return result; } @@ -962,7 +961,7 @@ void MergeRamBufferFreeList(SharedMemoryContext *context, int slab_index) { int new_slab_size_in_bytes = bigger_slab_unit_size * pool->block_sizes[0]; int old_slab_size_in_bytes = this_slab_unit_size * pool->block_sizes[0]; - BeginTicketMutex(&pool->ticket_mutex); + pool->ticket_mutex.Lock(); // TODO(chogan): Assuming first Device is RAM DeviceID device_id = 0; BufferID id = PeekFirstFreeBufferId(context, device_id, slab_index); @@ -1069,7 +1068,7 @@ void MergeRamBufferFreeList(SharedMemoryContext *context, int slab_index) { id = header_to_merge->next_free; } } - EndTicketMutex(&pool->ticket_mutex); + pool->ticket_mutex.Unlock(); } /** Split RAM buffer free list. @@ -1099,7 +1098,7 @@ void SplitRamBufferFreeList(SharedMemoryContext *context, int slab_index) { // TODO(chogan): @optimization We don't really want to wait for a long queue // on the ticket mutex. If we need to split, we want to stop the world and do // it immediately. - BeginTicketMutex(&pool->ticket_mutex); + pool->ticket_mutex.Lock(); // TODO(chogan): Assuming first Device is RAM DeviceID device_id = 0; BufferID id = PeekFirstFreeBufferId(context, device_id, slab_index); @@ -1146,7 +1145,7 @@ void SplitRamBufferFreeList(SharedMemoryContext *context, int slab_index) { old_data_offset += new_slab_size_in_bytes; } } - EndTicketMutex(&pool->ticket_mutex); + pool->ticket_mutex.Unlock(); } /** diff --git a/src/buffer_pool.h b/src/buffer_pool.h index fad6d77f5..618ef55f8 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -80,7 +80,7 @@ struct Target { std::atomic remaining_space; /**< remaining space */ std::atomic speed; /**< speed */ ChunkedIdList effective_blobs; /**< ID list of BLOBs */ - TicketMutex effective_blobs_lock; /**< ticket lock for BLOBs */ + labstor::Mutex effective_blobs_lock; /**< ticket lock for BLOBs */ }; /** diff --git a/src/buffer_pool_internal.h b/src/buffer_pool_internal.h index 3a0df58a6..1955b7841 100644 --- a/src/buffer_pool_internal.h +++ b/src/buffer_pool_internal.h @@ -14,7 +14,6 @@ #define HERMES_BUFFER_POOL_INTERNAL_H_ #include "buffer_pool.h" -#include "memory_management.h" /** * @file buffer_pool_internal.h diff --git a/src/buffer_pool_visualizer/buffer_pool_visualizer.cc b/src/buffer_pool_visualizer/buffer_pool_visualizer.cc index ee7d70785..4133d2794 100644 --- a/src/buffer_pool_visualizer/buffer_pool_visualizer.cc +++ b/src/buffer_pool_visualizer/buffer_pool_visualizer.cc @@ -742,7 +742,7 @@ static SDL_Rect OffsetToRect(HeapMetadata *hmd, Heap *heap, u32 offset, static void DrawAllocatedHeapBlocks(DebugState *state, HeapMetadata *hmd, Heap *heap, SDL_Surface *surface) { global_color_counter = 0; - BeginTicketMutex(&state->mutex); + state->mutex.Lock();; for (u32 i = 0; i < state->allocation_count; ++i) { DebugHeapAllocation *allocation = &state->allocations[i]; SDL_Rect rect = OffsetToRect(hmd, heap, allocation->offset, @@ -758,7 +758,7 @@ static void DrawAllocatedHeapBlocks(DebugState *state, HeapMetadata *hmd, u32 color = global_id_colors[global_color_counter]; DrawWrappingRect(&rect, hmd->screen_width, 0, surface, color); } - EndTicketMutex(&state->mutex); + state->mutex.Unlock();; } static void DrawHeapExtent(HeapMetadata *hmd, Heap *heap, int w, @@ -780,7 +780,7 @@ static void DrawHeapExtent(HeapMetadata *hmd, Heap *heap, int w, static void DrawFreeHeapBlocks(HeapMetadata *hmd, Heap *heap, SDL_Surface *surface) { - BeginTicketMutex(&heap->mutex); + heap->mutex.Lock(); u32 offset = heap->free_list_offset; FreeBlock *head = GetHeapFreeList(heap); while (head) { @@ -793,7 +793,7 @@ static void DrawFreeHeapBlocks(HeapMetadata *hmd, Heap *heap, offset = head->next_offset; head = NextFreeBlock(heap, head); } - EndTicketMutex(&heap->mutex); + heap->mutex.Unlock(); } #if DRAW_BUCKETS @@ -804,10 +804,10 @@ static int DrawBucketsAndVBuckets(MetadataManager *mdm, SDL_Surface *surface, // BucketInfo for (size_t i = 0; i < mdm->max_buckets; ++i) { - BeginTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Lock(); BucketInfo *info = LocalGetBucketInfoByIndex(mdm, i); bool active = info->active; - EndTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Unlock(); if (x > width) { x = 0; @@ -829,10 +829,10 @@ static int DrawBucketsAndVBuckets(MetadataManager *mdm, SDL_Surface *surface, // VBucketInfo for (size_t i = 0; i < mdm->max_vbuckets; ++i) { - BeginTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Lock(); VBucketInfo *info = GetVBucketInfoByIndex(mdm, i); bool active = info->active; - EndTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Unlock(); if (x > width) { x = 0; @@ -887,7 +887,7 @@ static bool PopulateByteCounts(DebugState *state, Heap *heap, static bool CheckFreeBlocks(Heap *heap, const std::vector &byte_counts, u32 heap_size) { - BeginTicketMutex(&heap->mutex); + heap->mutex.Lock(); u32 extent_offset_from_start = heap->extent; if (!heap->grows_up) { extent_offset_from_start = heap_size - heap->extent; @@ -927,7 +927,7 @@ static bool CheckFreeBlocks(Heap *heap, const std::vector &byte_counts, offset = head->next_offset; head = NextFreeBlock(heap, head); } - EndTicketMutex(&heap->mutex); + heap->mutex.Unlock(); return result; } @@ -936,8 +936,8 @@ static bool CheckOverlap(HeapMetadata *hmd, Heap *map_heap, Heap *id_heap) { std::vector heap_byte_counts(hmd->heap_size, 0); - BeginTicketMutex(&global_id_debug_state->mutex); - BeginTicketMutex(&global_map_debug_state->mutex); + global_id_debug_state->mutex.Lock(); + global_map_debug_state->mutex.Lock(); bool result = true; if (!PopulateByteCounts(global_id_debug_state, id_heap, heap_byte_counts, @@ -957,8 +957,8 @@ static bool CheckOverlap(HeapMetadata *hmd, Heap *map_heap, result = false; } - EndTicketMutex(&global_map_debug_state->mutex); - EndTicketMutex(&global_id_debug_state->mutex); + global_id_debug_state->mutex.Unlock(); + global_map_debug_state->mutex.Unlock(); return result; } @@ -1037,18 +1037,6 @@ int main() { exit(1); } - SharedMemoryContext id_debug_context = - GetSharedMemoryContext(global_debug_id_name); - SharedMemoryContext map_debug_context = - GetSharedMemoryContext(global_debug_map_name); - - if (id_debug_context.shm_base) { - global_id_debug_state = (DebugState *)id_debug_context.shm_base; - } - if (map_debug_context.shm_base) { - global_map_debug_state = (DebugState *)map_debug_context.shm_base; - } - while (win_data.running) { HandleInput(&context, &win_data, full_shmem_name); @@ -1074,9 +1062,6 @@ int main() { ReleaseSharedMemoryContext(&context); - UnmapSharedMemory(&id_debug_context); - UnmapSharedMemory(&map_debug_context); - SDL_FreeSurface(win_data.back_buffer); SDL_DestroyWindow(win_data.window); SDL_Quit(); diff --git a/src/communication.h b/src/communication.h index 0f00a33e3..14e2bfb79 100644 --- a/src/communication.h +++ b/src/communication.h @@ -62,7 +62,7 @@ struct CommunicationContext { bool first_on_node; }; -size_t InitCommunication(CommunicationContext *comm, Arena *arena, +size_t InitCommunication(CommunicationContext *comm, size_t trans_arena_size_per_node, bool is_daemon = false, bool is_adapter = false); /** world communicator */ diff --git a/src/communication_mpi.cc b/src/communication_mpi.cc index 0a42204f3..2e6de6b5d 100644 --- a/src/communication_mpi.cc +++ b/src/communication_mpi.cc @@ -11,7 +11,6 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "communication.h" -#include "memory_management.h" /** * @file communication_mpi.cc diff --git a/src/debug_state.cc b/src/debug_state.cc deleted file mode 100644 index ebff9ed00..000000000 --- a/src/debug_state.cc +++ /dev/null @@ -1,108 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#if HERMES_DEBUG_HEAP - -#include "debug_state.h" - -namespace hermes { - -DebugState *InitDebugState(const char *shmem_name) { - u8 *base = InitSharedMemory(shmem_name, sizeof(DebugState)); - DebugState *result = (DebugState *)base; - - return result; -} - -void CloseDebugState(bool unlink) { - munmap(global_debug_map_name, sizeof(DebugState)); - munmap(global_debug_id_name, sizeof(DebugState)); - if (unlink) { - shm_unlink(global_debug_map_name); - shm_unlink(global_debug_id_name); - } -} - -void AddDebugAllocation(DebugState *state, u32 offset, u32 size) { - BeginTicketMutex(&state->mutex); - assert(state->allocation_count < kGlobalDebugMaxAllocations); - int i = state->allocation_count++; - state->allocations[i].offset = offset; - state->allocations[i].size = size; - EndTicketMutex(&state->mutex); -} - -void RemoveDebugAllocation(DebugState *state, u32 offset, u32 size) { - BeginTicketMutex(&state->mutex); - for (u32 i = 0; i < state->allocation_count; ++i) { - if (state->allocations[i].offset == offset && - state->allocations[i].size == size) { - state->allocations[i] = state->allocations[--state->allocation_count]; - break; - } - } - EndTicketMutex(&state->mutex); -} - -#define HERMES_DEBUG_SERVER_INIT(grows_up) \ - if (grows_up) { \ - global_debug_map_state = InitDebugState(global_debug_map_name); \ - } else { \ - global_debug_id_state = InitDebugState(global_debug_id_name); \ - } - -#define HERMES_DEBUG_CLIENT_INIT() \ - if (!global_debug_id_state) { \ - SharedMemoryContext context = \ - GetSharedMemoryContext(global_debug_id_name); \ - global_debug_id_state = (DebugState *)context.shm_base; \ - } \ - if (!global_debug_map_state) { \ - SharedMemoryContext context = \ - GetSharedMemoryContext(global_debug_map_name); \ - global_debug_map_state = (DebugState *)context.shm_base; \ - } - -#define HERMES_DEBUG_SERVER_CLOSE() CloseDebugState(true) -#define HERMES_DEBUG_CLIENT_CLOSE() CloseDebugState(false) - -#define HERMES_DEBUG_TRACK_ALLOCATION(ptr, size, map) \ - if ((map)) { \ - AddDebugAllocation(global_debug_map_state, \ - GetHeapOffset(heap, (u8 *)(ptr)), (size)); \ - } else { \ - AddDebugAllocation(global_debug_id_state, \ - GetHeapOffset(heap, (u8 *)(ptr)), (size)); \ - } - -#define HERMES_DEBUG_TRACK_FREE(ptr, size, map) \ - if ((map)) { \ - RemoveDebugAllocation(global_debug_map_state, \ - GetHeapOffset(heap, (u8 *)(ptr)), (size)); \ - } else { \ - RemoveDebugAllocation(global_debug_id_state, \ - GetHeapOffset(heap, (u8 *)(ptr)), (size)); \ - } - -} // namespace hermes - -#else - -#define HERMES_DEBUG_SERVER_INIT(grows_up) -#define HERMES_DEBUG_CLIENT_INIT() -#define HERMES_DEBUG_SERVER_CLOSE() -#define HERMES_DEBUG_CLIENT_CLOSE() -#define HERMES_DEBUG_TRACK_ALLOCATION(ptr, size, map) -#define HERMES_DEBUG_TRACK_FREE(ptr, size, map) - -#endif // HERMES_DEBUG_HEAP - diff --git a/src/debug_state.h b/src/debug_state.h deleted file mode 100644 index 93f5b85d3..000000000 --- a/src/debug_state.h +++ /dev/null @@ -1,48 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_DEBUG_STATE_H_ -#define HERMES_DEBUG_STATE_H_ - -namespace hermes { - -/** - A structure to represent debug heap allocation -*/ -struct DebugHeapAllocation { - u32 offset; /**< heap offset */ - u32 size; /**< heap size */ -}; - -/** global debug maxium allocations */ -const int kGlobalDebugMaxAllocations = KILOBYTES(64); - -/** - A structure to represent debug state -*/ -struct DebugState { - u8 *shmem_base; /**< shared memory base address pointer */ - /** 64KB debug heap allocations */ - DebugHeapAllocation allocations[kGlobalDebugMaxAllocations]; - TicketMutex mutex; /**< ticket-based mutex */ - u32 allocation_count; /**< counter for allocation */ -}; - -DebugState *global_debug_id_state; /**< global debug id state */ -DebugState *global_debug_map_state; /**< global debug map state */ -/** name for global debug map heap */ -char global_debug_map_name[] = "/hermes_debug_map_heap"; -/** name for global debug id heap */ -char global_debug_id_name[] = "/hermes_debug_id_heap"; - -} // namespace hermes -#endif // HERMES_DEBUG_STATE_H_ diff --git a/src/metadata_management.cc b/src/metadata_management.cc index f26d81059..471c596df 100644 --- a/src/metadata_management.cc +++ b/src/metadata_management.cc @@ -17,7 +17,6 @@ #include #include -#include "memory_management.h" #include "metadata_management_internal.h" #include "buffer_pool.h" #include "buffer_pool_internal.h" @@ -483,7 +482,7 @@ BucketID LocalGetNextFreeBucketId(SharedMemoryContext *context, BucketID LocalGetOrCreateBucketId(SharedMemoryContext *context, const std::string &name) { MetadataManager *mdm = GetMetadataManagerFromContext(context); - BeginTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Lock();; BucketID result = LocalGetBucketId(context, name.c_str()); if (result.as_int != 0) { @@ -493,7 +492,7 @@ BucketID LocalGetOrCreateBucketId(SharedMemoryContext *context, LOG(INFO) << "Creating Bucket '" << name << "'" << std::endl; result = LocalGetNextFreeBucketId(context, name); } - EndTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Unlock(); return result; } @@ -554,7 +553,7 @@ VBucketID LocalGetOrCreateVBucketId(SharedMemoryContext *context, const std::string &name) { MetadataManager *mdm = GetMetadataManagerFromContext(context); - BeginTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Lock(); VBucketID result = LocalGetVBucketId(context, name.c_str()); if (result.as_int != 0) { @@ -564,7 +563,7 @@ VBucketID LocalGetOrCreateVBucketId(SharedMemoryContext *context, LOG(INFO) << "Creating VBucket '" << name << "'" << std::endl; result = LocalGetNextFreeVBucketId(context, name); } - EndTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Unlock(); return result; } @@ -724,9 +723,9 @@ void LocalCreateBlobMetadata(SharedMemoryContext *context, MetadataManager *mdm, if (effective_target != kSwapTargetId) { assert(blob_id.bits.node_id == (int)effective_target.bits.node_id); Target *target = GetTargetFromId(context, effective_target); - BeginTicketMutex(&target->effective_blobs_lock); + target->effective_blobs_lock.Lock(); AppendToChunkedIdList(mdm, &target->effective_blobs, blob_id.as_int); - EndTicketMutex(&target->effective_blobs_lock); + target->effective_blobs_lock.Unlock(); } LocalPut(mdm, blob_id, blob_info); @@ -802,22 +801,12 @@ void LocalDeleteBlobMetadata(MetadataManager *mdm, const char *blob_name, /** wait for outstanding BLOB operations */ void WaitForOutstandingBlobOps(MetadataManager *mdm, BlobID blob_id) { - Ticket t = {}; - Ticket *ticket = 0; - - while (!t.acquired) { - BlobInfo *blob_info = GetBlobInfoPtr(mdm, blob_id); - if (blob_info) { - t = TryBeginTicketMutex(&blob_info->lock, ticket); - } else { - // Blob was deleted - ReleaseBlobInfoPtr(mdm); - break; - } - if (!t.acquired) { - ReleaseBlobInfoPtr(mdm); - } - ticket = &t; + BlobInfo *blob_info = GetBlobInfoPtr(mdm, blob_id); + if (blob_info) { + blob_info->lock.Lock(); + blob_info->lock.Unlock(); + } else { + ReleaseBlobInfoPtr(mdm); } } @@ -1587,13 +1576,13 @@ f32 ScoringFunction(MetadataManager *mdm, Stats *stats) { int LocalGetNumOutstandingFlushingTasks(SharedMemoryContext *context, VBucketID id) { MetadataManager *mdm = GetMetadataManagerFromContext(context); - BeginTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Lock(); VBucketInfo *info = LocalGetVBucketInfoById(mdm, id); int result = 0; if (info) { result = info->async_flush_count; } - EndTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Unlock(); return result; } @@ -1615,63 +1604,41 @@ int GetNumOutstandingFlushingTasks(SharedMemoryContext *context, } bool LocalLockBlob(SharedMemoryContext *context, BlobID blob_id) { - Ticket t = {}; - Ticket *ticket = 0; - bool result = true; MetadataManager *mdm = GetMetadataManagerFromContext(context); - - while (!t.acquired) { - BlobInfo *blob_info = GetBlobInfoPtr(mdm, blob_id); - if (blob_info) { - t = TryBeginTicketMutex(&blob_info->lock, ticket); - if (!ticket) { - blob_info->last = t.ticket; - } - } else { - result = false; - ReleaseBlobInfoPtr(mdm); - break; - } - if (!t.acquired) { - ReleaseBlobInfoPtr(mdm); - sched_yield(); - } else { - if (blob_info->stop) { - // This BlobID is no longer valid. Release the lock and delete the entry - // if we're the last ticket on that lock. - EndTicketMutex(&blob_info->lock); - result = false; - if (t.ticket == blob_info->last) { - LocalDelete(mdm, blob_id); - LocalFreeBufferIdList(context, blob_id); - } - } - ReleaseBlobInfoPtr(mdm); - } - ticket = &t; + BlobInfo *blob_info = GetBlobInfoPtr(mdm, blob_id); + if (blob_info) { + blob_info->lock.Lock(); + } else { + ReleaseBlobInfoPtr(mdm); + return false; } - return result; + if (blob_info->stop) { + blob_info->lock.Unlock(); + LocalDelete(mdm, blob_id); + LocalFreeBufferIdList(context, blob_id); + ReleaseBlobInfoPtr(mdm); + return false; + } + ReleaseBlobInfoPtr(mdm); + return true; } bool LocalUnlockBlob(SharedMemoryContext *context, BlobID blob_id) { MetadataManager *mdm = GetMetadataManagerFromContext(context); BlobInfo *blob_info = GetBlobInfoPtr(mdm, blob_id); bool result = false; - if (blob_info) { - EndTicketMutex(&blob_info->lock); + blob_info->lock.Unlock(); result = true; } - ReleaseBlobInfoPtr(mdm); - return result; } /** lock BLOB */ bool LockBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id) { u32 target_node = GetBlobNodeId(blob_id); - bool result = false; + bool result; if (target_node == rpc->node_id) { result = LocalLockBlob(context, blob_id); } else { @@ -1683,7 +1650,7 @@ bool LockBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id) { /** unlock BLOB */ bool UnlockBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id) { u32 target_node = GetBlobNodeId(blob_id); - bool result = false; + bool result; if (target_node == rpc->node_id) { result = LocalUnlockBlob(context, blob_id); } else { @@ -1693,29 +1660,4 @@ bool UnlockBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id) { return result; } -/** make shared memory string */ -void MakeShmemString(ShmemString *sms, u8 *memory, const char *val, u32 size) { - memcpy(memory, val, size); - sms->size = size; - // NOTE(chogan): Offset is from the beginning of this ShmemString instance, so - // the memory for a ShmemString should always be at a higher address than the - // ShmemString itself. - CHECK_LT((u8 *)sms, (u8 *)memory); - sms->offset = (u8 *)memory - (u8 *)sms; -} - -void MakeShmemString(ShmemString *sms, u8 *memory, const std::string &val) { - MakeShmemString(sms, memory, val.data(), val.size()); -} - -std::string GetShmemString(ShmemString *sms) { - std::string result; - if (sms->offset >= sizeof(ShmemString) && sms->size > 0) { - const char *internal_string = (char *)((u8 *)sms + sms->offset); - result = std::string(internal_string, sms->size); - } - - return result; -} - } // namespace hermes diff --git a/src/metadata_management.h b/src/metadata_management.h index 61510bc5a..f0c220fb3 100644 --- a/src/metadata_management.h +++ b/src/metadata_management.h @@ -19,7 +19,6 @@ #include #include "buffer_pool.h" -#include "memory_management.h" namespace hermes { @@ -270,8 +269,7 @@ struct RpcContext; /** * */ -void InitMetadataManager(MetadataManager *mdm, RpcContext *rpc, Arena *arena, - Config *config); +void InitMetadataManager(MetadataManager *mdm, RpcContext *rpc, Config *config); /** * diff --git a/src/metadata_management_internal.h b/src/metadata_management_internal.h index 5387cb39a..cbbb7c0ef 100644 --- a/src/metadata_management_internal.h +++ b/src/metadata_management_internal.h @@ -21,7 +21,7 @@ bool IsNullBucketId(BucketID id); bool IsNullVBucketId(VBucketID id); bool IsNullBlobId(BlobID id); bool IsNullTargetId(TargetID id); -TicketMutex *GetMapMutex(MetadataManager *mdm, MapType map_type); +labstor::Mutex& GetMapMutex(MetadataManager *mdm, MapType map_type); VBucketID GetVBucketId(SharedMemoryContext *context, RpcContext *rpc, const char *name); u32 HashString(MetadataManager *mdm, RpcContext *rpc, const char *str); @@ -84,8 +84,7 @@ std::vector GetGlobalDeviceCapacities(SharedMemoryContext *context, void UpdateGlobalSystemViewState(SharedMemoryContext *context, RpcContext *rpc); void StartGlobalSystemViewStateUpdateThread(SharedMemoryContext *context, - RpcContext *rpc, Arena *arena, - double sleep_ms); + RpcContext *rpc, double sleep_ms); void InitMetadataStorage(SharedMemoryContext *context, MetadataManager *mdm, Config *config); diff --git a/src/metadata_storage_stb_ds.cc b/src/metadata_storage_stb_ds.cc index 8810697fe..24e138541 100644 --- a/src/metadata_storage_stb_ds.cc +++ b/src/metadata_storage_stb_ds.cc @@ -95,31 +95,25 @@ void CheckHeapOverlap(MetadataManager *mdm) { } /** get ticket mutex based on \a map_type */ -TicketMutex *GetMapMutex(MetadataManager *mdm, MapType map_type) { - TicketMutex *mutex = 0; +labstor::Mutex& GetMapMutex(MetadataManager *mdm, MapType map_type) { switch (map_type) { case kMapType_Bucket: { - mutex = &mdm->bucket_map_mutex; - break; + return mdm->bucket_map_mutex; } case kMapType_VBucket: { - mutex = &mdm->vbucket_map_mutex; - break; + return mdm->vbucket_map_mutex; } case kMapType_BlobId: { - mutex = &mdm->blob_id_map_mutex; + return mdm->blob_id_map_mutex; break; } case kMapType_BlobInfo: { - mutex = &mdm->blob_info_map_mutex; - break; + return mdm->blob_info_map_mutex; } default: { HERMES_INVALID_CODE_PATH; } } - - return mutex; } /** @@ -131,9 +125,8 @@ TicketMutex *GetMapMutex(MetadataManager *mdm, MapType map_type) { */ IdMap *GetMap(MetadataManager *mdm, MapType map_type) { IdMap *result = 0; - TicketMutex *mutex = GetMapMutex(mdm, map_type); - BeginTicketMutex(mutex); - + labstor::Mutex &mutex = GetMapMutex(mdm, map_type); + mutex.Lock(); switch (map_type) { case kMapType_Bucket: { result = GetBucketMap(mdm); @@ -163,8 +156,8 @@ BlobInfoMap *GetBlobInfoMapNoLock(MetadataManager *mdm) { /** get BLOB information map */ BlobInfoMap *GetBlobInfoMap(MetadataManager *mdm) { - TicketMutex *mutex = GetMapMutex(mdm, kMapType_BlobInfo); - BeginTicketMutex(mutex); + labstor::Mutex &mutex = GetMapMutex(mdm, kMapType_BlobInfo); + mutex.Lock(); BlobInfoMap *result = GetBlobInfoMapNoLock(mdm); return result; @@ -174,30 +167,27 @@ BlobInfoMap *GetBlobInfoMap(MetadataManager *mdm) { * Releases the lock acquired by `GetMap`. */ void ReleaseMap(MetadataManager *mdm, MapType map_type) { - TicketMutex *mutex = 0; switch (map_type) { case kMapType_Bucket: { - mutex = &mdm->bucket_map_mutex; + mdm->bucket_map_mutex.Unlock(); break; } case kMapType_VBucket: { - mutex = &mdm->vbucket_map_mutex; + mdm->vbucket_map_mutex.Unlock(); break; } case kMapType_BlobId: { - mutex = &mdm->blob_id_map_mutex; + mdm->blob_id_map_mutex.Unlock(); break; } case kMapType_BlobInfo: { - mutex = &mdm->blob_info_map_mutex; + mdm->blob_info_map_mutex.Unlock(); break; } default: { HERMES_INVALID_CODE_PATH; } } - - EndTicketMutex(mutex); } /** @@ -219,7 +209,7 @@ BlobInfo *GetBlobInfoPtr(MetadataManager *mdm, BlobID blob_id) { /** release pointer to BLOB information */ void ReleaseBlobInfoPtr(MetadataManager *mdm) { - EndTicketMutex(&mdm->blob_info_map_mutex); + mdm->blob_info_map_mutex.Unlock(); } /** get BLOB stats locally */ @@ -246,7 +236,7 @@ Stats LocalGetBlobStats(SharedMemoryContext *context, BlobID blob_id) { */ u64 *GetIdsPtr(MetadataManager *mdm, IdList id_list) { Heap *id_heap = GetIdHeap(mdm); - BeginTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Lock(); u64 *result = (u64 *)HeapOffsetToPtr(id_heap, id_list.head_offset); return result; @@ -258,7 +248,7 @@ u64 *GetIdsPtr(MetadataManager *mdm, IdList id_list) { */ u64 *GetIdsPtr(MetadataManager *mdm, ChunkedIdList id_list) { Heap *id_heap = GetIdHeap(mdm); - BeginTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Lock(); u64 *result = (u64 *)HeapOffsetToPtr(id_heap, id_list.head_offset); return result; @@ -275,11 +265,10 @@ u64 *GetIdsPtr(MetadataManager *mdm, ChunkedIdList id_list) { */ IdList GetEmbeddedIdList(MetadataManager *mdm, u32 offset) { Heap *id_heap = GetIdHeap(mdm); - BeginTicketMutex(&mdm->id_mutex); + &mdm->id_mutex.Lock(); IdList *embedded_id_list = (IdList *)HeapOffsetToPtr(id_heap, offset); IdList result = *embedded_id_list; - EndTicketMutex(&mdm->id_mutex); - + mdm->id_mutex.Unlock(); return result; } @@ -301,7 +290,7 @@ BufferID *GetBufferIdsPtrFromBlobId(MetadataManager *mdm, BlobID blob_id, /** release IDs pointer */ void ReleaseIdsPtr(MetadataManager *mdm) { - EndTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Unlock(); } /** Convert a key offset into the pointer where the string is stored. @@ -324,28 +313,28 @@ static char *GetKey(MetadataManager *mdm, IdMap *map, u32 index) { template void FreeIdList(MetadataManager *mdm, T id_list) { Heap *id_heap = GetIdHeap(mdm); - BeginTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Lock(); u8 *ptr = HeapOffsetToPtr(id_heap, id_list.head_offset); HeapFree(id_heap, ptr); - EndTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Unlock(); } /** free \a id_list ID list */ void FreeIdList(MetadataManager *mdm, IdList id_list) { Heap *id_heap = GetIdHeap(mdm); - BeginTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Lock(); u8 *ptr = HeapOffsetToPtr(id_heap, id_list.head_offset); HeapFree(id_heap, ptr); - EndTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Unlock(); } /** free embedded ID list */ void FreeEmbeddedIdList(MetadataManager *mdm, u32 offset) { Heap *id_heap = GetIdHeap(mdm); - BeginTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Lock(); u8 *to_free = HeapOffsetToPtr(id_heap, offset); HeapFree(id_heap, to_free); - EndTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Unlock(); } /** @@ -476,7 +465,7 @@ void LocalReplaceBlobIdInBucket(SharedMemoryContext *context, BucketID bucket_id, BlobID old_blob_id, BlobID new_blob_id) { MetadataManager *mdm = GetMetadataManagerFromContext(context); - BeginTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Lock(); BucketInfo *info = LocalGetBucketInfoById(mdm, bucket_id); if (info && info->active) { @@ -492,19 +481,19 @@ void LocalReplaceBlobIdInBucket(SharedMemoryContext *context, ReleaseIdsPtr(mdm); } - EndTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Unlock(); } /** add BLOB ID to bucket locally */ void LocalAddBlobIdToBucket(MetadataManager *mdm, BucketID bucket_id, BlobID blob_id, bool track_stats) { - BeginTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Lock(); BucketInfo *info = LocalGetBucketInfoById(mdm, bucket_id); AppendToChunkedIdList(mdm, &info->blobs, blob_id.as_int); if (track_stats) { LocalIncrementBlobStats(mdm, blob_id); } - EndTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Unlock(); CheckHeapOverlap(mdm); } @@ -512,10 +501,10 @@ void LocalAddBlobIdToBucket(MetadataManager *mdm, BucketID bucket_id, /** add BLOB ID to virtual bucket locally */ void LocalAddBlobIdToVBucket(MetadataManager *mdm, VBucketID vbucket_id, BlobID blob_id) { - BeginTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Lock(); VBucketInfo *info = LocalGetVBucketInfoById(mdm, vbucket_id); AppendToChunkedIdList(mdm, &info->blobs, blob_id.as_int); - EndTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Unlock(); CheckHeapOverlap(mdm); } @@ -524,12 +513,12 @@ void LocalAddBlobIdToVBucket(MetadataManager *mdm, VBucketID vbucket_id, IdList AllocateIdList(MetadataManager *mdm, u32 length) { static_assert(sizeof(IdList) == sizeof(u64)); Heap *id_heap = GetIdHeap(mdm); - BeginTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Lock(); u64 *id_list_memory = HeapPushArray(id_heap, length); IdList result = {}; result.length = length; result.head_offset = GetHeapOffset(id_heap, (u8 *)(id_list_memory)); - EndTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Unlock(); CheckHeapOverlap(mdm); return result; @@ -539,7 +528,7 @@ IdList AllocateIdList(MetadataManager *mdm, u32 length) { u32 AllocateEmbeddedIdList(MetadataManager *mdm, u32 length) { static_assert(sizeof(IdList) == sizeof(u64)); Heap *id_heap = GetIdHeap(mdm); - BeginTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Lock(); // NOTE(chogan): Add 1 extra for the embedded IdList u64 *id_list_memory = HeapPushArray(id_heap, length + 1); IdList *embedded_id_list = (IdList *)id_list_memory; @@ -547,7 +536,7 @@ u32 AllocateEmbeddedIdList(MetadataManager *mdm, u32 length) { embedded_id_list->head_offset = GetHeapOffset(id_heap, (u8 *)(embedded_id_list + 1)); u32 result = GetHeapOffset(id_heap, (u8 *)embedded_id_list); - EndTicketMutex(&mdm->id_mutex); + mdm->id_mutex.Unlock(); CheckHeapOverlap(mdm); return result; @@ -557,7 +546,7 @@ u32 AllocateEmbeddedIdList(MetadataManager *mdm, u32 length) { std::vector LocalGetBlobIds(SharedMemoryContext *context, BucketID bucket_id) { MetadataManager *mdm = GetMetadataManagerFromContext(context); - BeginTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Lock(); BucketInfo *info = LocalGetBucketInfoById(mdm, bucket_id); u32 num_blobs = info->blobs.length; std::vector result(num_blobs); @@ -567,7 +556,7 @@ std::vector LocalGetBlobIds(SharedMemoryContext *context, result[i] = blob_ids[i]; } ReleaseIdsPtr(mdm); - EndTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Unlock(); return result; } @@ -622,7 +611,7 @@ void LocalFreeBufferIdList(SharedMemoryContext *context, BlobID blob_id) { void LocalRemoveBlobFromBucketInfo(SharedMemoryContext *context, BucketID bucket_id, BlobID blob_id) { MetadataManager *mdm = GetMetadataManagerFromContext(context); - BeginTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Lock(); BucketInfo *info = LocalGetBucketInfoById(mdm, bucket_id); ChunkedIdList *blobs = &info->blobs; @@ -635,14 +624,14 @@ void LocalRemoveBlobFromBucketInfo(SharedMemoryContext *context, } ReleaseIdsPtr(mdm); - EndTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Unlock(); } /** does \a bucket_id contain \a blob_id BLOB locally? */ bool LocalContainsBlob(SharedMemoryContext *context, BucketID bucket_id, BlobID blob_id) { MetadataManager *mdm = GetMetadataManagerFromContext(context); - BeginTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Lock(); BucketInfo *info = LocalGetBucketInfoById(mdm, bucket_id); ChunkedIdList *blobs = &info->blobs; BlobID *blob_id_arr = (BlobID *)GetIdsPtr(mdm, *blobs); @@ -655,7 +644,7 @@ bool LocalContainsBlob(SharedMemoryContext *context, BucketID bucket_id, } } ReleaseIdsPtr(mdm); - EndTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Unlock(); return result; } @@ -687,7 +676,7 @@ bool LocalDestroyBucket(SharedMemoryContext *context, RpcContext *rpc, bool destroyed = false; MetadataManager *mdm = GetMetadataManagerFromContext(context); BeginWriterLock(&mdm->bucket_delete_lock); - BeginTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Lock(); BucketInfo *info = LocalGetBucketInfoById(mdm, bucket_id); int ref_count = info->ref_count.load(); @@ -731,7 +720,7 @@ bool LocalDestroyBucket(SharedMemoryContext *context, RpcContext *rpc, LOG(INFO) << "Cannot destroy bucket " << bucket_name << ". It's refcount is " << ref_count << std::endl; } - EndTicketMutex(&mdm->bucket_mutex); + mdm->bucket_mutex.Unlock(); EndWriterLock(&mdm->bucket_delete_lock); return destroyed; @@ -742,7 +731,7 @@ bool LocalDestroyVBucket(SharedMemoryContext *context, const char *vbucket_name, VBucketID vbucket_id) { bool destroyed = false; MetadataManager *mdm = GetMetadataManagerFromContext(context); - BeginTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Lock(); VBucketInfo *info = LocalGetVBucketInfoById(mdm, vbucket_id); // TODO(chogan): @optimization Lock granularity can probably be relaxed if @@ -773,7 +762,7 @@ bool LocalDestroyVBucket(SharedMemoryContext *context, const char *vbucket_name, LOG(INFO) << "Cannot destroy vbucket " << vbucket_name << ". It's refcount is " << ref_count << std::endl; } - EndTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Unlock(); return destroyed; } @@ -1052,13 +1041,13 @@ void InitMetadataStorage(SharedMemoryContext *context, MetadataManager *mdm, std::vector LocalGetBlobsFromVBucketInfo(SharedMemoryContext *context, VBucketID vbucket_id) { MetadataManager *mdm = GetMetadataManagerFromContext(context); - BeginTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Lock(); VBucketInfo *info = LocalGetVBucketInfoById(mdm, vbucket_id); ChunkedIdList *blobs = &info->blobs; BlobID *blobs_arr = (BlobID *)GetIdsPtr(mdm, *blobs); std::vector blobids(blobs_arr, blobs_arr + blobs->length); ReleaseIdsPtr(mdm); - EndTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Unlock(); return blobids; } @@ -1066,7 +1055,7 @@ std::vector LocalGetBlobsFromVBucketInfo(SharedMemoryContext *context, void LocalRemoveBlobFromVBucketInfo(SharedMemoryContext *context, VBucketID vbucket_id, BlobID blob_id) { MetadataManager *mdm = GetMetadataManagerFromContext(context); - BeginTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Lock(); VBucketInfo *info = LocalGetVBucketInfoById(mdm, vbucket_id); ChunkedIdList *blobs = &info->blobs; BlobID *blobs_arr = (BlobID *)GetIdsPtr(mdm, *blobs); @@ -1077,7 +1066,7 @@ void LocalRemoveBlobFromVBucketInfo(SharedMemoryContext *context, } } ReleaseIdsPtr(mdm); - EndTicketMutex(&mdm->vbucket_mutex); + mdm->vbucket_mutex.Unlock(); } /** get BLOB's importance score locally */ diff --git a/src/rpc.h b/src/rpc.h index 0c3ca3bb1..40d94b79c 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -18,6 +18,7 @@ #include "hermes_types.h" #include "metadata_management.h" +#include namespace hermes { @@ -47,7 +48,7 @@ struct RpcContext { size_t state_size; /** Array of host names stored in shared memory. This array size is * RpcContext::num_nodes. */ - ShmemString *host_names; + labstor::ipc::lockless::string host_names; u32 node_id; /**< node ID */ u32 num_nodes; /**< number of nodes */ int port; /**< port number */ @@ -63,15 +64,13 @@ struct RpcContext { void InitRpcContext(RpcContext *rpc, u32 num_nodes, u32 node_id, Config *config); -void *CreateRpcState(Arena *arena); +void *CreateRpcState(); void InitRpcClients(RpcContext *rpc); void ShutdownRpcClients(RpcContext *rpc); void RunDaemon(SharedMemoryContext *context, RpcContext *rpc, - CommunicationContext *comm, Arena *trans_arena, - const char *shmem_name); + CommunicationContext *comm, const char *shmem_name); void FinalizeClient(SharedMemoryContext *context, RpcContext *rpc, - CommunicationContext *comm, Arena *trans_arena, - bool stop_daemon); + CommunicationContext *comm, bool stop_daemon); void FinalizeRpcContext(RpcContext *rpc, bool is_daemon); std::string GetServerName(RpcContext *rpc, u32 node_id, bool is_buffer_organizer = false); diff --git a/test/config_parser_test.cc b/test/config_parser_test.cc index eb0e45fba..b7fc84635 100644 --- a/test/config_parser_test.cc +++ b/test/config_parser_test.cc @@ -15,13 +15,10 @@ #include #include "hermes_types.h" -#include "memory_management.h" #include "buffer_pool_internal.h" #include "test_utils.h" #include "config_parser.h" - -using hermes::Arena; using hermes::u8; using hermes::Config; @@ -30,17 +27,17 @@ namespace testing { Config ParseConfigStringTest(const std::string &config_string) { Config config = {}; - ParseConfigString(arena, config_string, &config); + ParseConfigString(config_string, &config); return config; } void RunHostNumbersTest(const std::string &config_string, const std::vector &expected) { - Config config = ParseConfigStringTest(arena, config_string); + Config config = ParseConfigStringTest(config_string); Assert(config.host_names == expected); } -void TestParseRangeList(Arena *arena) { +void TestParseRangeList() { { std::vector expected{ "localhost-1", "localhost-3", "localhost-4", "localhost-5", @@ -49,7 +46,7 @@ void TestParseRangeList(Arena *arena) { std::string yaml = "rpc_server_base_name: localhost-\n" "rpc_host_number_range: [1, 3-5, 7, 10-12]\n"; - RunHostNumbersTest(arena, yaml, expected); + RunHostNumbersTest(yaml, expected); } { @@ -59,7 +56,7 @@ void TestParseRangeList(Arena *arena) { std::string yaml = "rpc_server_base_name: localhost-\n" "rpc_host_number_range: [001-003]\n"; - RunHostNumbersTest(arena, yaml, expected); + RunHostNumbersTest(yaml, expected); } { @@ -69,7 +66,7 @@ void TestParseRangeList(Arena *arena) { std::string yaml = "rpc_server_base_name: localhost-\n" "rpc_host_number_range: [1]\n"; - RunHostNumbersTest(arena, yaml, expected); + RunHostNumbersTest(yaml, expected); } { @@ -77,20 +74,20 @@ void TestParseRangeList(Arena *arena) { std::string yaml = "rpc_server_base_name: localhost\n" "rpc_host_number_range: []\n"; - RunHostNumbersTest(arena, yaml, expected); + RunHostNumbersTest(yaml, expected); } } void RunCapacityValuesTest(const std::string &config_string, const std::vector &expected) { - Config config = ParseConfigStringTest(arena, config_string); + Config config = ParseConfigStringTest(config_string); Assert((size_t)config.num_devices == expected.size()); for (int i = 0; i < config.num_devices; ++i) { Assert(config.capacities[i] == expected[i]); } } -void TestPathExclusions(Arena *arena) { +void TestPathExclusions() { std::vector expected{"/bin/", "/boot/", "/dev/", "/etc/", "/lib/", "/opt/", "/proc/", "/sbin/", "/sys/", "/usr/", "/var/", "/run/", @@ -101,7 +98,7 @@ void TestPathExclusions(Arena *arena) { " \"/sys/\", \"/usr/\", \"/var/\", \"/run/\",\n" " \"pipe\", \"socket:\", \"anon_inode:\"\n" "]"; - Config config = ParseConfigStringTest(arena, config_string); + Config config = ParseConfigStringTest(config_string); for (size_t i = 0; i < expected.size(); ++i) { auto &e = expected[i]; auto &e2 = config.path_exclusions[i]; @@ -109,77 +106,77 @@ void TestPathExclusions(Arena *arena) { } } -void TestCapacityValues(Arena *arena) { +void TestCapacityValues() { std::string base_config = "num_devices: 4\n"; { std::vector expected{50, 50, 50, 50}; std::string config_string = "capacities_bytes: [50, 50, 50, 50]\n"; - RunCapacityValuesTest(arena, base_config + config_string, expected); + RunCapacityValuesTest(base_config + config_string, expected); } { std::vector expected{KILOBYTES(50), KILOBYTES(50), KILOBYTES(50), KILOBYTES(50)}; std::string config_string = "capacities_kb: [50, 50, 50, 50]\n"; - RunCapacityValuesTest(arena, base_config + config_string, expected); + RunCapacityValuesTest(base_config + config_string, expected); } { std::vector expected{MEGABYTES(50), MEGABYTES(50), MEGABYTES(50), MEGABYTES(50)}; std::string config_string = "capacities_mb: [50, 50, 50, 50]\n"; - RunCapacityValuesTest(arena, base_config + config_string, expected); + RunCapacityValuesTest(base_config + config_string, expected); } { std::vector expected{GIGABYTES(50), GIGABYTES(50), GIGABYTES(50), GIGABYTES(50)}; std::string config_string = "capacities_gb: [50, 50, 50, 50]\n"; - RunCapacityValuesTest(arena, base_config + config_string, expected); + RunCapacityValuesTest(base_config + config_string, expected); } } void RunBlockSizesTest(const std::string &config_string, const std::vector &expected) { - Config config = ParseConfigStringTest(arena, config_string); + Config config = ParseConfigStringTest(config_string); Assert((size_t)config.num_devices == expected.size()); for (int i = 0; i < config.num_devices; ++i) { Assert(config.block_sizes[i] == expected[i]); } } -void TestBlockSizes(Arena *arena) { +void TestBlockSizes() { std::string base_config = "num_devices: 4\n"; { std::vector expected{50, 50, 50, 50}; std::string config_string = "block_sizes_bytes: [50, 50, 50, 50]\n"; - RunBlockSizesTest(arena, base_config + config_string, expected); + RunBlockSizesTest(base_config + config_string, expected); } { std::vector expected{KILOBYTES(50), KILOBYTES(50), KILOBYTES(50), KILOBYTES(50)}; std::string config_string = "block_sizes_kb: [50, 50, 50, 50]\n"; - RunBlockSizesTest(arena, base_config + config_string, expected); + RunBlockSizesTest(base_config + config_string, expected); } { std::vector expected{MEGABYTES(50), MEGABYTES(50), MEGABYTES(50), MEGABYTES(50)}; std::string config_string = "block_sizes_mb: [50, 50, 50, 50]\n"; - RunBlockSizesTest(arena, base_config + config_string, expected); + RunBlockSizesTest(base_config + config_string, expected); } { std::vector expected{GIGABYTES(1), GIGABYTES(1), GIGABYTES(1), GIGABYTES(1)}; std::string config_string = "block_sizes_gb: [1, 1, 1, 1]\n"; - RunBlockSizesTest(arena, base_config + config_string, expected); + RunBlockSizesTest(base_config + config_string, expected); } } void TestDefaultConfig(const char *config_file) { hermes::Config config = {}; - hermes::ParseConfig(arena, config_file, &config); + hermes::ParseConfig(config_file, &config); Assert(config.num_devices == 4); Assert(config.num_targets == 4); @@ -263,16 +260,11 @@ int main(int argc, char **argv) { exit(-1); } - const size_t kConfigMemorySize = KILOBYTES(16); - u8 config_memory[kConfigMemorySize]; - Arena arena = {}; - hermes::InitArena(&arena, kConfigMemorySize, config_memory); - - hermes::testing::TestDefaultConfig(&arena, argv[1]); - hermes::testing::TestParseRangeList(&arena); - hermes::testing::TestCapacityValues(&arena); - hermes::testing::TestBlockSizes(&arena); - hermes::testing::TestPathExclusions(&arena); + hermes::testing::TestDefaultConfig(argv[1]); + hermes::testing::TestParseRangeList(); + hermes::testing::TestCapacityValues(); + hermes::testing::TestBlockSizes(); + hermes::testing::TestPathExclusions(); printf("SUCCESS!"); return 0; diff --git a/test/memory_test.cc b/test/memory_test.cc index acd01c8f4..52b5915dd 100644 --- a/test/memory_test.cc +++ b/test/memory_test.cc @@ -11,7 +11,6 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "test_utils.h" -#include "memory_management.h" using namespace hermes; // NOLINT(*) diff --git a/test/stb_map_test.cc b/test/stb_map_test.cc index c3dba880e..fd6602c3f 100644 --- a/test/stb_map_test.cc +++ b/test/stb_map_test.cc @@ -15,7 +15,6 @@ #include #include "test_utils.h" -#include "memory_management.h" #define STBDS_ASSERT(x) Assert((x)) From 72f9aac5a0c7777f05e51ee5d294f022dc9448ef Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Tue, 29 Nov 2022 21:22:44 -0600 Subject: [PATCH 028/511] Remove stb --- .../buffer_pool_visualizer.cc | 1 - src/stb_ds.h | 1931 ----------------- test/stb_map_test.cc | 58 - 3 files changed, 1990 deletions(-) delete mode 100644 src/stb_ds.h delete mode 100644 test/stb_map_test.cc diff --git a/src/buffer_pool_visualizer/buffer_pool_visualizer.cc b/src/buffer_pool_visualizer/buffer_pool_visualizer.cc index 4133d2794..a66ec0dfa 100644 --- a/src/buffer_pool_visualizer/buffer_pool_visualizer.cc +++ b/src/buffer_pool_visualizer/buffer_pool_visualizer.cc @@ -19,7 +19,6 @@ #include "buffer_pool_internal.h" #include "metadata_management.h" #include "metadata_management_internal.h" -#include "debug_state.h" #include "utils.h" #define DRAW_BUCKETS 0 diff --git a/src/stb_ds.h b/src/stb_ds.h deleted file mode 100644 index 964402d74..000000000 --- a/src/stb_ds.h +++ /dev/null @@ -1,1931 +0,0 @@ -/* stb_ds.h - v0.64 - public domain data structures - Sean Barrett 2019 - - This is a single-header-file library that provides easy-to-use - dynamic arrays and hash tables for C (also works in C++). - - For a gentle introduction: - http://nothings.org/stb_ds - - To use this library, do this in *one* C or C++ file: - #define STB_DS_IMPLEMENTATION - #include "stb_ds.h" - - NOTE(chogan): MODIFICATIONS FOR HERMES PROJECT, 5/8/20 - - In order for the string hash table to work in shared memory, we have made - some modifications. - - 1. We define STBDS_FREE and STBDS_REALLOC as hermes::HeapFree and - hermes::HeapRealloc. These allocation functions are designed to work in - shared memory. However, they require a hermes::Heap instance to be passed. - Thus, each stb function that calls STBDS_FREE or STBDS_REALLOC was modified - to accept a Heap instance. - - 2. Pointers internal to the stb map structure were changed to offsets. The - offsets are calculated with respect to the beginning of the header (the data - that lives before the beginning of the array). When the data corresponding to - these offsets need to be accessed, they are converted to pointers. This - ensures that the shared memory pointer is correct for each calling process. - - 3. The char* key for string hash maps is treated internally as a u64 because - it represents an offset into shared memory. When a pointer to the key is - requested, the offset is converted to the correct pointer. Therefore, - map[i].key will not work as expected. Instead, Hermes provides the function - GetKey(), which converts the offset into the correct pointer. - -TABLE OF CONTENTS - - Table of Contents - Compile-time options - License - Documentation - Notes - Notes - Dynamic arrays - Notes - Hash maps - Credits - -COMPILE-TIME OPTIONS - - #define STBDS_NO_SHORT_NAMES - - This flag needs to be set globally. - - By default stb_ds exposes shorter function names that are not qualified - with the "stbds_" prefix. If these names conflict with the names in your - code, define this flag. - - #define STBDS_SIPHASH_2_4 - - This flag only needs to be set in the file containing #define STB_DS_IMPLEMENTATION. - - By default stb_ds.h hashes using a weaker variant of SipHash and a custom hash for - 4- and 8-byte keys. On 64-bit platforms, you can define the above flag to force - stb_ds.h to use specification-compliant SipHash-2-4 for all keys. Doing so makes - hash table insertion about 20% slower on 4- and 8-byte keys, 5% slower on - 64-byte keys, and 10% slower on 256-byte keys on my test computer. - - #define STBDS_REALLOC(context,ptr,size) better_realloc - #define STBDS_FREE(context,ptr) better_free - - These defines only need to be set in the file containing #define STB_DS_IMPLEMENTATION. - - By default stb_ds uses stdlib realloc() and free() for memory management. You can - substitute your own functions instead by defining these symbols. You must either - define both, or neither. Note that at the moment, 'context' will always be NULL. - @TODO add an array/hash initialization function that takes a memory context pointer. - - #define STBDS_UNIT_TESTS - - Defines a function stbds_unit_tests() that checks the functioning of the data structures. - - Note that on older versions of gcc (e.g. 5.x.x) you may need to build with '-std=c++0x' - (or equivalentally '-std=c++11') when using anonymous structures as seen on the web - page or in STBDS_UNIT_TESTS. - -LICENSE - - Placed in the public domain and also MIT licensed. - See end of file for detailed license information. - -DOCUMENTATION - - Dynamic Arrays - - Non-function interface: - - Declare an empty dynamic array of type T - T* foo = NULL; - - Access the i'th item of a dynamic array 'foo' of type T, T* foo: - foo[i] - - Functions (actually macros) - - arrfree: - void arrfree(T*); - Frees the array. - - arrlen: - ptrdiff_t arrlen(T*); - Returns the number of elements in the array. - - arrlenu: - size_t arrlenu(T*); - Returns the number of elements in the array as an unsigned type. - - arrpop: - T arrpop(T* a) - Removes the final element of the array and returns it. - - arrput: - T arrput(T* a, T b); - Appends the item b to the end of array a. Returns b. - - arrins: - T arrins(T* a, int p, T b); - Inserts the item b into the middle of array a, into a[p], - moving the rest of the array over. Returns b. - - arrinsn: - void arrins(T* a, int p, int n); - Inserts n uninitialized items into array a starting at a[p], - moving the rest of the array over. - - arraddn: - T* arraddn(T* a, int n) - Appends n uninitialized items onto array at the end. - Returns a pointer to the first uninitialized item added. - - arrdel: - void arrdel(T* a, int p); - Deletes the element at a[p], moving the rest of the array over. - - arrdeln: - void arrdel(T* a, int p, int n); - Deletes n elements starting at a[p], moving the rest of the array over. - - arrdelswap: - void arrdelswap(T* a, int p); - Deletes the element at a[p], replacing it with the element from - the end of the array. O(1) performance. - - arrsetlen: - void arrsetlen(T* a, int n); - Changes the length of the array to n. Allocates uninitialized - slots at the end if necessary. - - arrsetcap: - size_t arrsetcap(T* a, int n); - Sets the length of allocated storage to at least n. It will not - change the length of the array. - - arrcap: - size_t arrcap(T* a); - Returns the number of total elements the array can contain without - needing to be reallocated. - - Hash maps & String hash maps - - Given T is a structure type: struct { TK key; TV value; }. Note that some - functions do not require TV value and can have other fields. For string - hash maps, TK must be 'char *'. - - Special interface: - - stbds_rand_seed: - void stbds_rand_seed(size_t seed); - For security against adversarially chosen data, you should seed the - library with a strong random number. Or at least seed it with time(). - - stbds_hash_string: - size_t stbds_hash_string(char *str, size_t seed); - Returns a hash value for a string. - - stbds_hash_bytes: - size_t stbds_hash_bytes(void *p, size_t len, size_t seed); - These functions hash an arbitrary number of bytes. The function - uses a custom hash for 4- and 8-byte data, and a weakened version - of SipHash for everything else. On 64-bit platforms you can get - specification-compliant SipHash-2-4 on all data by defining - STBDS_SIPHASH_2_4, at a significant cost in speed. - - Non-function interface: - - Declare an empty hash map of type T - T* foo = NULL; - - Access the i'th entry in a hash table T* foo: - foo[i] - - Function interface (actually macros): - - hmfree - shfree - void hmfree(T*); - void shfree(T*); - Frees the hashmap and sets the pointer to NULL. - - hmlen - shlen - ptrdiff_t hmlen(T*) - ptrdiff_t shlen(T*) - Returns the number of elements in the hashmap. - - hmlenu - shlenu - size_t hmlenu(T*) - size_t shlenu(T*) - Returns the number of elements in the hashmap. - - hmgeti - shgeti - hmgeti_ts - ptrdiff_t hmgeti(T*, TK key) - ptrdiff_t shgeti(T*, char* key) - ptrdiff_t hmgeti_ts(T*, TK key, ptrdiff_t tempvar) - Returns the index in the hashmap which has the key 'key', or -1 - if the key is not present. - - hmget - hmget_ts - shget - TV hmget(T*, TK key) - TV shget(T*, char* key) - TV hmget_ts(T*, TK key, ptrdiff_t tempvar) - Returns the value corresponding to 'key' in the hashmap. - The structure must have a 'value' field - - hmgets - shgets - T hmgets(T*, TK key) - T shgets(T*, char* key) - Returns the structure corresponding to 'key' in the hashmap. - - hmgetp - shgetp - hmgetp_ts - hmgetp_null - shgetp_null - T* hmgetp(T*, TK key) - T* shgetp(T*, char* key) - T* hmgetp_ts(T*, TK key, ptrdiff_t tempvar) - T* hmgetp_null(T*, TK key) - T* shgetp_null(T*, char *key) - Returns a pointer to the structure corresponding to 'key' in - the hashmap. Functions ending in "_null" return NULL if the key - is not present in the hashmap; the others return a pointer to a - structure holding the default value (but not the searched-for key). - - hmdefault - shdefault - TV hmdefault(T*, TV value) - TV shdefault(T*, TV value) - Sets the default value for the hashmap, the value which will be - returned by hmget/shget if the key is not present. - - hmdefaults - shdefaults - TV hmdefaults(T*, T item) - TV shdefaults(T*, T item) - Sets the default struct for the hashmap, the contents which will be - returned by hmgets/shgets if the key is not present. - - hmput - shput - TV hmput(T*, TK key, TV value) - TV shput(T*, char* key, TV value) - Inserts a pair into the hashmap. If the key is already - present in the hashmap, updates its value. - - hmputs - shputs - T hmputs(T*, T item) - T shputs(T*, T item) - Inserts a struct with T.key into the hashmap. If the struct is already - present in the hashmap, updates it. - - hmdel - shdel - int hmdel(T*, TK key) - int shdel(T*, char* key) - If 'key' is in the hashmap, deletes its entry and returns 1. - Otherwise returns 0. - - Function interface (actually macros) for strings only: - - sh_new_strdup - void sh_new_strdup(T*); - Overwrites the existing pointer with a newly allocated - string hashmap which will automatically allocate and free - each string key using realloc/free - - sh_new_arena - void sh_new_arena(T*); - Overwrites the existing pointer with a newly allocated - string hashmap which will automatically allocate each string - key to a string arena. Every string key ever used by this - hash table remains in the arena until the arena is freed. - Additionally, any key which is deleted and reinserted will - be allocated multiple times in the string arena. - -NOTES - - * These data structures are realloc'd when they grow, and the macro - "functions" write to the provided pointer. This means: (a) the pointer - must be an lvalue, and (b) the pointer to the data structure is not - stable, and you must maintain it the same as you would a realloc'd - pointer. For example, if you pass a pointer to a dynamic array to a - function which updates it, the function must return back the new - pointer to the caller. This is the price of trying to do this in C. - - * The following are the only functions that are thread-safe on a single data - structure, i.e. can be run in multiple threads simultaneously on the same - data structure - hmlen shlen - hmlenu shlenu - hmget_ts shget_ts - hmgeti_ts shgeti_ts - hmgets_ts shgets_ts - - * You iterate over the contents of a dynamic array and a hashmap in exactly - the same way, using arrlen/hmlen/shlen: - - for (i=0; i < arrlen(foo); ++i) - ... foo[i] ... - - * All operations except arrins/arrdel are O(1) amortized, but individual - operations can be slow, so these data structures may not be suitable - for real time use. Dynamic arrays double in capacity as needed, so - elements are copied an average of once. Hash tables double/halve - their size as needed, with appropriate hysteresis to maintain O(1) - performance. - -NOTES - DYNAMIC ARRAY - - * If you know how long a dynamic array is going to be in advance, you can avoid - extra memory allocations by using arrsetlen to allocate it to that length in - advance and use foo[n] while filling it out, or arrsetcap to allocate the memory - for that length and use arrput/arrpush as normal. - - * Unlike some other versions of the dynamic array, this version should - be safe to use with strict-aliasing optimizations. - -NOTES - HASH MAP - - * For compilers other than GCC and clang (e.g. Visual Studio), for hmput/hmget/hmdel - and variants, the key must be an lvalue (so the macro can take the address of it). - Extensions are used that eliminate this requirement if you're using C99 and later - in GCC or clang, or if you're using C++ in GCC. But note that this can make your - code less portable. - - * To test for presence of a key in a hashmap, just do 'hmgeti(foo,key) >= 0'. - - * The iteration order of your data in the hashmap is determined solely by the - order of insertions and deletions. In particular, if you never delete, new - keys are always added at the end of the array. This will be consistent - across all platforms and versions of the library. However, you should not - attempt to serialize the internal hash table, as the hash is not consistent - between different platforms, and may change with future versions of the library. - - * Use sh_new_arena() for string hashmaps that you never delete from. Initialize - with NULL if you're managing the memory for your strings, or your strings are - never freed (at least until the hashmap is freed). Otherwise, use sh_new_strdup(). - @TODO: make an arena variant that garbage collects the strings with a trivial - copy collector into a new arena whenever the table shrinks / rebuilds. Since - current arena recommendation is to only use arena if it never deletes, then - this can just replace current arena implementation. - - * If adversarial input is a serious concern and you're on a 64-bit platform, - enable STBDS_SIPHASH_2_4 (see the 'Compile-time options' section), and pass - a strong random number to stbds_rand_seed. - - * The default value for the hash table is stored in foo[-1], so if you - use code like 'hmget(T,k)->value = 5' you can accidentally overwrite - the value stored by hmdefault if 'k' is not present. - -CREDITS - - Sean Barrett -- library, idea for dynamic array API/implementation - Per Vognsen -- idea for hash table API/implementation - Rafael Sachetto -- arrpop() - - Bugfixes: - Andy Durdin - Shane Liesegang - Vinh Truong -*/ - -#ifdef STBDS_UNIT_TESTS -#define _CRT_SECURE_NO_WARNINGS -#endif - -#ifndef INCLUDE_STB_DS_H -#define INCLUDE_STB_DS_H - -#include -#include - -#ifndef STBDS_NO_SHORT_NAMES -#define arrlen stbds_arrlen -#define arrlenu stbds_arrlenu -#define arrput stbds_arrput -#define arrpush stbds_arrput -#define arrpop stbds_arrpop -#define arrfree stbds_arrfree -#define arraddn stbds_arraddn -#define arrsetlen stbds_arrsetlen -#define arrlast stbds_arrlast -#define arrins stbds_arrins -#define arrinsn stbds_arrinsn -#define arrdel stbds_arrdel -#define arrdeln stbds_arrdeln -#define arrdelswap stbds_arrdelswap -#define arrcap stbds_arrcap -#define arrsetcap stbds_arrsetcap - -#define hmput stbds_hmput -#define hmputs stbds_hmputs -#define hmget stbds_hmget -#define hmget_ts stbds_hmget_ts -#define hmgets stbds_hmgets -#define hmgetp stbds_hmgetp -#define hmgetp_ts stbds_hmgetp_ts -#define hmgetp_null stbds_hmgetp_null -#define hmgeti stbds_hmgeti -#define hmgeti_ts stbds_hmgeti_ts -#define hmdel stbds_hmdel -#define hmlen stbds_hmlen -#define hmlenu stbds_hmlenu -#define hmfree stbds_hmfree -#define hmdefault stbds_hmdefault -#define hmdefaults stbds_hmdefaults - -#define shput stbds_shput -#define shputi stbds_shputi -#define shputs stbds_shputs -#define shget stbds_shget -#define shgeti stbds_shgeti -#define shgets stbds_shgets -#define shgetp stbds_shgetp -#define shgetp_null stbds_shgetp_null -#define shdel stbds_shdel -#define shlen stbds_shlen -#define shlenu stbds_shlenu -#define shfree stbds_shfree -#define shdefault stbds_shdefault -#define shdefaults stbds_shdefaults -#define sh_new_arena stbds_sh_new_arena -#define sh_new_strdup stbds_sh_new_strdup - -#define stralloc stbds_stralloc -#define strreset stbds_strreset -#endif - -#if defined(STBDS_REALLOC) && !defined(STBDS_FREE) || !defined(STBDS_REALLOC) && defined(STBDS_FREE) -#error "You must define both STBDS_REALLOC and STBDS_FREE, or neither." -#endif -#if !defined(STBDS_REALLOC) && !defined(STBDS_FREE) -#include -#define STBDS_REALLOC(c,p,s) realloc(p,s) -#define STBDS_FREE(c,p) free(p) -#endif - -#ifdef __cplusplus -using hermes::Heap; -extern "C" { -#endif - -// for security against attackers, seed the library with a random number, at least time() but stronger is better -extern void stbds_rand_seed(size_t seed); - -// these are the hash functions used internally if you want to test them or use them for other purposes -extern size_t stbds_hash_bytes(void *p, size_t len, size_t seed); -extern size_t stbds_hash_string(char *str, size_t seed); - -// this is a simple string arena allocator, initialize with e.g. 'stbds_string_arena my_arena={0}'. -typedef struct stbds_string_arena stbds_string_arena; -extern char * stbds_stralloc(stbds_string_arena *a, char *str, Heap *heap); -extern void stbds_strreset(stbds_string_arena *a, Heap *heap); - -// have to #define STBDS_UNIT_TESTS to call this -extern void stbds_unit_tests(void); - -/////////////// -// -// Everything below here is implementation details -// - -extern void * stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap, Heap *heap); -extern void stbds_hmfree_func(void *p, size_t elemsize, Heap *heap); -extern void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode, Heap *heap); -extern void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode, Heap *heap); -extern void * stbds_hmput_default(void *a, size_t elemsize, Heap *heap); -extern void * stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode, Heap *heap); -extern void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode, Heap *heap); -extern void * stbds_shmode_func(size_t elemsize, size_t capacity, int mode, Heap *heap); - -#ifdef __cplusplus -} -#endif - -#if defined(__GNUC__) || defined(__clang__) -#define STBDS_HAS_TYPEOF -#ifdef __cplusplus -//#define STBDS_HAS_LITERAL_ARRAY // this is currently broken for clang -#endif -#endif - -#if !defined(__cplusplus) -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#define STBDS_HAS_LITERAL_ARRAY -#endif -#endif - -// this macro takes the address of the argument, but on gcc/clang can accept rvalues -#if defined(STBDS_HAS_LITERAL_ARRAY) && defined(STBDS_HAS_TYPEOF) - #if __clang__ - #define STBDS_ADDRESSOF(typevar, value) ((__typeof__(typevar)[1]){value}) // literal array decays to pointer to value - #else - #define STBDS_ADDRESSOF(typevar, value) ((typeof(typevar)[1]){value}) // literal array decays to pointer to value - #endif -#else -#define STBDS_ADDRESSOF(typevar, value) &(value) -#endif - -#define STBDS_OFFSETOF(var,field) ((char *) &(var)->field - (char *) (var)) - -#define stbds_header(t) ((stbds_array_header *) (t) - 1) -#define stbds_temp(t) stbds_header(t)->temp - -#define stbds_arrsetcap(a,n,heap) (stbds_arrgrow(a,0,n,heap)) -#define stbds_arrsetlen(a,n) ((stbds_arrcap(a) < (size_t) (n) ? stbds_arrsetcap((a),(size_t)(n)),0 : 0), (a) ? stbds_header(a)->length = (size_t) (n) : 0) -#define stbds_arrcap(a) ((a) ? stbds_header(a)->capacity : 0) -#define stbds_arrlen(a) ((a) ? (ptrdiff_t) stbds_header(a)->length : 0) -#define stbds_arrlenu(a) ((a) ? stbds_header(a)->length : 0) -#define stbds_arrput(a,v,heap) (stbds_arrmaybegrow(a,1,heap), (a)[stbds_header(a)->length++] = (v)) -#define stbds_arrpush stbds_arrput // synonym -#define stbds_arrpop(a) (stbds_header(a)->length--, (a)[stbds_header(a)->length]) -#define stbds_arraddn(a,n,heap) (stbds_arrmaybegrow(a,n,heap), stbds_header(a)->length += (n), stbds_header(a)->length-(n)) -#define stbds_arrlast(a) ((a)[stbds_header(a)->length-1]) -#define stbds_arrfree(a,heap) ((void) ((a) ? STBDS_FREE(heap,stbds_header(a)) : (void)0), (a)=NULL) -#define stbds_arrdel(a,i) stbds_arrdeln(a,i,1) -#define stbds_arrdeln(a,i,n) (memmove(&(a)[i], &(a)[(i)+(n)], sizeof *(a) * (stbds_header(a)->length-(n)-(i))), stbds_header(a)->length -= (n)) -#define stbds_arrdelswap(a,i) ((a)[i] = stbds_arrlast(a), stbds_header(a)->length -= 1) -#define stbds_arrinsn(a,i,n,heap) (stbds_arraddn((a),(n),(heap)), memmove(&(a)[(i)+(n)], &(a)[i], sizeof *(a) * (stbds_header(a)->length-(n)-(i)))) -#define stbds_arrins(a,i,v,heap) (stbds_arrinsn((a),(i),1,heap), (a)[i]=(v)) - -#define stbds_arrmaybegrow(a,n,heap) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \ - ? (stbds_arrgrow(a,n,0,heap),0) : 0) - -#define stbds_arrgrow(a,b,c,heap) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c), heap)) - -#define stbds_hmput(t, k, v, heap) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, 0,heap), \ - (t)[stbds_temp((t)-1)].key = (k), \ - (t)[stbds_temp((t)-1)].value = (v)) - -#define stbds_hmputs(t, s, heap) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), &(s).key, sizeof (s).key, STBDS_HM_BINARY, heap), \ - (t)[stbds_temp((t)-1)] = (s)) - -#define stbds_hmgeti(t,k, heap) \ - ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_HM_BINARY, heap), \ - stbds_temp((t)-1)) - -#define stbds_hmgeti_ts(t,k,temp,heap) \ - ((t) = stbds_hmget_key_ts_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, &(temp), STBDS_HM_BINARY, heap), \ - (temp)) - -#define stbds_hmgetp(t, k, heap) \ - ((void) stbds_hmgeti(t,k,heap), &(t)[stbds_temp((t)-1)]) - -#define stbds_hmgetp_ts(t, k, temp, heap) \ - ((void) stbds_hmgeti_ts(t,k,temp, heap), &(t)[temp]) - -#define stbds_hmdel(t,k,heap) \ - (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_BINARY, heap)),(t)?stbds_temp((t)-1):0) - -#define stbds_hmdefault(t, v, heap) \ - ((t) = stbds_hmput_default_wrapper((t), sizeof *(t), (heap)), (t)[-1].value = (v)) - -#define stbds_hmdefaults(t, s) \ - ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1] = (s)) - -#define stbds_hmfree(p, heap) \ - ((void) ((p) != NULL ? stbds_hmfree_func((p)-1,sizeof*(p), heap),0 : 0),(p)=NULL) - -#define stbds_hmgets(t, k, heap) (*stbds_hmgetp(t,k,heap)) -#define stbds_hmget(t, k, heap) (stbds_hmgetp(t,k,heap)->value) -#define stbds_hmget_ts(t, k, temp,heap) (stbds_hmgetp_ts(t,k,temp,heap)->value) -#define stbds_hmlen(t) ((t) ? (ptrdiff_t) stbds_header((t)-1)->length-1 : 0) -#define stbds_hmlenu(t) ((t) ? stbds_header((t)-1)->length-1 : 0) -#define stbds_hmgetp_null(t,k,heap) (stbds_hmgeti(t,k,heap) == -1 ? NULL : &(t)[stbds_temp((t)-1)]) - -#define stbds_shput(t, k, v, heap) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING, heap), \ - (t)[stbds_temp((t)-1)].value = (v)) - -#define stbds_shputi(t, k, v) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ - (t)[stbds_temp((t)-1)].value = (v), stbds_temp((t)-1)) - -#define stbds_shputs(t, s) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (s).key, sizeof (s).key, STBDS_HM_STRING), \ - (t)[stbds_temp((t)-1)] = (s)) - -#define stbds_pshput(t, p) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (p)->key, sizeof (p)->key, STBDS_HM_PTR_TO_STRING), \ - (t)[stbds_temp((t)-1)] = (p)) - -#define stbds_shgeti(t,k,heap) \ - ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING, heap), \ - stbds_temp((t)-1)) - -#define stbds_pshgeti(t,k) \ - ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_HM_PTR_TO_STRING), \ - stbds_temp((t)-1)) - -#define stbds_shgetp(t, k, heap) \ - ((void) stbds_shgeti(t,k, heap), &(t)[stbds_temp((t)-1)]) - -#define stbds_pshget(t, k) \ - ((void) stbds_pshgeti(t,k), (t)[stbds_temp((t)-1)]) - -#define stbds_shdel(t,k,heap) \ - (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_STRING, heap)),(t)?stbds_temp((t)-1):0) -#define stbds_pshdel(t,k) \ - (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_OFFSETOF(*(t),key), STBDS_HM_PTR_TO_STRING)),(t)?stbds_temp((t)-1):0) - -#define stbds_sh_new_arena(t, heap) \ - ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_ARENA, heap)) -#define stbds_sh_new_strdup(t, cap, heap) \ - ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), cap, STBDS_SH_STRDUP, heap)) - -#define stbds_shdefault(t, v, heap) stbds_hmdefault(t,v,heap) -#define stbds_shdefaults(t, s) stbds_hmdefaults(t,s) - -#define stbds_shfree stbds_hmfree -#define stbds_shlenu stbds_hmlenu - -#define stbds_shgets(t, k) (*stbds_shgetp(t,k)) -#define stbds_shget(t, k, heap) (stbds_shgetp(t,k, heap)->value) -#define stbds_shgetp_null(t,k) (stbds_shgeti(t,k) == -1 ? NULL : &(t)[stbds_temp((t)-1)]) -#define stbds_shlen stbds_hmlen - -typedef struct -{ - size_t length; - size_t capacity; - ptrdiff_t hash_table_offset; - ptrdiff_t temp; -} stbds_array_header; - -typedef struct stbds_string_block -{ - struct stbds_string_block *next; - char storage[8]; -} stbds_string_block; - -struct stbds_string_arena -{ - stbds_string_block *storage; - size_t remaining; - unsigned char block; - unsigned char mode; // this isn't used by the string arena itself -}; - -#define STBDS_HM_BINARY 0 -#define STBDS_HM_STRING 1 - -enum -{ - STBDS_SH_NONE, - STBDS_SH_DEFAULT, - STBDS_SH_STRDUP, - STBDS_SH_ARENA -}; - -#ifdef __cplusplus -// in C we use implicit assignment from these void*-returning functions to T*. -// in C++ these templates make the same code work -template static T * stbds_arrgrowf_wrapper(T *a, size_t elemsize, size_t addlen, size_t min_cap, Heap *heap) { - return (T*)stbds_arrgrowf((void *)a, elemsize, addlen, min_cap, heap); -} -template static T * stbds_hmget_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode, Heap *heap) { - return (T*)stbds_hmget_key((void*)a, elemsize, key, keysize, mode, heap); -} -template static T * stbds_hmget_key_ts_wrapper(T *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode, Heap *heap) { - return (T*)stbds_hmget_key_ts((void*)a, elemsize, key, keysize, temp, mode, heap); -} -template static T * stbds_hmput_default_wrapper(T *a, size_t elemsize, Heap *heap) { - return (T*)stbds_hmput_default((void *)a, elemsize, heap); -} -template static T * stbds_hmput_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode, Heap *heap) { - return (T*)stbds_hmput_key((void*)a, elemsize, key, keysize, mode, heap); -} -template static T * stbds_hmdel_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode, Heap *heap){ - return (T*)stbds_hmdel_key((void*)a, elemsize, key, keysize, keyoffset, mode, heap); -} -template static T * stbds_shmode_func_wrapper(T *, size_t elemsize, size_t capacity, int mode, Heap *heap) { - return (T*)stbds_shmode_func(elemsize, capacity, mode, heap); -} -#else -#define stbds_arrgrowf_wrapper stbds_arrgrowf -#define stbds_hmget_key_wrapper stbds_hmget_key -#define stbds_hmget_key_ts_wrapper stbds_hmget_key_ts -#define stbds_hmput_default_wrapper stbds_hmput_default -#define stbds_hmput_key_wrapper stbds_hmput_key -#define stbds_hmdel_key_wrapper stbds_hmdel_key -#define stbds_shmode_func_wrapper(t,e,m,heap) stbds_shmode_func(e,m,heap) -#endif - -#endif // INCLUDE_STB_DS_H - - -////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// - -#ifdef STB_DS_IMPLEMENTATION -#include -#include - -#ifndef STBDS_ASSERT -#define STBDS_ASSERT_WAS_UNDEFINED -#define STBDS_ASSERT(x) ((void) 0) -#endif - -#ifdef STBDS_STATISTICS -#define STBDS_STATS(x) x -size_t stbds_array_grow; -size_t stbds_hash_grow; -size_t stbds_hash_shrink; -size_t stbds_hash_rebuild; -size_t stbds_hash_probes; -size_t stbds_hash_alloc; -size_t stbds_rehash_probes; -size_t stbds_rehash_items; -#else -#define STBDS_STATS(x) -#endif - -// -// stbds_arr implementation -// - -//int *prev_allocs[65536]; -//int num_prev; - -void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap, Heap *heap) -{ - void *b; - size_t min_len = stbds_arrlen(a) + addlen; - - // compute the minimum capacity needed - if (min_len > min_cap) - min_cap = min_len; - - if (min_cap <= stbds_arrcap(a)) - return a; - - // increase needed capacity to guarantee O(1) amortized - if (min_cap < 2 * stbds_arrcap(a)) - min_cap = 2 * stbds_arrcap(a); - else if (min_cap < 4) - min_cap = 4; - - //if (num_prev < 65536) if (a) prev_allocs[num_prev++] = (int *) ((char *) a+1); - //if (num_prev == 2201) - // num_prev = num_prev; - b = STBDS_REALLOC(heap, (a) ? stbds_header(a) : 0, elemsize * min_cap + sizeof(stbds_array_header)); - //if (num_prev < 65536) prev_allocs[num_prev++] = (int *) (char *) b; - b = (char *) b + sizeof(stbds_array_header); - if (a == NULL) { - stbds_header(b)->length = 0; - stbds_header(b)->hash_table_offset = 0; - stbds_header(b)->temp = 0; - } else { - STBDS_STATS(++stbds_array_grow); - } - stbds_header(b)->capacity = min_cap; - - return b; -} - -// -// stbds_hm hash table implementation -// - -#ifdef STBDS_INTERNAL_SMALL_BUCKET -#define STBDS_BUCKET_LENGTH 4 -#else -#define STBDS_BUCKET_LENGTH 8 -#endif - -#define STBDS_BUCKET_SHIFT (STBDS_BUCKET_LENGTH == 8 ? 3 : 2) -#define STBDS_BUCKET_MASK (STBDS_BUCKET_LENGTH-1) -#define STBDS_CACHE_LINE_SIZE 64 - -#define STBDS_ALIGN_FWD(n,a) (((n) + (a) - 1) & ~((a)-1)) - -typedef struct -{ - size_t hash [STBDS_BUCKET_LENGTH]; - ptrdiff_t index[STBDS_BUCKET_LENGTH]; -} stbds_hash_bucket; // in 32-bit, this is one 64-byte cache line; in 64-bit, each array is one 64-byte cache line - -typedef struct -{ - size_t slot_count; - size_t used_count; - size_t used_count_threshold; - size_t used_count_shrink_threshold; - size_t tombstone_count; - size_t tombstone_count_threshold; - size_t seed; - size_t slot_count_log2; - stbds_string_arena string; - ptrdiff_t storage_offset; // not a separate allocation, just 64-byte aligned storage after this struct. stbds_hash_bucket -} stbds_hash_index; - -#define STBDS_INDEX_EMPTY -1 -#define STBDS_INDEX_DELETED -2 -#define STBDS_INDEX_IN_USE(x) ((x) >= 0) - -#define STBDS_HASH_EMPTY 0 -#define STBDS_HASH_DELETED 1 - -static size_t stbds_hash_seed=0x31415926; - -void stbds_rand_seed(size_t seed) -{ - stbds_hash_seed = seed; -} - -#define stbds_load_32_or_64(var, temp, v32, v64_hi, v64_lo) \ - temp = v64_lo ^ v32, temp <<= 16, temp <<= 16, temp >>= 16, temp >>= 16, /* discard if 32-bit */ \ - var = v64_hi, var <<= 16, var <<= 16, /* discard if 32-bit */ \ - var ^= temp ^ v32 - -#define STBDS_SIZE_T_BITS ((sizeof (size_t)) * 8) - -#define stbds_table_storage(t) ((stbds_hash_bucket *)(t->storage_offset ? (char *)t + t->storage_offset : 0)) - -static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_log2) -{ - (void)slot_log2; - size_t pos; - pos = hash & (slot_count-1); - #ifdef STBDS_INTERNAL_BUCKET_START - pos &= ~STBDS_BUCKET_MASK; - #endif - return pos; -} - -static size_t stbds_log2(size_t slot_count) -{ - size_t n=0; - while (slot_count > 1) { - slot_count >>= 1; - ++n; - } - return n; -} - -static stbds_hash_index *stbds_make_hash_index(size_t slot_count, stbds_hash_index *ot, Heap *heap) -{ - stbds_hash_index *t; - t = (stbds_hash_index *) STBDS_REALLOC(heap,0,(slot_count >> STBDS_BUCKET_SHIFT) * sizeof(stbds_hash_bucket) + sizeof(stbds_hash_index) + STBDS_CACHE_LINE_SIZE-1); - stbds_hash_bucket *t_storage = (stbds_hash_bucket *) STBDS_ALIGN_FWD((size_t) (t+1), STBDS_CACHE_LINE_SIZE); - t->storage_offset = (char *)t_storage - (char *)t; - t->slot_count = slot_count; - t->slot_count_log2 = stbds_log2(slot_count); - t->tombstone_count = 0; - t->used_count = 0; - - #if 0 // A1 - t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow - t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild - t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink - #elif 1 // A2 - //t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow - //t->tombstone_count_threshold = slot_count* 3/16; // if tombstones are 3/16th of table, rebuild - //t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink - - // compute without overflowing - t->used_count_threshold = slot_count - (slot_count>>2); - t->tombstone_count_threshold = (slot_count>>3) + (slot_count>>4); - t->used_count_shrink_threshold = slot_count >> 2; - - #elif 0 // B1 - t->used_count_threshold = slot_count*13/16; // if 13/16th of table is occupied, grow - t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild - t->used_count_shrink_threshold = slot_count* 5/16; // if table is only 5/16th full, shrink - #else // C1 - t->used_count_threshold = slot_count*14/16; // if 14/16th of table is occupied, grow - t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild - t->used_count_shrink_threshold = slot_count* 6/16; // if table is only 6/16th full, shrink - #endif - // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 - // Note that the larger tables have high variance as they were run fewer times - // A1 A2 B1 C1 - // 0.10ms : 0.10ms : 0.10ms : 0.11ms : 2,000 inserts creating 2K table - // 0.96ms : 0.95ms : 0.97ms : 1.04ms : 20,000 inserts creating 20K table - // 14.48ms : 14.46ms : 10.63ms : 11.00ms : 200,000 inserts creating 200K table - // 195.74ms : 196.35ms : 203.69ms : 214.92ms : 2,000,000 inserts creating 2M table - // 2193.88ms : 2209.22ms : 2285.54ms : 2437.17ms : 20,000,000 inserts creating 20M table - // 65.27ms : 53.77ms : 65.33ms : 65.47ms : 500,000 inserts & deletes in 2K table - // 72.78ms : 62.45ms : 71.95ms : 72.85ms : 500,000 inserts & deletes in 20K table - // 89.47ms : 77.72ms : 96.49ms : 96.75ms : 500,000 inserts & deletes in 200K table - // 97.58ms : 98.14ms : 97.18ms : 97.53ms : 500,000 inserts & deletes in 2M table - // 118.61ms : 119.62ms : 120.16ms : 118.86ms : 500,000 inserts & deletes in 20M table - // 192.11ms : 194.39ms : 196.38ms : 195.73ms : 500,000 inserts & deletes in 200M table - - if (slot_count <= STBDS_BUCKET_LENGTH) - t->used_count_shrink_threshold = 0; - // to avoid infinite loop, we need to guarantee that at least one slot is empty and will terminate probes - STBDS_ASSERT(t->used_count_threshold + t->tombstone_count_threshold < t->slot_count); - STBDS_STATS(++stbds_hash_alloc); - if (ot) { - t->string = ot->string; - // reuse old seed so we can reuse old hashes so below "copy out old data" doesn't do any hashing - t->seed = ot->seed; - } else { - size_t a,b,temp; - memset(&t->string, 0, sizeof(t->string)); - t->seed = stbds_hash_seed; - // LCG - // in 32-bit, a = 2147001325 b = 715136305 - // in 64-bit, a = 2862933555777941757 b = 3037000493 - stbds_load_32_or_64(a,temp, 2147001325, 0x27bb2ee6, 0x87b0b0fd); - stbds_load_32_or_64(b,temp, 715136305, 0, 0xb504f32d); - stbds_hash_seed = stbds_hash_seed * a + b; - } - - { - size_t i,j; - for (i=0; i < slot_count >> STBDS_BUCKET_SHIFT; ++i) { - stbds_hash_bucket *b = &stbds_table_storage(t)[i]; - for (j=0; j < STBDS_BUCKET_LENGTH; ++j) - b->hash[j] = STBDS_HASH_EMPTY; - for (j=0; j < STBDS_BUCKET_LENGTH; ++j) - b->index[j] = STBDS_INDEX_EMPTY; - } - } - - // copy out the old data, if any - if (ot) { - size_t i,j; - t->used_count = ot->used_count; - for (i=0; i < ot->slot_count >> STBDS_BUCKET_SHIFT; ++i) { - stbds_hash_bucket *ob = &stbds_table_storage(ot)[i]; - for (j=0; j < STBDS_BUCKET_LENGTH; ++j) { - if (STBDS_INDEX_IN_USE(ob->index[j])) { - size_t hash = ob->hash[j]; - size_t pos = stbds_probe_position(hash, t->slot_count, t->slot_count_log2); - size_t step = STBDS_BUCKET_LENGTH; - STBDS_STATS(++stbds_rehash_items); - for (;;) { - size_t limit,z; - stbds_hash_bucket *bucket; - bucket = &stbds_table_storage(t)[pos >> STBDS_BUCKET_SHIFT]; - STBDS_STATS(++stbds_rehash_probes); - - for (z=pos & STBDS_BUCKET_MASK; z < STBDS_BUCKET_LENGTH; ++z) { - if (bucket->hash[z] == 0) { - bucket->hash[z] = hash; - bucket->index[z] = ob->index[j]; - goto done; - } - } - - limit = pos & STBDS_BUCKET_MASK; - for (z = 0; z < limit; ++z) { - if (bucket->hash[z] == 0) { - bucket->hash[z] = hash; - bucket->index[z] = ob->index[j]; - goto done; - } - } - - pos += step; // quadratic probing - step += STBDS_BUCKET_LENGTH; - pos &= (t->slot_count-1); - } - } - done: - ; - } - } - } - - return t; -} - -#define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n)))) -#define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n)))) - -size_t stbds_hash_string(char *str, size_t seed) -{ - size_t hash = seed; - while (*str) - hash = STBDS_ROTATE_LEFT(hash, 9) + (unsigned char) *str++; - - // Thomas Wang 64-to-32 bit mix function, hopefully also works in 32 bits - hash ^= seed; - hash = (~hash) + (hash << 18); - hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,31); - hash = hash * 21; - hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,11); - hash += (hash << 6); - hash ^= STBDS_ROTATE_RIGHT(hash,22); - return hash+seed; -} - -#ifdef STBDS_SIPHASH_2_4 -#define STBDS_SIPHASH_C_ROUNDS 2 -#define STBDS_SIPHASH_D_ROUNDS 4 -typedef int STBDS_SIPHASH_2_4_can_only_be_used_in_64_bit_builds[sizeof(size_t) == 8 ? 1 : -1]; -#endif - -#ifndef STBDS_SIPHASH_C_ROUNDS -#define STBDS_SIPHASH_C_ROUNDS 1 -#endif -#ifndef STBDS_SIPHASH_D_ROUNDS -#define STBDS_SIPHASH_D_ROUNDS 1 -#endif - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4127) // conditional expression is constant, for do..while(0) and sizeof()== -#endif - -static size_t stbds_siphash_bytes(void *p, size_t len, size_t seed) -{ - unsigned char *d = (unsigned char *) p; - size_t i,j; - size_t v0,v1,v2,v3, data; - - // hash that works on 32- or 64-bit registers without knowing which we have - // (computes different results on 32-bit and 64-bit platform) - // derived from siphash, but on 32-bit platforms very different as it uses 4 32-bit state not 4 64-bit - v0 = ((((size_t) 0x736f6d65 << 16) << 16) + 0x70736575) ^ seed; - v1 = ((((size_t) 0x646f7261 << 16) << 16) + 0x6e646f6d) ^ ~seed; - v2 = ((((size_t) 0x6c796765 << 16) << 16) + 0x6e657261) ^ seed; - v3 = ((((size_t) 0x74656462 << 16) << 16) + 0x79746573) ^ ~seed; - - #ifdef STBDS_TEST_SIPHASH_2_4 - // hardcoded with key material in the siphash test vectors - v0 ^= 0x0706050403020100ull ^ seed; - v1 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; - v2 ^= 0x0706050403020100ull ^ seed; - v3 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; - #endif - - #define STBDS_SIPROUND() \ - do { \ - v0 += v1; v1 = STBDS_ROTATE_LEFT(v1, 13); v1 ^= v0; v0 = STBDS_ROTATE_LEFT(v0,STBDS_SIZE_T_BITS/2); \ - v2 += v3; v3 = STBDS_ROTATE_LEFT(v3, 16); v3 ^= v2; \ - v2 += v1; v1 = STBDS_ROTATE_LEFT(v1, 17); v1 ^= v2; v2 = STBDS_ROTATE_LEFT(v2,STBDS_SIZE_T_BITS/2); \ - v0 += v3; v3 = STBDS_ROTATE_LEFT(v3, 21); v3 ^= v0; \ - } while (0) - - for (i=0; i+sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) { - data = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); - data |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // discarded if size_t == 4 - - v3 ^= data; - for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) - STBDS_SIPROUND(); - v0 ^= data; - } - data = len << (STBDS_SIZE_T_BITS-8); - switch (len - i) { - case 7: data |= ((size_t) d[6] << 24) << 24; // fall through - case 6: data |= ((size_t) d[5] << 20) << 20; // fall through - case 5: data |= ((size_t) d[4] << 16) << 16; // fall through - case 4: data |= (d[3] << 24); // fall through - case 3: data |= (d[2] << 16); // fall through - case 2: data |= (d[1] << 8); // fall through - case 1: data |= d[0]; // fall through - case 0: break; - } - v3 ^= data; - for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) - STBDS_SIPROUND(); - v0 ^= data; - v2 ^= 0xff; - for (j=0; j < STBDS_SIPHASH_D_ROUNDS; ++j) - STBDS_SIPROUND(); - -#ifdef STBDS_SIPHASH_2_4 - return v0^v1^v2^v3; -#else - return v1^v2^v3; // slightly stronger since v0^v3 in above cancels out final round operation? I tweeted at the authors of SipHash about this but they didn't reply -#endif -} - -size_t stbds_hash_bytes(void *p, size_t len, size_t seed) -{ -#ifdef STBDS_SIPHASH_2_4 - return stbds_siphash_bytes(p,len,seed); -#else - unsigned char *d = (unsigned char *) p; - - if (len == 4) { - unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); - #if 0 - // HASH32-A Bob Jenkin's hash function w/o large constants - hash ^= seed; - hash -= (hash<<6); - hash ^= (hash>>17); - hash -= (hash<<9); - hash ^= seed; - hash ^= (hash<<4); - hash -= (hash<<3); - hash ^= (hash<<10); - hash ^= (hash>>15); - #elif 1 - // HASH32-BB Bob Jenkin's presumably-accidental version of Thomas Wang hash with rotates turned into shifts. - // Note that converting these back to rotates makes it run a lot slower, presumably due to collisions, so I'm - // not really sure what's going on. - hash ^= seed; - hash = (hash ^ 61) ^ (hash >> 16); - hash = hash + (hash << 3); - hash = hash ^ (hash >> 4); - hash = hash * 0x27d4eb2d; - hash ^= seed; - hash = hash ^ (hash >> 15); - #else // HASH32-C - Murmur3 - hash ^= seed; - hash *= 0xcc9e2d51; - hash = (hash << 17) | (hash >> 15); - hash *= 0x1b873593; - hash ^= seed; - hash = (hash << 19) | (hash >> 13); - hash = hash*5 + 0xe6546b64; - hash ^= hash >> 16; - hash *= 0x85ebca6b; - hash ^= seed; - hash ^= hash >> 13; - hash *= 0xc2b2ae35; - hash ^= hash >> 16; - #endif - // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 - // Note that the larger tables have high variance as they were run fewer times - // HASH32-A // HASH32-BB // HASH32-C - // 0.10ms // 0.10ms // 0.10ms : 2,000 inserts creating 2K table - // 0.96ms // 0.95ms // 0.99ms : 20,000 inserts creating 20K table - // 14.69ms // 14.43ms // 14.97ms : 200,000 inserts creating 200K table - // 199.99ms // 195.36ms // 202.05ms : 2,000,000 inserts creating 2M table - // 2234.84ms // 2187.74ms // 2240.38ms : 20,000,000 inserts creating 20M table - // 55.68ms // 53.72ms // 57.31ms : 500,000 inserts & deletes in 2K table - // 63.43ms // 61.99ms // 65.73ms : 500,000 inserts & deletes in 20K table - // 80.04ms // 77.96ms // 81.83ms : 500,000 inserts & deletes in 200K table - // 100.42ms // 97.40ms // 102.39ms : 500,000 inserts & deletes in 2M table - // 119.71ms // 120.59ms // 121.63ms : 500,000 inserts & deletes in 20M table - // 185.28ms // 195.15ms // 187.74ms : 500,000 inserts & deletes in 200M table - // 15.58ms // 14.79ms // 15.52ms : 200,000 inserts creating 200K table with varying key spacing - - return (((size_t) hash << 16 << 16) | hash) ^ seed; - } else if (len == 8 && sizeof(size_t) == 8) { - size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); - hash |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4 - hash ^= seed; - hash = (~hash) + (hash << 21); - hash ^= STBDS_ROTATE_RIGHT(hash,24); - hash *= 265; - hash ^= STBDS_ROTATE_RIGHT(hash,14); - hash ^= seed; - hash *= 21; - hash ^= STBDS_ROTATE_RIGHT(hash,28); - hash += (hash << 31); - hash = (~hash) + (hash << 18); - return hash; - } else { - return stbds_siphash_bytes(p,len,seed); - } -#endif -} -#ifdef _MSC_VER -#pragma warning(pop) -#endif - - -static int stbds_is_key_equal(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode, size_t i, Heap *heap) -{ - (void)keyoffset; - if (mode >= STBDS_HM_STRING) { - hermes::u64 heap_offset = *(hermes::u64 *) ((char *) a + elemsize*i); - hermes::u8 *heap_ptr = HeapOffsetToPtr(heap, (hermes::u32)heap_offset); - return 0==strcmp((char *) key, (char *)heap_ptr); - } - else - return 0==memcmp(key, (char *) a + elemsize*i, keysize); -} - -#define STBDS_HASH_TO_ARR(x,elemsize) ((char*) (x) - (elemsize)) -#define STBDS_ARR_TO_HASH(x,elemsize) ((char*) (x) + (elemsize)) - -#define stbds_hash_table(a) ((stbds_hash_index *) (stbds_header(a)->hash_table_offset ? (char *)stbds_header(a) + stbds_header(a)->hash_table_offset : 0)) - -void stbds_hmfree_func(void *a, size_t elemsize, Heap *heap) -{ - if (a == NULL) return; - if (stbds_hash_table(a) != NULL) { - if (stbds_hash_table(a)->string.mode == STBDS_SH_STRDUP) { - size_t i; - // skip 0th element, which is default - for (i=1; i < stbds_header(a)->length; ++i) { - hermes::u64 heap_offset = *(hermes::u64 *) ((char *) a + elemsize*i); - hermes::u8 *heap_ptr = HeapOffsetToPtr(heap, (hermes::u32)heap_offset); - STBDS_FREE(heap, heap_ptr); - } - } - stbds_strreset(&stbds_hash_table(a)->string, heap); - } - STBDS_FREE(heap, stbds_hash_table(a)); - STBDS_FREE(heap, stbds_header(a)); -} - -static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode, Heap *heap) -{ - void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); - stbds_hash_index *table = stbds_hash_table(raw_a); - size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); - size_t step = STBDS_BUCKET_LENGTH; - size_t limit,i; - size_t pos; - stbds_hash_bucket *bucket; - - if (hash < 2) hash += 2; // stored hash values are forbidden from being 0, so we can detect empty slots - - pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); - - for (;;) { - STBDS_STATS(++stbds_hash_probes); - bucket = &stbds_table_storage(table)[pos >> STBDS_BUCKET_SHIFT]; - - // start searching from pos to end of bucket, this should help performance on small hash tables that fit in cache - for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { - if (bucket->hash[i] == hash) { - if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i], heap)) { - return (pos & ~STBDS_BUCKET_MASK)+i; - } - } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { - return -1; - } - } - - // search from beginning of bucket to pos - limit = pos & STBDS_BUCKET_MASK; - for (i = 0; i < limit; ++i) { - if (bucket->hash[i] == hash) { - if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i], heap)) { - return (pos & ~STBDS_BUCKET_MASK)+i; - } - } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { - return -1; - } - } - - // quadratic probing - pos += step; - step += STBDS_BUCKET_LENGTH; - pos &= (table->slot_count-1); - } - /* NOTREACHED */ -} - -void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode, Heap *heap) -{ - size_t keyoffset = 0; - if (a == NULL) { - // make it non-empty so we can return a temp - a = stbds_arrgrowf(0, elemsize, 0, 1, heap); - stbds_header(a)->length += 1; - memset(a, 0, elemsize); - *temp = STBDS_INDEX_EMPTY; - // adjust a to point after the default element - return STBDS_ARR_TO_HASH(a,elemsize); - } else { - stbds_hash_index *table; - void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); - // adjust a to point to the default element - table = stbds_hash_table(raw_a); - if (table == 0) { - *temp = -1; - } else { - ptrdiff_t slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode, heap); - if (slot < 0) { - *temp = STBDS_INDEX_EMPTY; - } else { - stbds_hash_bucket *b = &stbds_table_storage(table)[slot >> STBDS_BUCKET_SHIFT]; - *temp = b->index[slot & STBDS_BUCKET_MASK]; - } - } - return a; - } -} - -void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode, Heap *heap) -{ - ptrdiff_t temp; - void *p = stbds_hmget_key_ts(a, elemsize, key, keysize, &temp, mode, heap); - stbds_temp(STBDS_HASH_TO_ARR(p,elemsize)) = temp; - return p; -} - -void * stbds_hmput_default(void *a, size_t elemsize, Heap *heap) -{ - // three cases: - // a is NULL <- allocate - // a has a hash table but no entries, because of shmode <- grow - // a has entries <- do nothing - if (a == NULL || stbds_header(STBDS_HASH_TO_ARR(a,elemsize))->length == 0) { - a = stbds_arrgrowf(a ? STBDS_HASH_TO_ARR(a,elemsize) : NULL, elemsize, 0, 1, heap); - stbds_header(a)->length += 1; - memset(a, 0, elemsize); - a=STBDS_ARR_TO_HASH(a,elemsize); - } - return a; -} - -static hermes::u64 stbds_strdup(char *str, Heap *heap); - -void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode, Heap *heap) -{ - size_t keyoffset=0; - void *raw_a; - stbds_hash_index *table; - - if (a == NULL) { - a = stbds_arrgrowf(0, elemsize, 0, 1, heap); - memset(a, 0, elemsize); - stbds_header(a)->length += 1; - // adjust a to point AFTER the default element - a = STBDS_ARR_TO_HASH(a,elemsize); - } - - // adjust a to point to the default element - raw_a = a; - a = STBDS_HASH_TO_ARR(a,elemsize); - - table = stbds_hash_table(a); - - if (table == NULL || table->used_count >= table->used_count_threshold) { - stbds_hash_index *nt; - size_t slot_count; - - slot_count = (table == NULL) ? STBDS_BUCKET_LENGTH : table->slot_count*2; - nt = stbds_make_hash_index(slot_count, table, heap); - if (table) - STBDS_FREE(heap, table); - else - nt->string.mode = mode >= STBDS_HM_STRING ? STBDS_SH_DEFAULT : 0; - table = nt; - stbds_header(a)->hash_table_offset = table ? (char *)table - (char *)stbds_header(a) : 0; - STBDS_STATS(++stbds_hash_grow); - } - - // we iterate hash table explicitly because we want to track if we saw a tombstone - { - size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); - size_t step = STBDS_BUCKET_LENGTH; - size_t limit,i; - size_t pos; - ptrdiff_t tombstone = -1; - stbds_hash_bucket *bucket; - - // stored hash values are forbidden from being 0, so we can detect empty slots to early out quickly - if (hash < 2) hash += 2; - - pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); - - for (;;) { - STBDS_STATS(++stbds_hash_probes); - bucket = &stbds_table_storage(table)[pos >> STBDS_BUCKET_SHIFT]; - - // start searching from pos to end of bucket - for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { - if (bucket->hash[i] == hash) { - if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i], heap)) { - stbds_temp(a) = bucket->index[i]; - return STBDS_ARR_TO_HASH(a,elemsize); - } - } else if (bucket->hash[i] == 0) { - pos = (pos & ~STBDS_BUCKET_MASK) + i; - goto found_empty_slot; - } else if (tombstone < 0) { - if (bucket->index[i] == STBDS_INDEX_DELETED) - tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); - } - } - - // search from beginning of bucket to pos - limit = pos & STBDS_BUCKET_MASK; - for (i = 0; i < limit; ++i) { - if (bucket->hash[i] == hash) { - if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i], heap)) { - stbds_temp(a) = bucket->index[i]; - return STBDS_ARR_TO_HASH(a,elemsize); - } - } else if (bucket->hash[i] == 0) { - pos = (pos & ~STBDS_BUCKET_MASK) + i; - goto found_empty_slot; - } else if (tombstone < 0) { - if (bucket->index[i] == STBDS_INDEX_DELETED) - tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); - } - } - - // quadratic probing - pos += step; - step += STBDS_BUCKET_LENGTH; - pos &= (table->slot_count-1); - } - found_empty_slot: - if (tombstone >= 0) { - pos = tombstone; - --table->tombstone_count; - } - ++table->used_count; - - { - ptrdiff_t i = (ptrdiff_t) stbds_arrlen(a); - // we want to do stbds_arraddn(1), but we can't use the macros since we don't have something of the right type - if ((size_t) i+1 > stbds_arrcap(a)) - *(void **) &a = stbds_arrgrowf(a, elemsize, 1, 0, heap); - raw_a = STBDS_ARR_TO_HASH(a,elemsize); - - STBDS_ASSERT((size_t) i+1 <= stbds_arrcap(a)); - stbds_header(a)->length = i+1; - bucket = &stbds_table_storage(table)[pos >> STBDS_BUCKET_SHIFT]; - bucket->hash[pos & STBDS_BUCKET_MASK] = hash; - bucket->index[pos & STBDS_BUCKET_MASK] = i-1; - stbds_temp(a) = i-1; - - switch (table->string.mode) { - case STBDS_SH_STRDUP: *(hermes::u64 *) ((char *) a + elemsize*i) = stbds_strdup((char*) key, heap); break; - case STBDS_SH_ARENA: *(char **) ((char *) a + elemsize*i) = stbds_stralloc(&table->string, (char*)key, heap); break; - case STBDS_SH_DEFAULT: *(char **) ((char *) a + elemsize*i) = (char *) key; break; - default: memcpy((char *) a + elemsize*i, key, keysize); break; - } - } - return STBDS_ARR_TO_HASH(a,elemsize); - } -} - -void * stbds_shmode_func(size_t elemsize, size_t capacity, int mode, Heap *heap) -{ - void *a = stbds_arrgrowf(0, elemsize, 0, capacity, heap); - stbds_hash_index *h; - memset(a, 0, elemsize); - stbds_header(a)->length = 1; - h = (stbds_hash_index *) stbds_make_hash_index(STBDS_BUCKET_LENGTH, NULL, heap); - stbds_header(a)->hash_table_offset = h ? (char *)h - (char *)stbds_header(a) : 0; - h->string.mode = (unsigned char) mode; - return STBDS_ARR_TO_HASH(a,elemsize); -} - -void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode, Heap *heap) -{ - if (a == NULL) { - return 0; - } else { - stbds_hash_index *table; - void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); - table = stbds_hash_table(raw_a); - stbds_temp(raw_a) = 0; - if (table == 0) { - return a; - } else { - ptrdiff_t slot; - slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode, heap); - if (slot < 0) - return a; - else { - stbds_hash_bucket *b = &stbds_table_storage(table)[slot >> STBDS_BUCKET_SHIFT]; - int i = slot & STBDS_BUCKET_MASK; - ptrdiff_t old_index = b->index[i]; - ptrdiff_t final_index = (ptrdiff_t) stbds_arrlen(raw_a)-1-1; // minus one for the raw_a vs a, and minus one for 'last' - STBDS_ASSERT(slot < (ptrdiff_t) table->slot_count); - --table->used_count; - ++table->tombstone_count; - stbds_temp(raw_a) = 1; - // STBDS_ASSERT(table->used_count >= 0); - //STBDS_ASSERT(table->tombstone_count < table->slot_count/4); - b->hash[i] = STBDS_HASH_DELETED; - b->index[i] = STBDS_INDEX_DELETED; - - if (mode == STBDS_HM_STRING && table->string.mode == STBDS_SH_STRDUP) { - hermes::u64 heap_offset = *(hermes::u64 *) ((char *) a + elemsize*old_index); - hermes::u8 *heap_ptr = hermes::HeapOffsetToPtr(heap, (hermes::u32)heap_offset); - STBDS_FREE(heap, heap_ptr); - } - - // if indices are the same, memcpy is a no-op, but back-pointer-fixup will fail, so skip - if (old_index != final_index) { - // swap delete - memmove((char*) a + elemsize*old_index, (char*) a + elemsize*final_index, elemsize); - - // now find the slot for the last element - if (mode == STBDS_HM_STRING) { - hermes::u64 heap_offset = *(hermes::u64 *) ((char *) a + elemsize*old_index + keyoffset); - hermes::u8 *heap_ptr = HeapOffsetToPtr(heap, (hermes::u32)heap_offset); - slot = stbds_hm_find_slot(a, elemsize, heap_ptr, keysize, keyoffset, mode, heap); - } - else - slot = stbds_hm_find_slot(a, elemsize, (char* ) a+elemsize*old_index + keyoffset, keysize, keyoffset, mode, heap); - STBDS_ASSERT(slot >= 0); - b = &stbds_table_storage(table)[slot >> STBDS_BUCKET_SHIFT]; - i = slot & STBDS_BUCKET_MASK; - STBDS_ASSERT(b->index[i] == final_index); - b->index[i] = old_index; - } - stbds_header(raw_a)->length -= 1; - - if (table->used_count < table->used_count_shrink_threshold && table->slot_count > STBDS_BUCKET_LENGTH) { - void *tmp = stbds_make_hash_index(table->slot_count>>1, table, heap); - stbds_header(raw_a)->hash_table_offset = tmp ? (char *)tmp - (char *)stbds_header(raw_a) : 0; - STBDS_FREE(heap, table); - STBDS_STATS(++stbds_hash_shrink); - } else if (table->tombstone_count > table->tombstone_count_threshold) { - void *tmp = stbds_make_hash_index(table->slot_count , table, heap); - stbds_header(raw_a)->hash_table_offset = tmp ? (char *)tmp - (char *)stbds_header(raw_a) : 0; - STBDS_FREE(heap, table); - STBDS_STATS(++stbds_hash_rebuild); - } - - return a; - } - } - } - /* NOTREACHED */ -} - -static hermes::u64 stbds_strdup(char *str, Heap *heap) -{ - // to keep replaceable allocator simple, we don't want to use strdup. - // rolling our own also avoids problem of strdup vs _strdup - size_t len = strlen(str)+1; - char *p = (char*) STBDS_REALLOC(heap, 0, len); - memmove(p, str, len); - - hermes::u64 result = hermes::GetHeapOffset(heap, (hermes::u8 *)p); - - return result; -} - -#ifndef STBDS_STRING_ARENA_BLOCKSIZE_MIN -#define STBDS_STRING_ARENA_BLOCKSIZE_MIN 512u -#endif -#ifndef STBDS_STRING_ARENA_BLOCKSIZE_MAX -#define STBDS_STRING_ARENA_BLOCKSIZE_MAX (1u<<20) -#endif - -char *stbds_stralloc(stbds_string_arena *a, char *str, Heap *heap) -{ - char *p; - size_t len = strlen(str)+1; - if (len > a->remaining) { - // compute the next blocksize - size_t blocksize = a->block; - - // size is 512, 512, 1024, 1024, 2048, 2048, 4096, 4096, etc., so that - // there are log(SIZE) allocations to free when we destroy the table - blocksize = (size_t) (STBDS_STRING_ARENA_BLOCKSIZE_MIN) << (blocksize>>1); - - // if size is under 1M, advance to next blocktype - if (blocksize < (size_t)(STBDS_STRING_ARENA_BLOCKSIZE_MAX)) - ++a->block; - - if (len > blocksize) { - // if string is larger than blocksize, then just allocate the full size. - // note that we still advance string_block so block size will continue - // increasing, so e.g. if somebody only calls this with 1000-long strings, - // eventually the arena will start doubling and handling those as well - stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(heap, 0, sizeof(*sb)-8 + len); - memmove(sb->storage, str, len); - if (a->storage) { - // insert it after the first element, so that we don't waste the space there - sb->next = a->storage->next; - a->storage->next = sb; - } else { - sb->next = 0; - a->storage = sb; - a->remaining = 0; // this is redundant, but good for clarity - } - return sb->storage; - } else { - stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(heap, 0, sizeof(*sb)-8 + blocksize); - sb->next = a->storage; - a->storage = sb; - a->remaining = blocksize; - } - } - - STBDS_ASSERT(len <= a->remaining); - p = a->storage->storage + a->remaining - len; - a->remaining -= len; - memmove(p, str, len); - return p; -} - -void stbds_strreset(stbds_string_arena *a, Heap *heap) -{ - stbds_string_block *x,*y; - x = a->storage; - while (x) { - y = x->next; - STBDS_FREE(heap, x); - x = y; - } - memset(a, 0, sizeof(*a)); -} - -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// UNIT TESTS -// - -#ifdef STBDS_UNIT_TESTS -#include -#ifdef STBDS_ASSERT_WAS_UNDEFINED -#undef STBDS_ASSERT -#endif -#ifndef STBDS_ASSERT -#define STBDS_ASSERT assert -#include -#endif - -typedef struct { int key,b,c,d; } stbds_struct; -typedef struct { int key[2],b,c,d; } stbds_struct2; - -static char buffer[256]; -char *strkey(int n) -{ -#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) - sprintf_s(buffer, sizeof(buffer), "test_%d", n); -#else - sprintf(buffer, "test_%d", n); -#endif - return buffer; -} - -struct TestIntMap { - int key; - int value; -}; - -struct TestStrMap { - char *key; - int value; -}; - -struct TestStbdsMap { - stbds_struct key; - int value; -}; - -void stbds_unit_tests(Heap *heap) -{ -#if defined(_MSC_VER) && _MSC_VER <= 1200 && defined(__cplusplus) - // VC6 C++ doesn't like the template<> trick on unnamed structures, so do nothing! - STBDS_ASSERT(0); -#else - const int testsize = 100000; - // const int testsize2 = testsize/20; - int *arr=NULL; - // struct { int key; int value; } *intmap = NULL; - // struct { char *key; int value; } *strmap = NULL; - struct TestIntMap *intmap = NULL; - struct TestStrMap *strmap = NULL; - struct TestStbdsMap *map = NULL; - stbds_struct *map2 = NULL; - stbds_struct2 *map3 = NULL; - // stbds_string_arena sa = { 0 }; - // int key3[2] = { 1,2 }; - ptrdiff_t temp; - - int i,j; - - STBDS_ASSERT(arrlen(arr)==0); - - for (i=0; i < 20000; i += 50) { - arrsetcap(arr, i + 1, heap); - for (j=0; j < i; ++j) - arrpush(arr,j, heap); - arrfree(arr, heap); - } - - for (i=0; i < 4; ++i) { - arrsetcap(arr, 4, heap); - arrpush(arr,1,heap); arrpush(arr,2,heap); arrpush(arr,3,heap); arrpush(arr,4,heap); - arrdel(arr,i); - arrfree(arr, heap); - arrsetcap(arr, 4, heap); - arrpush(arr,1,heap); arrpush(arr,2,heap); arrpush(arr,3,heap); arrpush(arr,4,heap); - arrdelswap(arr,i); - arrfree(arr, heap); - } - - for (i=0; i < 5; ++i) { - arrsetcap(arr, 5, heap); - arrpush(arr,1, heap); arrpush(arr,2, heap); arrpush(arr,3, heap); arrpush(arr,4, heap); - stbds_arrins(arr,i,5,heap); - STBDS_ASSERT(arr[i] == 5); - if (i < 4) - STBDS_ASSERT(arr[4] == 4); - arrfree(arr, heap); - } - - i = 1; - intmap = (struct TestIntMap *)stbds_arrgrowf(intmap, sizeof(*intmap), 0, testsize, heap); - intmap = (TestIntMap *)STBDS_ARR_TO_HASH(intmap, sizeof(TestIntMap)); - STBDS_ASSERT(hmgeti(intmap,i, heap) == -1); - hmdefault(intmap, -2, heap); - STBDS_ASSERT(hmgeti(intmap, i, heap) == -1); - STBDS_ASSERT(hmget (intmap, i, heap) == -2); - for (i=0; i < testsize; i+=2) - hmput(intmap, i, i*5, heap); - for (i=0; i < testsize; i+=1) { - if (i & 1) STBDS_ASSERT(hmget(intmap, i, heap) == -2 ); - else STBDS_ASSERT(hmget(intmap, i, heap) == i*5); - if (i & 1) STBDS_ASSERT(hmget_ts(intmap, i, temp, heap) == -2 ); - else STBDS_ASSERT(hmget_ts(intmap, i, temp, heap) == i*5); - if (i & 1) STBDS_ASSERT(hmgetp_null(intmap, i, heap) == NULL); - else STBDS_ASSERT(hmgetp_null(intmap, i, heap)); - } - for (i=0; i < testsize; i+=2) - hmput(intmap, i, i*3, heap); - for (i=0; i < testsize; i+=1) - if (i & 1) STBDS_ASSERT(hmget(intmap, i, heap) == -2 ); - else STBDS_ASSERT(hmget(intmap, i, heap) == i*3); - for (i=2; i < testsize; i+=4) - hmdel(intmap, i, heap); // delete half the entries - for (i=0; i < testsize; i+=1) - if (i & 3) STBDS_ASSERT(hmget(intmap, i, heap) == -2 ); - else STBDS_ASSERT(hmget(intmap, i, heap) == i*3); - for (i=0; i < testsize; i+=1) - hmdel(intmap, i, heap); // delete the rest of the entries - for (i=0; i < testsize; i+=1) - STBDS_ASSERT(hmget(intmap, i, heap) == -2 ); - hmfree(intmap, heap); - intmap = (struct TestIntMap *)stbds_arrgrowf(intmap, sizeof(*intmap), 0, testsize, heap); - intmap = (TestIntMap *)STBDS_ARR_TO_HASH(intmap, sizeof(TestIntMap)); - for (i=0; i < testsize; i+=2) - hmput(intmap, i, i*3, heap); - hmfree(intmap, heap); - - { - int val = 1; - int key = 0; - int nonexistent_key = -1; - hmdefault(intmap, -2, heap); - hmput(intmap, key, val, heap); - STBDS_ASSERT(hmget(intmap, key, heap) == val); - STBDS_ASSERT(hmgeti(intmap, key, heap) != -1); - TestIntMap *element = hmgetp_null(intmap, key, heap); - STBDS_ASSERT(element); - STBDS_ASSERT(element->value == val); - element = hmgetp_null(intmap, nonexistent_key, heap); - STBDS_ASSERT(element == NULL); - hmfree(intmap, heap); - } - - #if defined(__clang__) || defined(__GNUC__) - #ifndef __cplusplus - intmap = NULL; - hmput(intmap, 15, 7); - hmput(intmap, 11, 3); - hmput(intmap, 9, 5); - STBDS_ASSERT(hmget(intmap, 9) == 5); - STBDS_ASSERT(hmget(intmap, 11) == 3); - STBDS_ASSERT(hmget(intmap, 15) == 7); - #endif - #endif - - // for (i=0; i < testsize; ++i) - // stralloc(&sa, strkey(i), heap); - // strreset(&sa, heap); - - sh_new_strdup(strmap, testsize, heap); - // NOTE(chogan): Just testing sh_new_strdup - for (j=0; j < 1; ++j) { - STBDS_ASSERT(shgeti(strmap,"foo", heap) == -1); - // if (j == 0) - // sh_new_strdup(strmap, heap); - // else - // sh_new_arena(strmap, heap); - STBDS_ASSERT(shgeti(strmap,"foo", heap) == -1); - shdefault(strmap, -2, heap); - STBDS_ASSERT(shgeti(strmap,"foo", heap) == -1); - for (i=0; i < testsize; i+=2) - shput(strmap, strkey(i), i*3, heap); - for (i=0; i < testsize; i+=1) - if (i & 1) STBDS_ASSERT(shget(strmap, strkey(i), heap) == -2 ); - else STBDS_ASSERT(shget(strmap, strkey(i), heap) == i*3); - for (i=2; i < testsize; i+=4) - shdel(strmap, strkey(i), heap); // delete half the entries - for (i=0; i < testsize; i+=1) - if (i & 3) STBDS_ASSERT(shget(strmap, strkey(i), heap) == -2 ); - else STBDS_ASSERT(shget(strmap, strkey(i), heap) == i*3); - for (i=0; i < testsize; i+=1) - shdel(strmap, strkey(i), heap); // delete the rest of the entries - for (i=0; i < testsize; i+=1) - STBDS_ASSERT(shget(strmap, strkey(i), heap) == -2 ); - shfree(strmap, heap); - } - - { - struct { char *key; char value; } *hash = NULL; - sh_new_strdup(hash, 10, heap); - char name[4] = "jen"; - shput(hash, "bob" , 'h', heap); - shput(hash, "sally" , 'e', heap); - shput(hash, "fred" , 'l', heap); - shput(hash, "jen" , 'x', heap); - shput(hash, "doug" , 'o', heap); - - shput(hash, name , 'l', heap); - shfree(hash, heap); - } - - // NOTE(chogan): Preallocate map to avoid realloc - map = (TestStbdsMap *)stbds_arrgrowf(map, sizeof(*map), 0, testsize, heap); - map = (TestStbdsMap *)STBDS_ARR_TO_HASH(map, sizeof(*map)); - for (i=0; i < testsize; i += 2) { - stbds_struct s = { i,i*2,i*3,i*4 }; - hmput(map, s, i*5, heap); - } - - for (i=0; i < testsize; i += 1) { - stbds_struct s = { i,i*2,i*3 ,i*4 }; - // stbds_struct t = { i,i*2,i*3+1,i*4 }; - if (i & 1) STBDS_ASSERT(hmget(map, s, heap) == 0); - else STBDS_ASSERT(hmget(map, s, heap) == i*5); - if (i & 1) STBDS_ASSERT(hmget_ts(map, s, temp, heap) == 0); - else STBDS_ASSERT(hmget_ts(map, s, temp, heap) == i*5); - //STBDS_ASSERT(hmget(map, t.key) == 0); - } - hmfree(map, heap); - - map2 = (stbds_struct *)stbds_arrgrowf(map2, sizeof(*map2), 0, testsize, heap); - map2 = (stbds_struct *)STBDS_ARR_TO_HASH(map2, sizeof(*map2)); - for (i=0; i < testsize; i += 2) { - stbds_struct s = { i,i*2,i*3,i*4 }; - hmputs(map2, s, heap); - } - - for (i=0; i < testsize; i += 1) { - stbds_struct s = { i,i*2,i*3,i*4 }; - // stbds_struct t = { i,i*2,i*3+1,i*4 }; - if (i & 1) STBDS_ASSERT(hmgets(map2, s.key, heap).d == 0); - else STBDS_ASSERT(hmgets(map2, s.key, heap).d == i*4); - //STBDS_ASSERT(hmgetp(map2, t.key) == 0); - } - hmfree(map2, heap); - - map3 = (stbds_struct2 *)stbds_arrgrowf(map3, sizeof(*map3), 0, testsize, heap); - map3 = (stbds_struct2 *)STBDS_ARR_TO_HASH(map3, sizeof(*map3)); - for (i=0; i < testsize; i += 2) { - stbds_struct2 s = { { i,i*2 }, i*3,i*4, i*5 }; - hmputs(map3, s, heap); - } - for (i=0; i < testsize; i += 1) { - stbds_struct2 s = { { i,i*2}, i*3, i*4, i*5 }; - // stbds_struct2 t = { { i,i*2}, i*3+1, i*4, i*5 }; - if (i & 1) STBDS_ASSERT(hmgets(map3, s.key, heap).d == 0); - else STBDS_ASSERT(hmgets(map3, s.key, heap).d == i*5); - //STBDS_ASSERT(hmgetp(map3, t.key) == 0); - } -#endif -} -#endif - - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2019 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/ diff --git a/test/stb_map_test.cc b/test/stb_map_test.cc deleted file mode 100644 index fd6602c3f..000000000 --- a/test/stb_map_test.cc +++ /dev/null @@ -1,58 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -#include - -#include "test_utils.h" - -#define STBDS_ASSERT(x) Assert((x)) - -#define STBDS_REALLOC(heap, ptr, size) hermes::HeapRealloc(heap, ptr, size) -#define STBDS_FREE(heap, ptr) hermes::HeapFree(heap, ptr) - -#define STBDS_UNIT_TESTS -#define STB_DS_IMPLEMENTATION -#include "stb_ds.h" - -using namespace hermes; // NOLINT(*) -namespace hapi = hermes::api; - -int main(int argc, char** argv) { - MPI_Init(&argc, &argv); - -#if HERMES_DEBUG_HEAP - std::shared_ptr hermes = InitHermesDaemon(); -#endif - - Arena arena = InitArenaAndAllocate(MEGABYTES(64)); - TemporaryMemory temp_memory = BeginTemporaryMemory(&arena); - Heap *heap = InitHeapInArena(&arena, true, 8); - stbds_unit_tests(heap); - EndTemporaryMemory(&temp_memory); - - temp_memory = BeginTemporaryMemory(&arena); - Heap *reverse_heap = InitHeapInArena(&arena, false, 8); - stbds_unit_tests(reverse_heap); - EndTemporaryMemory(&temp_memory); - - DestroyArena(&arena); - -#if HERMES_DEBUG_HEAP - hermes->Finalize(true); -#endif - - MPI_Finalize(); - - return 0; -} From cc52ab3fa0be4ed6c22651d961aa74d64ca97899 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 30 Nov 2022 17:33:06 -0600 Subject: [PATCH 029/511] CommunicationFactory + RpcFactory + begin borg --- src/api/hermes.cc | 157 ++++--- src/api/hermes.h | 13 +- src/buffer_organizer.cc | 4 +- src/buffer_organizer.h | 78 +--- src/buffer_pool.h | 18 - src/communication.h | 17 +- src/communication_factory.h | 34 ++ src/communication_mpi.cc | 423 +++++++++---------- src/rpc.h | 92 +++-- src/rpc_factory.h | 37 ++ src/rpc_thallium.cc | 786 ++++++++++++++++-------------------- src/rpc_thallium.h | 172 ++++---- 12 files changed, 872 insertions(+), 959 deletions(-) create mode 100644 src/communication_factory.h create mode 100644 src/rpc_factory.h diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 31df9420b..3d8ef1fdb 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -26,6 +26,8 @@ #include "config_parser.h" #include "prefetcher.h" #include "singleton.h" +#include "communication_factory.h" +#include "rpc_factory.h" namespace hermes { @@ -147,40 +149,6 @@ void Hermes::RunDaemon() { } // namespace api -/** get arena information from \a config configuration */ -ArenaInfo GetArenaInfo(Config *config) { - size_t page_size = sysconf(_SC_PAGESIZE); - // NOTE(chogan): Assumes first Device is RAM - size_t total_hermes_memory = RoundDownToMultiple(config->capacities[0], - page_size); - size_t total_pages = total_hermes_memory / page_size; - size_t pages_left = total_pages; - - ArenaInfo result = {}; - - for (int i = kArenaType_Count - 1; i > kArenaType_BufferPool; --i) { - size_t desired_pages = - std::floor(config->arena_percentages[i] * total_pages); - // NOTE(chogan): Each arena gets 1 page at minimum - size_t pages = std::max(desired_pages, 1UL); - pages_left -= pages; - size_t num_bytes = pages * page_size; - result.sizes[i] = num_bytes; - result.total += num_bytes; - } - - if (pages_left == 0) { - // TODO(chogan): @errorhandling - HERMES_NOT_IMPLEMENTED_YET; - } - - // NOTE(chogan): BufferPool Arena gets remainder of pages - result.sizes[kArenaType_BufferPool] = pages_left * page_size; - result.total += result.sizes[kArenaType_BufferPool]; - - return result; -} - /** get hosts from \a host_file file */ std::vector GetHostsFromFile(const std::string &host_file) { std::vector result; @@ -270,36 +238,6 @@ SharedMemoryContext InitHermesCore(Config *config, CommunicationContext *comm, return context; } -/** boostrap shared memory */ -SharedMemoryContext -BootstrapSharedMemory(Arena *arenas, Config *config, CommunicationContext *comm, - RpcContext *rpc, bool is_daemon, bool is_adapter) { - size_t bootstrap_size = KILOBYTES(4); - u8 *bootstrap_memory = (u8 *)malloc(bootstrap_size); - InitArena(&arenas[kArenaType_Transient], bootstrap_size, bootstrap_memory); - - ArenaInfo arena_info = GetArenaInfo(config); - // NOTE(chogan): The buffering capacity for the RAM Device is the size of the - // BufferPool Arena - config->capacities[0] = arena_info.sizes[kArenaType_BufferPool]; - size_t trans_arena_size = - InitCommunication(comm, &arenas[kArenaType_Transient], - arena_info.sizes[kArenaType_Transient], is_daemon, - is_adapter); - - GrowArena(&arenas[kArenaType_Transient], trans_arena_size); - comm->state = arenas[kArenaType_Transient].base; - - InitRpcContext(rpc, comm->num_nodes, comm->node_id, config); - - SharedMemoryContext result = {}; - if (comm->proc_kind == ProcessKind::kHermes && comm->first_on_node) { - result = InitHermesCore(config, comm, &arena_info, arenas, rpc); - } - - return result; -} - // TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 #if 0 static void InitGlog() { @@ -317,8 +255,58 @@ static void InitGlog() { } #endif -std::shared_ptr InitHermes(Config *config, bool is_daemon, - bool is_adapter) { +namespace api { + +/** get arena information from \a config configuration */ +ArenaInfo GetArenaInfo(Config *config) { + size_t page_size = sysconf(_SC_PAGESIZE); + // NOTE(chogan): Assumes first Device is RAM + size_t total_hermes_memory = RoundDownToMultiple(config->capacities[0], + page_size); + size_t total_pages = total_hermes_memory / page_size; + size_t pages_left = total_pages; + + ArenaInfo result = {}; + + for (int i = kArenaType_Count - 1; i > kArenaType_BufferPool; --i) { + size_t desired_pages = + std::floor(config->arena_percentages[i] * total_pages); + // NOTE(chogan): Each arena gets 1 page at minimum + size_t pages = std::max(desired_pages, 1UL); + pages_left -= pages; + size_t num_bytes = pages * page_size; + result.sizes[i] = num_bytes; + result.total += num_bytes; + } + + if (pages_left == 0) { + // TODO(chogan): @errorhandling + HERMES_NOT_IMPLEMENTED_YET; + } + + // NOTE(chogan): BufferPool Arena gets remainder of pages + result.sizes[kArenaType_BufferPool] = pages_left * page_size; + result.total += result.sizes[kArenaType_BufferPool]; + + return result; +} + +/** boostrap shared memory */ +void Hermes::BootstrapSharedMemory(bool is_daemon, bool is_adapter) { + ArenaInfo arena_info = GetArenaInfo(config); + // NOTE(chogan): The buffering capacity for the RAM Device is the size of the + // BufferPool Arena + config_->capacities[0] = arena_info.sizes[kArenaType_BufferPool]; + InitRpcContext(rpc, comm->num_nodes, comm->node_id, config); + + SharedMemoryContext result = {}; + if (comm->proc_kind == ProcessKind::kHermes && comm->first_on_node) { + result = InitHermesCore(config, comm, &arena_info, arenas, rpc); + } +} + +Hermes::Hermes(Config *config, bool is_daemon, bool is_adapter) : + config_(config) { // TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 // InitGlog(); @@ -327,13 +315,12 @@ std::shared_ptr InitHermes(Config *config, bool is_daemon, // TODO(chogan): Do we need a transfer window arena? We can probably just use // the transient arena for this. - Arena arenas[kArenaType_Count] = {}; - CommunicationContext comm = {}; - RpcContext rpc = {}; + comm_ = CommunicationFactory::Get(CommunicationType::kMpi); SharedMemoryContext context = - BootstrapSharedMemory(arenas, config, &comm, &rpc, is_daemon, is_adapter); + BootstrapSharedMemory(config, is_daemon, is_adapter); + rpc_ = RpcFactory::Get(RpcType::kThallium); - WorldBarrier(&comm); + WorldBarrier(comm_); std::shared_ptr result = nullptr; if (comm.proc_kind == ProcessKind::kHermes) { @@ -348,7 +335,7 @@ std::shared_ptr InitHermes(Config *config, bool is_daemon, MetadataManager *mdm = GetMetadataManagerFromContext(&context); rpc.state = (void *)(context.shm_base + mdm->rpc_state_offset); rpc.host_names = - (ShmemString *)((u8 *)context.shm_base + mdm->host_names_offset); + (ShmemString *)((u8 *)context.shm_base + mdm->host_names_offset); } InitFilesForBuffering(&context, comm); @@ -358,7 +345,6 @@ std::shared_ptr InitHermes(Config *config, bool is_daemon, rpc.node_id = comm.node_id; rpc.num_nodes = comm.num_nodes; - result->trans_arena_ = arenas[kArenaType_Transient]; result->comm_ = comm; result->context_ = context; result->rpc_ = rpc; @@ -368,15 +354,15 @@ std::shared_ptr InitHermes(Config *config, bool is_daemon, // Hermes instance. if (comm.proc_kind == ProcessKind::kHermes) { std::string rpc_server_addr = - GetRpcAddress(&result->rpc_, config, result->rpc_.node_id, - config->rpc_port); + result->rpc_.GetRpcAddress(config, result->rpc_.node_id, + config->rpc_port); std::string bo_address = - GetRpcAddress(&result->rpc_, config, result->rpc_.node_id, - config->buffer_organizer_port); + result->rpc_.GetRpcAddress(config, result->rpc_.node_id, + config->buffer_organizer_port); - result->rpc_.start_server(&result->context_, &result->rpc_, - &result->trans_arena_, rpc_server_addr.c_str(), - config->rpc_num_threads); + result->rpc_.StartServer(&result->context_, &result->rpc_, + &result->trans_arena_, rpc_server_addr.c_str(), + config->rpc_num_threads); StartBufferOrganizer(&result->context_, &result->rpc_, &result->trans_arena_, bo_address.c_str(), @@ -395,7 +381,7 @@ std::shared_ptr InitHermes(Config *config, bool is_daemon, WorldBarrier(&comm); api::Context::default_buffer_organizer_retries = - config->num_buffer_organizer_retries; + config->num_buffer_organizer_retries; api::Context::default_placement_policy = config->default_placement_policy; api::Context::default_rr_split = config->default_rr_split; RoundRobin::InitDevices(config, result); @@ -413,8 +399,6 @@ std::shared_ptr InitHermes(Config *config, bool is_daemon, return result; } -namespace api { - std::shared_ptr InitHermes(const char *config_file, bool is_daemon, bool is_adapter) { u16 endian_test = 0x1; @@ -436,9 +420,14 @@ std::shared_ptr InitHermes(const char *config_file, bool is_daemon, } // namespace api +std::shared_ptr InitHermes(Config *config, bool is_daemon, + bool is_adapter) { + return std::make_shared(config, is_daemon, is_adapter); +} + std::shared_ptr InitHermesClient(const char *config_file) { std::shared_ptr result = - api::InitHermes(config_file, false, true); + api::InitHermes(config_file, false, true); return result; } diff --git a/src/api/hermes.h b/src/api/hermes.h index cba50d614..d2fe2c7b6 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -50,10 +50,10 @@ class Hermes { bool is_initialized; // TODO(chogan): Temporarily public to facilitate iterative development. + Config *config_; hermes::SharedMemoryContext context_; /**< shared memory context */ - hermes::CommunicationContext comm_; /**< communication context */ - hermes::RpcContext rpc_; /**< remote procedure call context */ - hermes::Arena trans_arena_; /**< arena backed by allocated memory. */ + std::unique_ptr comm_; /**< communication context */ + std::unique_ptr rpc_; /**< remote procedure call context */ /** The name of the shared memory segment in which all Hermes data is * stored. */ @@ -64,9 +64,10 @@ class Hermes { Hermes() {} /** - Constructor - */ - explicit Hermes(SharedMemoryContext context) : context_(context) {} + * Constructor + * */ + + Hermes(Config *config, bool is_daemon, bool is_adapter); /** \brief Return \bool{this rank is an application core} * diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 9e6ebb112..4dfa2e015 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -21,8 +21,8 @@ namespace hermes { -BufferOrganizer::BufferOrganizer(int num_threads) : pool(num_threads) { -} +BufferOrganizer::BufferOrganizer(int num_threads) : + pool(num_threads) {} bool operator==(const BufferInfo &lhs, const BufferInfo &rhs) { return (lhs.id == rhs.id && lhs.size == rhs.size && diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index ea806548b..18d1bd4a9 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -80,78 +80,20 @@ bool operator==(const BufferInfo &lhs, const BufferInfo &rhs); /** A structure to represent buffer organizer */ -struct BufferOrganizer { +class BufferOrganizer { + public: + SharedMemoryContext *context_; + RpcContext *rpc_; ThreadPool pool; /**< a pool of threads */ + + public: /** initialize buffer organizer with \a num_threads number of threads. */ - explicit BufferOrganizer(int num_threads); + explicit BufferOrganizer(SharedMemoryContext *context, + RpcContext *rpc, int num_threads); + + }; -/** enqueue flushing task locally */ -bool LocalEnqueueFlushingTask(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id, const std::string &filename, - u64 offset); -/** enqueue flushing task */ -bool EnqueueFlushingTask(RpcContext *rpc, BlobID blob_id, - const std::string &filename, u64 offset); - -void BoMove(SharedMemoryContext *context, RpcContext *rpc, - const BoMoveList &moves, BlobID blob_id, BucketID bucket_id, - const std::string &internal_blob_name); -void FlushBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id, - const std::string &filename, u64 offset, bool async = false); -/** shut down buffer organizer locally */ -void LocalShutdownBufferOrganizer(SharedMemoryContext *context); -/** increment flush count */ -void IncrementFlushCount(SharedMemoryContext *context, RpcContext *rpc, - const std::string &vbkt_name); -/** decrement flush count */ -void DecrementFlushCount(SharedMemoryContext *context, RpcContext *rpc, - const std::string &vbkt_name); -/** increment flush count locally */ -void LocalIncrementFlushCount(SharedMemoryContext *context, - const std::string &vbkt_name); -/** decrement flush count locally */ -void LocalDecrementFlushCount(SharedMemoryContext *context, - const std::string &vbkt_name); -/** await asynchronous flushing tasks */ -void AwaitAsyncFlushingTasks(SharedMemoryContext *context, RpcContext *rpc, - VBucketID id); -/** organize BLOB locally */ -void LocalOrganizeBlob(SharedMemoryContext *context, RpcContext *rpc, - const std::string &internal_blob_name, - BucketID bucket_id, f32 epsilon, - f32 explicit_importance_score); -/** organize BLOB */ -void OrganizeBlob(SharedMemoryContext *context, RpcContext *rpc, - BucketID bucket_id, const std::string &blob_name, f32 epsilon, - f32 importance_score = -1); -/** organize device */ -void OrganizeDevice(SharedMemoryContext *context, RpcContext *rpc, - DeviceID devices_id); - -/** get buffer information */ -std::vector GetBufferInfo(SharedMemoryContext *context, - RpcContext *rpc, - const std::vector &buffer_ids); -/** compute BLOB access score */ -f32 ComputeBlobAccessScore(SharedMemoryContext *context, - const std::vector &buffer_info); -/** enqueue buffer organizer move list locally */ -void LocalEnqueueBoMove(SharedMemoryContext *context, RpcContext *rpc, - const BoMoveList &moves, BlobID blob_id, - BucketID bucket_id, - const std::string &internal_blob_name, - BoPriority priority); -/** enqueue buffer organizer move list */ -void EnqueueBoMove(RpcContext *rpc, const BoMoveList &moves, BlobID blob_id, - BucketID bucket_id, const std::string &internal_name, - BoPriority priority); -/** enforce capacity threholds */ -void EnforceCapacityThresholds(SharedMemoryContext *context, RpcContext *rpc, - ViolationInfo info); -/** enforce capacity threholds locally */ -void LocalEnforceCapacityThresholds(SharedMemoryContext *context, - RpcContext *rpc, ViolationInfo info); } // namespace hermes #endif // HERMES_BUFFER_ORGANIZER_H_ diff --git a/src/buffer_pool.h b/src/buffer_pool.h index 618ef55f8..12cdb3710 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -272,14 +272,10 @@ struct BufferOrganizer; A structure to represent shared memory context */ struct SharedMemoryContext { - /** A pointer to the beginning of shared memory. */ - u8 *shm_base; /** The offset from the beginning of shared memory to the BufferPool. */ ptrdiff_t buffer_pool_offset; /** The offset from the beginning of shared memory to the Metadata Arena. */ ptrdiff_t metadata_manager_offset; - /** The total size of the shared memory (needed for munmap). */ - u64 shm_size; /** This will only be valid on Hermes cores, and NULL on client cores. */ BufferOrganizer *bo; @@ -335,20 +331,6 @@ void MakeFullShmemName(char *dest, const char *base); void InitFilesForBuffering(SharedMemoryContext *context, CommunicationContext &comm); -/** - * Retrieves information required for accessing the BufferPool shared memory. - * - * Maps an existing shared memory segment into the calling process's address - * space. Application cores will call this function, and the Hermes core - * initialization will have already created the shared memory segment. - * Application cores can then use the context to access the BufferPool. - * - * @param shmem_name The name of the shared memory segment. - * - * @return The shared memory context required to access the BufferPool. - */ -SharedMemoryContext GetSharedMemoryContext(char *shmem_name); - /** * Unmaps the shared memory represented by context and closes any open file * descriptors diff --git a/src/communication.h b/src/communication.h index 14e2bfb79..dbbd969d9 100644 --- a/src/communication.h +++ b/src/communication.h @@ -25,19 +25,22 @@ namespace hermes { -typedef void (*BarrierFunc)(void *); /**< MPI barrier function pointer */ -typedef void (*FinalizeFunc)(void *); /**< MPI finalize function pointer */ +/** + * The type of communicator + * */ + +enum class CommunicationType { + kMpi +}; /** A structure to represent MPI communication context */ struct CommunicationContext { - BarrierFunc world_barrier; /**< MPI communication world barrier */ - BarrierFunc sub_barrier; /**< MPI communication subset barrier */ - FinalizeFunc finalize; /**< MPI communication finalize */ + virtual void WorldBarrier() = 0; /** E.g., MPI_Barrier(MPI_COMM_WORLD)*/ + virtual void SubBarrier() = 0; /** E.g., MPI_Barrier(something else)*/ + virtual void Finalize() = 0; /** E.g., MPI_Finalize() */ - /** Details relative to the backing communciation implementation. */ - void *state; /** A unique identifier for each rank, relative to all ranks. */ i32 world_proc_id; /** a unique identifier for each rank, releative to each ProcessKind. */ diff --git a/src/communication_factory.h b/src/communication_factory.h new file mode 100644 index 000000000..d5ea87ae4 --- /dev/null +++ b/src/communication_factory.h @@ -0,0 +1,34 @@ +// +// Created by lukemartinlogan on 11/30/22. +// + +#ifndef HERMES_SRC_RPC_FACTORY_H_ +#define HERMES_SRC_RPC_FACTORY_H_ + +#include "communication.h" +#include "communication_mpi.cc" +#include + +namespace hermes { +class CommunicationFactory { + public: + /** + * Return an RPC. Uses factory pattern. + * + * @param type, RpcType, type of mapper to be used by the STDIO adapter. + * @return Instance of RPC given a type. + */ + static std::unique_ptr Get( + const CommunicationType &type) { + switch (type) { + case CommunicationType::kMpi: { + return std::make_unique(); + } + default: + return nullptr; + } + } +}; +} // namespace hermes + +#endif // HERMES_SRC_RPC_FACTORY_H_ diff --git a/src/communication_mpi.cc b/src/communication_mpi.cc index 2e6de6b5d..3fb2e64a6 100644 --- a/src/communication_mpi.cc +++ b/src/communication_mpi.cc @@ -20,280 +20,241 @@ namespace hermes { -/** - A structure to represent MPI state -*/ -struct MPIState { +class MpiCommunicator : public CommunicationContext { + public: MPI_Comm world_comm; /**< MPI world communicator */ /** This communicator is in one of two groups, depending on the value of the * rank's ProcessKind. When its kHermes, sub_comm groups all Hermes cores, and * when its kApp, it groups all application cores. */ MPI_Comm sub_comm; -}; - -/** - get the application's communicator -*/ -void *GetAppCommunicator(CommunicationContext *comm) { - MPIState *mpi_state = (MPIState *)comm->state; - - return &mpi_state->sub_comm; -} - -/** - get the MPI process ID of \a comm MPI communicator. -*/ -inline int MpiGetProcId(MPI_Comm comm) { - int result; - MPI_Comm_rank(comm, &result); - return result; -} -/** - get the MPI process ID of MPI world communicator from \a state MPIState. -*/ -inline int MpiGetWorldProcId(void *state) { - MPIState *mpi_state = (MPIState *)state; - int result = MpiGetProcId(mpi_state->world_comm); - - return result; -} - -/** - get the MPI process ID of MPI sub-communicator from \a state MPIState. -*/ -inline int MpiGetSubProcId(void *state) { - MPIState *mpi_state = (MPIState *)state; - int result = MpiGetProcId(mpi_state->sub_comm); - - return result; -} + public: + /** + * get the MPI process ID of \a comm MPI communicator. + */ + inline int GetProcId(MPI_Comm comm) { + int result; + MPI_Comm_rank(comm, &result); + return result; + } -/** - get the number of MPI processes of \a comm MPI communicator. + /** + get the MPI process ID of MPI world communicator from \a MPI. */ -inline int MpiGetNumProcs(MPI_Comm comm) { - int result; - MPI_Comm_size(comm, &result); + inline int GetWorldProcId() { + int result = GetProcId(world_comm); + return result; + } - return result; -} + /** + get the MPI process ID of MPI sub-communicator from \a MPI. + */ + inline int GetSubProcId() { + int result = GetProcId(sub_comm); + return result; + } -/** - get the number of MPI processes of MPI world communicator. -*/ -inline int MpiGetNumWorldProcs(void *state) { - MPIState *mpi_state = (MPIState *)state; - int result = MpiGetNumProcs(mpi_state->world_comm); + /** + get the number of MPI processes of \a comm MPI communicator. + */ + inline int GetNumProcs(MPI_Comm comm) { + int result; + MPI_Comm_size(comm, &result); + return result; + } - return result; -} + /** + get the number of MPI processes of MPI world communicator. + */ + inline int GetNumWorldProcs() { + return GetNumProcs(world_comm); + } -/** - a wrapper for MPI_Barrier() fucntion -*/ -inline void MpiBarrier(MPI_Comm comm) { - MPI_Barrier(comm); -} + /** + a wrapper for MPI_Barrier() fucntion + */ + inline void Barrier(MPI_Comm comm) { + MPI_Barrier(comm); + } -/** - a wrapper for MPI global communicator's MPI_Barrier() function -*/ -inline void MpiWorldBarrier(void *state) { - MPIState *mpi_state = (MPIState *)state; - MpiBarrier(mpi_state->world_comm); -} + /** + a wrapper for MPI global communicator's MPI_Barrier() function + */ + inline void WorldBarrier() override { + Barrier(world_comm); + } -/** - a wrapper for MPI sub-communicator's MPI_Barrier() function -*/ -inline void MpiSubBarrier(void *state) { - MPIState *mpi_state = (MPIState *)state; - MpiBarrier(mpi_state->sub_comm); -} + /** + a wrapper for MPI sub-communicator's MPI_Barrier() function + */ + inline void SubBarrier() override { + Barrier(sub_comm); + } -/** + /** * Returns true if the calling rank is the lowest numbered rank on its node in * communicator @p comm. - */ -bool MpiFirstOnNode(MPI_Comm comm) { - int rank = MpiGetProcId(comm); - int size = MpiGetNumProcs(comm); - - size_t scratch_size = (size * sizeof(char *) + - size * sizeof(char) * MPI_MAX_PROCESSOR_NAME); - u8 *scratch_memory = (u8 *)malloc(scratch_size); - Arena scratch_arena = {}; - InitArena(&scratch_arena, scratch_size, scratch_memory); - - char **node_names = PushArray(&scratch_arena, size); - for (int i = 0; i < size; ++i) { - node_names[i] = PushArray(&scratch_arena, MPI_MAX_PROCESSOR_NAME); - } - - int length; - MPI_Get_processor_name(node_names[rank], &length); + */ + bool FirstOnNode(MPI_Comm comm) { + int rank = GetProcId(comm); + int size = GetNumProcs(comm); + + // TODO(llogan): arena -> labstor allocator + size_t scratch_size = (size * sizeof(char *) + + size * sizeof(char) * MPI_MAX_PROCESSOR_NAME); + std::vector node_names(size); + for (size_t i = 0; i < size; ++i) { + node_names[i] = new char[MPI_MAX_PROCESSOR_NAME]; + } - MPI_Allgather(MPI_IN_PLACE, 0, 0, node_names[0], MPI_MAX_PROCESSOR_NAME, - MPI_CHAR, comm); + int length; + MPI_Get_processor_name(node_names[rank], &length); - int first_on_node = 0; - while (strncmp(node_names[rank], node_names[first_on_node], - MPI_MAX_PROCESSOR_NAME) != 0) { - first_on_node++; - } + MPI_Allgather(MPI_IN_PLACE, 0, 0, node_names[0], MPI_MAX_PROCESSOR_NAME, + MPI_CHAR, comm); - DestroyArena(&scratch_arena); + int first_on_node = 0; + while (strncmp(node_names[rank], node_names[first_on_node], + MPI_MAX_PROCESSOR_NAME) != 0) { + first_on_node++; + } - bool result = false; + bool result = false; + if (first_on_node == rank) { + result = true; + } - if (first_on_node == rank) { - result = true; + return result; } - return result; -} - -/** + /** * Assigns each node an ID and returns the size in bytes of the transient arena * for the calling rank. - */ -size_t MpiAssignIDsToNodes(CommunicationContext *comm, - size_t trans_arena_size_per_node) { - int rank = comm->world_proc_id; - int size = comm->world_size; - - size_t scratch_size = (size * sizeof(char *) + - size * sizeof(char) * MPI_MAX_PROCESSOR_NAME); - - Arena scratch_arena = InitArenaAndAllocate(scratch_size); - - char **node_names = PushArray(&scratch_arena, size); - for (int i = 0; i < size; ++i) { - node_names[i] = PushArray(&scratch_arena, MPI_MAX_PROCESSOR_NAME); - } + */ + size_t AssignIDsToNodes(size_t trans_arena_size_per_node) { + int rank = world_proc_id; + int size = world_size; + + // TODO(llogan): arena -> labstor allocator + size_t scratch_size = (size * sizeof(char *) + + size * sizeof(char) * MPI_MAX_PROCESSOR_NAME); + std::vector node_names; + node_names.resize(size); + for (size_t i = 0; i < size; ++i) { + node_names[i] = new char[MPI_MAX_PROCESSOR_NAME]; + } - int length; - MPI_Get_processor_name(node_names[rank], &length); + int length; + MPI_Get_processor_name(node_names[rank], &length); - MPIState *mpi_state = (MPIState *)comm->state; - MPI_Allgather(MPI_IN_PLACE, 0, 0, node_names[0], MPI_MAX_PROCESSOR_NAME, - MPI_CHAR, mpi_state->world_comm); + MPI_Allgather(MPI_IN_PLACE, 0, 0, node_names[0], MPI_MAX_PROCESSOR_NAME, + MPI_CHAR, world_comm); - // NOTE(chogan): Assign the first rank on each node to be the process that - // runs the Hermes core. The other ranks become application cores. - int first_on_node = 0; - while (strncmp(node_names[rank], node_names[first_on_node], - MPI_MAX_PROCESSOR_NAME) != 0) { - first_on_node++; - } + // NOTE(chogan): Assign the first rank on each node to be the process that + // runs the Hermes core. The other ranks become application cores. + int first_on_node = 0; + while (strncmp(node_names[rank], node_names[first_on_node], + MPI_MAX_PROCESSOR_NAME) != 0) { + first_on_node++; + } - if (first_on_node == rank) { - comm->proc_kind = ProcessKind::kHermes; - } else { - comm->proc_kind = ProcessKind::kApp; - } + if (first_on_node == rank) { + proc_kind = ProcessKind::kHermes; + } else { + proc_kind = ProcessKind::kApp; + } - // NOTE(chogan): Create a set of unique node names - std::set names; - for (int i = 0; i < size; ++i) { - std::string name(node_names[i], length); - names.insert(name); - } + // NOTE(chogan): Create a set of unique node names + std::set names; + for (int i = 0; i < size; ++i) { + std::string name(node_names[i], length); + names.insert(name); + } - comm->num_nodes = names.size(); + num_nodes = names.size(); - std::vector ranks_per_node_local(comm->num_nodes, 0); + std::vector ranks_per_node_local(num_nodes, 0); - // NOTE(chogan): 1-based index so 0 can be the NULL BufferID - int index = 1; - for (auto &name : names) { - if (name == node_names[rank]) { - comm->node_id = index; - ranks_per_node_local[index - 1]++; - break; + // NOTE(chogan): 1-based index so 0 can be the NULL BufferID + int index = 1; + for (auto &name : names) { + if (name == node_names[rank]) { + node_id = index; + ranks_per_node_local[index - 1]++; + break; + } + ++index; } - ++index; - } - - // NOTE(chogan): We're returning the transient arena size in bytes for the - // calling rank. To calculate that, we need to divide the total transient - // arena size for each node by the number of ranks on that node. - std::vector ranks_per_node(comm->num_nodes); - MPI_Allreduce(ranks_per_node_local.data(), ranks_per_node.data(), - comm->num_nodes, MPI_INT, MPI_SUM, mpi_state->world_comm); - size_t result = - trans_arena_size_per_node / (size_t)ranks_per_node[comm->node_id - 1]; + // NOTE(chogan): We're returning the transient arena size in bytes for the + // calling rank. To calculate that, we need to divide the total transient + // arena size for each node by the number of ranks on that node. + std::vector ranks_per_node(num_nodes); + MPI_Allreduce(ranks_per_node_local.data(), ranks_per_node.data(), + num_nodes, MPI_INT, MPI_SUM, world_comm); - DestroyArena(&scratch_arena); + size_t result = + trans_arena_size_per_node / (size_t)ranks_per_node[node_id - 1]; - return result; -} + return result; + } -/** - a wrapper for MPI_Finalize() function - */ -void MpiFinalize(void *state) { - (void)state; - MPI_Finalize(); -} + /** + a wrapper for MPI_Finalize() function + */ + void Finalize() override { + MPI_Finalize(); + } -/** - initialize MPI communication. - */ -size_t InitCommunication(CommunicationContext *comm, Arena *arena, - size_t trans_arena_size_per_node, bool is_daemon, - bool is_adapter) { - comm->world_barrier = MpiWorldBarrier; - comm->sub_barrier = MpiSubBarrier; - comm->finalize = MpiFinalize; - - MPIState *mpi_state = PushClearedStruct(arena); - mpi_state->world_comm = MPI_COMM_WORLD; - comm->state = mpi_state; - comm->world_proc_id = MpiGetWorldProcId(comm->state); - comm->world_size = MpiGetNumWorldProcs(comm->state); - - size_t trans_arena_size_for_rank = - MpiAssignIDsToNodes(comm, trans_arena_size_per_node); - - if (is_daemon || is_adapter) { - mpi_state->sub_comm = mpi_state->world_comm; - comm->sub_proc_id = comm->world_proc_id; - if (is_daemon) { - comm->hermes_size = comm->world_size; - comm->proc_kind = ProcessKind::kHermes; - } else { - comm->app_size = comm->world_size; - comm->proc_kind = ProcessKind::kApp; - } - comm->first_on_node = MpiFirstOnNode(mpi_state->world_comm); - } else { - int color = (int)comm->proc_kind; - MPI_Comm_split(mpi_state->world_comm, color, comm->world_proc_id, - &mpi_state->sub_comm); - - comm->first_on_node = MpiFirstOnNode(mpi_state->sub_comm); - comm->sub_proc_id = MpiGetSubProcId(comm->state); - - switch (comm->proc_kind) { - case ProcessKind::kHermes: { - MPI_Comm_size(mpi_state->sub_comm, &comm->hermes_size); - break; + /** + initialize MPI communication. + */ + MpiCommunicator(size_t trans_arena_size_per_node, bool is_daemon, + bool is_adapter) { + world_comm = MPI_COMM_WORLD; + world_proc_id = GetWorldProcId(); + world_size = GetNumWorldProcs(); + + size_t trans_arena_size_for_rank = + AssignIDsToNodes(trans_arena_size_per_node); + + if (is_daemon || is_adapter) { + sub_comm = world_comm; + sub_proc_id = world_proc_id; + if (is_daemon) { + hermes_size = world_size; + proc_kind = ProcessKind::kHermes; + } else { + app_size = world_size; + proc_kind = ProcessKind::kApp; } - case ProcessKind::kApp: { - MPI_Comm_size(mpi_state->sub_comm, &comm->app_size); - break; - } - default: { - HERMES_INVALID_CODE_PATH; - break; + first_on_node = FirstOnNode(world_comm); + } else { + int color = (int)proc_kind; + MPI_Comm_split(world_comm, color, world_proc_id, + &sub_comm); + + first_on_node = FirstOnNode(sub_comm); + sub_proc_id = GetSubProcId(); + + switch (proc_kind) { + case ProcessKind::kHermes: { + MPI_Comm_size(sub_comm, &hermes_size); + break; + } + case ProcessKind::kApp: { + MPI_Comm_size(sub_comm, &app_size); + break; + } + default: { + HERMES_INVALID_CODE_PATH; + break; + } } } - } - return trans_arena_size_for_rank; -} + return trans_arena_size_for_rank; + } +}; } // namespace hermes diff --git a/src/rpc.h b/src/rpc.h index 40d94b79c..36176bb38 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -19,67 +19,79 @@ #include "hermes_types.h" #include "metadata_management.h" #include +#include namespace hermes { -struct RpcContext; - const int kMaxServerNameSize = 128; /**< maximum size of server name */ const int kMaxServerSuffixSize = 16; /**< maximum size of server suffix */ -/** start function for RPC server */ -typedef void (*StartFunc)(SharedMemoryContext *, RpcContext *, Arena *, - const char *, int); -/** - A structure to represent a client's RPC context. - */ -struct ClientRpcContext { - void *state; /**< pointer to state */ - size_t state_size; /**< size of state */ +/** RPC types */ +enum class RpcType { + kThallium }; /** A structure to represent RPC context. */ -struct RpcContext { - ClientRpcContext client_rpc; /**< client's RPC context */ - void *state; /**< pointer to state*/ - /** The size of the internal RPC state. */ - size_t state_size; +namespace labstor_l = labstor::ipc::lockless; + +class RpcContext { + public: + CommunicationContext *comm_; + SharedMemoryContext *context_; + Config *config_; /** The hermes configuration used to initialize this RPC */ /** Array of host names stored in shared memory. This array size is * RpcContext::num_nodes. */ - labstor::ipc::lockless::string host_names; - u32 node_id; /**< node ID */ - u32 num_nodes; /**< number of nodes */ - int port; /**< port number */ - bool use_host_file; /**< use host file if true */ + labstor_l::vector host_names; + u32 node_id_; /**< node ID */ + u32 num_nodes_; /**< number of nodes */ + // The number of host numbers in the rpc_host_number_range entry of the + // configuration file. Not necessarily the number of nodes because when there + // is only 1 node, the entry can be left blank, or contain 1 host number. + int port_; /**< port number */ + bool use_host_file_; /**< use host file if true */ // TODO(chogan): Also allow reading hostnames from a file for heterogeneous or // non-contiguous hostnames (e.g., compute-node-20, compute-node-30, // storage-node-16, storage-node-24) // char *host_file_name; - StartFunc start_server; /**< start function */ + public: + explicit RpcContext(CommunicationContext *comm, + SharedMemoryContext *context, + u32 num_nodes, u32 node_id, Config *config) : + comm_(comm), context_(context), num_nodes_(num_nodes), + node_id_(node_id), config_(config) { + port_ = config->rpc_port; + if (!config->rpc_server_host_file.empty()) { + use_host_file_ = true; + } + } + + /** get RPC address */ + std::string GetRpcAddress(u32 node_id, int port) { + std::string result = config_->rpc_protocol + "://"; + + if (!config_->rpc_domain.empty()) { + result += config_->rpc_domain + "/"; + } + std::string host_name = GetHostNameFromNodeId(node_id); + result += host_name + ":" + std::to_string(port); + + return result; + } + + /** get host name from node ID */ + std::string GetHostNameFromNodeId(u32 node_id) { + std::string result; + // NOTE(chogan): node_id 0 is reserved as the NULL node + u32 index = node_id - 1; + result = host_names[index].str(); + return result; + } }; -void InitRpcContext(RpcContext *rpc, u32 num_nodes, u32 node_id, - Config *config); -void *CreateRpcState(); -void InitRpcClients(RpcContext *rpc); -void ShutdownRpcClients(RpcContext *rpc); -void RunDaemon(SharedMemoryContext *context, RpcContext *rpc, - CommunicationContext *comm, const char *shmem_name); -void FinalizeClient(SharedMemoryContext *context, RpcContext *rpc, - CommunicationContext *comm, bool stop_daemon); -void FinalizeRpcContext(RpcContext *rpc, bool is_daemon); -std::string GetServerName(RpcContext *rpc, u32 node_id, - bool is_buffer_organizer = false); -std::string GetProtocol(RpcContext *rpc); -void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, - const char *addr, int num_threads, - int port); -void StartPrefetcher(SharedMemoryContext *context, - RpcContext *rpc, double sleep_ms); } // namespace hermes // TODO(chogan): I don't like that code similar to this is in buffer_pool.cc. diff --git a/src/rpc_factory.h b/src/rpc_factory.h new file mode 100644 index 000000000..2b7a710a6 --- /dev/null +++ b/src/rpc_factory.h @@ -0,0 +1,37 @@ +// +// Created by lukemartinlogan on 11/30/22. +// + +#ifndef HERMES_SRC_RPC_FACTORY_H_ +#define HERMES_SRC_RPC_FACTORY_H_ + +#include "rpc.h" +#include "rpc_thallium.h" + +namespace hermes { +class RpcFactory { + public: + /** + * Return an RPC. Uses factory pattern. + * + * @param type, RpcType, type of mapper to be used by the STDIO adapter. + * @return Instance of RPC given a type. + */ + static std::unique_ptr Get( + const RpcType &type, + CommunicationContext *comm, + SharedMemoryContext *context, + u32 num_nodes, u32 node_id, Config *config) { + switch (type) { + case RpcType::kThallium: { + return std::make_unique( + comm, context, num_nodes, node_id, config); + } + default: + return nullptr; + } + } +}; +} // namespace hermes + +#endif // HERMES_SRC_RPC_FACTORY_H_ diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index a0b7ddf20..46a424acd 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -34,15 +34,170 @@ void CopyStringToCharArray(const std::string &src, char *dest, size_t max) { dest[copy_size] = '\0'; } +/** Get protocol */ +std::string ThalliumRpc::GetProtocol() { + std::string prefix = std::string(server_name_prefix); + // NOTE(chogan): Chop "://" off the end of the server_name_prefix to get the + // protocol + std::string result = prefix.substr(0, prefix.length() - 3); + return result; +} + +/** initialize RPC clients */ +void ThalliumRpc::InitClients() { + std::string protocol = GetProtocol(); + // TODO(chogan): This should go in a per-client persistent arena + client_engine_ = new tl::engine(protocol, THALLIUM_CLIENT_MODE, true, 1); +} + +/** shut down RPC clients */ +void ThalliumRpc::ShutdownClients() { + if (client_engine_) { + delete client_engine_; + client_engine_ = 0; + } +} + +/** finalize RPC context */ +void ThalliumRpc::Finalize(bool is_daemon) { + if (is_daemon) { + engine->wait_for_finalize(); + bo_engine->wait_for_finalize(); + } else { + engine->finalize(); + bo_engine->finalize(); + } + delete engine; + delete bo_engine; +} + +/** run daemon */ +void ThalliumRpc::RunDaemon(const char *shmem_name) { + engine->enable_remote_shutdown(); + bo_engine->enable_remote_shutdown(); + + auto prefinalize_callback = [this, &comm = comm_]() { + comm->SubBarrier(); + StopPrefetcher(); + StopGlobalSystemViewStateUpdateThread(); + SubBarrier(comm); + ShutdownRpcClients(); + }; + + engine->push_prefinalize_callback(prefinalize_callback); + + bo_engine->wait_for_finalize(); + engine->wait_for_finalize(); + + LocalShutdownBufferOrganizer(); + delete engine; + delete bo_engine; + ReleaseSharedMemoryContext(context); + shm_unlink(shmem_name); + HERMES_DEBUG_SERVER_CLOSE(); + + DestroyArena(trans_arena); + // TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 + // google::ShutdownGoogleLogging(); +} + +/** finalize client */ +void ThalliumRpc::FinalizeClient(bool stop_daemon) { + SubBarrier(comm); + + if (stop_daemon && comm->first_on_node) { + ClientThalliumState *state = GetClientThalliumState(rpc); + + std::string bo_server_name = GetServerName(rpc, rpc->node_id, true); + tl::endpoint bo_server = engine->lookup(bo_server_name); + engine->shutdown_remote_engine(bo_server); + + std::string server_name = GetServerName(rpc, rpc->node_id); + tl::endpoint server = engine->lookup(server_name); + engine->shutdown_remote_engine(server); + } + + SubBarrier(comm); + ShutdownRpcClients(rpc); + ReleaseSharedMemoryContext(context); + HERMES_DEBUG_CLIENT_CLOSE(); + DestroyArena(trans_arena); + // TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 + // google::ShutdownGoogleLogging(); +} + +/** get server name */ +std::string ThalliumRpc::GetServerName(u32 node_id, bool is_buffer_organizer) { + std::string host_name = GetHostNameFromNodeId(node_id); + // TODO(chogan): @optimization Could cache the last N hostname->IP mappings to + // avoid excessive syscalls. Should profile first. + struct hostent hostname_info = {}; + struct hostent *hostname_result; + int hostname_error = 0; + char hostname_buffer[4096] = {}; +#ifdef __APPLE__ + hostname_result = gethostbyname(host_name.c_str()); + in_addr **addr_list = (struct in_addr **)hostname_result->h_addr_list; +#else + int gethostbyname_result = gethostbyname_r(host_name.c_str(), &hostname_info, + hostname_buffer, 4096, + &hostname_result, &hostname_error); + if (gethostbyname_result != 0) { + LOG(FATAL) << hstrerror(h_errno); + } + in_addr **addr_list = (struct in_addr **)hostname_info.h_addr_list; +#endif + if (!addr_list[0]) { + LOG(FATAL) << hstrerror(h_errno); + } + + char ip_address[INET_ADDRSTRLEN]; + const char *inet_result = inet_ntop(AF_INET, addr_list[0], ip_address, + INET_ADDRSTRLEN); + if (!inet_result) { + FailedLibraryCall("inet_ntop"); + } + + std::string result = std::string(server_name_prefix); + result += std::string(ip_address); + + if (is_buffer_organizer) { + result += std::string(bo_server_name_postfix); + } else { + result += std::string(server_name_postfix); + } + + return result; +} + +/** read bulk */ +size_t ThalliumRpc::BulkRead(u32 node_id, const char *func_name, + u8 *data, size_t max_size, BufferID id) { + std::string server_name = GetServerName(node_id, false); + std::string protocol = GetProtocol(); + + tl::engine engine(protocol, THALLIUM_CLIENT_MODE, true); + tl::remote_procedure remote_proc = engine.define(func_name); + tl::endpoint server = engine.lookup(server_name); + + std::vector> segments(1); + segments[0].first = data; + segments[0].second = max_size; + + tl::bulk bulk = engine.expose(segments, tl::bulk_mode::write_only); + size_t result = remote_proc.on(server)(bulk, id); + + return result; +} + /** start Thallium RPC server */ -void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, - const char *addr, - i32 num_rpc_threads) { +void ThalliumRpc::StartServer(const char *addr, + i32 num_rpc_threads) { ThalliumState *state = GetThalliumState(rpc); - state->engine = new tl::engine(addr, THALLIUM_SERVER_MODE, true, + engine = new tl::engine(addr, THALLIUM_SERVER_MODE, true, num_rpc_threads); - tl::engine *rpc_server = state->engine; + tl::engine *rpc_server = engine; std::string rpc_server_name = rpc_server->self(); LOG(INFO) << "Serving at " << rpc_server_name << " with " @@ -50,12 +205,12 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, size_t end_of_protocol = rpc_server_name.find_first_of(":"); std::string server_name_prefix = - rpc_server_name.substr(0, end_of_protocol) + "://"; - CopyStringToCharArray(server_name_prefix, state->server_name_prefix, + rpc_server_name.substr(0, end_of_protocol) + "://"; + CopyStringToCharArray(server_name_prefix, server_name_prefix, kMaxServerNamePrefix); std::string server_name_postfix = ":" + std::to_string(rpc->port); - CopyStringToCharArray(server_name_postfix, state->server_name_postfix, + CopyStringToCharArray(server_name_postfix, server_name_postfix, kMaxServerNamePostfix); using std::function; @@ -66,10 +221,10 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, // BufferPool requests auto rpc_get_buffers = - [context](const request &req, const PlacementSchema &schema) { - std::vector result = GetBuffers(context, schema); - req.respond(result); - }; + [context](const request &req, const PlacementSchema &schema) { + std::vector result = GetBuffers(context, schema); + req.respond(result); + }; auto rpc_release_buffer = [context](const request &req, BufferID id) { LocalReleaseBuffer(context, id); @@ -93,15 +248,15 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, }; auto rpc_write_buffer_by_id = - [context](const request &req, BufferID id, std::vector data, - size_t offset) { - Blob blob = {}; - blob.size = data.size(); - blob.data = data.data(); - size_t result = LocalWriteBufferById(context, id, blob, offset); + [context](const request &req, BufferID id, std::vector data, + size_t offset) { + Blob blob = {}; + blob.size = data.size(); + blob.data = data.data(); + size_t result = LocalWriteBufferById(context, id, blob, offset); - req.respond(result); - }; + req.respond(result); + }; auto rpc_read_buffer_by_id = [context](const request &req, BufferID id) { BufferHeader *header = GetHeaderByBufferId(context, id); @@ -117,92 +272,92 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, }; auto rpc_bulk_read_buffer_by_id = - [context, rpc_server, arena](const request &req, tl::bulk &bulk, - BufferID id) { - tl::endpoint endpoint = req.get_endpoint(); - BufferHeader *header = GetHeaderByBufferId(context, id); - ScopedTemporaryMemory temp_memory(arena); - - u8 *buffer_data = 0; - size_t size = header->used; - - if (BufferIsByteAddressable(context, id)) { - buffer_data = GetRamBufferPtr(context, id); - } else { - // TODO(chogan): Probably need a way to lock the trans_arena. Currently - // an assertion will fire if multiple threads try to use it at once. - if (size > GetRemainingCapacity(temp_memory)) { - // TODO(chogan): Need to transfer in a loop if we don't have enough - // temporary memory available - HERMES_NOT_IMPLEMENTED_YET; + [context, rpc_server, arena](const request &req, tl::bulk &bulk, + BufferID id) { + tl::endpoint endpoint = req.get_endpoint(); + BufferHeader *header = GetHeaderByBufferId(context, id); + ScopedTemporaryMemory temp_memory(arena); + + u8 *buffer_data = 0; + size_t size = header->used; + + if (BufferIsByteAddressable(context, id)) { + buffer_data = GetRamBufferPtr(context, id); + } else { + // TODO(chogan): Probably need a way to lock the trans_arena. Currently + // an assertion will fire if multiple threads try to use it at once. + if (size > GetRemainingCapacity(temp_memory)) { + // TODO(chogan): Need to transfer in a loop if we don't have enough + // temporary memory available + HERMES_NOT_IMPLEMENTED_YET; + } + buffer_data = PushSize(temp_memory, size); + Blob blob = {}; + blob.data = buffer_data; + blob.size = size; + size_t read_offset = 0; + LocalReadBufferById(context, id, &blob, read_offset); } - buffer_data = PushSize(temp_memory, size); - Blob blob = {}; - blob.data = buffer_data; - blob.size = size; - size_t read_offset = 0; - LocalReadBufferById(context, id, &blob, read_offset); - } - std::vector> segments(1); - segments[0].first = buffer_data; - segments[0].second = size; - tl::bulk local_bulk = rpc_server->expose(segments, - tl::bulk_mode::read_only); + std::vector> segments(1); + segments[0].first = buffer_data; + segments[0].second = size; + tl::bulk local_bulk = rpc_server->expose(segments, + tl::bulk_mode::read_only); - size_t bytes_read = local_bulk >> bulk.on(endpoint); - // TODO(chogan): @errorhandling - assert(bytes_read == size); + size_t bytes_read = local_bulk >> bulk.on(endpoint); + // TODO(chogan): @errorhandling + assert(bytes_read == size); - req.respond(bytes_read); - }; + req.respond(bytes_read); + }; // Metadata requests auto rpc_map_get = - [context](const request &req, string name, const MapType &map_type) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - u64 result = LocalGet(mdm, name.c_str(), map_type); + [context](const request &req, string name, const MapType &map_type) { + MetadataManager *mdm = GetMetadataManagerFromContext(context); + u64 result = LocalGet(mdm, name.c_str(), map_type); - req.respond(result); - }; + req.respond(result); + }; auto rpc_map_put = - [context](const request &req, const string &name, u64 val, - const MapType &map_type) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalPut(mdm, name.c_str(), val, map_type); - req.respond(true); - }; + [context](const request &req, const string &name, u64 val, + const MapType &map_type) { + MetadataManager *mdm = GetMetadataManagerFromContext(context); + LocalPut(mdm, name.c_str(), val, map_type); + req.respond(true); + }; auto rpc_map_delete = - [context](const request &req, string name, const MapType &map_type) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalDelete(mdm, name.c_str(), map_type); - req.respond(true); - }; + [context](const request &req, string name, const MapType &map_type) { + MetadataManager *mdm = GetMetadataManagerFromContext(context); + LocalDelete(mdm, name.c_str(), map_type); + req.respond(true); + }; auto rpc_add_blob_bucket = - [context](const request &req, BucketID bucket_id, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalAddBlobIdToBucket(mdm, bucket_id, blob_id); - req.respond(true); - }; + [context](const request &req, BucketID bucket_id, BlobID blob_id) { + MetadataManager *mdm = GetMetadataManagerFromContext(context); + LocalAddBlobIdToBucket(mdm, bucket_id, blob_id); + req.respond(true); + }; auto rpc_add_blob_vbucket = - [context](const request &req, VBucketID vbucket_id, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalAddBlobIdToVBucket(mdm, vbucket_id, blob_id); - req.respond(true); - }; + [context](const request &req, VBucketID vbucket_id, BlobID blob_id) { + MetadataManager *mdm = GetMetadataManagerFromContext(context); + LocalAddBlobIdToVBucket(mdm, vbucket_id, blob_id); + req.respond(true); + }; auto rpc_get_buffer_id_list = - [context](const request &req, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - std::vector result = LocalGetBufferIdList(mdm, blob_id); + [context](const request &req, BlobID blob_id) { + MetadataManager *mdm = GetMetadataManagerFromContext(context); + std::vector result = LocalGetBufferIdList(mdm, blob_id); - req.respond(result); - }; + req.respond(result); + }; auto rpc_free_buffer_id_list = [context](const request &req, BlobID blob_id) { LocalFreeBufferIdList(context, blob_id); @@ -210,11 +365,11 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, }; auto rpc_destroy_bucket = - [context, rpc](const request &req, const string &name, BucketID id) { - bool result = LocalDestroyBucket(context, rpc, name.c_str(), id); + [context, rpc](const request &req, const string &name, BucketID id) { + bool result = LocalDestroyBucket(context, rpc, name.c_str(), id); - req.respond(result); - }; + req.respond(result); + }; auto rpc_destroy_vbucket = [context](const request &req, const string &name, VBucketID id) { @@ -223,70 +378,70 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, }; auto rpc_get_or_create_bucket_id = - [context](const request &req, const std::string &name) { - BucketID result = LocalGetOrCreateBucketId(context, name); + [context](const request &req, const std::string &name) { + BucketID result = LocalGetOrCreateBucketId(context, name); - req.respond(result); - }; + req.respond(result); + }; auto rpc_get_or_create_vbucket_id = - [context](const request &req, std::string &name) { - VBucketID result = LocalGetOrCreateVBucketId(context, name); + [context](const request &req, std::string &name) { + VBucketID result = LocalGetOrCreateVBucketId(context, name); - req.respond(result); - }; + req.respond(result); + }; auto rpc_allocate_buffer_id_list = - [context](const request &req, const vector &buffer_ids) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - u32 result = LocalAllocateBufferIdList(mdm, buffer_ids); + [context](const request &req, const vector &buffer_ids) { + MetadataManager *mdm = GetMetadataManagerFromContext(context); + u32 result = LocalAllocateBufferIdList(mdm, buffer_ids); - req.respond(result); - }; + req.respond(result); + }; auto rpc_rename_bucket = - [context, rpc](const request &req, BucketID id, const string &old_name, - const string &new_name) { - LocalRenameBucket(context, rpc, id, old_name, new_name); - req.respond(true); - }; + [context, rpc](const request &req, BucketID id, const string &old_name, + const string &new_name) { + LocalRenameBucket(context, rpc, id, old_name, new_name); + req.respond(true); + }; auto rpc_destroy_blob_by_name = - [context, rpc](const request &req, const string &name, BlobID id, - BucketID bucket_id) { - LocalDestroyBlobByName(context, rpc, name.c_str(), id, bucket_id); - req.respond(true); - }; + [context, rpc](const request &req, const string &name, BlobID id, + BucketID bucket_id) { + LocalDestroyBlobByName(context, rpc, name.c_str(), id, bucket_id); + req.respond(true); + }; auto rpc_destroy_blob_by_id = - [context, rpc](const request &req, BlobID id, BucketID bucket_id) { - LocalDestroyBlobById(context, rpc, id, bucket_id); - req.respond(true); - }; + [context, rpc](const request &req, BlobID id, BucketID bucket_id) { + LocalDestroyBlobById(context, rpc, id, bucket_id); + req.respond(true); + }; auto rpc_contains_blob = - [context](const request &req, BucketID bucket_id, BlobID blob_id) { - bool result = LocalContainsBlob(context, bucket_id, blob_id); - req.respond(result); - }; + [context](const request &req, BucketID bucket_id, BlobID blob_id) { + bool result = LocalContainsBlob(context, bucket_id, blob_id); + req.respond(result); + }; auto rpc_remove_blob_from_bucket_info = - [context](const request &req, BucketID bucket_id, BlobID blob_id) { - LocalRemoveBlobFromBucketInfo(context, bucket_id, blob_id); - req.respond(true); - }; + [context](const request &req, BucketID bucket_id, BlobID blob_id) { + LocalRemoveBlobFromBucketInfo(context, bucket_id, blob_id); + req.respond(true); + }; auto rpc_decrement_refcount_bucket = - [context](const request &req, BucketID id) { - LocalDecrementRefcount(context, id); - req.respond(true); - }; + [context](const request &req, BucketID id) { + LocalDecrementRefcount(context, id); + req.respond(true); + }; - auto rpc_decrement_refcount_vbucket = - [context](const request &req, VBucketID id) { - LocalDecrementRefcount(context, id); - req.respond(true); - }; + auto rpc_decrement_refcount_vbucket = + [context](const request &req, VBucketID id) { + LocalDecrementRefcount(context, id); + req.respond(true); + }; auto rpc_get_global_device_capacities = [context](const request &req) { std::vector result = LocalGetGlobalDeviceCapacities(context); @@ -301,12 +456,12 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, }; auto rpc_update_global_system_view_state = - [context, rpc](const request &req, std::vector adjustments) { - std::vector result = - LocalUpdateGlobalSystemViewState(context, rpc->node_id, adjustments); + [context, rpc](const request &req, std::vector adjustments) { + std::vector result = + LocalUpdateGlobalSystemViewState(context, rpc->node_id, adjustments); - req.respond(result); - }; + req.respond(result); + }; auto rpc_get_blob_ids = [context](const request &req, BucketID bucket_id) { std::vector result = LocalGetBlobIds(context, bucket_id); @@ -321,11 +476,11 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, }; auto rpc_get_bucket_id_from_blob_id = - [context](const request &req, BlobID id) { - BucketID result = LocalGetBucketIdFromBlobId(context, id); + [context](const request &req, BlobID id) { + BucketID result = LocalGetBucketIdFromBlobId(context, id); - req.respond(result); - }; + req.respond(result); + }; auto rpc_get_blob_name_from_id = [context](const request &req, BlobID id) { std::string result = LocalGetBlobNameFromId(context, id); @@ -336,19 +491,19 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, auto rpc_finalize = [rpc](const request &req) { (void)req; ThalliumState *state = GetThalliumState(rpc); - state->engine->finalize(); + engine->finalize(); }; auto rpc_remove_blob_from_vbucket_info = [context](const request &req, - VBucketID vbucket_id, - BlobID blob_id) { + VBucketID vbucket_id, + BlobID blob_id) { LocalRemoveBlobFromVBucketInfo(context, vbucket_id, blob_id); req.respond(true); }; auto rpc_get_blobs_from_vbucket_info = [context](const request &req, - VBucketID vbucket_id) { + VBucketID vbucket_id) { auto ret = LocalGetBlobsFromVBucketInfo(context, vbucket_id); req.respond(ret); @@ -361,19 +516,19 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, }; auto rpc_increment_blob_stats = - [context](const request &req, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalIncrementBlobStats(mdm, blob_id); + [context](const request &req, BlobID blob_id) { + MetadataManager *mdm = GetMetadataManagerFromContext(context); + LocalIncrementBlobStats(mdm, blob_id); - req.respond(true); - }; + req.respond(true); + }; auto rpc_get_blob_importance_score = - [context](const request &req, BlobID blob_id) { - f32 result = LocalGetBlobImportanceScore(context, blob_id); + [context](const request &req, BlobID blob_id) { + f32 result = LocalGetBlobImportanceScore(context, blob_id); - req.respond(result); - }; + req.respond(result); + }; auto rpc_increment_flush_count = [context](const request &req, const std::string &name) { @@ -390,11 +545,11 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, }; auto rpc_get_num_outstanding_flushing_tasks = - [context](const request &req, VBucketID id) { - int result = LocalGetNumOutstandingFlushingTasks(context, id); + [context](const request &req, VBucketID id) { + int result = LocalGetNumOutstandingFlushingTasks(context, id); - req.respond(result); - }; + req.respond(result); + }; auto rpc_lock_blob = [context](const request &req, BlobID id) { bool result = LocalLockBlob(context, id); @@ -409,14 +564,14 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, }; auto rpc_create_blob_metadata = - [context](const request &req, const std::string &blob_name, - BlobID blob_id, TargetID effective_target) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalCreateBlobMetadata(context, mdm, blob_name, blob_id, - effective_target); + [context](const request &req, const std::string &blob_name, + BlobID blob_id, TargetID effective_target) { + MetadataManager *mdm = GetMetadataManagerFromContext(context); + LocalCreateBlobMetadata(context, mdm, blob_name, blob_id, + effective_target); - req.respond(true); - }; + req.respond(true); + }; auto rpc_replace_blob_id_in_bucket = [context](const request &req, BucketID bucket_id, @@ -458,7 +613,7 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, rpc_server->define("RemoteDestroyBlobById", rpc_destroy_blob_by_id); rpc_server->define("RemoteContainsBlob", rpc_contains_blob); rpc_server->define("RemoteRemoveBlobFromBucketInfo", - rpc_remove_blob_from_bucket_info); + rpc_remove_blob_from_bucket_info); rpc_server->define("RemoteAllocateBufferIdList", rpc_allocate_buffer_id_list); rpc_server->define("RemoteGetBufferIdList", rpc_get_buffer_id_list); rpc_server->define("RemoteFreeBufferIdList", rpc_free_buffer_id_list); @@ -503,18 +658,17 @@ void ThalliumStartRpcServer(SharedMemoryContext *context, RpcContext *rpc, } /** start buffer organizer */ -void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, - const char *addr, int num_threads, - int port) { +void ThalliumRpc::StartBufferOrganizer(const char *addr, int num_threads, + int port) { context->bo = PushStruct(arena); new(context->bo) BufferOrganizer(num_threads); ThalliumState *state = GetThalliumState(rpc); int num_bo_rpc_threads = 1; - state->bo_engine = new tl::engine(addr, THALLIUM_SERVER_MODE, true, + bo_engine = new tl::engine(addr, THALLIUM_SERVER_MODE, true, num_bo_rpc_threads); - tl::engine *rpc_server = state->bo_engine; + tl::engine *rpc_server = bo_engine; std::string rpc_server_name = rpc_server->self(); LOG(INFO) << "Buffer organizer serving at " << rpc_server_name << " with " @@ -522,7 +676,7 @@ void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, << " BO worker threads" << std::endl; std::string server_name_postfix = ":" + std::to_string(port); - CopyStringToCharArray(server_name_postfix, state->bo_server_name_postfix, + CopyStringToCharArray(server_name_postfix, bo_server_name_postfix, kMaxServerNamePostfix); auto rpc_place_in_hierarchy = [context, rpc](const tl::request &req, @@ -540,11 +694,11 @@ void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, } else { ThalliumState *state = GetThalliumState(rpc); - if (state && state->bo_engine) { + if (state && bo_engine) { // TODO(chogan): We probably don't want to sleep here, but for now // this enables testing. double sleep_ms = 2000; - tl::thread::self().sleep(*state->bo_engine, sleep_ms); + tl::thread::self().sleep(*bo_engine, sleep_ms); } } } @@ -563,13 +717,13 @@ void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, }; auto rpc_enqueue_flushing_task = - [context, rpc](const tl::request &req, BlobID blob_id, - const std::string &filename, u64 offset) { - bool result = LocalEnqueueFlushingTask(context, rpc, blob_id, filename, - offset); + [context, rpc](const tl::request &req, BlobID blob_id, + const std::string &filename, u64 offset) { + bool result = LocalEnqueueFlushingTask(context, rpc, blob_id, filename, + offset); - req.respond(result); - }; + req.respond(result); + }; auto rpc_enqueue_bo_move = [context, rpc](const tl::request &req, const BoMoveList &moves, @@ -603,10 +757,8 @@ void StartBufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, } /** start prefetcher */ -void StartPrefetcher(SharedMemoryContext *context, - RpcContext *rpc, double sleep_ms) { - ThalliumState *state = GetThalliumState(rpc); - tl::engine *rpc_server = state->engine; +void ThalliumRpc::StartPrefetcher(double sleep_ms) { + tl::engine *rpc_server = engine; using tl::request; // Create the LogIoStat RPC @@ -632,9 +784,9 @@ void StartPrefetcher(SharedMemoryContext *context, ThalliumState *state = GetThalliumState(targs.rpc); LOG(INFO) << "Prefetching thread started" << std::endl; auto prefetcher = Singleton::GetInstance(); - while (!state->kill_requested.load()) { + while (!kill_requested.load()) { prefetcher->Process(); - tl::thread::self().sleep(*state->engine, targs.sleep_ms); + tl::thread::self().sleep(*engine, targs.sleep_ms); } LOG(INFO) << "Finished prefetcher" << std::endl; }; @@ -646,24 +798,21 @@ void StartPrefetcher(SharedMemoryContext *context, args->sleep_ms = sleep_ms; args->init_ = false; - ABT_xstream_create(ABT_SCHED_NULL, &state->execution_stream); - ABT_thread_create_on_xstream(state->execution_stream, + ABT_xstream_create(ABT_SCHED_NULL, &execution_stream); + ABT_thread_create_on_xstream(execution_stream, prefetch, args, ABT_THREAD_ATTR_NULL, NULL); } /** stop prefetcher */ -void StopPrefetcher(RpcContext *rpc) { - ThalliumState *state = GetThalliumState(rpc); - state->kill_requested.store(true); - ABT_xstream_join(state->execution_stream); - ABT_xstream_free(&state->execution_stream); +void ThalliumRpc::StopPrefetcher() { + kill_requested.store(true); + ABT_xstream_join(execution_stream); + ABT_xstream_free(&execution_stream); } /** start global system view state update thread */ -void StartGlobalSystemViewStateUpdateThread(SharedMemoryContext *context, - RpcContext *rpc, Arena *arena, - double sleep_ms) { +void ThalliumRpc::StartGlobalSystemViewStateUpdateThread(double sleep_ms) { struct ThreadArgs { SharedMemoryContext *context; RpcContext *rpc; @@ -674,9 +823,9 @@ void StartGlobalSystemViewStateUpdateThread(SharedMemoryContext *context, ThreadArgs *targs = (ThreadArgs *)args; ThalliumState *state = GetThalliumState(targs->rpc); LOG(INFO) << "Update global system view state start" << std::endl; - while (!state->kill_requested.load()) { + while (!kill_requested.load()) { UpdateGlobalSystemViewState(targs->context, targs->rpc); - tl::thread::self().sleep(*state->engine, targs->sleep_ms); + tl::thread::self().sleep(*engine, targs->sleep_ms); } LOG(INFO) << "Finished global system view update thread" << std::endl; }; @@ -687,244 +836,17 @@ void StartGlobalSystemViewStateUpdateThread(SharedMemoryContext *context, args->sleep_ms = sleep_ms; ThalliumState *state = GetThalliumState(rpc); - ABT_thread_create_on_xstream(state->execution_stream, + ABT_thread_create_on_xstream(execution_stream, update_global_system_view_state, args, ABT_THREAD_ATTR_NULL, NULL); } /** stop global system view state update thread */ -void StopGlobalSystemViewStateUpdateThread(RpcContext *rpc) { - ThalliumState *state = GetThalliumState(rpc); - state->kill_requested.store(true); - ABT_xstream_join(state->execution_stream); - ABT_xstream_free(&state->execution_stream); -} - -/** initialize RPC context */ -void InitRpcContext(RpcContext *rpc, u32 num_nodes, u32 node_id, - Config *config) { - rpc->num_nodes = num_nodes; - // The number of host numbers in the rpc_host_number_range entry of the - // configuration file. Not necessarily the number of nodes because when there - // is only 1 node, the entry can be left blank, or contain 1 host number. - rpc->node_id = node_id; - rpc->start_server = ThalliumStartRpcServer; - rpc->state_size = sizeof(ThalliumState); - rpc->port = config->rpc_port; - rpc->client_rpc.state_size = sizeof(ClientThalliumState); - if (!config->rpc_server_host_file.empty()) { - rpc->use_host_file = true; - } -} - -/** create RPC state */ -void *CreateRpcState(Arena *arena) { - ThalliumState *result = PushClearedStruct(arena); - - return result; -} - -/** get protocol */ -std::string GetProtocol(RpcContext *rpc) { - ThalliumState *tl_state = GetThalliumState(rpc); - - std::string prefix = std::string(tl_state->server_name_prefix); - // NOTE(chogan): Chop "://" off the end of the server_name_prefix to get the - // protocol - std::string result = prefix.substr(0, prefix.length() - 3); - - return result; -} - -/** initialize RPC clients */ -void InitRpcClients(RpcContext *rpc) { - // TODO(chogan): Need a per-client persistent arena - ClientThalliumState *state = - (ClientThalliumState *)malloc(sizeof(ClientThalliumState)); - std::string protocol = GetProtocol(rpc); - // TODO(chogan): This should go in a per-client persistent arena - state->engine = new tl::engine(protocol, THALLIUM_CLIENT_MODE, true, 1); - - rpc->client_rpc.state = state; -} - -/** shut down RPC clients */ -void ShutdownRpcClients(RpcContext *rpc) { - ClientThalliumState *state = GetClientThalliumState(rpc); - if (state) { - if (state->engine) { - delete state->engine; - state->engine = 0; - } - free(state); - state = 0; - } -} - -/** finalize RPC context */ -void FinalizeRpcContext(RpcContext *rpc, bool is_daemon) { +void ThalliumRpc::StopGlobalSystemViewStateUpdateThread() { ThalliumState *state = GetThalliumState(rpc); - - if (is_daemon) { - state->engine->wait_for_finalize(); - state->bo_engine->wait_for_finalize(); - } else { - state->engine->finalize(); - state->bo_engine->finalize(); - } - - delete state->engine; - delete state->bo_engine; -} - -/** run daemon */ -void RunDaemon(SharedMemoryContext *context, RpcContext *rpc, - CommunicationContext *comm, Arena *trans_arena, - const char *shmem_name) { - ThalliumState *state = GetThalliumState(rpc); - state->engine->enable_remote_shutdown(); - state->bo_engine->enable_remote_shutdown(); - - auto prefinalize_callback = [rpc, comm]() { - SubBarrier(comm); - StopPrefetcher(rpc); - StopGlobalSystemViewStateUpdateThread(rpc); - SubBarrier(comm); - ShutdownRpcClients(rpc); - }; - - state->engine->push_prefinalize_callback(prefinalize_callback); - - state->bo_engine->wait_for_finalize(); - state->engine->wait_for_finalize(); - - LocalShutdownBufferOrganizer(context); - delete state->engine; - delete state->bo_engine; - ReleaseSharedMemoryContext(context); - shm_unlink(shmem_name); - HERMES_DEBUG_SERVER_CLOSE(); - - DestroyArena(trans_arena); - // TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 - // google::ShutdownGoogleLogging(); -} - -/** finalize client */ -void FinalizeClient(SharedMemoryContext *context, RpcContext *rpc, - CommunicationContext *comm, Arena *trans_arena, - bool stop_daemon) { - SubBarrier(comm); - - if (stop_daemon && comm->first_on_node) { - ClientThalliumState *state = GetClientThalliumState(rpc); - - std::string bo_server_name = GetServerName(rpc, rpc->node_id, true); - tl::endpoint bo_server = state->engine->lookup(bo_server_name); - state->engine->shutdown_remote_engine(bo_server); - - std::string server_name = GetServerName(rpc, rpc->node_id); - tl::endpoint server = state->engine->lookup(server_name); - state->engine->shutdown_remote_engine(server); - } - - SubBarrier(comm); - ShutdownRpcClients(rpc); - ReleaseSharedMemoryContext(context); - HERMES_DEBUG_CLIENT_CLOSE(); - DestroyArena(trans_arena); - // TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 - // google::ShutdownGoogleLogging(); -} - -/** get host name from node ID */ -std::string GetHostNameFromNodeId(RpcContext *rpc, u32 node_id) { - std::string result; - // NOTE(chogan): node_id 0 is reserved as the NULL node - u32 index = node_id - 1; - result = GetShmemString(&rpc->host_names[index]); - return result; -} - -/** get RPC address */ -std::string GetRpcAddress(RpcContext *rpc, Config *config, u32 node_id, - int port) { - std::string result = config->rpc_protocol + "://"; - - if (!config->rpc_domain.empty()) { - result += config->rpc_domain + "/"; - } - std::string host_name = GetHostNameFromNodeId(rpc, node_id); - result += host_name + ":" + std::to_string(port); - - return result; -} - -/** get server name */ -std::string GetServerName(RpcContext *rpc, u32 node_id, - bool is_buffer_organizer) { - ThalliumState *tl_state = GetThalliumState(rpc); - std::string host_name = GetHostNameFromNodeId(rpc, node_id); - - // TODO(chogan): @optimization Could cache the last N hostname->IP mappings to - // avoid excessive syscalls. Should profile first. - struct hostent hostname_info = {}; - struct hostent *hostname_result; - int hostname_error = 0; - char hostname_buffer[4096] = {}; -#ifdef __APPLE__ - hostname_result = gethostbyname(host_name.c_str()); - in_addr **addr_list = (struct in_addr **)hostname_result->h_addr_list; -#else - int gethostbyname_result = gethostbyname_r(host_name.c_str(), &hostname_info, - hostname_buffer, 4096, - &hostname_result, &hostname_error); - if (gethostbyname_result != 0) { - LOG(FATAL) << hstrerror(h_errno); - } - in_addr **addr_list = (struct in_addr **)hostname_info.h_addr_list; -#endif - if (!addr_list[0]) { - LOG(FATAL) << hstrerror(h_errno); - } - - char ip_address[INET_ADDRSTRLEN]; - const char *inet_result = inet_ntop(AF_INET, addr_list[0], ip_address, - INET_ADDRSTRLEN); - if (!inet_result) { - FailedLibraryCall("inet_ntop"); - } - - std::string result = std::string(tl_state->server_name_prefix); - result += std::string(ip_address); - - if (is_buffer_organizer) { - result += std::string(tl_state->bo_server_name_postfix); - } else { - result += std::string(tl_state->server_name_postfix); - } - - return result; -} - -/** read bulk */ -size_t BulkRead(RpcContext *rpc, u32 node_id, const char *func_name, - u8 *data, size_t max_size, BufferID id) { - std::string server_name = GetServerName(rpc, node_id); - std::string protocol = GetProtocol(rpc); - - tl::engine engine(protocol, THALLIUM_CLIENT_MODE, true); - tl::remote_procedure remote_proc = engine.define(func_name); - tl::endpoint server = engine.lookup(server_name); - - std::vector> segments(1); - segments[0].first = data; - segments[0].second = max_size; - - tl::bulk bulk = engine.expose(segments, tl::bulk_mode::write_only); - size_t result = remote_proc.on(server)(bulk, id); - - return result; + kill_requested.store(true); + ABT_xstream_join(execution_stream); + ABT_xstream_free(&execution_stream); } } // namespace hermes diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index b1f5b5343..d0654a667 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -35,10 +35,33 @@ const char kBoPrefix[] = "BO::"; /**< buffer organizer prefix */ /** buffer organizer prefix length */ const int kBoPrefixLength = sizeof(kBoPrefix) - 1; +std::string GetRpcAddress(RpcContext *rpc, Config *config, u32 node_id, + int port); + +/** is \a func_name buffer organizer function? */ +static bool IsBoFunction(const char *func_name) { + bool result = false; + int i = 0; + + while (func_name && *func_name != '\0' && i < kBoPrefixLength) { + if (func_name[i] != kBoPrefix[i]) { + break; + } + ++i; + } + + if (i == kBoPrefixLength) { + result = true; + } + + return result; +} + /** A structure to represent Thallium state */ -struct ThalliumState { +class ThalliumRpc : public RpcContext { + public: char server_name_prefix[kMaxServerNamePrefix]; /**< server prefix */ char server_name_postfix[kMaxServerNamePostfix]; /**< server suffix */ char bo_server_name_postfix[kMaxServerNamePostfix]; /**< buf. org. suffix */ @@ -46,13 +69,84 @@ struct ThalliumState { tl::engine *engine; /**< pointer to engine */ tl::engine *bo_engine; /**< pointer to buf. org. engine */ ABT_xstream execution_stream; /**< Argobots execution stream */ -}; + tl::engine *client_engine_; /**< pointer to engine */ -/** - A structure to represent a client's Thallium state -*/ -struct ClientThalliumState { - tl::engine *engine; /**< pointer to engine */ + /** initialize RPC context */ + explicit ThalliumRpc(CommunicationContext *comm, + SharedMemoryContext *context, + u32 num_nodes, u32 node_id, Config *config) : + RpcContext(comm, context, num_nodes, node_id, config) { + } + + /** Get protocol */ + std::string GetProtocol(); + + /** initialize RPC clients */ + void InitClients(); + + /** shut down RPC clients */ + void ShutdownClients(); + + /** finalize RPC context */ + void Finalize(bool is_daemon); + + /** run daemon */ + void RunDaemon(const char *shmem_name); + + /** finalize client */ + void FinalizeClient(bool stop_daemon); + + /** get server name */ + std::string GetServerName(u32 node_id, bool is_buffer_organizer); + + /** read bulk */ + size_t BulkRead(u32 node_id, const char *func_name, + u8 *data, size_t max_size, BufferID id); + + /** start Thallium RPC server */ + void StartServer(const char *addr, i32 num_rpc_threads); + + /** start buffer organizer */ + void StartBufferOrganizer(const char *addr, int num_threads, int port); + + /** start prefetcher */ + void StartPrefetcher(double sleep_ms); + + /** stop prefetcher */ + void StopPrefetcher(); + + /** start global system view state update thread */ + void StartGlobalSystemViewStateUpdateThread(double sleep_ms); + + /** stop global system view state update thread */ + void StopGlobalSystemViewStateUpdateThread(); + + /** RPC call */ + template + ReturnType RpcCall(u32 node_id, const char *func_name, Ts... args) { + VLOG(1) << "Calling " << func_name << " on node " << node_id << " from node " + << node_id << std::endl; + bool is_bo_func = IsBoFunction(func_name); + std::string server_name = GetServerName(node_id, is_bo_func); + + if (is_bo_func) { + func_name += kBoPrefixLength; + } + + tl::remote_procedure remote_proc = client_engine_->define(func_name); + // TODO(chogan): @optimization We can save a little work by storing the + // endpoint instead of looking it up on every call + tl::endpoint server = client_engine_->lookup(server_name); + + if constexpr (std::is_same::value) { + remote_proc.disable_response(); + remote_proc.on(server)(std::forward(args)...); + } else { + ReturnType result = remote_proc.on(server)(std::forward(args)...); + + return result; + } + } }; /** @@ -280,70 +374,6 @@ void load(A &ar, api::Context &ctx) { } } // namespace api -std::string GetRpcAddress(RpcContext *rpc, Config *config, u32 node_id, - int port); -/** get Thallium state */ -static inline ThalliumState *GetThalliumState(RpcContext *rpc) { - ThalliumState *result = (ThalliumState *)rpc->state; - - return result; -} - -/** get Thallium client state */ -static inline ClientThalliumState *GetClientThalliumState(RpcContext *rpc) { - ClientThalliumState *result = (ClientThalliumState *)rpc->client_rpc.state; - - return result; -} - -/** is \a func_name buffer organizer function? */ -static bool IsBoFunction(const char *func_name) { - bool result = false; - int i = 0; - - while (func_name && *func_name != '\0' && i < kBoPrefixLength) { - if (func_name[i] != kBoPrefix[i]) { - break; - } - ++i; - } - - if (i == kBoPrefixLength) { - result = true; - } - - return result; -} - -/** RPC call */ -template -ReturnType RpcCall(RpcContext *rpc, u32 node_id, const char *func_name, - Ts... args) { - VLOG(1) << "Calling " << func_name << " on node " << node_id << " from node " - << rpc->node_id << std::endl; - ClientThalliumState *state = GetClientThalliumState(rpc); - bool is_bo_func = IsBoFunction(func_name); - std::string server_name = GetServerName(rpc, node_id, is_bo_func); - - if (is_bo_func) { - func_name += kBoPrefixLength; - } - - tl::remote_procedure remote_proc = state->engine->define(func_name); - // TODO(chogan): @optimization We can save a little work by storing the - // endpoint instead of looking it up on every call - tl::endpoint server = state->engine->lookup(server_name); - - if constexpr (std::is_same::value) { - remote_proc.disable_response(); - remote_proc.on(server)(std::forward(args)...); - } else { - ReturnType result = remote_proc.on(server)(std::forward(args)...); - - return result; - } -} - } // namespace hermes #endif // HERMES_RPC_THALLIUM_H_ From e6f3566aeb212afacd80ef5f1845b6936d43d2ca Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 30 Nov 2022 17:55:29 -0600 Subject: [PATCH 030/511] BORG is now a class --- src/buffer_organizer.cc | 159 +++++++++++++++++-------------------- src/buffer_organizer.h | 85 +++++++++++++++++++- src/metadata_management.cc | 4 +- src/metadata_management.h | 40 ++++++---- 4 files changed, 180 insertions(+), 108 deletions(-) diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 4dfa2e015..015864d34 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -21,25 +21,17 @@ namespace hermes { -BufferOrganizer::BufferOrganizer(int num_threads) : - pool(num_threads) {} +BufferOrganizer::BufferOrganizer(SharedMemoryContext *context, + RpcContext *rpc, int num_threads) : + context_(context), rpc_(rpc), pool(num_threads) {} bool operator==(const BufferInfo &lhs, const BufferInfo &rhs) { return (lhs.id == rhs.id && lhs.size == rhs.size && lhs.bandwidth_mbps == rhs.bandwidth_mbps); } -/** - A structure to represent Target information -*/ -struct TargetInfo { - TargetID id; /**< unique ID */ - f32 bandwidth_mbps; /**< bandwidth in Megabits per second */ - u64 capacity; /**< capacity */ -}; /** get buffer information locally */ -BufferInfo LocalGetBufferInfo(SharedMemoryContext *context, - BufferID buffer_id) { +BufferInfo BufferOrganizer::LocalGetBufferInfo(BufferID buffer_id) { BufferInfo result = {}; BufferHeader *header = GetHeaderByBufferId(context, buffer_id); @@ -56,8 +48,7 @@ BufferInfo LocalGetBufferInfo(SharedMemoryContext *context, } /** get buffer information */ -BufferInfo GetBufferInfo(SharedMemoryContext *context, RpcContext *rpc, - BufferID buffer_id) { +BufferInfo BufferOrganizer::GetBufferInfo(BufferID buffer_id) { BufferInfo result = {}; u32 target_node = buffer_id.bits.node_id; @@ -71,9 +62,20 @@ BufferInfo GetBufferInfo(SharedMemoryContext *context, RpcContext *rpc, return result; } +/** get information for multiple buffers */ +std::vector +BufferOrganizer::GetBufferInfo(const std::vector &buffer_ids) { + std::vector result(buffer_ids.size()); + + for (size_t i = 0; i < buffer_ids.size(); ++i) { + result[i] = GetBufferInfo(context, rpc, buffer_ids[i]); + } + + return result; +} + /** normalize access score from \a raw-score using \a size_mb */ -f32 NormalizeAccessScore(SharedMemoryContext *context, f32 raw_score, - f32 size_mb) { +f32 BufferOrganizer::NormalizeAccessScore(f32 raw_score, f32 size_mb) { BufferPool *pool = GetBufferPoolFromContext(context); f32 min_seconds = size_mb * (1.0 / pool->max_device_bw_mbps); @@ -86,26 +88,8 @@ f32 NormalizeAccessScore(SharedMemoryContext *context, f32 raw_score, return result; } -static inline f32 BytesToMegabytes(size_t bytes) { - f32 result = (f32)bytes / (f32)MEGABYTES(1); - - return result; -} - -std::vector GetBufferInfo(SharedMemoryContext *context, - RpcContext *rpc, - const std::vector &buffer_ids) { - std::vector result(buffer_ids.size()); - - for (size_t i = 0; i < buffer_ids.size(); ++i) { - result[i] = GetBufferInfo(context, rpc, buffer_ids[i]); - } - - return result; -} - -f32 ComputeBlobAccessScore(SharedMemoryContext *context, - const std::vector &buffer_info) { +f32 BufferOrganizer::ComputeBlobAccessScore( + const std::vector &buffer_info) { f32 result = 0; f32 raw_score = 0; f32 total_blob_size_mb = 0; @@ -124,7 +108,8 @@ f32 ComputeBlobAccessScore(SharedMemoryContext *context, } /** sort buffer information */ -void SortBufferInfo(std::vector &buffer_info, bool increasing) { +void BufferOrganizer::SortBufferInfo(std::vector &buffer_info, + bool increasing) { #define HERMES_BUFFER_INFO_COMPARATOR(direction, comp) \ auto direction##_buffer_info_comparator = \ [](const BufferInfo &lhs, const BufferInfo &rhs) { \ @@ -150,7 +135,8 @@ void SortBufferInfo(std::vector &buffer_info, bool increasing) { } /** sort target information */ -void SortTargetInfo(std::vector &target_info, bool increasing) { +void BufferOrganizer::SortTargetInfo(std::vector &target_info, + bool increasing) { auto increasing_target_info_comparator = [](const TargetInfo &lhs, const TargetInfo &rhs) { return lhs.bandwidth_mbps > rhs.bandwidth_mbps; @@ -169,18 +155,12 @@ void SortTargetInfo(std::vector &target_info, bool increasing) { } } -void EnqueueBoMove(RpcContext *rpc, const BoMoveList &moves, BlobID blob_id, - BucketID bucket_id, const std::string &internal_name, - BoPriority priority) { - RpcCall(rpc, rpc->node_id, "BO::EnqueueBoMove", moves, blob_id, - bucket_id, internal_name, priority); -} - -void LocalEnqueueBoMove(SharedMemoryContext *context, RpcContext *rpc, - const BoMoveList &moves, BlobID blob_id, - BucketID bucket_id, - const std::string &internal_blob_name, - BoPriority priority) { +/** Local enqueue of buffer information */ +void BufferOrganizer::LocalEnqueueBoMove(const BoMoveList &moves, + BlobID blob_id, + BucketID bucket_id, + const std::string &internal_blob_name, + BoPriority priority) { ThreadPool *pool = &context->bo->pool; bool is_high_priority = priority == BoPriority::kHigh; // NOTE(llogan): VLOG(1) -> LOG(INFO) @@ -190,12 +170,23 @@ void LocalEnqueueBoMove(SharedMemoryContext *context, RpcContext *rpc, is_high_priority); } +/** enqueue a move operation */ +void BufferOrganizer::EnqueueBoMove(const BoMoveList &moves, BlobID blob_id, + BucketID bucket_id, + const std::string &internal_name, + BoPriority priority) { + RpcCall(rpc, rpc->node_id, "BO::EnqueueBoMove", moves, blob_id, + bucket_id, internal_name, priority); +} + /** - * Assumes all BufferIDs in destinations are local - */ -void BoMove(SharedMemoryContext *context, RpcContext *rpc, - const BoMoveList &moves, BlobID blob_id, BucketID bucket_id, - const std::string &internal_blob_name) { + * copy a set of buffers into a set of new buffers. + * + * assumes all BufferIDs in destinations are local + * */ +void BufferOrganizer::BoMove(const BoMoveList &moves, + BlobID blob_id, BucketID bucket_id, + const std::string &internal_blob_name) { // NOTE(llogan): VLOG(1) -> LOG(INFO) LOG(INFO) << "Moving blob " << internal_blob_name.substr(kBucketIdStringSize, std::string::npos) @@ -315,10 +306,10 @@ void BoMove(SharedMemoryContext *context, RpcContext *rpc, } } -void LocalOrganizeBlob(SharedMemoryContext *context, RpcContext *rpc, - const std::string &internal_blob_name, - BucketID bucket_id, f32 epsilon, - f32 explicit_importance_score) { +/** change the composition of a blob based on importance */ +void BufferOrganizer::LocalOrganizeBlob(const std::string &internal_blob_name, + BucketID bucket_id, f32 epsilon, + f32 explicit_importance_score) { MetadataManager *mdm = GetMetadataManagerFromContext(context); BlobID blob_id = {}; blob_id.as_int = LocalGet(mdm, internal_blob_name.c_str(), kMapType_BlobId); @@ -439,9 +430,9 @@ void LocalOrganizeBlob(SharedMemoryContext *context, RpcContext *rpc, BoPriority::kLow); } -void OrganizeBlob(SharedMemoryContext *context, RpcContext *rpc, - BucketID bucket_id, const std::string &blob_name, - f32 epsilon, f32 importance_score) { +void BufferOrganizer::OrganizeBlob(BucketID bucket_id, + const std::string &blob_name, + f32 epsilon, f32 importance_score) { MetadataManager *mdm = GetMetadataManagerFromContext(context); std::string internal_name = MakeInternalBlobName(blob_name, bucket_id); u32 target_node = HashString(mdm, rpc, internal_name.c_str()); @@ -455,8 +446,7 @@ void OrganizeBlob(SharedMemoryContext *context, RpcContext *rpc, } } -void EnforceCapacityThresholds(SharedMemoryContext *context, RpcContext *rpc, - ViolationInfo info) { +void BufferOrganizer::EnforceCapacityThresholds(ViolationInfo info) { u32 target_node = info.target_id.bits.node_id; if (target_node == rpc->node_id) { LocalEnforceCapacityThresholds(context, rpc, info); @@ -465,8 +455,7 @@ void EnforceCapacityThresholds(SharedMemoryContext *context, RpcContext *rpc, } } -void LocalEnforceCapacityThresholds(SharedMemoryContext *context, - RpcContext *rpc, ViolationInfo info) { +void BufferOrganizer::LocalEnforceCapacityThresholds(ViolationInfo info) { MetadataManager *mdm = GetMetadataManagerFromContext(context); // TODO(chogan): Factor out the common code in the kMin and kMax cases @@ -674,14 +663,14 @@ void LocalEnforceCapacityThresholds(SharedMemoryContext *context, } } -void LocalShutdownBufferOrganizer(SharedMemoryContext *context) { +void BufferOrganizer::LocalShutdownBufferOrganizer() { // NOTE(chogan): ThreadPool destructor needs to be called manually since we // allocated the BO instance with placement new. context->bo->pool.~ThreadPool(); } -void FlushBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id, - const std::string &filename, u64 offset, bool async) { +void BufferOrganizer::FlushBlob(BlobID blob_id, const std::string &filename, + u64 offset, bool async) { if (LockBlob(context, rpc, blob_id)) { int open_flags = 0; mode_t open_mode = 0; @@ -733,7 +722,7 @@ void FlushBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id, // } } -bool EnqueueFlushingTask(RpcContext *rpc, BlobID blob_id, +bool BufferOrganizer::EnqueueFlushingTask(BlobID blob_id, const std::string &filename, u64 offset) { bool result = RpcCall(rpc, rpc->node_id, "BO::EnqueueFlushingTask", blob_id, filename, offset); @@ -741,8 +730,7 @@ bool EnqueueFlushingTask(RpcContext *rpc, BlobID blob_id, return result; } -bool LocalEnqueueFlushingTask(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id, const std::string &filename, +bool BufferOrganizer::LocalEnqueueFlushingTask(BlobID blob_id, const std::string &filename, u64 offset) { bool result = false; @@ -763,9 +751,9 @@ bool LocalEnqueueFlushingTask(SharedMemoryContext *context, RpcContext *rpc, /** place BLOBs in hierarchy */ -Status PlaceInHierarchy(SharedMemoryContext *context, RpcContext *rpc, - SwapBlob swap_blob, const std::string &name, - const api::Context &ctx) { +Status BufferOrganizer::PlaceInHierarchy(SwapBlob swap_blob, + const std::string &name, + const api::Context &ctx) { std::vector schemas; std::vector sizes(1, swap_blob.size); Status result = CalculatePlacement(context, rpc, sizes, schemas, ctx); @@ -786,8 +774,8 @@ Status PlaceInHierarchy(SharedMemoryContext *context, RpcContext *rpc, } /** adjust flush coun locally */ -void LocalAdjustFlushCount(SharedMemoryContext *context, - const std::string &vbkt_name, int adjustment) { +void BufferOrganizer::LocalAdjustFlushCount(const std::string &vbkt_name, + int adjustment) { MetadataManager *mdm = GetMetadataManagerFromContext(context); VBucketID id = LocalGetVBucketId(context, vbkt_name.c_str()); mdm->vbucket_mutex.Lock(); @@ -801,18 +789,15 @@ void LocalAdjustFlushCount(SharedMemoryContext *context, mdm->vbucket_mutex.Unlock(); } -void LocalIncrementFlushCount(SharedMemoryContext *context, - const std::string &vbkt_name) { +void BufferOrganizer::LocalIncrementFlushCount(const std::string &vbkt_name) { LocalAdjustFlushCount(context, vbkt_name, 1); } -void LocalDecrementFlushCount(SharedMemoryContext *context, - const std::string &vbkt_name) { +void BufferOrganizer::LocalDecrementFlushCount(const std::string &vbkt_name) { LocalAdjustFlushCount(context, vbkt_name, -1); } -void IncrementFlushCount(SharedMemoryContext *context, RpcContext *rpc, - const std::string &vbkt_name) { +void BufferOrganizer::IncrementFlushCount(const std::string &vbkt_name) { MetadataManager *mdm = GetMetadataManagerFromContext(context); u32 target_node = HashString(mdm, rpc, vbkt_name.c_str()); @@ -824,8 +809,7 @@ void IncrementFlushCount(SharedMemoryContext *context, RpcContext *rpc, } } -void DecrementFlushCount(SharedMemoryContext *context, RpcContext *rpc, - const std::string &vbkt_name) { +void BufferOrganizer::DecrementFlushCount(const std::string &vbkt_name) { MetadataManager *mdm = GetMetadataManagerFromContext(context); u32 target_node = HashString(mdm, rpc, vbkt_name.c_str()); @@ -837,15 +821,14 @@ void DecrementFlushCount(SharedMemoryContext *context, RpcContext *rpc, } } -void AwaitAsyncFlushingTasks(SharedMemoryContext *context, RpcContext *rpc, - VBucketID id) { +void BufferOrganizer::AwaitAsyncFlushingTasks(VBucketID id) { auto sleep_time = std::chrono::milliseconds(500); int outstanding_flushes = 0; int log_every = 10; int counter = 0; while ((outstanding_flushes = - GetNumOutstandingFlushingTasks(context, rpc, id)) != 0) { + GetNumOutstandingFlushingTasks(id)) != 0) { if (++counter == log_every) { LOG(INFO) << "Waiting for " << outstanding_flushes << " outstanding flushes" << std::endl; diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index 18d1bd4a9..edf033884 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -14,6 +14,7 @@ #define HERMES_BUFFER_ORGANIZER_H_ #include "thread_pool.h" +#include "hermes_status.h" namespace hermes { @@ -77,6 +78,15 @@ struct BufferInfo { /** comparison operator */ bool operator==(const BufferInfo &lhs, const BufferInfo &rhs); +/** + A structure to represent Target information +*/ +struct TargetInfo { + TargetID id; /**< unique ID */ + f32 bandwidth_mbps; /**< bandwidth in Megabits per second */ + u64 capacity; /**< capacity */ +}; + /** A structure to represent buffer organizer */ @@ -91,9 +101,82 @@ class BufferOrganizer { explicit BufferOrganizer(SharedMemoryContext *context, RpcContext *rpc, int num_threads); - + /** get buffer information locally */ + BufferInfo LocalGetBufferInfo(BufferID buffer_id); + + /** get buffer information */ + BufferInfo GetBufferInfo(BufferID buffer_id); + + /** get information for multiple buffers */ + std::vector + GetBufferInfo(const std::vector &buffer_ids); + + /** normalize access score from \a raw-score using \a size_mb */ + f32 NormalizeAccessScore(f32 raw_score, f32 size_mb); + + /** compute blob access score */ + f32 ComputeBlobAccessScore(const std::vector &buffer_info); + + /** sort buffer information */ + void SortBufferInfo(std::vector &buffer_info, bool increasing); + + /** sort target information */ + void SortTargetInfo(std::vector &target_info, bool increasing); + + /** Local enqueue of buffer information */ + void LocalEnqueueBoMove(const BoMoveList &moves, BlobID blob_id, + BucketID bucket_id, + const std::string &internal_blob_name, + BoPriority priority); + + /** enqueue a move operation */ + void EnqueueBoMove(const BoMoveList &moves, BlobID blob_id, + BucketID bucket_id, const std::string &internal_name, + BoPriority priority); + + /** + * copy a set of buffers into a set of new buffers. + * + * assumes all BufferIDs in destinations are local + * */ + void BoMove(const BoMoveList &moves, BlobID blob_id, BucketID bucket_id, + const std::string &internal_blob_name); + + /** change the composition of a blob based on importance locally */ + void LocalOrganizeBlob(const std::string &internal_blob_name, + BucketID bucket_id, f32 epsilon, + f32 explicit_importance_score); + + /** change the composition of a blob */ + void OrganizeBlob(BucketID bucket_id, const std::string &blob_name, + f32 epsilon, f32 importance_score); + + + void EnforceCapacityThresholds(ViolationInfo info); + void LocalEnforceCapacityThresholds(ViolationInfo info); + void LocalShutdownBufferOrganizer(); + void FlushBlob(BlobID blob_id, const std::string &filename, + u64 offset, bool async); + bool EnqueueFlushingTask(BlobID blob_id, + const std::string &filename, u64 offset); + bool LocalEnqueueFlushingTask(BlobID blob_id, const std::string &filename, + u64 offset); + api::Status PlaceInHierarchy(SwapBlob swap_blob, const std::string &name, + const api::Context &ctx); + void LocalAdjustFlushCount(const std::string &vbkt_name, int adjustment); + void LocalIncrementFlushCount(const std::string &vbkt_name); + void LocalDecrementFlushCount(const std::string &vbkt_name); + void IncrementFlushCount(const std::string &vbkt_name); + void DecrementFlushCount(const std::string &vbkt_name); + void AwaitAsyncFlushingTasks(VBucketID id); }; +static inline f32 BytesToMegabytes(size_t bytes) { + f32 result = (f32)bytes / (f32)MEGABYTES(1); + + return result; +} + } // namespace hermes #endif // HERMES_BUFFER_ORGANIZER_H_ diff --git a/src/metadata_management.cc b/src/metadata_management.cc index 471c596df..f75cff620 100644 --- a/src/metadata_management.cc +++ b/src/metadata_management.cc @@ -1275,8 +1275,8 @@ SwapBlob IdArrayToSwapBlob(BufferIdArray ids) { } /** initialize metadata manager */ -void InitMetadataManager(MetadataManager *mdm, RpcContext *rpc, Arena *arena, - Config *config) { +MetadataManager::MetadataManager(RpcContext *rpc, Config *config) : + config_(config), rpc_(rpc) { // NOTE(chogan): All MetadataManager offsets are relative to the address of // the MDM itself. u32 node_id = rpc->node_id; diff --git a/src/metadata_management.h b/src/metadata_management.h index f0c220fb3..7296961e4 100644 --- a/src/metadata_management.h +++ b/src/metadata_management.h @@ -104,7 +104,7 @@ struct BufferIdArray { */ struct BlobInfo { Stats stats; /**< BLOB statistics */ - TicketMutex lock; /**< lock */ + labstor::Mutex lock; /**< lock */ TargetID effective_target; /**< target ID */ u32 last; /**< last */ bool stop; /**< stop */ @@ -202,7 +202,12 @@ struct GlobalSystemViewState { /** A structure to represent metadata manager */ -struct MetadataManager { +class MetadataManager { + public: + Config *config_; + SharedMemoryContext *context_; + RpcContext *rpc_; + // All offsets are relative to the beginning of the MDM ptrdiff_t bucket_info_offset; /**< bucket information */ BucketID first_free_bucket; /**< ID of first free bucket */ @@ -227,28 +232,28 @@ struct MetadataManager { ptrdiff_t swap_filename_prefix_offset; /**< swap file name prefix */ ptrdiff_t swap_filename_suffix_offset; /**< swap file name suffix */ - // TODO(chogan): @optimization Should the TicketMutexes here be reader/writer + // TODO(chogan): @optimization Should the mutexes here be reader/writer // locks? /** Lock for accessing `BucketInfo` structures located at * `bucket_info_offset` */ - TicketMutex bucket_mutex; - RwLock bucket_delete_lock; /**< lock for bucket deletion */ + labstor::Mutex bucket_mutex; + labstor::RwLock bucket_delete_lock; /**< lock for bucket deletion */ /** Lock for accessing `VBucketInfo` structures located at * `vbucket_info_offset` */ - TicketMutex vbucket_mutex; + labstor::Mutex vbucket_mutex; /** Lock for accessing the `IdMap` located at `bucket_map_offset` */ - TicketMutex bucket_map_mutex; + labstor::Mutex bucket_map_mutex; /** Lock for accessing the `IdMap` located at `vbucket_map_offset` */ - TicketMutex vbucket_map_mutex; + labstor::Mutex vbucket_map_mutex; /** Lock for accessing the `IdMap` located at `blob_id_map_offset` */ - TicketMutex blob_id_map_mutex; + labstor::Mutex blob_id_map_mutex; /** Lock for accessing the `BlobInfoMap` located at `blob_info_map_offset` */ - TicketMutex blob_info_map_mutex; + labstor::Mutex blob_info_map_mutex; /** Lock for accessing `IdList`s and `ChunkedIdList`s */ - TicketMutex id_mutex; + labstor::Mutex id_mutex; size_t map_seed; /**< map seed */ @@ -262,9 +267,10 @@ struct MetadataManager { u32 num_vbuckets; /**< number of virtual buckets */ u32 max_vbuckets; /**< maximum number of virtual buckets */ std::atomic clock; /**< clock */ -}; -struct RpcContext; + public: + MetadataManager(RpcContext *context, Config *config); +}; /** * @@ -453,22 +459,22 @@ bool IsNullBlobId(BlobID id); /** * begin global ticket mutex */ -void BeginGlobalTicketMutex(SharedMemoryContext *context, RpcContext *rpc); +void BeginGloballabstor::Mutex(SharedMemoryContext *context, RpcContext *rpc); /** * end global ticket mutex */ -void EndGlobalTicketMutex(SharedMemoryContext *context, RpcContext *rpc); +void EndGloballabstor::Mutex(SharedMemoryContext *context, RpcContext *rpc); /** * begin global ticket mutex locally */ -void LocalBeginGlobalTicketMutex(MetadataManager *mdm); +void LocalBeginGloballabstor::Mutex(MetadataManager *mdm); /** * end global ticket mutex locally */ -void LocalEndGlobalTicketMutex(MetadataManager *mdm); +void LocalEndGloballabstor::Mutex(MetadataManager *mdm); /** * attach BLOB to VBucket From d2dcf8a29710eb979762cb85f18a7f889d59e4e7 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 30 Nov 2022 18:38:12 -0600 Subject: [PATCH 031/511] All mdm prototypes created --- src/hermes_types.h | 10 + src/metadata_management.cc | 594 ++++++++++++---------------- src/metadata_management.h | 596 ++++++++++++++++------------- src/metadata_management_internal.h | 151 -------- 4 files changed, 594 insertions(+), 757 deletions(-) delete mode 100644 src/metadata_management_internal.h diff --git a/src/hermes_types.h b/src/hermes_types.h index 01bbff50b..4c13f8297 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -71,6 +71,8 @@ union BucketID { /** The BucketID as a unsigned 64-bit integer */ u64 as_int; + + bool IsNull() { return as_int == 0; } }; // NOTE(chogan): We reserve sizeof(BucketID) * 2 bytes in order to embed the @@ -94,6 +96,8 @@ union VBucketID { /** The VBucketID as a unsigned 64-bit integer */ u64 as_int; + + bool IsNull() { return as_int == 0; } }; union BlobID { @@ -109,6 +113,10 @@ union BlobID { /** The BlobID as an unsigned 64-bit integer */ u64 as_int; + + bool IsNull() { return as_int == 0; } + bool InSwap() { return bits.node_id < 0; } + i32 GetNodeId() { return bits.node_id; } }; /** @@ -284,6 +292,8 @@ union TargetID { /** The TargetID as a unsigned 64-bit integer */ u64 as_int; + + bool IsNull() { return as_int == 0; } }; /** diff --git a/src/metadata_management.cc b/src/metadata_management.cc index f75cff620..9d4848721 100644 --- a/src/metadata_management.cc +++ b/src/metadata_management.cc @@ -17,7 +17,6 @@ #include #include -#include "metadata_management_internal.h" #include "buffer_pool.h" #include "buffer_pool_internal.h" #include "buffer_organizer.h" @@ -63,100 +62,51 @@ bool IsVBucketNameTooLong(const std::string &name) { return result; } -/** is \a id null? */ -static inline bool IsNullId(u64 id) { - bool result = id == 0; - - return result; -} - -/** is Bucket \a id null? */ -bool IsNullBucketId(BucketID id) { - return IsNullId(id.as_int); -} - -/** is VBucket \a id null? */ -bool IsNullVBucketId(VBucketID id) { - return IsNullId(id.as_int); -} - -/** is BLOB \a id null? */ -bool IsNullBlobId(BlobID id) { - return IsNullId(id.as_int); -} - -/** is Target \a id null? */ -bool IsNullTargetId(TargetID id) { - return IsNullId(id.as_int); -} - -/** get the node ID of \a id BLOB */ -static u32 GetBlobNodeId(BlobID id) { - u32 result = (u32)abs(id.bits.node_id); - - return result; -} - /** put \a key, \a value, and \a map_type locally */ -void LocalPut(MetadataManager *mdm, const char *key, u64 val, +void LocalPut(const char *key, u64 val, MapType map_type) { - PutToStorage(mdm, key, val, map_type); + PutToStorage(key, val, map_type); } /** put \a key and \a value locally */ -void LocalPut(MetadataManager *mdm, BlobID key, const BlobInfo &value) { - PutToStorage(mdm, key, value); +void LocalPut(BlobID key, const BlobInfo &value) { + PutToStorage(key, value); } /** get the value of \a key and \a map_type locally */ -u64 LocalGet(MetadataManager *mdm, const char *key, MapType map_type) { - u64 result = GetFromStorage(mdm, key, map_type); +u64 LocalGet(const char *key, MapType map_type) { + u64 result = GetFromStorage(key, map_type); return result; } /** delete \a key locally */ -void LocalDelete(MetadataManager *mdm, BlobID key) { - DeleteFromStorage(mdm, key, false); +void LocalDelete(BlobID key) { + DeleteFromStorage(key, false); } /** delete \a map_type locally */ -void LocalDelete(MetadataManager *mdm, const char *key, MapType map_type) { - DeleteFromStorage(mdm, key, map_type); -} - -/** get metadata manager from \a context shared memory context */ -MetadataManager *GetMetadataManagerFromContext(SharedMemoryContext *context) { - MetadataManager *result = - (MetadataManager *)(context->shm_base + context->metadata_manager_offset); - - return result; -} - -/** log error when metadata arena capacity is full */ -static void MetadataArenaErrorHandler() { - LOG(FATAL) << "Metadata arena capacity exceeded. Consider increasing the " - << "value of metadata_arena_percentage in the Hermes configuration" - << std::endl; +void LocalDelete(const char *key, MapType map_type) { + DeleteFromStorage(key, map_type); } /** get hash string for metadata storage */ -u32 HashString(MetadataManager *mdm, RpcContext *rpc, const char *str) { - u32 result = HashStringForStorage(mdm, rpc, str); +u32 HashString(const char *str) { + u32 result = HashStringForStorage(rpc, str); return result; } /** get id */ -u64 GetId(SharedMemoryContext *context, RpcContext *rpc, const char *name, +u64 GetId(const char *name, MapType map_type) { u64 result = 0; - MetadataManager *mdm = GetMetadataManagerFromContext(context); - u32 target_node = HashString(mdm, rpc, name); + mdm = GetMetadataManagerFromContext(context); + u32 target_node = HashString(rpc, name); if (target_node == rpc->node_id) { - result = LocalGet(mdm, name, map_type); + result = LocalGet(name, map_type); } else { result = RpcCall(rpc, target_node, "RemoteGet", std::string(name), map_type); @@ -166,7 +116,7 @@ u64 GetId(SharedMemoryContext *context, RpcContext *rpc, const char *name, } /** get bucket id */ -BucketID GetBucketId(SharedMemoryContext *context, RpcContext *rpc, +BucketID GetBucketId( const char *name) { BucketID result = {}; result.as_int = GetId(context, rpc, name, kMapType_Bucket); @@ -175,15 +125,15 @@ BucketID GetBucketId(SharedMemoryContext *context, RpcContext *rpc, } /** get local bucket id */ -BucketID LocalGetBucketId(SharedMemoryContext *context, const char *name) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); +BucketID LocalGetBucketId(const char *name) { + mdm = GetMetadataManagerFromContext(context); BucketID result = {}; - result.as_int = LocalGet(mdm, name, kMapType_Bucket); + result.as_int = LocalGet(name, kMapType_Bucket); return result; } /** get virtual bucket id */ -VBucketID GetVBucketId(SharedMemoryContext *context, RpcContext *rpc, +VBucketID GetVBucketId( const char *name) { VBucketID result = {}; result.as_int = GetId(context, rpc, name, kMapType_VBucket); @@ -192,10 +142,10 @@ VBucketID GetVBucketId(SharedMemoryContext *context, RpcContext *rpc, } /** get local virtual bucket id */ -VBucketID LocalGetVBucketId(SharedMemoryContext *context, const char *name) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); +VBucketID LocalGetVBucketId(const char *name) { + mdm = GetMetadataManagerFromContext(context); VBucketID result = {}; - result.as_int = LocalGet(mdm, name, kMapType_VBucket); + result.as_int = LocalGet(name, kMapType_VBucket); return result; } @@ -223,7 +173,7 @@ std::string MakeInternalBlobName(const std::string &name, BucketID id) { } /** get BLOB id */ -BlobID GetBlobId(SharedMemoryContext *context, RpcContext *rpc, +BlobID GetBlobId( const std::string &name, BucketID bucket_id, bool track_stats) { std::string internal_name = MakeInternalBlobName(name, bucket_id); @@ -237,103 +187,103 @@ BlobID GetBlobId(SharedMemoryContext *context, RpcContext *rpc, } /** put BLOB id */ -void PutId(MetadataManager *mdm, RpcContext *rpc, const std::string &name, +void PutId(const std::string &name, u64 id, MapType map_type) { - u32 target_node = HashString(mdm, rpc, name.c_str()); + u32 target_node = HashString(rpc, name.c_str()); if (target_node == rpc->node_id) { - LocalPut(mdm, name.c_str(), id, map_type); + LocalPut(name.c_str(), id, map_type); } else { RpcCall(rpc, target_node, "RemotePut", name, id, map_type); } } /** put bucket id */ -void PutBucketId(MetadataManager *mdm, RpcContext *rpc, const std::string &name, +void PutBucketId(const std::string &name, BucketID id) { - PutId(mdm, rpc, name, id.as_int, kMapType_Bucket); + PutId(rpc, name, id.as_int, kMapType_Bucket); } /** put bucket id locally */ -void LocalPutBucketId(MetadataManager *mdm, const std::string &name, +void LocalPutBucketId(const std::string &name, BucketID id) { - LocalPut(mdm, name.c_str(), id.as_int, kMapType_Bucket); + LocalPut(name.c_str(), id.as_int, kMapType_Bucket); } /** put virtual bucket id */ -void PutVBucketId(MetadataManager *mdm, RpcContext *rpc, +void PutVBucketId( const std::string &name, VBucketID id) { - PutId(mdm, rpc, name, id.as_int, kMapType_VBucket); + PutId(rpc, name, id.as_int, kMapType_VBucket); } /** put virtual bucket id locally */ -void LocalPutVBucketId(MetadataManager *mdm, const std::string &name, +void LocalPutVBucketId(const std::string &name, VBucketID id) { - LocalPut(mdm, name.c_str(), id.as_int, kMapType_VBucket); + LocalPut(name.c_str(), id.as_int, kMapType_VBucket); } /** put BLOB id */ -void PutBlobId(MetadataManager *mdm, RpcContext *rpc, const std::string &name, +void PutBlobId(const std::string &name, BlobID id, BucketID bucket_id) { std::string internal_name = MakeInternalBlobName(name, bucket_id); - PutId(mdm, rpc, internal_name, id.as_int, kMapType_BlobId); + PutId(rpc, internal_name, id.as_int, kMapType_BlobId); } /** delete id */ -void DeleteId(MetadataManager *mdm, RpcContext *rpc, const std::string &name, +void DeleteId(const std::string &name, MapType map_type) { - u32 target_node = HashString(mdm, rpc, name.c_str()); + u32 target_node = HashString(rpc, name.c_str()); if (target_node == rpc->node_id) { - LocalDelete(mdm, name.c_str(), map_type); + LocalDelete(name.c_str(), map_type); } else { RpcCall(rpc, target_node, "RemoteDelete", name, map_type); } } /** delete bucket id */ -void DeleteBucketId(MetadataManager *mdm, RpcContext *rpc, +void DeleteBucketId( const std::string &name) { - DeleteId(mdm, rpc, name, kMapType_Bucket); + DeleteId(rpc, name, kMapType_Bucket); } /** delete virtual bucket id */ -void DeleteVBucketId(MetadataManager *mdm, RpcContext *rpc, +void DeleteVBucketId( const std::string &name) { - DeleteId(mdm, rpc, name, kMapType_VBucket); + DeleteId(rpc, name, kMapType_VBucket); } /** delete BLOB information locally */ -void LocalDeleteBlobInfo(MetadataManager *mdm, BlobID blob_id) { - LocalDelete(mdm, blob_id); +void LocalDeleteBlobInfo(BlobID blob_id) { + LocalDelete(blob_id); } /** delete BLOB id locally */ -void LocalDeleteBlobId(MetadataManager *mdm, const std::string &name, +void LocalDeleteBlobId(const std::string &name, BucketID bucket_id) { std::string internal_name = MakeInternalBlobName(name, bucket_id); - LocalDelete(mdm, internal_name.c_str(), kMapType_BlobId); + LocalDelete(internal_name.c_str(), kMapType_BlobId); } /** delete BLOB id */ -void DeleteBlobId(MetadataManager *mdm, RpcContext *rpc, +void DeleteBlobId( const std::string &name, BucketID bucket_id) { std::string internal_name = MakeInternalBlobName(name, bucket_id); - DeleteId(mdm, rpc, internal_name, kMapType_BlobId); + DeleteId(rpc, internal_name, kMapType_BlobId); } /** get bucket information by \a index index locally */ -BucketInfo *LocalGetBucketInfoByIndex(MetadataManager *mdm, u32 index) { - BucketInfo *info_array = (BucketInfo *)((u8 *)mdm + mdm->bucket_info_offset); +BucketInfo *LocalGetBucketInfoByIndex(u32 index) { + BucketInfo *info_array = (BucketInfo *)((u8 *)mdm + bucket_info_offset); BucketInfo *result = info_array + index; return result; } /** get BLOB name from \a blob_id locally */ -std::string LocalGetBlobNameFromId(SharedMemoryContext *context, +std::string LocalGetBlobNameFromId( BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - std::string blob_name = ReverseGetFromStorage(mdm, blob_id.as_int, + mdm = GetMetadataManagerFromContext(context); + std::string blob_name = ReverseGetFromStorage(blob_id.as_int, kMapType_BlobId); std::string result; @@ -345,7 +295,7 @@ std::string LocalGetBlobNameFromId(SharedMemoryContext *context, } /** get BLOB name from \a blob_id */ -std::string GetBlobNameFromId(SharedMemoryContext *context, RpcContext *rpc, +std::string GetBlobNameFromId( BlobID blob_id) { u32 target_node = GetBlobNodeId(blob_id); std::string result; @@ -385,9 +335,9 @@ u64 HexStringToU64(const std::string &s) { } /** get bucket ID from \a blob_id locally */ -BucketID LocalGetBucketIdFromBlobId(SharedMemoryContext *context, BlobID id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - std::string internal_name = ReverseGetFromStorage(mdm, id.as_int, +BucketID LocalGetBucketIdFromBlobId(BlobID id) { + mdm = GetMetadataManagerFromContext(context); + std::string internal_name = ReverseGetFromStorage(id.as_int, kMapType_BlobId); BucketID result = {}; if (internal_name.size() > kBucketIdStringSize) { @@ -398,7 +348,7 @@ BucketID LocalGetBucketIdFromBlobId(SharedMemoryContext *context, BlobID id) { } /** get bucket ID from \a blob_id */ -BucketID GetBucketIdFromBlobId(SharedMemoryContext *context, RpcContext *rpc, +BucketID GetBucketIdFromBlobId( BlobID id) { BucketID result = {}; u32 target_node = GetBlobNodeId(id); @@ -413,14 +363,14 @@ BucketID GetBucketIdFromBlobId(SharedMemoryContext *context, RpcContext *rpc, } /** get bucket information from \a bucket_id */ -BucketInfo *LocalGetBucketInfoById(MetadataManager *mdm, BucketID id) { - BucketInfo *result = LocalGetBucketInfoByIndex(mdm, id.bits.index); +BucketInfo *LocalGetBucketInfoById(BucketID id) { + BucketInfo *result = LocalGetBucketInfoByIndex(id.bits.index); return result; } /** get BLOB IDs from \a bucket_id */ -std::vector GetBlobIds(SharedMemoryContext *context, RpcContext *rpc, +std::vector GetBlobIds( BucketID bucket_id) { std::vector result; u32 target_node = bucket_id.bits.node_id; @@ -435,9 +385,9 @@ std::vector GetBlobIds(SharedMemoryContext *context, RpcContext *rpc, } /** get virtual bucket information by \a index */ -VBucketInfo *GetVBucketInfoByIndex(MetadataManager *mdm, u32 index) { +VBucketInfo *GetVBucketInfoByIndex(u32 index) { VBucketInfo *info_array = - (VBucketInfo *)((u8 *)mdm + mdm->vbucket_info_offset); + (VBucketInfo *)((u8 *)mdm + vbucket_info_offset); VBucketInfo *result = info_array + index; return result; @@ -446,23 +396,23 @@ VBucketInfo *GetVBucketInfoByIndex(MetadataManager *mdm, u32 index) { /** * Returns an available BucketID and marks it as in use in the MDM. * - * Assumes MetadataManager::bucket_mutex is already held by the caller. + * Assumes bucket_mutex is already held by the caller. */ -BucketID LocalGetNextFreeBucketId(SharedMemoryContext *context, +BucketID LocalGetNextFreeBucketId( const std::string &name) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); + mdm = GetMetadataManagerFromContext(context); BucketID result = {}; - if (mdm->num_buckets < mdm->max_buckets) { - result = mdm->first_free_bucket; + if (num_buckets < max_buckets) { + result = first_free_bucket; if (!IsNullBucketId(result)) { - BucketInfo *info = LocalGetBucketInfoByIndex(mdm, result.bits.index); + BucketInfo *info = LocalGetBucketInfoByIndex(result.bits.index); info->blobs = {}; info->ref_count.store(1); info->active = true; - mdm->first_free_bucket = info->next_free; - mdm->num_buckets++; + first_free_bucket = info->next_free; + num_buckets++; } } else { LOG(ERROR) << "Exceeded max allowed buckets. " @@ -472,17 +422,17 @@ BucketID LocalGetNextFreeBucketId(SharedMemoryContext *context, if (!IsNullBucketId(result)) { // NOTE(chogan): Add metadata entry - LocalPutBucketId(mdm, name, result); + LocalPutBucketId(name, result); } return result; } /** get or create a bucket ID locally */ -BucketID LocalGetOrCreateBucketId(SharedMemoryContext *context, +BucketID LocalGetOrCreateBucketId( const std::string &name) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - mdm->bucket_mutex.Lock();; + mdm = GetMetadataManagerFromContext(context); + bucket_mutex.Lock();; BucketID result = LocalGetBucketId(context, name.c_str()); if (result.as_int != 0) { @@ -492,16 +442,16 @@ BucketID LocalGetOrCreateBucketId(SharedMemoryContext *context, LOG(INFO) << "Creating Bucket '" << name << "'" << std::endl; result = LocalGetNextFreeBucketId(context, name); } - mdm->bucket_mutex.Unlock(); + bucket_mutex.Unlock(); return result; } /** get or create a bucket ID */ -BucketID GetOrCreateBucketId(SharedMemoryContext *context, RpcContext *rpc, +BucketID GetOrCreateBucketId( const std::string &name) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - u32 target_node = HashString(mdm, rpc, name.c_str()); + mdm = GetMetadataManagerFromContext(context); + u32 target_node = HashString(rpc, name.c_str()); BucketID result = {}; if (target_node == rpc->node_id) { result = LocalGetOrCreateBucketId(context, name); @@ -518,23 +468,23 @@ BucketID GetOrCreateBucketId(SharedMemoryContext *context, RpcContext *rpc, * * Assumes MetadataManager::vbucket_mutex is already held by the caller. */ -VBucketID LocalGetNextFreeVBucketId(SharedMemoryContext *context, +VBucketID LocalGetNextFreeVBucketId( const std::string &name) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); + mdm = GetMetadataManagerFromContext(context); VBucketID result = {}; // TODO(chogan): Could replace this with lock-free version if/when it matters - if (mdm->num_vbuckets < mdm->max_vbuckets) { - result = mdm->first_free_vbucket; + if (num_vbuckets < max_vbuckets) { + result = first_free_vbucket; if (!IsNullVBucketId(result)) { - VBucketInfo *info = GetVBucketInfoByIndex(mdm, result.bits.index); + VBucketInfo *info = GetVBucketInfoByIndex(result.bits.index); info->blobs = {}; memset(info->traits, 0, sizeof(TraitID) * kMaxTraitsPerVBucket); info->ref_count.store(1); info->active = true; - mdm->first_free_vbucket = info->next_free; - mdm->num_vbuckets++; + first_free_vbucket = info->next_free; + num_vbuckets++; } } else { LOG(ERROR) << "Exceeded max allowed vbuckets. " @@ -542,18 +492,18 @@ VBucketID LocalGetNextFreeVBucketId(SharedMemoryContext *context, << std::endl; } if (!IsNullVBucketId(result)) { - LocalPutVBucketId(mdm, name, result); + LocalPutVBucketId(name, result); } return result; } /** get or create a virtual bucket ID locally */ -VBucketID LocalGetOrCreateVBucketId(SharedMemoryContext *context, +VBucketID LocalGetOrCreateVBucketId( const std::string &name) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); + mdm = GetMetadataManagerFromContext(context); - mdm->vbucket_mutex.Lock(); + vbucket_mutex.Lock(); VBucketID result = LocalGetVBucketId(context, name.c_str()); if (result.as_int != 0) { @@ -563,17 +513,17 @@ VBucketID LocalGetOrCreateVBucketId(SharedMemoryContext *context, LOG(INFO) << "Creating VBucket '" << name << "'" << std::endl; result = LocalGetNextFreeVBucketId(context, name); } - mdm->vbucket_mutex.Unlock(); + vbucket_mutex.Unlock(); return result; } /** get or create a virtual bucket ID */ -VBucketID GetOrCreateVBucketId(SharedMemoryContext *context, RpcContext *rpc, +VBucketID GetOrCreateVBucketId( const std::string &name) { VBucketID result = {}; - MetadataManager *mdm = GetMetadataManagerFromContext(context); - u32 target_node = HashString(mdm, rpc, name.c_str()); + mdm = GetMetadataManagerFromContext(context); + u32 target_node = HashString(rpc, name.c_str()); if (target_node == rpc->node_id) { result = LocalGetOrCreateVBucketId(context, name); } else { @@ -592,7 +542,7 @@ void CopyIds(u64 *dest, u64 *src, u32 count) { } } -void ReplaceBlobIdInBucket(SharedMemoryContext *context, RpcContext *rpc, +void ReplaceBlobIdInBucket( BucketID bucket_id, BlobID old_blob_id, BlobID new_blob_id) { u32 target_node = bucket_id.bits.node_id; @@ -605,12 +555,12 @@ void ReplaceBlobIdInBucket(SharedMemoryContext *context, RpcContext *rpc, } /** add BLOB ID to bucket */ -void AddBlobIdToBucket(MetadataManager *mdm, RpcContext *rpc, BlobID blob_id, +void AddBlobIdToBucket(BlobID blob_id, BucketID bucket_id) { u32 target_node = bucket_id.bits.node_id; if (target_node == rpc->node_id) { - LocalAddBlobIdToBucket(mdm, bucket_id, blob_id); + LocalAddBlobIdToBucket(bucket_id, blob_id); } else { RpcCall(rpc, target_node, "RemoteAddBlobIdToBucket", bucket_id, blob_id); @@ -618,12 +568,12 @@ void AddBlobIdToBucket(MetadataManager *mdm, RpcContext *rpc, BlobID blob_id, } /** add BLOB ID to virtual bucket */ -void AddBlobIdToVBucket(MetadataManager *mdm, RpcContext *rpc, BlobID blob_id, +void AddBlobIdToVBucket(BlobID blob_id, VBucketID vbucket_id) { u32 target_node = vbucket_id.bits.node_id; if (target_node == rpc->node_id) { - LocalAddBlobIdToVBucket(mdm, vbucket_id, blob_id); + LocalAddBlobIdToVBucket(vbucket_id, blob_id); } else { RpcCall(rpc, target_node, "RemoteAddBlobIdToVBucket", vbucket_id, blob_id); @@ -631,14 +581,14 @@ void AddBlobIdToVBucket(MetadataManager *mdm, RpcContext *rpc, BlobID blob_id, } /** allocate buffer ID list */ -u32 AllocateBufferIdList(SharedMemoryContext *context, RpcContext *rpc, +u32 AllocateBufferIdList( u32 target_node, const std::vector &buffer_ids) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); + mdm = GetMetadataManagerFromContext(context); u32 result = 0; if (target_node == rpc->node_id) { - result = LocalAllocateBufferIdList(mdm, buffer_ids); + result = LocalAllocateBufferIdList(buffer_ids); } else { result = RpcCall(rpc, target_node, "RemoteAllocateBufferIdList", buffer_ids); @@ -647,42 +597,34 @@ u32 AllocateBufferIdList(SharedMemoryContext *context, RpcContext *rpc, return result; } -/** is BLOB in swap? */ -bool BlobIsInSwap(BlobID id) { - bool result = id.bits.node_id < 0; - - return result; -} - /** get buffer ID list */ -void GetBufferIdList(SharedMemoryContext *context, - RpcContext *rpc, BlobID blob_id, +void GetBufferIdList( + BlobID blob_id, BufferIdArray *buffer_ids) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); + mdm = GetMetadataManagerFromContext(context); u32 target_node = GetBlobNodeId(blob_id); if (target_node == rpc->node_id) { - LocalGetBufferIdList(arena, mdm, blob_id, buffer_ids); + LocalGetBufferIdList(blob_id, buffer_ids); } else { std::vector result = RpcCall>(rpc, target_node, "RemoteGetBufferIdList", blob_id); - buffer_ids->ids = PushArray(arena, result.size()); + buffer_ids->ids = PushArray(result.size()); buffer_ids->length = (u32)result.size(); CopyIds((u64 *)buffer_ids->ids, (u64 *)result.data(), result.size()); } } /** get buffer ID list as vector */ -std::vector GetBufferIdList(SharedMemoryContext *context, - RpcContext *rpc, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); +std::vector GetBufferIdList(BlobID blob_id) { + mdm = GetMetadataManagerFromContext(context); u32 target_node = GetBlobNodeId(blob_id); std::vector result; if (target_node == rpc->node_id) { - result = LocalGetBufferIdList(mdm, blob_id); + result = LocalGetBufferIdList(blob_id); } else { result = RpcCall>(rpc, target_node, "RemoteGetBufferIdList", blob_id); @@ -692,15 +634,13 @@ std::vector GetBufferIdList(SharedMemoryContext *context, } /** get buffer IDs from BLOB id */ -BufferIdArray GetBufferIdsFromBlobId(Arena *arena, - SharedMemoryContext *context, - RpcContext *rpc, BlobID blob_id, +BufferIdArray GetBufferIdsFromBlobId(BlobID blob_id, u32 **sizes) { BufferIdArray result = {}; - GetBufferIdList(arena, context, rpc, blob_id, &result); + GetBufferIdList(context, rpc, blob_id, &result); if (sizes) { - u32 *buffer_sizes = PushArray(arena, result.length); + u32 *buffer_sizes = PushArray(result.length); for (u32 i = 0; i < result.length; ++i) { buffer_sizes[i] = GetBufferSize(context, rpc, result.ids[i]); } @@ -711,34 +651,32 @@ BufferIdArray GetBufferIdsFromBlobId(Arena *arena, } /** create BLOB metadata locally */ -void LocalCreateBlobMetadata(SharedMemoryContext *context, MetadataManager *mdm, - const std::string &blob_name, BlobID blob_id, +void LocalCreateBlobMetadata(const std::string &blob_name, BlobID blob_id, TargetID effective_target) { - LocalPut(mdm, blob_name.c_str(), blob_id.as_int, kMapType_BlobId); + LocalPut(blob_name.c_str(), blob_id.as_int, kMapType_BlobId); BlobInfo blob_info = {}; blob_info.stats.frequency = 1; - blob_info.stats.recency = mdm->clock++; + blob_info.stats.recency = clock++; blob_info.effective_target = effective_target; if (effective_target != kSwapTargetId) { assert(blob_id.bits.node_id == (int)effective_target.bits.node_id); Target *target = GetTargetFromId(context, effective_target); target->effective_blobs_lock.Lock(); - AppendToChunkedIdList(mdm, &target->effective_blobs, blob_id.as_int); + AppendToChunkedIdList(&target->effective_blobs, blob_id.as_int); target->effective_blobs_lock.Unlock(); } - LocalPut(mdm, blob_id, blob_info); + LocalPut(blob_id, blob_info); } /** create BLOB metadata */ -void CreateBlobMetadata(SharedMemoryContext *context, RpcContext *rpc, - const std::string &blob_name, BlobID blob_id, +void CreateBlobMetadata(const std::string &blob_name, BlobID blob_id, TargetID effective_target) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); + mdm = GetMetadataManagerFromContext(context); u32 target_node = GetBlobNodeId(blob_id); if (target_node == rpc->node_id) { - LocalCreateBlobMetadata(context, mdm, blob_name, blob_id, effective_target); + LocalCreateBlobMetadata(context, blob_name, blob_id, effective_target); } else { RpcCall(rpc, target_node, "RemoteCreateBlobMetadata", blob_name, blob_id, effective_target); @@ -746,15 +684,14 @@ void CreateBlobMetadata(SharedMemoryContext *context, RpcContext *rpc, } /** attach BLOB to bucket */ -void AttachBlobToBucket(SharedMemoryContext *context, RpcContext *rpc, - const char *blob_name, BucketID bucket_id, +void AttachBlobToBucket(const char *blob_name, BucketID bucket_id, const std::vector &buffer_ids, TargetID effective_target, bool is_swap_blob, bool called_from_buffer_organizer) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); + mdm = GetMetadataManagerFromContext(context); std::string internal_name = MakeInternalBlobName(blob_name, bucket_id); - int target_node = HashString(mdm, rpc, internal_name.c_str()); + int target_node = HashString(rpc, internal_name.c_str()); BlobID blob_id = {}; if (called_from_buffer_organizer) { @@ -778,12 +715,11 @@ void AttachBlobToBucket(SharedMemoryContext *context, RpcContext *rpc, target_node, buffer_ids); CreateBlobMetadata(context, rpc, internal_name, blob_id, effective_target); - AddBlobIdToBucket(mdm, rpc, blob_id, bucket_id); + AddBlobIdToBucket(rpc, blob_id, bucket_id); } /** free buffer ID list */ -void FreeBufferIdList(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id) { +void FreeBufferIdList(BlobID blob_id) { u32 target_node = GetBlobNodeId(blob_id); if (target_node == rpc->node_id) { LocalFreeBufferIdList(context, blob_id); @@ -793,15 +729,15 @@ void FreeBufferIdList(SharedMemoryContext *context, RpcContext *rpc, } /** delete BLOB metadata locally */ -void LocalDeleteBlobMetadata(MetadataManager *mdm, const char *blob_name, +void LocalDeleteBlobMetadata(const char *blob_name, BlobID blob_id, BucketID bucket_id) { - LocalDeleteBlobId(mdm, blob_name, bucket_id); - LocalDeleteBlobInfo(mdm, blob_id); + LocalDeleteBlobId(blob_name, bucket_id); + LocalDeleteBlobInfo(blob_id); } /** wait for outstanding BLOB operations */ -void WaitForOutstandingBlobOps(MetadataManager *mdm, BlobID blob_id) { - BlobInfo *blob_info = GetBlobInfoPtr(mdm, blob_id); +void WaitForOutstandingBlobOps(BlobID blob_id) { + BlobInfo *blob_info = GetBlobInfoPtr(blob_id); if (blob_info) { blob_info->lock.Lock(); blob_info->lock.Unlock(); @@ -811,13 +747,12 @@ void WaitForOutstandingBlobOps(MetadataManager *mdm, BlobID blob_id) { } /** destroy BLOB by name locally */ -void LocalDestroyBlobByName(SharedMemoryContext *context, RpcContext *rpc, - const char *blob_name, BlobID blob_id, +void LocalDestroyBlobByName(const char *blob_name, BlobID blob_id, BucketID bucket_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); + mdm = GetMetadataManagerFromContext(context); - // NOTE(chogan): Holding the mdm->blob_info_map_mutex - WaitForOutstandingBlobOps(mdm, blob_id); + // NOTE(chogan): Holding the blob_info_map_mutex + WaitForOutstandingBlobOps(blob_id); if (!BlobIsInSwap(blob_id)) { std::vector buffer_ids = GetBufferIdList(context, rpc, blob_id); @@ -828,14 +763,13 @@ void LocalDestroyBlobByName(SharedMemoryContext *context, RpcContext *rpc, FreeBufferIdList(context, rpc, blob_id); - LocalDeleteBlobMetadata(mdm, blob_name, blob_id, bucket_id); + LocalDeleteBlobMetadata(blob_name, blob_id, bucket_id); ReleaseBlobInfoPtr(mdm); } /** destroy BLOB by ID locally */ -void LocalDestroyBlobById(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id, BucketID bucket_id) { +void LocalDestroyBlobById(BlobID blob_id, BucketID bucket_id) { std::string blob_name = LocalGetBlobNameFromId(context, blob_id); if (blob_name.size() > 0) { LocalDestroyBlobByName(context, rpc, blob_name.c_str(), blob_id, bucket_id); @@ -845,8 +779,7 @@ void LocalDestroyBlobById(SharedMemoryContext *context, RpcContext *rpc, } } -void RemoveBlobFromBucketInfo(SharedMemoryContext *context, RpcContext *rpc, - BucketID bucket_id, BlobID blob_id) { +void RemoveBlobFromBucketInfo(BucketID bucket_id, BlobID blob_id) { u32 target_node = bucket_id.bits.node_id; if (target_node == rpc->node_id) { LocalRemoveBlobFromBucketInfo(context, bucket_id, blob_id); @@ -857,8 +790,7 @@ void RemoveBlobFromBucketInfo(SharedMemoryContext *context, RpcContext *rpc, } /** destroy BLOB by name */ -void DestroyBlobByName(SharedMemoryContext *context, RpcContext *rpc, - BucketID bucket_id, const std::string &blob_name) { +void DestroyBlobByName(BucketID bucket_id, const std::string &blob_name) { BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id); if (!IsNullBlobId(blob_id)) { u32 blob_id_target_node = GetBlobNodeId(blob_id); @@ -875,22 +807,20 @@ void DestroyBlobByName(SharedMemoryContext *context, RpcContext *rpc, } /** rename BLOB */ -void RenameBlob(SharedMemoryContext *context, RpcContext *rpc, - const std::string &old_name, const std::string &new_name, +void RenameBlob(const std::string &old_name, const std::string &new_name, BucketID bucket_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); + mdm = GetMetadataManagerFromContext(context); BlobID blob_id = GetBlobId(context, rpc, old_name, bucket_id); if (!IsNullBlobId(blob_id)) { - DeleteBlobId(mdm, rpc, old_name, bucket_id); - PutBlobId(mdm, rpc, new_name, blob_id, bucket_id); + DeleteBlobId(rpc, old_name, bucket_id); + PutBlobId(rpc, new_name, blob_id, bucket_id); } else { LOG(ERROR) << "Invalid BlobID for Blob '" << old_name << "'" << std::endl; } } /** does \a bucket_id bucket contain \a blob_name BLOB? */ -bool ContainsBlob(SharedMemoryContext *context, RpcContext *rpc, - BucketID bucket_id, const std::string &blob_name) { +bool ContainsBlob(BucketID bucket_id, const std::string &blob_name) { BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id); bool result = false; @@ -908,7 +838,7 @@ bool ContainsBlob(SharedMemoryContext *context, RpcContext *rpc, } /** destroy BLOB by ID */ -void DestroyBlobById(SharedMemoryContext *context, RpcContext *rpc, BlobID id, +void DestroyBlobById(BlobID id, BucketID bucket_id) { u32 target_node = GetBlobNodeId(id); if (target_node == rpc->node_id) { @@ -919,8 +849,7 @@ void DestroyBlobById(SharedMemoryContext *context, RpcContext *rpc, BlobID id, } /** destroy bucket */ -bool DestroyBucket(SharedMemoryContext *context, RpcContext *rpc, - const char *name, BucketID bucket_id) { +bool DestroyBucket(const char *name, BucketID bucket_id) { u32 target_node = bucket_id.bits.node_id; bool destroyed = false; if (target_node == rpc->node_id) { @@ -934,8 +863,7 @@ bool DestroyBucket(SharedMemoryContext *context, RpcContext *rpc, } /** destroy virtual bucket */ -bool DestroyVBucket(SharedMemoryContext *context, RpcContext *rpc, - const char *name, VBucketID vbucket_id) { +bool DestroyVBucket(const char *name, VBucketID vbucket_id) { u32 target_node = vbucket_id.bits.node_id; bool destroyed = false; if (target_node == rpc->node_id) { @@ -949,16 +877,15 @@ bool DestroyVBucket(SharedMemoryContext *context, RpcContext *rpc, } /** rename bucket locally */ -void LocalRenameBucket(SharedMemoryContext *context, RpcContext *rpc, - BucketID id, const std::string &old_name, +void LocalRenameBucket(BucketID id, const std::string &old_name, const std::string &new_name) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - DeleteBucketId(mdm, rpc, old_name); - PutBucketId(mdm, rpc, new_name, id); + mdm = GetMetadataManagerFromContext(context); + DeleteBucketId(rpc, old_name); + PutBucketId(rpc, new_name, id); } /** rename bucket */ -void RenameBucket(SharedMemoryContext *context, RpcContext *rpc, BucketID id, +void RenameBucket(BucketID id, const std::string &old_name, const std::string &new_name) { u32 target_node = id.bits.node_id; if (target_node == rpc->node_id) { @@ -970,23 +897,22 @@ void RenameBucket(SharedMemoryContext *context, RpcContext *rpc, BucketID id, } /** increment reference count locally */ -void LocalIncrementRefcount(SharedMemoryContext *context, BucketID id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - BucketInfo *info = LocalGetBucketInfoById(mdm, id); +void LocalIncrementRefcount(BucketID id) { + mdm = GetMetadataManagerFromContext(context); + BucketInfo *info = LocalGetBucketInfoById(id); info->ref_count.fetch_add(1); } /** decrement reference count locally */ -void LocalDecrementRefcount(SharedMemoryContext *context, BucketID id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - BucketInfo *info = LocalGetBucketInfoById(mdm, id); +void LocalDecrementRefcount(BucketID id) { + mdm = GetMetadataManagerFromContext(context); + BucketInfo *info = LocalGetBucketInfoById(id); info->ref_count.fetch_sub(1); assert(info->ref_count.load() >= 0); } /** decrement reference count */ -void DecrementRefcount(SharedMemoryContext *context, RpcContext *rpc, - BucketID id) { +void DecrementRefcount(BucketID id) { u32 target_node = id.bits.node_id; if (target_node == rpc->node_id) { LocalDecrementRefcount(context, id); @@ -996,7 +922,7 @@ void DecrementRefcount(SharedMemoryContext *context, RpcContext *rpc, } /** get remaning target capacity locally */ -u64 LocalGetRemainingTargetCapacity(SharedMemoryContext *context, TargetID id) { +u64 LocalGetRemainingTargetCapacity(TargetID id) { Target *target = GetTargetFromId(context, id); u64 result = target->remaining_space.load(); @@ -1004,16 +930,16 @@ u64 LocalGetRemainingTargetCapacity(SharedMemoryContext *context, TargetID id) { } /** get local system view state from \a mdm metadata mamanger */ -SystemViewState *GetLocalSystemViewState(MetadataManager *mdm) { +SystemViewState *GetLocalSystemViewState() { SystemViewState *result = - (SystemViewState *)((u8 *)mdm + mdm->system_view_state_offset); + (SystemViewState *)((u8 *)mdm + system_view_state_offset); return result; } /** get local system view state from \a context */ SystemViewState *GetLocalSystemViewState(SharedMemoryContext *context) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); + mdm = GetMetadataManagerFromContext(context); SystemViewState *result = GetLocalSystemViewState(mdm); return result; @@ -1032,10 +958,10 @@ std::vector LocalGetGlobalDeviceCapacities(SharedMemoryContext *context) { } /** get global device capacities */ -std::vector GetGlobalDeviceCapacities(SharedMemoryContext *context, +std::vector GetGlobalDeviceCapacities( RpcContext *rpc) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - u32 target_node = mdm->global_system_view_state_node_id; + mdm = GetMetadataManagerFromContext(context); + u32 target_node = global_system_view_state_node_id; std::vector result; @@ -1051,9 +977,9 @@ std::vector GetGlobalDeviceCapacities(SharedMemoryContext *context, /** get global system view state from \a context */ GlobalSystemViewState *GetGlobalSystemViewState(SharedMemoryContext *context) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); + mdm = GetMetadataManagerFromContext(context); GlobalSystemViewState *result = - (GlobalSystemViewState *)((u8 *)mdm + mdm->global_system_view_state_offset); + (GlobalSystemViewState *)((u8 *)mdm + global_system_view_state_offset); assert((u8 *)result != (u8 *)mdm); return result; @@ -1061,7 +987,7 @@ GlobalSystemViewState *GetGlobalSystemViewState(SharedMemoryContext *context) { /** update global system view state locally */ std::vector -LocalUpdateGlobalSystemViewState(SharedMemoryContext *context, u32 node_id, +LocalUpdateGlobalSystemViewState(u32 node_id, std::vector adjustments) { std::vector result; for (size_t device_idx = 0; device_idx < adjustments.size(); ++device_idx) { @@ -1115,9 +1041,9 @@ LocalUpdateGlobalSystemViewState(SharedMemoryContext *context, u32 node_id, } /** update global system view state */ -void UpdateGlobalSystemViewState(SharedMemoryContext *context, +void UpdateGlobalSystemViewState( RpcContext *rpc) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); + mdm = GetMetadataManagerFromContext(context); BufferPool *pool = GetBufferPoolFromContext(context); bool update_needed = false; @@ -1131,7 +1057,7 @@ void UpdateGlobalSystemViewState(SharedMemoryContext *context, std::vector devices_to_organize; if (update_needed) { - u32 target_node = mdm->global_system_view_state_node_id; + u32 target_node = global_system_view_state_node_id; if (target_node == rpc->node_id) { devices_to_organize = LocalUpdateGlobalSystemViewState(context, rpc->node_id, adjustments); @@ -1166,7 +1092,7 @@ TargetID FindTargetIdFromDeviceId(const std::vector &targets, } /** get offset from metadata manager */ -static ptrdiff_t GetOffsetFromMdm(MetadataManager *mdm, void *ptr) { +static ptrdiff_t GetOffsetFromMdm(void *ptr) { assert((u8 *)ptr >= (u8 *)mdm); ptrdiff_t result = (u8 *)ptr - (u8 *)mdm; @@ -1189,9 +1115,7 @@ SystemViewState *CreateSystemViewState(Config *config) { } /** create global system view state */ -GlobalSystemViewState *CreateGlobalSystemViewState(RpcContext *rpc, - Arena *arena, - Config *config) { +GlobalSystemViewState *CreateGlobalSystemViewState(Config *config) { GlobalSystemViewState *result = PushClearedStruct(arena); result->num_devices = config->num_devices; @@ -1204,7 +1128,7 @@ GlobalSystemViewState *CreateGlobalSystemViewState(RpcContext *rpc, size_t num_targets = config->num_devices * rpc->num_nodes; result->num_targets = num_targets; result->bytes_available = - PushClearedArray>(arena, num_targets); + PushClearedArray>(num_targets); for (u32 node_idx = 0; node_idx < rpc->num_nodes; ++node_idx) { for (int device_idx = 0; device_idx < result->num_devices; ++device_idx) { @@ -1217,9 +1141,9 @@ GlobalSystemViewState *CreateGlobalSystemViewState(RpcContext *rpc, } /** get swap file name */ -std::string GetSwapFilename(MetadataManager *mdm, u32 node_id) { - char *prefix = (char *)((u8 *)mdm + mdm->swap_filename_prefix_offset); - char *suffix = (char *)((u8 *)mdm + mdm->swap_filename_suffix_offset); +std::string GetSwapFilename(u32 node_id) { + char *prefix = (char *)((u8 *)mdm + swap_filename_prefix_offset); + char *suffix = (char *)((u8 *)mdm + swap_filename_suffix_offset); std::string result = (prefix + std::to_string(node_id) + suffix); return result; @@ -1279,39 +1203,38 @@ MetadataManager::MetadataManager(RpcContext *rpc, Config *config) : config_(config), rpc_(rpc) { // NOTE(chogan): All MetadataManager offsets are relative to the address of // the MDM itself. - u32 node_id = rpc->node_id; - arena->error_handler = MetadataArenaErrorHandler; - - mdm->map_seed = 0x4E58E5DF; - SeedHashForStorage(mdm->map_seed); + u32 node_id = rpc->node_id_; + + map_seed = 0x4E58E5DF; + SeedHashForStorage(map_seed); - mdm->system_view_state_update_interval_ms = + system_view_state_update_interval_ms = config->system_view_state_update_interval_ms; // Initialize SystemViewState - SystemViewState *sv_state = CreateSystemViewState(arena, config); - mdm->system_view_state_offset = GetOffsetFromMdm(mdm, sv_state); + SystemViewState *sv_state = CreateSystemViewState(config); + system_view_state_offset = GetOffsetFromMdm(sv_state); // Initialize Global SystemViewState if (node_id == 1) { // NOTE(chogan): Only Node 1 has the Global SystemViewState GlobalSystemViewState *global_state = - CreateGlobalSystemViewState(rpc, arena, config); - mdm->global_system_view_state_offset = GetOffsetFromMdm(mdm, global_state); + CreateGlobalSystemViewState(rpc, config); + global_system_view_state_offset = GetOffsetFromMdm(global_state); } - mdm->global_system_view_state_node_id = 1; + global_system_view_state_node_id = 1; // Initialize BucketInfo array BucketInfo *buckets = PushArray(arena, config->max_buckets_per_node); - mdm->bucket_info_offset = GetOffsetFromMdm(mdm, buckets); - mdm->first_free_bucket.bits.node_id = (u32)node_id; - mdm->first_free_bucket.bits.index = 0; - mdm->num_buckets = 0; - mdm->max_buckets = config->max_buckets_per_node; + bucket_info_offset = GetOffsetFromMdm(buckets); + first_free_bucket.bits.node_id = (u32)node_id; + first_free_bucket.bits.index = 0; + num_buckets = 0; + max_buckets = config->max_buckets_per_node; for (u32 i = 0; i < config->max_buckets_per_node; ++i) { BucketInfo *info = buckets + i; @@ -1329,11 +1252,11 @@ MetadataManager::MetadataManager(RpcContext *rpc, Config *config) : VBucketInfo *vbuckets = PushArray(arena, config->max_vbuckets_per_node); - mdm->vbucket_info_offset = GetOffsetFromMdm(mdm, vbuckets); - mdm->first_free_vbucket.bits.node_id = (u32)node_id; - mdm->first_free_vbucket.bits.index = 0; - mdm->num_vbuckets = 0; - mdm->max_vbuckets = config->max_vbuckets_per_node; + vbucket_info_offset = GetOffsetFromMdm(vbuckets); + first_free_vbucket.bits.node_id = (u32)node_id; + first_free_vbucket.bits.index = 0; + num_vbuckets = 0; + max_vbuckets = config->max_vbuckets_per_node; for (u32 i = 0; i < config->max_vbuckets_per_node; ++i) { VBucketInfo *info = vbuckets + i; @@ -1350,37 +1273,36 @@ MetadataManager::MetadataManager(RpcContext *rpc, Config *config) : } /** get virtual bucket information by index locally */ -VBucketInfo *LocalGetVBucketInfoByIndex(MetadataManager *mdm, u32 index) { +VBucketInfo* MetadataManager::LocalGetVBucketInfoByIndex(u32 index) { VBucketInfo *info_array = - (VBucketInfo *)((u8 *)mdm + mdm->vbucket_info_offset); + (VBucketInfo *)((u8 *)mdm + vbucket_info_offset); VBucketInfo *result = info_array + index; return result; } /** get virtual bucket information by id locally */ -VBucketInfo *LocalGetVBucketInfoById(MetadataManager *mdm, VBucketID id) { - VBucketInfo *result = LocalGetVBucketInfoByIndex(mdm, id.bits.index); +VBucketInfo* MetadataManager::LocalGetVBucketInfoById(VBucketID id) { + VBucketInfo *result = LocalGetVBucketInfoByIndex(id.bits.index); return result; } /** increment reference counter locally */ -void LocalIncrementRefcount(SharedMemoryContext *context, VBucketID id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - VBucketInfo *info = LocalGetVBucketInfoById(mdm, id); +void MetadataManager::LocalIncrementRefcount(VBucketID id) { + mdm = GetMetadataManagerFromContext(context); + VBucketInfo *info = LocalGetVBucketInfoById(id); info->ref_count.fetch_add(1); } /** decrement reference counter locally */ -void LocalDecrementRefcount(SharedMemoryContext *context, VBucketID id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - VBucketInfo *info = LocalGetVBucketInfoById(mdm, id); +void MetadataManager::LocalDecrementRefcount(VBucketID id) { + mdm = GetMetadataManagerFromContext(context); + VBucketInfo *info = LocalGetVBucketInfoById(id); info->ref_count.fetch_sub(1); assert(info->ref_count.load() >= 0); } /** decrement reference counter */ -void DecrementRefcount(SharedMemoryContext *context, RpcContext *rpc, - VBucketID id) { +void MetadataManager::DecrementRefcount(VBucketID id) { u32 target_node = id.bits.node_id; if (target_node == rpc->node_id) { LocalDecrementRefcount(context, id); @@ -1390,7 +1312,7 @@ void DecrementRefcount(SharedMemoryContext *context, RpcContext *rpc, } /** get relative node ID */ -u32 GetRelativeNodeId(RpcContext *rpc, int offset) { +u32 MetadataManager::GetRelativeNodeId(int offset) { int result = rpc->node_id + offset; assert(result >= 0); assert(result <= (int)(rpc->num_nodes + 1)); @@ -1405,22 +1327,21 @@ u32 GetRelativeNodeId(RpcContext *rpc, int offset) { } /** get next node */ -u32 GetNextNode(RpcContext *rpc) { - u32 result = GetRelativeNodeId(rpc, 1); +u32 MetadataManager::GetNextNode() { + u32 result = GetRelativeNodeId(1); return result; } /** get previous node */ -u32 GetPreviousNode(RpcContext *rpc) { - u32 result = GetRelativeNodeId(rpc, -1); +u32 MetadataManager::GetPreviousNode() { + u32 result = GetRelativeNodeId(-1); return result; } /** get node targets */ -std::vector GetNodeTargets(SharedMemoryContext *context, - RpcContext *rpc, u32 target_node) { +std::vector MetadataManager::GetNodeTargets(u32 target_node) { std::vector result; if (target_node == rpc->node_id) { @@ -1434,8 +1355,7 @@ std::vector GetNodeTargets(SharedMemoryContext *context, } /** get neighborhood node targets */ -std::vector GetNeighborhoodTargets(SharedMemoryContext *context, - RpcContext *rpc) { +std::vector MetadataManager::GetNeighborhoodTargets() { // TODO(chogan): Inform the concept of "neighborhood" with a network topology // NOTE(chogan): For now, each node has 2 neighbors, NodeID-1 and NodeID+1 // (wrapping around for nodes 1 and N). @@ -1471,8 +1391,7 @@ std::vector GetNeighborhoodTargets(SharedMemoryContext *context, } /** get remaining target capacity */ -u64 GetRemainingTargetCapacity(SharedMemoryContext *context, RpcContext *rpc, - TargetID target_id) { +u64 MetadataManager::GetRemainingTargetCapacity(TargetID target_id) { u64 result = 0; u32 target_node = target_id.bits.node_id; @@ -1487,9 +1406,8 @@ u64 GetRemainingTargetCapacity(SharedMemoryContext *context, RpcContext *rpc, } /** get remaining target capacities */ -std::vector -GetRemainingTargetCapacities(SharedMemoryContext *context, RpcContext *rpc, - const std::vector &targets) { +std::vector MetadataManager::GetRemainingTargetCapacities( + const std::vector &targets) { std::vector result(targets.size()); for (size_t i = 0; i < targets.size(); ++i) { @@ -1499,27 +1417,26 @@ GetRemainingTargetCapacities(SharedMemoryContext *context, RpcContext *rpc, return result; } -void AttachBlobToVBucket(SharedMemoryContext *context, RpcContext *rpc, - const char *blob_name, const char *bucket_name, - VBucketID vbucket_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); +void MetadataManager::AttachBlobToVBucket(const char *blob_name, + const char *bucket_name, + VBucketID vbucket_id) { + mdm = GetMetadataManagerFromContext(context); BucketID bucket_id = GetBucketId(context, rpc, bucket_name); BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id); - AddBlobIdToVBucket(mdm, rpc, blob_id, vbucket_id); + AddBlobIdToVBucket(rpc, blob_id, vbucket_id); } /** get bucket name by ID locally */ -std::string LocalGetBucketNameById(SharedMemoryContext *context, - BucketID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); +std::string +MetadataManager::LocalGetBucketNameById(BucketID blob_id) { + mdm = GetMetadataManagerFromContext(context); std::string bucket_name = - ReverseGetFromStorage(mdm, blob_id.as_int, kMapType_Bucket); + ReverseGetFromStorage(blob_id.as_int, kMapType_Bucket); return bucket_name; } -std::vector GetBlobsFromVBucketInfo(SharedMemoryContext *context, - RpcContext *rpc, - VBucketID vbucket_id) { +std::vector +MetadataManager::GetBlobsFromVBucketInfo(VBucketID vbucket_id) { u32 target_node = vbucket_id.bits.node_id; if (target_node == rpc->node_id) { return LocalGetBlobsFromVBucketInfo(context, vbucket_id); @@ -1529,9 +1446,9 @@ std::vector GetBlobsFromVBucketInfo(SharedMemoryContext *context, } } -void RemoveBlobFromVBucketInfo(SharedMemoryContext *context, RpcContext *rpc, - VBucketID vbucket_id, const char *blob_name, - const char *bucket_name) { +void MetadataManager::RemoveBlobFromVBucketInfo(VBucketID vbucket_id, + const char *blob_name, + const char *bucket_name) { BucketID bucket_id = GetBucketId(context, rpc, bucket_name); BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id); u32 target_node = vbucket_id.bits.node_id; @@ -1543,8 +1460,7 @@ void RemoveBlobFromVBucketInfo(SharedMemoryContext *context, RpcContext *rpc, } } -std::string GetBucketNameById(SharedMemoryContext *context, RpcContext *rpc, - BucketID id) { +std::string MetadataManager::GetBucketNameById(BucketID id) { auto target_node = id.bits.node_id; if (target_node == rpc->node_id) { return LocalGetBucketNameById(context, id); @@ -1561,11 +1477,11 @@ std::string GetBucketNameById(SharedMemoryContext *context, RpcContext *rpc, * recently or frequently. * */ -f32 ScoringFunction(MetadataManager *mdm, Stats *stats) { +f32 MetadataManager::ScoringFunction(Stats *stats) { f32 recency_weight = 0.5; f32 frequency_weight = 0.5; // NOTE(chogan): A high relative_recency corresponds to a "cold" Blob. - f32 relative_recency = mdm->clock - stats->recency; + f32 relative_recency = clock - stats->recency; f32 result = (relative_recency * recency_weight - stats->frequency * frequency_weight); @@ -1573,23 +1489,21 @@ f32 ScoringFunction(MetadataManager *mdm, Stats *stats) { } /** get number of outstanding flushing tasks locally */ -int LocalGetNumOutstandingFlushingTasks(SharedMemoryContext *context, - VBucketID id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - mdm->vbucket_mutex.Lock(); - VBucketInfo *info = LocalGetVBucketInfoById(mdm, id); +int MetadataManager::LocalGetNumOutstandingFlushingTasks(VBucketID id) { + mdm = GetMetadataManagerFromContext(context); + vbucket_mutex.Lock(); + VBucketInfo *info = LocalGetVBucketInfoById(id); int result = 0; if (info) { result = info->async_flush_count; } - mdm->vbucket_mutex.Unlock(); + vbucket_mutex.Unlock(); return result; } /** get number of outstanding flushing tasks */ -int GetNumOutstandingFlushingTasks(SharedMemoryContext *context, - RpcContext *rpc, VBucketID id) { +int MetadataManager::GetNumOutstandingFlushingTasks(VBucketID id) { u32 target_node = id.bits.node_id; int result = 0; @@ -1603,9 +1517,9 @@ int GetNumOutstandingFlushingTasks(SharedMemoryContext *context, return result; } -bool LocalLockBlob(SharedMemoryContext *context, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - BlobInfo *blob_info = GetBlobInfoPtr(mdm, blob_id); +bool MetadataManager::LocalLockBlob(BlobID blob_id) { + mdm = GetMetadataManagerFromContext(context); + BlobInfo *blob_info = GetBlobInfoPtr(blob_id); if (blob_info) { blob_info->lock.Lock(); } else { @@ -1614,7 +1528,7 @@ bool LocalLockBlob(SharedMemoryContext *context, BlobID blob_id) { } if (blob_info->stop) { blob_info->lock.Unlock(); - LocalDelete(mdm, blob_id); + LocalDelete(blob_id); LocalFreeBufferIdList(context, blob_id); ReleaseBlobInfoPtr(mdm); return false; @@ -1623,9 +1537,9 @@ bool LocalLockBlob(SharedMemoryContext *context, BlobID blob_id) { return true; } -bool LocalUnlockBlob(SharedMemoryContext *context, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - BlobInfo *blob_info = GetBlobInfoPtr(mdm, blob_id); +bool MetadataManager::LocalUnlockBlob(BlobID blob_id) { + mdm = GetMetadataManagerFromContext(context); + BlobInfo *blob_info = GetBlobInfoPtr(blob_id); bool result = false; if (blob_info) { blob_info->lock.Unlock(); @@ -1636,7 +1550,7 @@ bool LocalUnlockBlob(SharedMemoryContext *context, BlobID blob_id) { } /** lock BLOB */ -bool LockBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id) { +bool MetadataManager::LockBlob(BlobID blob_id) { u32 target_node = GetBlobNodeId(blob_id); bool result; if (target_node == rpc->node_id) { @@ -1648,7 +1562,7 @@ bool LockBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id) { } /** unlock BLOB */ -bool UnlockBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id) { +bool MetadataManager::UnlockBlob(BlobID blob_id) { u32 target_node = GetBlobNodeId(blob_id); bool result; if (target_node == rpc->node_id) { diff --git a/src/metadata_management.h b/src/metadata_management.h index 7296961e4..64de6cde1 100644 --- a/src/metadata_management.h +++ b/src/metadata_management.h @@ -104,7 +104,7 @@ struct BufferIdArray { */ struct BlobInfo { Stats stats; /**< BLOB statistics */ - labstor::Mutex lock; /**< lock */ + labstor::Mutex lock; /**< lock */ TargetID effective_target; /**< target ID */ u32 last; /**< last */ bool stop; /**< stop */ @@ -112,16 +112,12 @@ struct BlobInfo { BlobInfo() : last(0), stop(false) { stats.recency = 0; stats.frequency = 0; - lock.ticket.store(0); - lock.serving.store(0); effective_target.as_int = 0; } /** Copy \a other BlobInfo sturcture. */ BlobInfo &operator=(const BlobInfo &other) { stats = other.stats; - lock.ticket.store(other.lock.ticket.load()); - lock.serving.store(other.lock.serving.load()); effective_target = other.effective_target; last = other.last; stop = other.stop; @@ -269,316 +265,384 @@ class MetadataManager { std::atomic clock; /**< clock */ public: - MetadataManager(RpcContext *context, Config *config); -}; -/** - * - */ -void InitMetadataManager(MetadataManager *mdm, RpcContext *rpc, Config *config); + /** + * initialize metadata manager + * */ + MetadataManager(SharedMemoryContext *context, RpcContext *rpc, Config *config); -/** - * - */ -void InitNeighborhoodTargets(SharedMemoryContext *context, RpcContext *rpc); + /** get virtual bucket information by index locally */ + VBucketInfo* LocalGetVBucketInfoByIndex(u32 index); -/** - * - */ -bool DestroyBucket(SharedMemoryContext *context, RpcContext *rpc, - const char *name, BucketID bucket_id); + /** get virtual bucket information by id locally */ + VBucketInfo* LocalGetVBucketInfoById(VBucketID id); -/** - * - */ -bool DestroyVBucket(SharedMemoryContext *context, RpcContext *rpc, - const char *name, VBucketID vbucket_id); + /** increment reference counter locally */ + void LocalIncrementRefcount(VBucketID id); -/** - * - */ -void DestroyBlobByName(SharedMemoryContext *context, RpcContext *rpc, - BucketID bucket_id, const std::string &blob_name); + /** decrement reference counter locally */ + void LocalDecrementRefcount(VBucketID id); -/** - * - */ -void RenameBlob(SharedMemoryContext *context, RpcContext *rpc, - const std::string &old_name, const std::string &new_name, - BucketID bucket_id); + /** decrement reference counter */ + void DecrementRefcount(VBucketID id); -/** - * - */ -void RenameBucket(SharedMemoryContext *context, RpcContext *rpc, BucketID id, - const std::string &old_name, const std::string &new_name); + /** get relative node ID */ + u32 GetRelativeNodeId(int offset); -/** - * - */ -bool ContainsBlob(SharedMemoryContext *context, RpcContext *rpc, - BucketID bucket_id, const std::string &blob_name); + /** get next node */ + u32 GetNextNode(); -/** - * - */ -BufferIdArray GetBufferIdsFromBlobId(SharedMemoryContext *context, - RpcContext *rpc, BlobID blob_id, - u32 **sizes); + /** get previous node */ + u32 GetPreviousNode(); -/** - * - */ -BlobID GetBlobId(SharedMemoryContext *context, RpcContext *rpc, - const std::string &name, BucketID bucket_id, - bool track_stats = true); + /** get node targets */ + std::vector GetNodeTargets(u32 target_node); -/** - * - */ -std::string GetBlobNameFromId(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id); + /** get neighborhood node targets */ + std::vector GetNeighborhoodTargets(); -/** - * - */ -bool BlobIsInSwap(BlobID id); + /** get remaining target capacity */ + u64 GetRemainingTargetCapacity(TargetID target_id); -/** - * - */ -BucketID GetOrCreateBucketId(SharedMemoryContext *context, RpcContext *rpc, - const std::string &name); + /** get remaining target capacities */ + std::vector + GetRemainingTargetCapacities(const std::vector &targets); -/** - * - */ -VBucketID GetOrCreateVBucketId(SharedMemoryContext *context, RpcContext *rpc, - const std::string &name); + void AttachBlobToVBucket(const char *blob_name, const char *bucket_name, + VBucketID vbucket_id); -/** - * - */ -void AttachBlobToBucket(SharedMemoryContext *context, RpcContext *rpc, - const char *blob_name, BucketID bucket_id, - const std::vector &buffer_ids, - TargetID effective_target, bool is_swap_blob = false, - bool called_from_buffer_organizer = false); + /** get bucket name by ID locally */ + std::string LocalGetBucketNameById(BucketID blob_id); -/** - * - */ -void DecrementRefcount(SharedMemoryContext *context, RpcContext *rpc, - BucketID id); + std::vector GetBlobsFromVBucketInfo(VBucketID vbucket_id); -/** - * - */ -std::vector SwapBlobToVec(SwapBlob swap_blob); + void RemoveBlobFromVBucketInfo(VBucketID vbucket_id, const char *blob_name, + const char *bucket_name); -/** - * - */ -SwapBlob VecToSwapBlob(std::vector &vec); + std::string GetBucketNameById(BucketID id); -/** - * - */ -SwapBlob IdArrayToSwapBlob(BufferIdArray ids); + f32 ScoringFunction(Stats *stats); -/** - * - */ -bool IsBlobNameTooLong(const std::string &name); + int LocalGetNumOutstandingFlushingTasks(VBucketID id); -/** - * - */ -bool IsBucketNameTooLong(const std::string &name); + int GetNumOutstandingFlushingTasks(VBucketID id); -/** - * - */ -bool IsVBucketNameTooLong(const std::string &name); + bool LocalLockBlob(BlobID blob_id); -/** - * - */ -TargetID FindTargetIdFromDeviceId(const std::vector &targets, - DeviceID device_id); + bool LocalUnlockBlob(BlobID blob_id); -/** - * - */ -std::vector GetNeighborhoodTargets(SharedMemoryContext *context, - RpcContext *rpc); -/** - * - */ -std::vector GetRemainingTargetCapacities( - SharedMemoryContext *context, RpcContext *rpc, - const std::vector &targets); -/** - * - */ -std::vector GetBlobIds(SharedMemoryContext *context, RpcContext *rpc, - BucketID bucket_id); + /** lock BLOB */ + bool LockBlob(BlobID blob_id); -/** - * - */ -BucketID GetBucketId(SharedMemoryContext *context, RpcContext *rpc, - const char *name); + /** unlock BLOB */ + bool UnlockBlob(BlobID blob_id); -/** - * - */ -BucketID GetBucketIdFromBlobId(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id); + private: -/** - * - */ -void DecrementRefcount(SharedMemoryContext *context, RpcContext *rpc, - VBucketID id); -/** - * - */ -bool IsNullBucketId(BucketID id); + /** is BLOB's \a name too long for kMaxBlobNameSize? */ + bool IsBlobNameTooLong(const std::string &name); -/** - * - */ -bool IsNullVBucketId(VBucketID id); + /** is Bucket's \a name too long for kMaxBucketNameSize? */ + bool IsBucketNameTooLong(const std::string &name); -/** - * - */ -bool IsNullBlobId(BlobID id); + /** is vBucket's \a name too long for kMaxVBucketNameSize? */ + bool IsVBucketNameTooLong(const std::string &name); -/** - * begin global ticket mutex - */ -void BeginGloballabstor::Mutex(SharedMemoryContext *context, RpcContext *rpc); + /** put \a key, \a value, and \a map_type locally */ + void LocalPut(const char *key, u64 val, MapType map_type); -/** - * end global ticket mutex - */ -void EndGloballabstor::Mutex(SharedMemoryContext *context, RpcContext *rpc); + /** put \a key and \a value locally */ + void LocalPut(BlobID key, const BlobInfo &value); -/** - * begin global ticket mutex locally - */ -void LocalBeginGloballabstor::Mutex(MetadataManager *mdm); + /** get the value of \a key and \a map_type locally */ + u64 LocalGet(const char *key, MapType map_type); -/** - * end global ticket mutex locally - */ -void LocalEndGloballabstor::Mutex(MetadataManager *mdm); + /** delete \a key locally */ + void LocalDelete(BlobID key); -/** - * attach BLOB to VBucket - */ -void AttachBlobToVBucket(SharedMemoryContext *context, RpcContext *rpc, - const char *blob_name, const char *bucket_name, - VBucketID vbucket_id); + /** delete \a map_type locally */ + void LocalDelete(const char *key, MapType map_type); -/** - * remove BLOB from Bucket - */ -void RemoveBlobFromBucketInfo(SharedMemoryContext *context, RpcContext *rpc, - BucketID bucket_id, BlobID blob_id); + /** log error when metadata arena capacity is full */ + static void MetadataArenaErrorHandler(); -/** - * remove BLOB from VBucket - */ -void RemoveBlobFromVBucketInfo(SharedMemoryContext *context, RpcContext *rpc, - VBucketID vbucket_id, const char *blob_name, - const char *bucket_name); + /** get hash string for metadata storage */ + u32 HashString(const char *str); -/** - * get BLOB from VBucket - */ -std::vector GetBlobsFromVBucketInfo(SharedMemoryContext *context, - RpcContext *rpc, - VBucketID vbucket_id); + /** get id */ + u64 GetId(const char *name, MapType map_type); -/** - * get bucket name by bucket ID - */ -std::string GetBucketNameById(SharedMemoryContext *context, RpcContext *rpc, - BucketID id); -/** - * increment BLOB stats - */ -void IncrementBlobStats(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id); + /** get bucket id */ + BucketID GetBucketId(const char *name); -/** - * increment BLOB stats locally - */ -void LocalIncrementBlobStats(MetadataManager *mdm, BlobID blob_id); + /** get local bucket id */ + BucketID LocalGetBucketId(const char *name); -/** - * lock BLOB - */ -bool LockBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id); + /** get virtual bucket id */ + VBucketID GetVBucketId(const char *name); -/** - * unlock BLOB - */ -bool UnlockBlob(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id); + /** get local virtual bucket id */ + VBucketID LocalGetVBucketId(const char *name); -/** - * lock BLOB locally - */ -bool LocalLockBlob(SharedMemoryContext *context, BlobID blob_id); + /** make an internal BLOB name */ + std::string MakeInternalBlobName(const std::string &name, BucketID id); -/** - * unlock BLOB locally - */ -bool LocalUnlockBlob(SharedMemoryContext *context, BlobID blob_id); + /** get BLOB id */ + BlobID GetBlobId(const std::string &name, BucketID bucket_id, + bool track_stats); -/** - * get local system view state - */ -SystemViewState *GetLocalSystemViewState(SharedMemoryContext *context); + /** put BLOB id */ + void PutId(const std::string &name, u64 id, MapType map_type); -/** - * replace BLOB ID in bucket locally - */ -void LocalReplaceBlobIdInBucket(SharedMemoryContext *context, - BucketID bucket_id, BlobID old_blob_id, - BlobID new_blob_id); -/** - * Deletes @p old_blob_id from @p bucket_id and adds @p new_blob_id. It combines - * the delete and the add into one call in order to avoid multiple RPCs. - */ -void ReplaceBlobIdInBucket(SharedMemoryContext *context, RpcContext *rpc, - BucketID bucket_id, BlobID old_blob_id, - BlobID new_blob_id); + /** put bucket id */ + void PutBucketId(const std::string &name, BucketID id); -/** - * Creates a ShmemString with the value @p val at location @p memory. - * - * @pre The address of @p sms must be lower than @p memory because the @p offset - * is from the beginning of the \a sms. - * - * @param[out] sms The ShmemString instance to be filled out. - * @param memory The location in shared memory to store the @p val. - * @param val The string to store. - */ -void MakeShmemString(ShmemString *sms, u8 *memory, const std::string &val); + /** put bucket id locally */ + void LocalPutBucketId(const std::string &name,BucketID id); -/** - * Retrieves a ShmemString into a std::string + /** put virtual bucket id */ + void PutVBucketId(const std::string &name, VBucketID id); + + /** put virtual bucket id locally */ + void LocalPutVBucketId(const std::string &name, VBucketID id); + + /** put BLOB id */ + void PutBlobId(const std::string &name, BlobID id, BucketID bucket_id); + + /** delete id */ + void DeleteId(const std::string &name,MapType map_type); + + /** delete bucket id */ + void DeleteBucketId(const std::string &name); + + /** delete virtual bucket id */ + void DeleteVBucketId(const std::string &name); + + /** delete BLOB information locally */ + void LocalDeleteBlobInfo(BlobID blob_id); + + /** delete BLOB id locally */ + void LocalDeleteBlobId(const std::string &name, + BucketID bucket_id); + + /** delete BLOB id */ + void DeleteBlobId(const std::string &name, BucketID bucket_id); + + /** get bucket information by \a index index locally */ + BucketInfo *LocalGetBucketInfoByIndex(u32 index); + + /** get BLOB name from \a blob_id locally */ + std::string LocalGetBlobNameFromId(BlobID blob_id); + + /** get BLOB name from \a blob_id */ + std::string GetBlobNameFromId(BlobID blob_id); + + u64 HexStringToU64(const std::string &s); + + /** get bucket ID from \a blob_id locally */ + BucketID LocalGetBucketIdFromBlobId(BlobID id); + + /** get bucket ID from \a blob_id */ + BucketID GetBucketIdFromBlobId(BlobID id); + + /** get bucket information from \a bucket_id */ + BucketInfo *LocalGetBucketInfoById(BucketID id); + + /** get BLOB IDs from \a bucket_id */ + std::vector GetBlobIds(BucketID bucket_id); + + /** get virtual bucket information by \a index */ + VBucketInfo *GetVBucketInfoByIndex(u32 index); + + /** + * Returns an available BucketID and marks it as in use in the MDM. * - * @param sms The ShmemString that represents the internal string + * Assumes bucket_mutex is already held by the caller. + */ + BucketID LocalGetNextFreeBucketId(const std::string &name); + + /** get or create a bucket ID locally */ + BucketID LocalGetOrCreateBucketId(const std::string &name); + + /** get or create a bucket ID */ + BucketID GetOrCreateBucketId(const std::string &name); + + /** + * Returns an available VBucketID and marks it as in use in the MDM. * - * @return A newly allocated std::string containing a copy of the string from - * shared memory, or an empty std::string if the ShmemString is invalid. - */ -std::string GetShmemString(ShmemString *sms); + * Assumes MetadataManager::vbucket_mutex is already held by the caller. + */ + VBucketID LocalGetNextFreeVBucketId(const std::string &name); + + /** get or create a virtual bucket ID locally */ + VBucketID LocalGetOrCreateVBucketId(const std::string &name); + + /** get or create a virtual bucket ID */ + VBucketID GetOrCreateVBucketId(const std::string &name); + + /** copy IDs */ + void CopyIds(u64 *dest, u64 *src, u32 count); + + void ReplaceBlobIdInBucket(BucketID bucket_id, + BlobID old_blob_id, + BlobID new_blob_id); + + /** add BLOB ID to bucket */ + void AddBlobIdToBucket(BlobID blob_id, + BucketID bucket_id); + + /** add BLOB ID to virtual bucket */ + void AddBlobIdToVBucket(BlobID blob_id, + VBucketID vbucket_id); + + /** allocate buffer ID list */ + u32 AllocateBufferIdList(u32 target_node, + const std::vector &buffer_ids); + + /** get buffer ID list */ + void GetBufferIdList( + BlobID blob_id, + BufferIdArray *buffer_ids); + + /** get buffer ID list as vector */ + std::vector GetBufferIdList(BlobID blob_id); + + /** get buffer IDs from BLOB id */ + BufferIdArray GetBufferIdsFromBlobId(BlobID blob_id, + u32 **sizes); + + /** create BLOB metadata locally */ + void LocalCreateBlobMetadata(const std::string &blob_name, BlobID blob_id, + TargetID effective_target); + + /** create BLOB metadata */ + void CreateBlobMetadata( + const std::string &blob_name, BlobID blob_id, + TargetID effective_target); + + /** attach BLOB to bucket */ + void AttachBlobToBucket( + const char *blob_name, BucketID bucket_id, + const std::vector &buffer_ids, + TargetID effective_target, bool is_swap_blob, + bool called_from_buffer_organizer); + + /** free buffer ID list */ + void FreeBufferIdList( + BlobID blob_id); + + /** delete BLOB metadata locally */ + void LocalDeleteBlobMetadata(const char *blob_name, + BlobID blob_id, BucketID bucket_id); + + /** wait for outstanding BLOB operations */ + void WaitForOutstandingBlobOps(BlobID blob_id); + + /** destroy BLOB by name locally */ + void LocalDestroyBlobByName(const char *blob_name, + BlobID blob_id, + BucketID bucket_id); + + /** destroy BLOB by ID locally */ + void LocalDestroyBlobById(BlobID blob_id, BucketID bucket_id); + + void RemoveBlobFromBucketInfo(BucketID bucket_id, BlobID blob_id); + + /** destroy BLOB by name */ + void DestroyBlobByName(BucketID bucket_id, const std::string &blob_name); + + /** rename BLOB */ + void RenameBlob(const std::string &old_name, + const std::string &new_name, + BucketID bucket_id); + + /** does \a bucket_id bucket contain \a blob_name BLOB? */ + bool ContainsBlob( + BucketID bucket_id, const std::string &blob_name); + + /** destroy BLOB by ID */ + void DestroyBlobById(BlobID id, + BucketID bucket_id); + + /** destroy bucket */ + bool DestroyBucket( + const char *name, BucketID bucket_id); + + /** destroy virtual bucket */ + bool DestroyVBucket( + const char *name, VBucketID vbucket_id); + + /** rename bucket locally */ + void LocalRenameBucket( + BucketID id, const std::string &old_name, + const std::string &new_name); + + /** rename bucket */ + void RenameBucket(BucketID id, + const std::string &old_name, + const std::string &new_name); + + /** increment reference count locally */ + void LocalIncrementRefcount(BucketID id); + + /** decrement reference count locally */ + void LocalDecrementRefcount(BucketID id); + + /** decrement reference count */ + void DecrementRefcount(BucketID id); + + /** get remaning target capacity locally */ + u64 LocalGetRemainingTargetCapacity(TargetID id); + + /** get local system view state */ + SystemViewState *GetLocalSystemViewState(); + + /** get global device capacities locally */ + std::vector LocalGetGlobalDeviceCapacities(); + + /** get global device capacities */ + std::vector GetGlobalDeviceCapacities(); + + /** get global system view state from \a context */ + GlobalSystemViewState *GetGlobalSystemViewState(); + + /** update global system view state locally */ + std::vector + LocalUpdateGlobalSystemViewState(u32 node_id, + std::vector adjustments); + + /** update global system view state */ + void UpdateGlobalSystemViewState(); + + /** find target ID from device ID */ + TargetID FindTargetIdFromDeviceId(const std::vector &targets, + DeviceID device_id); + + /** create system view state */ + SystemViewState *CreateSystemViewState(Config *config); + + /** create global system view state */ + GlobalSystemViewState *CreateGlobalSystemViewState(Config *config); + + /** get swap file name */ + std::string GetSwapFilename(u32 node_id); + + /** swap BLOB to vector */ + std::vector SwapBlobToVec(SwapBlob swap_blob)l + + /** vector to swap BLOB */ + SwapBlob VecToSwapBlob(std::vector &vec)l + + /** ID array to swap BLOB */ + SwapBlob IdArrayToSwapBlob(BufferIdArray ids)l +}; + +/** log error when metadata arena capacity is full */ +static void MetadataArenaErrorHandler() { + LOG(FATAL) << "Metadata arena capacity exceeded. Consider increasing the " + << "value of metadata_arena_percentage in the Hermes configuration" + << std::endl; +} } // namespace hermes diff --git a/src/metadata_management_internal.h b/src/metadata_management_internal.h deleted file mode 100644 index cbbb7c0ef..000000000 --- a/src/metadata_management_internal.h +++ /dev/null @@ -1,151 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_METADATA_MANAGEMENT_INTERNAL_H_ -#define HERMES_METADATA_MANAGEMENT_INTERNAL_H_ - -#include "hermes_types.h" - -namespace hermes { - -bool IsNullBucketId(BucketID id); -bool IsNullVBucketId(VBucketID id); -bool IsNullBlobId(BlobID id); -bool IsNullTargetId(TargetID id); -labstor::Mutex& GetMapMutex(MetadataManager *mdm, MapType map_type); -VBucketID GetVBucketId(SharedMemoryContext *context, RpcContext *rpc, - const char *name); -u32 HashString(MetadataManager *mdm, RpcContext *rpc, const char *str); -MetadataManager *GetMetadataManagerFromContext(SharedMemoryContext *context); -BucketInfo *LocalGetBucketInfoByIndex(MetadataManager *mdm, u32 index); -VBucketInfo *GetVBucketInfoByIndex(MetadataManager *mdm, u32 index); -u32 AllocateBufferIdList(SharedMemoryContext *context, RpcContext *rpc, - u32 target_node, - const std::vector &buffer_ids); -std::vector GetBufferIdList(SharedMemoryContext *context, - RpcContext *rpc, BlobID blob_id); -void FreeBufferIdList(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id); - -void LocalAddBlobIdToBucket(MetadataManager *mdm, BucketID bucket_id, - BlobID blob_id, bool track_stats = true); -void LocalAddBlobIdToVBucket(MetadataManager *mdm, VBucketID vbucket_id, - BlobID blob_id); -std::vector LocalGetBufferIdList(MetadataManager *mdm, - BlobID blob_id); -void LocalGetBufferIdList(MetadataManager *mdm, BlobID blob_id, - BufferIdArray *buffer_ids); -void LocalFreeBufferIdList(SharedMemoryContext *context, BlobID blob_id); -bool LocalDestroyBucket(SharedMemoryContext *context, RpcContext *rpc, - const char *bucket_name, BucketID bucket_id); -bool LocalDestroyVBucket(SharedMemoryContext *context, const char *vbucket_name, - VBucketID vbucket_id); -void LocalDestroyBlobById(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id, BucketID bucket_id); -void LocalDestroyBlobByName(SharedMemoryContext *context, RpcContext *rpc, - const char *blob_name, BlobID blob_id, - BucketID bucket_id); -BucketID LocalGetNextFreeBucketId(SharedMemoryContext *context, - const std::string &name); -u32 LocalAllocateBufferIdList(MetadataManager *mdm, - const std::vector &buffer_ids); -void LocalRenameBucket(SharedMemoryContext *context, RpcContext *rpc, - BucketID id, const std::string &old_name, - const std::string &new_name); -bool LocalContainsBlob(SharedMemoryContext *context, BucketID bucket_id, - BlobID blob_id); -void LocalRemoveBlobFromBucketInfo(SharedMemoryContext *context, - BucketID bucket_id, BlobID blob_id); -void LocalIncrementRefcount(SharedMemoryContext *context, BucketID id); -void LocalDecrementRefcount(SharedMemoryContext *context, BucketID id); -void LocalIncrementRefcount(SharedMemoryContext *context, VBucketID id); -void LocalDecrementRefcount(SharedMemoryContext *context, VBucketID id); - -u64 LocalGet(MetadataManager *mdm, const char *key, MapType map_type); -void LocalPut(MetadataManager *mdm, const char *key, u64 val, MapType map_type); -void LocalDelete(MetadataManager *mdm, const char *key, MapType map_type); - -u64 LocalGetRemainingTargetCapacity(SharedMemoryContext *context, TargetID id); -std::vector LocalUpdateGlobalSystemViewState( - SharedMemoryContext *context, u32 node_id, std::vector adjustments); -GlobalSystemViewState *GetGlobalSystemViewState(SharedMemoryContext *context); -std::vector LocalGetGlobalDeviceCapacities(SharedMemoryContext *context); -std::vector GetGlobalDeviceCapacities(SharedMemoryContext *context, - RpcContext *rpc); -void UpdateGlobalSystemViewState(SharedMemoryContext *context, RpcContext *rpc); - -void StartGlobalSystemViewStateUpdateThread(SharedMemoryContext *context, - RpcContext *rpc, double sleep_ms); - -void InitMetadataStorage(SharedMemoryContext *context, MetadataManager *mdm, - Config *config); - -std::string GetSwapFilename(MetadataManager *mdm, u32 node_id); -std::vector LocalGetBlobIds(SharedMemoryContext *context, - BucketID bucket_id); -std::vector LocalGetNodeTargets(SharedMemoryContext *context); -u32 GetNextNode(RpcContext *rpc); -u32 GetPreviousNode(RpcContext *rpc); -BucketID LocalGetBucketIdFromBlobId(SharedMemoryContext *context, BlobID id); -std::string LocalGetBlobNameFromId(SharedMemoryContext *context, - BlobID blob_id); -BucketID LocalGetOrCreateBucketId(SharedMemoryContext *context, - const std::string &name); -VBucketID LocalGetOrCreateVBucketId(SharedMemoryContext *context, - const std::string &name); -f32 LocalGetBlobImportanceScore(SharedMemoryContext *context, BlobID blob_id); -f32 GetBlobImportanceScore(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id); - -/** - * Faster version of std::stoull. - * - * This is 4.1x faster than std::stoull. Since we generate all the numbers that - * we use this function on, we can guarantee the following: - * - The size will always be kBucketIdStringSize. - * - The number will always be unsigned and within the range of a u64. - * - There will never be invalid characters passed in (only 0-9 and a-f). - * - * Avoiding all this input sanitization and error checking is how we can get a - * 4.1x speedup. - * - * \param s A string with size at least kBucketIdStringSize, where the first - * kBucketIdStringSize characters consist only of 0-9 and a-f. - * - * \return The u64 representation of the first kBucketIdStringSize characters of - * \p s. - */ -u64 HexStringToU64(const std::string &s); -std::string MakeInternalBlobName(const std::string &name, BucketID id); - -void LocalRemoveBlobFromVBucketInfo(SharedMemoryContext *context, - VBucketID vbucket_id, BlobID blob_id); -std::vector LocalGetBlobsFromVBucketInfo(SharedMemoryContext *context, - VBucketID vbucket_id); -std::string LocalGetBucketNameById(SharedMemoryContext *context, - BucketID blob_id); - -void WaitForOutstandingBlobOps(MetadataManager *mdm, BlobID blob_id); -int LocalGetNumOutstandingFlushingTasks(SharedMemoryContext *context, - VBucketID id); -int GetNumOutstandingFlushingTasks(SharedMemoryContext *context, - RpcContext *rpc, VBucketID id); -void LocalCreateBlobMetadata(SharedMemoryContext *context, MetadataManager *mdm, - const std::string &blob_name, BlobID blob_id, - TargetID effective_target); -Heap *GetIdHeap(MetadataManager *mdm); -Heap *GetMapHeap(MetadataManager *mdm); -IdList AllocateIdList(MetadataManager *mdm, u32 length); -void FreeIdList(MetadataManager *mdm, IdList id_list); -u32 AppendToChunkedIdList(MetadataManager *mdm, ChunkedIdList *id_list, u64 id); -} // namespace hermes -#endif // HERMES_METADATA_MANAGEMENT_INTERNAL_H_ From e7e715650f2b8a9bd2feccd3bb40e66871ed476c Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 1 Dec 2022 04:59:59 -0600 Subject: [PATCH 032/511] All MetadataManager functions are class members --- src/metadata_management.cc | 279 ++++++++++++++++--------------------- src/metadata_management.h | 19 ++- src/rpc.h | 4 +- 3 files changed, 136 insertions(+), 166 deletions(-) diff --git a/src/metadata_management.cc b/src/metadata_management.cc index 9d4848721..f3c0de1e1 100644 --- a/src/metadata_management.cc +++ b/src/metadata_management.cc @@ -43,63 +43,61 @@ static bool IsNameTooLong(const std::string &name, size_t max) { } /** is BLOB's \a name too long for kMaxBlobNameSize? */ -bool IsBlobNameTooLong(const std::string &name) { +bool MetadataManager::IsBlobNameTooLong(const std::string &name) { bool result = IsNameTooLong(name, kMaxBlobNameSize); return result; } /** is Bucket's \a name too long for kMaxBucketNameSize? */ -bool IsBucketNameTooLong(const std::string &name) { +bool MetadataManager::IsBucketNameTooLong(const std::string &name) { bool result = IsNameTooLong(name, kMaxBucketNameSize); return result; } /** is vBucket's \a name too long for kMaxVBucketNameSize? */ -bool IsVBucketNameTooLong(const std::string &name) { +bool MetadataManager::IsVBucketNameTooLong(const std::string &name) { bool result = IsNameTooLong(name, kMaxVBucketNameSize); return result; } /** put \a key, \a value, and \a map_type locally */ -void LocalPut(const char *key, u64 val, - MapType map_type) { +void MetadataManager::LocalPut(const char *key, u64 val, MapType map_type) { PutToStorage(key, val, map_type); } /** put \a key and \a value locally */ -void LocalPut(BlobID key, const BlobInfo &value) { +void MetadataManager::LocalPut(BlobID key, const BlobInfo &value) { PutToStorage(key, value); } /** get the value of \a key and \a map_type locally */ -u64 LocalGet(const char *key, MapType map_type) { +u64 MetadataManager::LocalGet(const char *key, MapType map_type) { u64 result = GetFromStorage(key, map_type); return result; } /** delete \a key locally */ -void LocalDelete(BlobID key) { +void MetadataManager::LocalDelete(BlobID key) { DeleteFromStorage(key, false); } /** delete \a map_type locally */ -void LocalDelete(const char *key, MapType map_type) { +void MetadataManager::LocalDelete(const char *key, MapType map_type) { DeleteFromStorage(key, map_type); } /** get hash string for metadata storage */ -u32 HashString(const char *str) { +u32 MetadataManager::HashString(const char *str) { u32 result = HashStringForStorage(rpc, str); return result; } /** get id */ -u64 GetId(const char *name, - MapType map_type) { +u64 MetadataManager::GetId(const char *name, MapType map_type) { u64 result = 0; mdm = GetMetadataManagerFromContext(context); @@ -116,8 +114,7 @@ u64 GetId(const char *name, } /** get bucket id */ -BucketID GetBucketId( - const char *name) { +BucketID MetadataManager::GetBucketId(const char *name) { BucketID result = {}; result.as_int = GetId(context, rpc, name, kMapType_Bucket); @@ -125,7 +122,7 @@ BucketID GetBucketId( } /** get local bucket id */ -BucketID LocalGetBucketId(const char *name) { +BucketID MetadataManager::LocalGetBucketId(const char *name) { mdm = GetMetadataManagerFromContext(context); BucketID result = {}; result.as_int = LocalGet(name, kMapType_Bucket); @@ -133,8 +130,7 @@ BucketID LocalGetBucketId(const char *name) { return result; } /** get virtual bucket id */ -VBucketID GetVBucketId( - const char *name) { +VBucketID MetadataManager::GetVBucketId(const char *name) { VBucketID result = {}; result.as_int = GetId(context, rpc, name, kMapType_VBucket); @@ -142,7 +138,7 @@ VBucketID GetVBucketId( } /** get local virtual bucket id */ -VBucketID LocalGetVBucketId(const char *name) { +VBucketID MetadataManager::LocalGetVBucketId(const char *name) { mdm = GetMetadataManagerFromContext(context); VBucketID result = {}; result.as_int = LocalGet(name, kMapType_VBucket); @@ -151,7 +147,7 @@ VBucketID LocalGetVBucketId(const char *name) { } /** make an internal BLOB name */ -std::string MakeInternalBlobName(const std::string &name, BucketID id) { +std::string MetadataManager::MakeInternalBlobName(const std::string &name, BucketID id) { std::stringstream ss; // NOTE(chogan): Store the bytes of \p id at the beginning of the name. We @@ -173,9 +169,9 @@ std::string MakeInternalBlobName(const std::string &name, BucketID id) { } /** get BLOB id */ -BlobID GetBlobId( - const std::string &name, BucketID bucket_id, - bool track_stats) { +BlobID MetadataManager::GetBlobId(const std::string &name, + BucketID bucket_id, + bool track_stats) { std::string internal_name = MakeInternalBlobName(name, bucket_id); BlobID result = {}; result.as_int = GetId(context, rpc, internal_name.c_str(), kMapType_BlobId); @@ -187,8 +183,8 @@ BlobID GetBlobId( } /** put BLOB id */ -void PutId(const std::string &name, - u64 id, MapType map_type) { +void MetadataManager::PutId(const std::string &name, + u64 id, MapType map_type) { u32 target_node = HashString(rpc, name.c_str()); if (target_node == rpc->node_id) { LocalPut(name.c_str(), id, map_type); @@ -198,39 +194,35 @@ void PutId(const std::string &name, } /** put bucket id */ -void PutBucketId(const std::string &name, - BucketID id) { +void MetadataManager::PutBucketId(const std::string &name, BucketID id) { PutId(rpc, name, id.as_int, kMapType_Bucket); } /** put bucket id locally */ -void LocalPutBucketId(const std::string &name, - BucketID id) { +void MetadataManager::LocalPutBucketId(const std::string &name, BucketID id) { LocalPut(name.c_str(), id.as_int, kMapType_Bucket); } /** put virtual bucket id */ -void PutVBucketId( - const std::string &name, VBucketID id) { +void MetadataManager::PutVBucketId(const std::string &name, VBucketID id) { PutId(rpc, name, id.as_int, kMapType_VBucket); } /** put virtual bucket id locally */ -void LocalPutVBucketId(const std::string &name, - VBucketID id) { +void MetadataManager::LocalPutVBucketId(const std::string &name, VBucketID id) { LocalPut(name.c_str(), id.as_int, kMapType_VBucket); } /** put BLOB id */ -void PutBlobId(const std::string &name, - BlobID id, BucketID bucket_id) { +void MetadataManager::PutBlobId(const std::string &name, + BlobID id, BucketID bucket_id) { std::string internal_name = MakeInternalBlobName(name, bucket_id); PutId(rpc, internal_name, id.as_int, kMapType_BlobId); } /** delete id */ -void DeleteId(const std::string &name, - MapType map_type) { +void MetadataManager::DeleteId(const std::string &name, + MapType map_type) { u32 target_node = HashString(rpc, name.c_str()); if (target_node == rpc->node_id) { @@ -241,38 +233,36 @@ void DeleteId(const std::string &name, } /** delete bucket id */ -void DeleteBucketId( - const std::string &name) { +void MetadataManager::DeleteBucketId(const std::string &name) { DeleteId(rpc, name, kMapType_Bucket); } /** delete virtual bucket id */ -void DeleteVBucketId( - const std::string &name) { +void MetadataManager::DeleteVBucketId(const std::string &name) { DeleteId(rpc, name, kMapType_VBucket); } /** delete BLOB information locally */ -void LocalDeleteBlobInfo(BlobID blob_id) { +void MetadataManager::LocalDeleteBlobInfo(BlobID blob_id) { LocalDelete(blob_id); } /** delete BLOB id locally */ -void LocalDeleteBlobId(const std::string &name, - BucketID bucket_id) { +void MetadataManager::LocalDeleteBlobId(const std::string &name, + BucketID bucket_id) { std::string internal_name = MakeInternalBlobName(name, bucket_id); LocalDelete(internal_name.c_str(), kMapType_BlobId); } /** delete BLOB id */ -void DeleteBlobId( - const std::string &name, BucketID bucket_id) { +void MetadataManager::DeleteBlobId(const std::string &name, + BucketID bucket_id) { std::string internal_name = MakeInternalBlobName(name, bucket_id); DeleteId(rpc, internal_name, kMapType_BlobId); } /** get bucket information by \a index index locally */ -BucketInfo *LocalGetBucketInfoByIndex(u32 index) { +BucketInfo* MetadataManager::LocalGetBucketInfoByIndex(u32 index) { BucketInfo *info_array = (BucketInfo *)((u8 *)mdm + bucket_info_offset); BucketInfo *result = info_array + index; @@ -280,8 +270,7 @@ BucketInfo *LocalGetBucketInfoByIndex(u32 index) { } /** get BLOB name from \a blob_id locally */ -std::string LocalGetBlobNameFromId( - BlobID blob_id) { +std::string MetadataManager::LocalGetBlobNameFromId(BlobID blob_id) { mdm = GetMetadataManagerFromContext(context); std::string blob_name = ReverseGetFromStorage(blob_id.as_int, kMapType_BlobId); @@ -295,8 +284,7 @@ std::string LocalGetBlobNameFromId( } /** get BLOB name from \a blob_id */ -std::string GetBlobNameFromId( - BlobID blob_id) { +std::string MetadataManager::GetBlobNameFromId(BlobID blob_id) { u32 target_node = GetBlobNodeId(blob_id); std::string result; if (target_node == rpc->node_id) { @@ -325,7 +313,7 @@ static const u64 hextable[] = { 0, 0, 0, 0, 0, 0, 0 }; -u64 HexStringToU64(const std::string &s) { +u64 MetadataManager::HexStringToU64(const std::string &s) { u64 result = 0; for (size_t i = 0; i < kBucketIdStringSize; ++i) { result = (result << 4) | hextable[(int)s[i]]; @@ -335,7 +323,7 @@ u64 HexStringToU64(const std::string &s) { } /** get bucket ID from \a blob_id locally */ -BucketID LocalGetBucketIdFromBlobId(BlobID id) { +BucketID MetadataManager::LocalGetBucketIdFromBlobId(BlobID id) { mdm = GetMetadataManagerFromContext(context); std::string internal_name = ReverseGetFromStorage(id.as_int, kMapType_BlobId); @@ -348,8 +336,7 @@ BucketID LocalGetBucketIdFromBlobId(BlobID id) { } /** get bucket ID from \a blob_id */ -BucketID GetBucketIdFromBlobId( - BlobID id) { +BucketID MetadataManager::GetBucketIdFromBlobId(BlobID id) { BucketID result = {}; u32 target_node = GetBlobNodeId(id); if (target_node == rpc->node_id) { @@ -363,15 +350,14 @@ BucketID GetBucketIdFromBlobId( } /** get bucket information from \a bucket_id */ -BucketInfo *LocalGetBucketInfoById(BucketID id) { +BucketInfo* MetadataManager::LocalGetBucketInfoById(BucketID id) { BucketInfo *result = LocalGetBucketInfoByIndex(id.bits.index); return result; } /** get BLOB IDs from \a bucket_id */ -std::vector GetBlobIds( - BucketID bucket_id) { +std::vector MetadataManager::GetBlobIds(BucketID bucket_id) { std::vector result; u32 target_node = bucket_id.bits.node_id; if (target_node == rpc->node_id) { @@ -385,7 +371,7 @@ std::vector GetBlobIds( } /** get virtual bucket information by \a index */ -VBucketInfo *GetVBucketInfoByIndex(u32 index) { +VBucketInfo* MetadataManager::GetVBucketInfoByIndex(u32 index) { VBucketInfo *info_array = (VBucketInfo *)((u8 *)mdm + vbucket_info_offset); VBucketInfo *result = info_array + index; @@ -398,8 +384,7 @@ VBucketInfo *GetVBucketInfoByIndex(u32 index) { * * Assumes bucket_mutex is already held by the caller. */ -BucketID LocalGetNextFreeBucketId( - const std::string &name) { +BucketID MetadataManager::LocalGetNextFreeBucketId(const std::string &name) { mdm = GetMetadataManagerFromContext(context); BucketID result = {}; @@ -429,8 +414,7 @@ BucketID LocalGetNextFreeBucketId( } /** get or create a bucket ID locally */ -BucketID LocalGetOrCreateBucketId( - const std::string &name) { +BucketID MetadataManager::LocalGetOrCreateBucketId(const std::string &name) { mdm = GetMetadataManagerFromContext(context); bucket_mutex.Lock();; BucketID result = LocalGetBucketId(context, name.c_str()); @@ -448,8 +432,7 @@ BucketID LocalGetOrCreateBucketId( } /** get or create a bucket ID */ -BucketID GetOrCreateBucketId( - const std::string &name) { +BucketID MetadataManager::GetOrCreateBucketId(const std::string &name) { mdm = GetMetadataManagerFromContext(context); u32 target_node = HashString(rpc, name.c_str()); BucketID result = {}; @@ -468,8 +451,7 @@ BucketID GetOrCreateBucketId( * * Assumes MetadataManager::vbucket_mutex is already held by the caller. */ -VBucketID LocalGetNextFreeVBucketId( - const std::string &name) { +VBucketID MetadataManager::LocalGetNextFreeVBucketId(const std::string &name) { mdm = GetMetadataManagerFromContext(context); VBucketID result = {}; @@ -499,8 +481,7 @@ VBucketID LocalGetNextFreeVBucketId( } /** get or create a virtual bucket ID locally */ -VBucketID LocalGetOrCreateVBucketId( - const std::string &name) { +VBucketID MetadataManager::LocalGetOrCreateVBucketId(const std::string &name) { mdm = GetMetadataManagerFromContext(context); vbucket_mutex.Lock(); @@ -519,8 +500,7 @@ VBucketID LocalGetOrCreateVBucketId( } /** get or create a virtual bucket ID */ -VBucketID GetOrCreateVBucketId( - const std::string &name) { +VBucketID MetadataManager::GetOrCreateVBucketId(const std::string &name) { VBucketID result = {}; mdm = GetMetadataManagerFromContext(context); u32 target_node = HashString(rpc, name.c_str()); @@ -535,16 +515,16 @@ VBucketID GetOrCreateVBucketId( } /** copy IDs */ -void CopyIds(u64 *dest, u64 *src, u32 count) { +void MetadataManager::CopyIds(u64 *dest, u64 *src, u32 count) { static_assert(sizeof(BlobID) == sizeof(BufferID)); for (u32 i = 0; i < count; ++i) { dest[i] = src[i]; } } -void ReplaceBlobIdInBucket( - BucketID bucket_id, BlobID old_blob_id, - BlobID new_blob_id) { +void MetadataManager::ReplaceBlobIdInBucket(BucketID bucket_id, + BlobID old_blob_id, + BlobID new_blob_id) { u32 target_node = bucket_id.bits.node_id; if (target_node == rpc->node_id) { LocalReplaceBlobIdInBucket(context, bucket_id, old_blob_id, new_blob_id); @@ -555,8 +535,8 @@ void ReplaceBlobIdInBucket( } /** add BLOB ID to bucket */ -void AddBlobIdToBucket(BlobID blob_id, - BucketID bucket_id) { +void MetadataManager::AddBlobIdToBucket(BlobID blob_id, + BucketID bucket_id) { u32 target_node = bucket_id.bits.node_id; if (target_node == rpc->node_id) { @@ -568,8 +548,8 @@ void AddBlobIdToBucket(BlobID blob_id, } /** add BLOB ID to virtual bucket */ -void AddBlobIdToVBucket(BlobID blob_id, - VBucketID vbucket_id) { +void MetadataManager::AddBlobIdToVBucket(BlobID blob_id, + VBucketID vbucket_id) { u32 target_node = vbucket_id.bits.node_id; if (target_node == rpc->node_id) { @@ -581,9 +561,8 @@ void AddBlobIdToVBucket(BlobID blob_id, } /** allocate buffer ID list */ -u32 AllocateBufferIdList( - u32 target_node, - const std::vector &buffer_ids) { +u32 MetadataManager::AllocateBufferIdList( + u32 target_node, const std::vector &buffer_ids) { mdm = GetMetadataManagerFromContext(context); u32 result = 0; @@ -598,9 +577,8 @@ u32 AllocateBufferIdList( } /** get buffer ID list */ -void GetBufferIdList( - BlobID blob_id, - BufferIdArray *buffer_ids) { +void MetadataManager::GetBufferIdList(BlobID blob_id, + BufferIdArray *buffer_ids) { mdm = GetMetadataManagerFromContext(context); u32 target_node = GetBlobNodeId(blob_id); @@ -617,7 +595,7 @@ void GetBufferIdList( } /** get buffer ID list as vector */ -std::vector GetBufferIdList(BlobID blob_id) { +std::vector MetadataManager::GetBufferIdList(BlobID blob_id) { mdm = GetMetadataManagerFromContext(context); u32 target_node = GetBlobNodeId(blob_id); @@ -634,7 +612,7 @@ std::vector GetBufferIdList(BlobID blob_id) { } /** get buffer IDs from BLOB id */ -BufferIdArray GetBufferIdsFromBlobId(BlobID blob_id, +BufferIdArray MetadataManager::GetBufferIdsFromBlobId(BlobID blob_id, u32 **sizes) { BufferIdArray result = {}; GetBufferIdList(context, rpc, blob_id, &result); @@ -651,8 +629,9 @@ BufferIdArray GetBufferIdsFromBlobId(BlobID blob_id, } /** create BLOB metadata locally */ -void LocalCreateBlobMetadata(const std::string &blob_name, BlobID blob_id, - TargetID effective_target) { +void MetadataManager::LocalCreateBlobMetadata(const std::string &blob_name, + BlobID blob_id, + TargetID effective_target) { LocalPut(blob_name.c_str(), blob_id.as_int, kMapType_BlobId); BlobInfo blob_info = {}; blob_info.stats.frequency = 1; @@ -671,8 +650,9 @@ void LocalCreateBlobMetadata(const std::string &blob_name, BlobID blob_id, } /** create BLOB metadata */ -void CreateBlobMetadata(const std::string &blob_name, BlobID blob_id, - TargetID effective_target) { +void MetadataManager::CreateBlobMetadata(const std::string &blob_name, + BlobID blob_id, + TargetID effective_target) { mdm = GetMetadataManagerFromContext(context); u32 target_node = GetBlobNodeId(blob_id); if (target_node == rpc->node_id) { @@ -684,10 +664,11 @@ void CreateBlobMetadata(const std::string &blob_name, BlobID blob_id, } /** attach BLOB to bucket */ -void AttachBlobToBucket(const char *blob_name, BucketID bucket_id, - const std::vector &buffer_ids, - TargetID effective_target, bool is_swap_blob, - bool called_from_buffer_organizer) { +void MetadataManager::AttachBlobToBucket( + const char *blob_name, BucketID bucket_id, + const std::vector &buffer_ids, + TargetID effective_target, bool is_swap_blob, + bool called_from_buffer_organizer) { mdm = GetMetadataManagerFromContext(context); std::string internal_name = MakeInternalBlobName(blob_name, bucket_id); @@ -719,7 +700,7 @@ void AttachBlobToBucket(const char *blob_name, BucketID bucket_id, } /** free buffer ID list */ -void FreeBufferIdList(BlobID blob_id) { +void MetadataManager::FreeBufferIdList(BlobID blob_id) { u32 target_node = GetBlobNodeId(blob_id); if (target_node == rpc->node_id) { LocalFreeBufferIdList(context, blob_id); @@ -729,14 +710,14 @@ void FreeBufferIdList(BlobID blob_id) { } /** delete BLOB metadata locally */ -void LocalDeleteBlobMetadata(const char *blob_name, +void MetadataManager::LocalDeleteBlobMetadata(const char *blob_name, BlobID blob_id, BucketID bucket_id) { LocalDeleteBlobId(blob_name, bucket_id); LocalDeleteBlobInfo(blob_id); } /** wait for outstanding BLOB operations */ -void WaitForOutstandingBlobOps(BlobID blob_id) { +void MetadataManager::WaitForOutstandingBlobOps(BlobID blob_id) { BlobInfo *blob_info = GetBlobInfoPtr(blob_id); if (blob_info) { blob_info->lock.Lock(); @@ -747,8 +728,9 @@ void WaitForOutstandingBlobOps(BlobID blob_id) { } /** destroy BLOB by name locally */ -void LocalDestroyBlobByName(const char *blob_name, BlobID blob_id, - BucketID bucket_id) { +void MetadataManager::LocalDestroyBlobByName(const char *blob_name, + BlobID blob_id, + BucketID bucket_id) { mdm = GetMetadataManagerFromContext(context); // NOTE(chogan): Holding the blob_info_map_mutex @@ -769,7 +751,8 @@ void LocalDestroyBlobByName(const char *blob_name, BlobID blob_id, } /** destroy BLOB by ID locally */ -void LocalDestroyBlobById(BlobID blob_id, BucketID bucket_id) { +void MetadataManager::LocalDestroyBlobById(BlobID blob_id, + BucketID bucket_id) { std::string blob_name = LocalGetBlobNameFromId(context, blob_id); if (blob_name.size() > 0) { LocalDestroyBlobByName(context, rpc, blob_name.c_str(), blob_id, bucket_id); @@ -779,7 +762,8 @@ void LocalDestroyBlobById(BlobID blob_id, BucketID bucket_id) { } } -void RemoveBlobFromBucketInfo(BucketID bucket_id, BlobID blob_id) { +void MetadataManager::RemoveBlobFromBucketInfo(BucketID bucket_id, + BlobID blob_id) { u32 target_node = bucket_id.bits.node_id; if (target_node == rpc->node_id) { LocalRemoveBlobFromBucketInfo(context, bucket_id, blob_id); @@ -790,7 +774,8 @@ void RemoveBlobFromBucketInfo(BucketID bucket_id, BlobID blob_id) { } /** destroy BLOB by name */ -void DestroyBlobByName(BucketID bucket_id, const std::string &blob_name) { +void MetadataManager::DestroyBlobByName(BucketID bucket_id, + const std::string &blob_name) { BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id); if (!IsNullBlobId(blob_id)) { u32 blob_id_target_node = GetBlobNodeId(blob_id); @@ -807,8 +792,9 @@ void DestroyBlobByName(BucketID bucket_id, const std::string &blob_name) { } /** rename BLOB */ -void RenameBlob(const std::string &old_name, const std::string &new_name, - BucketID bucket_id) { +void MetadataManager::RenameBlob(const std::string &old_name, + const std::string &new_name, + BucketID bucket_id) { mdm = GetMetadataManagerFromContext(context); BlobID blob_id = GetBlobId(context, rpc, old_name, bucket_id); if (!IsNullBlobId(blob_id)) { @@ -820,7 +806,8 @@ void RenameBlob(const std::string &old_name, const std::string &new_name, } /** does \a bucket_id bucket contain \a blob_name BLOB? */ -bool ContainsBlob(BucketID bucket_id, const std::string &blob_name) { +bool MetadataManager::ContainsBlob(BucketID bucket_id, + const std::string &blob_name) { BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id); bool result = false; @@ -838,8 +825,7 @@ bool ContainsBlob(BucketID bucket_id, const std::string &blob_name) { } /** destroy BLOB by ID */ -void DestroyBlobById(BlobID id, - BucketID bucket_id) { +void MetadataManager::DestroyBlobById(BlobID id, BucketID bucket_id) { u32 target_node = GetBlobNodeId(id); if (target_node == rpc->node_id) { LocalDestroyBlobById(context, rpc, id, bucket_id); @@ -849,7 +835,7 @@ void DestroyBlobById(BlobID id, } /** destroy bucket */ -bool DestroyBucket(const char *name, BucketID bucket_id) { +bool MetadataManager::DestroyBucket(const char *name, BucketID bucket_id) { u32 target_node = bucket_id.bits.node_id; bool destroyed = false; if (target_node == rpc->node_id) { @@ -863,7 +849,7 @@ bool DestroyBucket(const char *name, BucketID bucket_id) { } /** destroy virtual bucket */ -bool DestroyVBucket(const char *name, VBucketID vbucket_id) { +bool MetadataManager::DestroyVBucket(const char *name, VBucketID vbucket_id) { u32 target_node = vbucket_id.bits.node_id; bool destroyed = false; if (target_node == rpc->node_id) { @@ -877,16 +863,18 @@ bool DestroyVBucket(const char *name, VBucketID vbucket_id) { } /** rename bucket locally */ -void LocalRenameBucket(BucketID id, const std::string &old_name, - const std::string &new_name) { +void MetadataManager::LocalRenameBucket(BucketID id, + const std::string &old_name, + const std::string &new_name) { mdm = GetMetadataManagerFromContext(context); DeleteBucketId(rpc, old_name); PutBucketId(rpc, new_name, id); } /** rename bucket */ -void RenameBucket(BucketID id, - const std::string &old_name, const std::string &new_name) { +void MetadataManager::RenameBucket(BucketID id, + const std::string &old_name, + const std::string &new_name) { u32 target_node = id.bits.node_id; if (target_node == rpc->node_id) { LocalRenameBucket(context, rpc, id, old_name, new_name); @@ -897,14 +885,14 @@ void RenameBucket(BucketID id, } /** increment reference count locally */ -void LocalIncrementRefcount(BucketID id) { +void MetadataManager::LocalIncrementRefcount(BucketID id) { mdm = GetMetadataManagerFromContext(context); BucketInfo *info = LocalGetBucketInfoById(id); info->ref_count.fetch_add(1); } /** decrement reference count locally */ -void LocalDecrementRefcount(BucketID id) { +void MetadataManager::LocalDecrementRefcount(BucketID id) { mdm = GetMetadataManagerFromContext(context); BucketInfo *info = LocalGetBucketInfoById(id); info->ref_count.fetch_sub(1); @@ -912,7 +900,7 @@ void LocalDecrementRefcount(BucketID id) { } /** decrement reference count */ -void DecrementRefcount(BucketID id) { +void MetadataManager::DecrementRefcount(BucketID id) { u32 target_node = id.bits.node_id; if (target_node == rpc->node_id) { LocalDecrementRefcount(context, id); @@ -922,31 +910,15 @@ void DecrementRefcount(BucketID id) { } /** get remaning target capacity locally */ -u64 LocalGetRemainingTargetCapacity(TargetID id) { +u64 MetadataManager::LocalGetRemainingTargetCapacity(TargetID id) { Target *target = GetTargetFromId(context, id); u64 result = target->remaining_space.load(); return result; } -/** get local system view state from \a mdm metadata mamanger */ -SystemViewState *GetLocalSystemViewState() { - SystemViewState *result = - (SystemViewState *)((u8 *)mdm + system_view_state_offset); - - return result; -} - -/** get local system view state from \a context */ -SystemViewState *GetLocalSystemViewState(SharedMemoryContext *context) { - mdm = GetMetadataManagerFromContext(context); - SystemViewState *result = GetLocalSystemViewState(mdm); - - return result; -} - /** get global device capacities locally */ -std::vector LocalGetGlobalDeviceCapacities(SharedMemoryContext *context) { +std::vector MetadataManager::LocalGetGlobalDeviceCapacities() { GlobalSystemViewState *global_svs = GetGlobalSystemViewState(context); std::vector result(global_svs->num_devices); @@ -958,8 +930,7 @@ std::vector LocalGetGlobalDeviceCapacities(SharedMemoryContext *context) { } /** get global device capacities */ -std::vector GetGlobalDeviceCapacities( - RpcContext *rpc) { +std::vector MetadataManager::GetGlobalDeviceCapacities() { mdm = GetMetadataManagerFromContext(context); u32 target_node = global_system_view_state_node_id; @@ -976,7 +947,7 @@ std::vector GetGlobalDeviceCapacities( } /** get global system view state from \a context */ -GlobalSystemViewState *GetGlobalSystemViewState(SharedMemoryContext *context) { +GlobalSystemViewState* MetadataManager::GetGlobalSystemViewState() { mdm = GetMetadataManagerFromContext(context); GlobalSystemViewState *result = (GlobalSystemViewState *)((u8 *)mdm + global_system_view_state_offset); @@ -987,8 +958,8 @@ GlobalSystemViewState *GetGlobalSystemViewState(SharedMemoryContext *context) { /** update global system view state locally */ std::vector -LocalUpdateGlobalSystemViewState(u32 node_id, - std::vector adjustments) { +MetadataManager::LocalUpdateGlobalSystemViewState( + u32 node_id, std::vector adjustments) { std::vector result; for (size_t device_idx = 0; device_idx < adjustments.size(); ++device_idx) { GlobalSystemViewState *state = GetGlobalSystemViewState(context); @@ -1041,8 +1012,7 @@ LocalUpdateGlobalSystemViewState(u32 node_id, } /** update global system view state */ -void UpdateGlobalSystemViewState( - RpcContext *rpc) { +void MetadataManager::UpdateGlobalSystemViewState() { mdm = GetMetadataManagerFromContext(context); BufferPool *pool = GetBufferPoolFromContext(context); @@ -1075,8 +1045,8 @@ void UpdateGlobalSystemViewState( } /** find target ID from device ID */ -TargetID FindTargetIdFromDeviceId(const std::vector &targets, - DeviceID device_id) { +TargetID MetadataManager::FindTargetIdFromDeviceId( + const std::vector &targets, DeviceID device_id) { TargetID result = {}; // TODO(chogan): @optimization Inefficient O(n) for (size_t target_index = 0; @@ -1091,16 +1061,9 @@ TargetID FindTargetIdFromDeviceId(const std::vector &targets, return result; } -/** get offset from metadata manager */ -static ptrdiff_t GetOffsetFromMdm(void *ptr) { - assert((u8 *)ptr >= (u8 *)mdm); - ptrdiff_t result = (u8 *)ptr - (u8 *)mdm; - - return result; -} - /** create system view state */ -SystemViewState *CreateSystemViewState(Config *config) { +SystemViewState* +MetadataManager::CreateSystemViewState(Config *config) { SystemViewState *result = PushClearedStruct(arena); result->num_devices = config->num_devices; for (int i = 0; i < result->num_devices; ++i) { @@ -1115,7 +1078,8 @@ SystemViewState *CreateSystemViewState(Config *config) { } /** create global system view state */ -GlobalSystemViewState *CreateGlobalSystemViewState(Config *config) { +GlobalSystemViewState* +MetadataManager::CreateGlobalSystemViewState(Config *config) { GlobalSystemViewState *result = PushClearedStruct(arena); result->num_devices = config->num_devices; @@ -1141,7 +1105,7 @@ GlobalSystemViewState *CreateGlobalSystemViewState(Config *config) { } /** get swap file name */ -std::string GetSwapFilename(u32 node_id) { +std::string MetadataManager::GetSwapFilename(u32 node_id) { char *prefix = (char *)((u8 *)mdm + swap_filename_prefix_offset); char *suffix = (char *)((u8 *)mdm + swap_filename_suffix_offset); std::string result = (prefix + std::to_string(node_id) + suffix); @@ -1150,7 +1114,8 @@ std::string GetSwapFilename(u32 node_id) { } /** swap BLOB to vector */ -std::vector SwapBlobToVec(SwapBlob swap_blob) { +std::vector +MetadataManager::SwapBlobToVec(SwapBlob swap_blob) { // TODO(chogan): @metaprogramming Improve this, since it currently only works // if each member in SwapBlob (plus padding) is eight bytes. static_assert((sizeof(SwapBlob) / 8) == SwapBlobMembers_Count); @@ -1165,7 +1130,7 @@ std::vector SwapBlobToVec(SwapBlob swap_blob) { } /** vector to swap BLOB */ -SwapBlob VecToSwapBlob(std::vector &vec) { +SwapBlob MetadataManager::VecToSwapBlob(std::vector &vec) { SwapBlob result = {}; if (vec.size() == SwapBlobMembers_Count) { @@ -1182,7 +1147,7 @@ SwapBlob VecToSwapBlob(std::vector &vec) { } /** ID array to swap BLOB */ -SwapBlob IdArrayToSwapBlob(BufferIdArray ids) { +SwapBlob MetadataManager::IdArrayToSwapBlob(BufferIdArray ids) { SwapBlob result = {}; if (ids.length == SwapBlobMembers_Count) { diff --git a/src/metadata_management.h b/src/metadata_management.h index 64de6cde1..daa55d702 100644 --- a/src/metadata_management.h +++ b/src/metadata_management.h @@ -19,6 +19,8 @@ #include #include "buffer_pool.h" +#include +#include namespace hermes { @@ -198,11 +200,18 @@ struct GlobalSystemViewState { /** A structure to represent metadata manager */ + +namespace lipc = labstor::ipc; +namespace lipcl = labstor::ipc::lockless; + + class MetadataManager { public: Config *config_; SharedMemoryContext *context_; RpcContext *rpc_; + SystemViewState local_state_; + GlobalSystemViewState global_state_; // All offsets are relative to the beginning of the MDM ptrdiff_t bucket_info_offset; /**< bucket information */ @@ -557,8 +566,7 @@ class MetadataManager { BucketID bucket_id); /** does \a bucket_id bucket contain \a blob_name BLOB? */ - bool ContainsBlob( - BucketID bucket_id, const std::string &blob_name); + bool ContainsBlob(BucketID bucket_id, const std::string &blob_name); /** destroy BLOB by ID */ void DestroyBlobById(BlobID id, @@ -603,9 +611,6 @@ class MetadataManager { /** get global device capacities */ std::vector GetGlobalDeviceCapacities(); - /** get global system view state from \a context */ - GlobalSystemViewState *GetGlobalSystemViewState(); - /** update global system view state locally */ std::vector LocalUpdateGlobalSystemViewState(u32 node_id, @@ -619,10 +624,10 @@ class MetadataManager { DeviceID device_id); /** create system view state */ - SystemViewState *CreateSystemViewState(Config *config); + SystemViewState* CreateSystemViewState(Config *config); /** create global system view state */ - GlobalSystemViewState *CreateGlobalSystemViewState(Config *config); + GlobalSystemViewState* CreateGlobalSystemViewState(Config *config); /** get swap file name */ std::string GetSwapFilename(u32 node_id); diff --git a/src/rpc.h b/src/rpc.h index 36176bb38..8aa42227c 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -34,7 +34,7 @@ enum class RpcType { /** A structure to represent RPC context. */ -namespace labstor_l = labstor::ipc::lockless; +namespace lipcl = labstor::ipc::lockless; class RpcContext { public: @@ -43,7 +43,7 @@ class RpcContext { Config *config_; /** The hermes configuration used to initialize this RPC */ /** Array of host names stored in shared memory. This array size is * RpcContext::num_nodes. */ - labstor_l::vector host_names; + lipcl::vector host_names; u32 node_id_; /**< node ID */ u32 num_nodes_; /**< number of nodes */ // The number of host numbers in the rpc_host_number_range entry of the From 123cf95f3984044c58cf0b62e9dc1c983e6973f8 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 1 Dec 2022 05:09:16 -0600 Subject: [PATCH 033/511] Begin fixing MetadataManager --- src/metadata_management.cc | 109 ++++++++++++++++----------------- src/metadata_management.h | 4 +- src/metadata_storage_stb_ds.cc | 4 +- src/rpc_thallium.h | 2 +- 4 files changed, 59 insertions(+), 60 deletions(-) diff --git a/src/metadata_management.cc b/src/metadata_management.cc index f3c0de1e1..31a129b49 100644 --- a/src/metadata_management.cc +++ b/src/metadata_management.cc @@ -103,7 +103,7 @@ u64 MetadataManager::GetId(const char *name, MapType map_type) { mdm = GetMetadataManagerFromContext(context); u32 target_node = HashString(rpc, name); - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalGet(name, map_type); } else { result = RpcCall(rpc, target_node, "RemoteGet", std::string(name), @@ -186,7 +186,7 @@ BlobID MetadataManager::GetBlobId(const std::string &name, void MetadataManager::PutId(const std::string &name, u64 id, MapType map_type) { u32 target_node = HashString(rpc, name.c_str()); - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { LocalPut(name.c_str(), id, map_type); } else { RpcCall(rpc, target_node, "RemotePut", name, id, map_type); @@ -225,7 +225,7 @@ void MetadataManager::DeleteId(const std::string &name, MapType map_type) { u32 target_node = HashString(rpc, name.c_str()); - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { LocalDelete(name.c_str(), map_type); } else { RpcCall(rpc, target_node, "RemoteDelete", name, map_type); @@ -285,9 +285,9 @@ std::string MetadataManager::LocalGetBlobNameFromId(BlobID blob_id) { /** get BLOB name from \a blob_id */ std::string MetadataManager::GetBlobNameFromId(BlobID blob_id) { - u32 target_node = GetBlobNodeId(blob_id); + u32 target_node = blob_id.GetNodeId(); std::string result; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalGetBlobNameFromId(context, blob_id); } else { result = RpcCall(rpc, target_node, "RemoteGetBlobNameFromId", @@ -339,7 +339,7 @@ BucketID MetadataManager::LocalGetBucketIdFromBlobId(BlobID id) { BucketID MetadataManager::GetBucketIdFromBlobId(BlobID id) { BucketID result = {}; u32 target_node = GetBlobNodeId(id); - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalGetBucketIdFromBlobId(context, id); } else { result = RpcCall(rpc, target_node, "RemoteGetBucketIdFromBlobId", @@ -360,7 +360,7 @@ BucketInfo* MetadataManager::LocalGetBucketInfoById(BucketID id) { std::vector MetadataManager::GetBlobIds(BucketID bucket_id) { std::vector result; u32 target_node = bucket_id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalGetBlobIds(context, bucket_id); } else { result = RpcCall>(rpc, target_node, "RemoteGetBlobIds", @@ -436,7 +436,7 @@ BucketID MetadataManager::GetOrCreateBucketId(const std::string &name) { mdm = GetMetadataManagerFromContext(context); u32 target_node = HashString(rpc, name.c_str()); BucketID result = {}; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalGetOrCreateBucketId(context, name); } else { result = RpcCall(rpc, target_node, "RemoteGetOrCreateBucketId", @@ -504,7 +504,7 @@ VBucketID MetadataManager::GetOrCreateVBucketId(const std::string &name) { VBucketID result = {}; mdm = GetMetadataManagerFromContext(context); u32 target_node = HashString(rpc, name.c_str()); - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalGetOrCreateVBucketId(context, name); } else { result = RpcCall(rpc, target_node, "RemoteGetOrCreateVBucketId", @@ -526,7 +526,7 @@ void MetadataManager::ReplaceBlobIdInBucket(BucketID bucket_id, BlobID old_blob_id, BlobID new_blob_id) { u32 target_node = bucket_id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { LocalReplaceBlobIdInBucket(context, bucket_id, old_blob_id, new_blob_id); } else { RpcCall(rpc, target_node, "RemoteReplaceBlobIdInBucket", bucket_id, @@ -539,7 +539,7 @@ void MetadataManager::AddBlobIdToBucket(BlobID blob_id, BucketID bucket_id) { u32 target_node = bucket_id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { LocalAddBlobIdToBucket(bucket_id, blob_id); } else { RpcCall(rpc, target_node, "RemoteAddBlobIdToBucket", bucket_id, @@ -552,7 +552,7 @@ void MetadataManager::AddBlobIdToVBucket(BlobID blob_id, VBucketID vbucket_id) { u32 target_node = vbucket_id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { LocalAddBlobIdToVBucket(vbucket_id, blob_id); } else { RpcCall(rpc, target_node, "RemoteAddBlobIdToVBucket", vbucket_id, @@ -566,7 +566,7 @@ u32 MetadataManager::AllocateBufferIdList( mdm = GetMetadataManagerFromContext(context); u32 result = 0; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalAllocateBufferIdList(buffer_ids); } else { result = RpcCall(rpc, target_node, "RemoteAllocateBufferIdList", @@ -580,9 +580,9 @@ u32 MetadataManager::AllocateBufferIdList( void MetadataManager::GetBufferIdList(BlobID blob_id, BufferIdArray *buffer_ids) { mdm = GetMetadataManagerFromContext(context); - u32 target_node = GetBlobNodeId(blob_id); + u32 target_node = blob_id.GetNodeId(); - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { LocalGetBufferIdList(blob_id, buffer_ids); } else { std::vector result = @@ -597,11 +597,11 @@ void MetadataManager::GetBufferIdList(BlobID blob_id, /** get buffer ID list as vector */ std::vector MetadataManager::GetBufferIdList(BlobID blob_id) { mdm = GetMetadataManagerFromContext(context); - u32 target_node = GetBlobNodeId(blob_id); + u32 target_node = blob_id.GetNodeId(); std::vector result; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalGetBufferIdList(blob_id); } else { result = RpcCall>(rpc, target_node, @@ -654,8 +654,8 @@ void MetadataManager::CreateBlobMetadata(const std::string &blob_name, BlobID blob_id, TargetID effective_target) { mdm = GetMetadataManagerFromContext(context); - u32 target_node = GetBlobNodeId(blob_id); - if (target_node == rpc->node_id) { + u32 target_node = blob_id.GetNodeId(); + if (target_node == rpc_->node_id_) { LocalCreateBlobMetadata(context, blob_name, blob_id, effective_target); } else { RpcCall(rpc, target_node, "RemoteCreateBlobMetadata", blob_name, @@ -701,8 +701,8 @@ void MetadataManager::AttachBlobToBucket( /** free buffer ID list */ void MetadataManager::FreeBufferIdList(BlobID blob_id) { - u32 target_node = GetBlobNodeId(blob_id); - if (target_node == rpc->node_id) { + u32 target_node = blob_id.GetNodeId(); + if (target_node == rpc_->node_id_) { LocalFreeBufferIdList(context, blob_id); } else { RpcCall(rpc, target_node, "RemoteFreeBufferIdList", blob_id); @@ -765,7 +765,7 @@ void MetadataManager::LocalDestroyBlobById(BlobID blob_id, void MetadataManager::RemoveBlobFromBucketInfo(BucketID bucket_id, BlobID blob_id) { u32 target_node = bucket_id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { LocalRemoveBlobFromBucketInfo(context, bucket_id, blob_id); } else { RpcCall(rpc, target_node, "RemoteRemoveBlobFromBucketInfo", bucket_id, @@ -778,9 +778,9 @@ void MetadataManager::DestroyBlobByName(BucketID bucket_id, const std::string &blob_name) { BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id); if (!IsNullBlobId(blob_id)) { - u32 blob_id_target_node = GetBlobNodeId(blob_id); + u32 blob_id_target_node = blob_id.GetNodeId(); - if (blob_id_target_node == rpc->node_id) { + if (blob_id_target_node == rpc_->node_id_) { LocalDestroyBlobByName(context, rpc, blob_name.c_str(), blob_id, bucket_id); } else { @@ -813,7 +813,7 @@ bool MetadataManager::ContainsBlob(BucketID bucket_id, if (!IsNullBlobId(blob_id)) { u32 target_node = bucket_id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalContainsBlob(context, bucket_id, blob_id); } else { result = RpcCall(rpc, target_node, "RemoteContainsBlob", bucket_id, @@ -827,7 +827,7 @@ bool MetadataManager::ContainsBlob(BucketID bucket_id, /** destroy BLOB by ID */ void MetadataManager::DestroyBlobById(BlobID id, BucketID bucket_id) { u32 target_node = GetBlobNodeId(id); - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { LocalDestroyBlobById(context, rpc, id, bucket_id); } else { RpcCall(rpc, target_node, "RemoteDestroyBlobById", id, bucket_id); @@ -838,7 +838,7 @@ void MetadataManager::DestroyBlobById(BlobID id, BucketID bucket_id) { bool MetadataManager::DestroyBucket(const char *name, BucketID bucket_id) { u32 target_node = bucket_id.bits.node_id; bool destroyed = false; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { destroyed = LocalDestroyBucket(context, rpc, name, bucket_id); } else { destroyed = RpcCall(rpc, target_node, "RemoteDestroyBucket", @@ -852,7 +852,7 @@ bool MetadataManager::DestroyBucket(const char *name, BucketID bucket_id) { bool MetadataManager::DestroyVBucket(const char *name, VBucketID vbucket_id) { u32 target_node = vbucket_id.bits.node_id; bool destroyed = false; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { destroyed = LocalDestroyVBucket(context, name, vbucket_id); } else { destroyed = RpcCall(rpc, target_node, "RemoteDestroyVBucket", @@ -876,7 +876,7 @@ void MetadataManager::RenameBucket(BucketID id, const std::string &old_name, const std::string &new_name) { u32 target_node = id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { LocalRenameBucket(context, rpc, id, old_name, new_name); } else { RpcCall(rpc, target_node, "RemoteRenameBucket", id, old_name, @@ -902,7 +902,7 @@ void MetadataManager::LocalDecrementRefcount(BucketID id) { /** decrement reference count */ void MetadataManager::DecrementRefcount(BucketID id) { u32 target_node = id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { LocalDecrementRefcount(context, id); } else { RpcCall(rpc, target_node, "RemoteDecrementRefcount", id); @@ -936,7 +936,7 @@ std::vector MetadataManager::GetGlobalDeviceCapacities() { std::vector result; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalGetGlobalDeviceCapacities(context); } else { result = RpcCall>(rpc, target_node, @@ -1028,9 +1028,9 @@ void MetadataManager::UpdateGlobalSystemViewState() { std::vector devices_to_organize; if (update_needed) { u32 target_node = global_system_view_state_node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { devices_to_organize = - LocalUpdateGlobalSystemViewState(context, rpc->node_id, adjustments); + LocalUpdateGlobalSystemViewState(context, rpc_->node_id_, adjustments); } else { devices_to_organize = RpcCall>(rpc, target_node, @@ -1089,12 +1089,12 @@ MetadataManager::CreateGlobalSystemViewState(Config *config) { // Min and max thresholds result->bo_capacity_thresholds[i] = config->bo_capacity_thresholds[i]; } - size_t num_targets = config->num_devices * rpc->num_nodes; + size_t num_targets = config->num_devices * rpc_->num_nodes; result->num_targets = num_targets; result->bytes_available = PushClearedArray>(num_targets); - for (u32 node_idx = 0; node_idx < rpc->num_nodes; ++node_idx) { + for (u32 node_idx = 0; node_idx < rpc_->num_nodes; ++node_idx) { for (int device_idx = 0; device_idx < result->num_devices; ++device_idx) { u64 index = (node_idx * result->num_devices) + device_idx; result->bytes_available[index].store(result->capacities[device_idx]); @@ -1168,7 +1168,7 @@ MetadataManager::MetadataManager(RpcContext *rpc, Config *config) : config_(config), rpc_(rpc) { // NOTE(chogan): All MetadataManager offsets are relative to the address of // the MDM itself. - u32 node_id = rpc->node_id_; + u32 node_id = rpc_->node_id__; map_seed = 0x4E58E5DF; SeedHashForStorage(map_seed); @@ -1269,7 +1269,7 @@ void MetadataManager::LocalDecrementRefcount(VBucketID id) { /** decrement reference counter */ void MetadataManager::DecrementRefcount(VBucketID id) { u32 target_node = id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { LocalDecrementRefcount(context, id); } else { RpcCall(rpc, target_node, "RemoteDecrementRefcountVBucket", id); @@ -1278,14 +1278,14 @@ void MetadataManager::DecrementRefcount(VBucketID id) { /** get relative node ID */ u32 MetadataManager::GetRelativeNodeId(int offset) { - int result = rpc->node_id + offset; + int result = rpc_->node_id_ + offset; assert(result >= 0); - assert(result <= (int)(rpc->num_nodes + 1)); + assert(result <= (int)(rpc_->num_nodes + 1)); - if (result > (int)rpc->num_nodes) { + if (result > (int)rpc_->num_nodes) { result = 1; } else if (result == 0) { - result = rpc->num_nodes; + result = rpc_->num_nodes; } return (u32)result; @@ -1309,7 +1309,7 @@ u32 MetadataManager::GetPreviousNode() { std::vector MetadataManager::GetNodeTargets(u32 target_node) { std::vector result; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalGetNodeTargets(context); } else { result = RpcCall>(rpc, target_node, @@ -1326,7 +1326,7 @@ std::vector MetadataManager::GetNeighborhoodTargets() { // (wrapping around for nodes 1 and N). std::vector result; - switch (rpc->num_nodes) { + switch (rpc_->num_nodes) { case 1: { // No neighbors break; @@ -1360,7 +1360,7 @@ u64 MetadataManager::GetRemainingTargetCapacity(TargetID target_id) { u64 result = 0; u32 target_node = target_id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalGetRemainingTargetCapacity(context, target_id); } else { result = RpcCall(rpc, target_node, "RemoteGetRemainingTargetCapacity", @@ -1403,7 +1403,7 @@ MetadataManager::LocalGetBucketNameById(BucketID blob_id) { std::vector MetadataManager::GetBlobsFromVBucketInfo(VBucketID vbucket_id) { u32 target_node = vbucket_id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { return LocalGetBlobsFromVBucketInfo(context, vbucket_id); } else { return RpcCall>( @@ -1417,7 +1417,7 @@ void MetadataManager::RemoveBlobFromVBucketInfo(VBucketID vbucket_id, BucketID bucket_id = GetBucketId(context, rpc, bucket_name); BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id); u32 target_node = vbucket_id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { LocalRemoveBlobFromVBucketInfo(context, vbucket_id, blob_id); } else { RpcCall(rpc, target_node, "RemoteRemoveBlobFromVBucketInfo", @@ -1427,7 +1427,7 @@ void MetadataManager::RemoveBlobFromVBucketInfo(VBucketID vbucket_id, std::string MetadataManager::GetBucketNameById(BucketID id) { auto target_node = id.bits.node_id; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { return LocalGetBucketNameById(context, id); } else { return RpcCall(rpc, target_node, "RemoteGetBucketNameById", @@ -1472,7 +1472,7 @@ int MetadataManager::GetNumOutstandingFlushingTasks(VBucketID id) { u32 target_node = id.bits.node_id; int result = 0; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalGetNumOutstandingFlushingTasks(context, id); } else { result = RpcCall(rpc, target_node, @@ -1503,7 +1503,6 @@ bool MetadataManager::LocalLockBlob(BlobID blob_id) { } bool MetadataManager::LocalUnlockBlob(BlobID blob_id) { - mdm = GetMetadataManagerFromContext(context); BlobInfo *blob_info = GetBlobInfoPtr(blob_id); bool result = false; if (blob_info) { @@ -1516,21 +1515,21 @@ bool MetadataManager::LocalUnlockBlob(BlobID blob_id) { /** lock BLOB */ bool MetadataManager::LockBlob(BlobID blob_id) { - u32 target_node = GetBlobNodeId(blob_id); + u32 target_node = blob_id.GetNodeId(); bool result; - if (target_node == rpc->node_id) { - result = LocalLockBlob(context, blob_id); + if (target_node == rpc_->node_id_) { + result = LocalLockBlob(blob_id); } else { - result = RpcCall(rpc, target_node, "RemoteLockBlob", blob_id); + result = rpc_->Call(target_node, "RemoteLockBlob", blob_id); } return result; } /** unlock BLOB */ bool MetadataManager::UnlockBlob(BlobID blob_id) { - u32 target_node = GetBlobNodeId(blob_id); + u32 target_node = blob_id.GetNodeId(); bool result; - if (target_node == rpc->node_id) { + if (target_node == rpc_->node_id_) { result = LocalUnlockBlob(context, blob_id); } else { result = RpcCall(rpc, target_node, "RemoteUnlockBlob", blob_id); diff --git a/src/metadata_management.h b/src/metadata_management.h index daa55d702..f0aae95f1 100644 --- a/src/metadata_management.h +++ b/src/metadata_management.h @@ -19,6 +19,7 @@ #include #include "buffer_pool.h" +#include "rpc_thallium.h" #include #include @@ -204,12 +205,11 @@ struct GlobalSystemViewState { namespace lipc = labstor::ipc; namespace lipcl = labstor::ipc::lockless; - class MetadataManager { public: Config *config_; SharedMemoryContext *context_; - RpcContext *rpc_; + ThalliumRpc *rpc_; SystemViewState local_state_; GlobalSystemViewState global_state_; diff --git a/src/metadata_storage_stb_ds.cc b/src/metadata_storage_stb_ds.cc index 24e138541..12c6b6901 100644 --- a/src/metadata_storage_stb_ds.cc +++ b/src/metadata_storage_stb_ds.cc @@ -436,7 +436,7 @@ void LocalIncrementBlobStats(MetadataManager *mdm, BlobID blob_id) { void IncrementBlobStats(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id) { - u32 target_node = GetBlobNodeId(blob_id); + u32 target_node = blob_id.GetNodeId(); if (target_node == rpc->node_id) { MetadataManager *mdm = GetMetadataManagerFromContext(context); LocalIncrementBlobStats(mdm, blob_id); @@ -1085,7 +1085,7 @@ f32 LocalGetBlobImportanceScore(SharedMemoryContext *context, BlobID blob_id) { f32 GetBlobImportanceScore(SharedMemoryContext *context, RpcContext *rpc, BlobID blob_id) { f32 result = 0; - u32 target_node = GetBlobNodeId(blob_id); + u32 target_node = blob_id.GetNodeId(); if (target_node == rpc->node_id) { result = LocalGetBlobImportanceScore(context, blob_id); } else { diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index d0654a667..a5cb2c543 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -123,7 +123,7 @@ class ThalliumRpc : public RpcContext { /** RPC call */ template - ReturnType RpcCall(u32 node_id, const char *func_name, Ts... args) { + ReturnType Call(u32 node_id, const char *func_name, Ts... args) { VLOG(1) << "Calling " << func_name << " on node " << node_id << " from node " << node_id << std::endl; bool is_bo_func = IsBoFunction(func_name); From 23c3740b774f63306a02f4a0a3f6aac31ae2bee4 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 1 Dec 2022 05:36:39 -0600 Subject: [PATCH 034/511] Unordered_maps for vbuckets, blobs, etc. --- src/metadata_management.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/metadata_management.h b/src/metadata_management.h index f0aae95f1..d3589bc0d 100644 --- a/src/metadata_management.h +++ b/src/metadata_management.h @@ -240,6 +240,11 @@ class MetadataManager { // TODO(chogan): @optimization Should the mutexes here be reader/writer // locks? + lipc::unordered_map blob_id_map_; + lipc::unordered_map blob_info_map_; + lipc::unordered_map bucket_map_; + lipc::unordered_map vbucket_map_; + /** Lock for accessing `BucketInfo` structures located at * `bucket_info_offset` */ labstor::Mutex bucket_mutex; From d9448b7c6305afd0f75c8d14efb4137e3ec2218a Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 1 Dec 2022 07:58:50 -0600 Subject: [PATCH 035/511] Begin RPC generator --- src/metadata_management.cc | 115 +- src/metadata_management.h | 83 +- src/metadata_storage_stb_ds.cc | 1099 ----------------- src/rpc_generator/metadata_management.py | 6 + .../rpc_generator/rpc_generator.py | 114 ++ test/CMakeLists.txt | 8 - 6 files changed, 181 insertions(+), 1244 deletions(-) delete mode 100644 src/metadata_storage_stb_ds.cc create mode 100644 src/rpc_generator/metadata_management.py create mode 100644 src/rpc_generator/rpc_generator/rpc_generator.py diff --git a/src/metadata_management.cc b/src/metadata_management.cc index 31a129b49..ceb2b6780 100644 --- a/src/metadata_management.cc +++ b/src/metadata_management.cc @@ -62,92 +62,52 @@ bool MetadataManager::IsVBucketNameTooLong(const std::string &name) { return result; } -/** put \a key, \a value, and \a map_type locally */ -void MetadataManager::LocalPut(const char *key, u64 val, MapType map_type) { - PutToStorage(key, val, map_type); -} - -/** put \a key and \a value locally */ -void MetadataManager::LocalPut(BlobID key, const BlobInfo &value) { - PutToStorage(key, value); -} - -/** get the value of \a key and \a map_type locally */ -u64 MetadataManager::LocalGet(const char *key, MapType map_type) { - u64 result = GetFromStorage(key, map_type); - - return result; -} - -/** delete \a key locally */ -void MetadataManager::LocalDelete(BlobID key) { - DeleteFromStorage(key, false); -} - -/** delete \a map_type locally */ -void MetadataManager::LocalDelete(const char *key, MapType map_type) { - DeleteFromStorage(key, map_type); -} - /** get hash string for metadata storage */ u32 MetadataManager::HashString(const char *str) { - u32 result = HashStringForStorage(rpc, str); + u32 result = HashStringForStorage(str); return result; } -/** get id */ -u64 MetadataManager::GetId(const char *name, MapType map_type) { - u64 result = 0; - - mdm = GetMetadataManagerFromContext(context); - u32 target_node = HashString(rpc, name); - +/** get bucket id */ +BucketID MetadataManager::GetBucketId(const char *name) { + u32 target_node = HashString(name); if (target_node == rpc_->node_id_) { - result = LocalGet(name, map_type); + LocalGetBucketId(name); } else { - result = RpcCall(rpc, target_node, "RemoteGet", std::string(name), - map_type); + // TODO(llogan): Add RemoteGetBucketId + return rpc_->Call(target_node, + "RemoteGetBucketId", + std::string(name)); } - - return result; -} - -/** get bucket id */ -BucketID MetadataManager::GetBucketId(const char *name) { - BucketID result = {}; - result.as_int = GetId(context, rpc, name, kMapType_Bucket); - - return result; } /** get local bucket id */ BucketID MetadataManager::LocalGetBucketId(const char *name) { - mdm = GetMetadataManagerFromContext(context); - BucketID result = {}; - result.as_int = LocalGet(name, kMapType_Bucket); - - return result; + return bucket_id_map_[name]; } + /** get virtual bucket id */ VBucketID MetadataManager::GetVBucketId(const char *name) { - VBucketID result = {}; - result.as_int = GetId(context, rpc, name, kMapType_VBucket); - - return result; + u32 target_node = HashString(name); + if (target_node == rpc_->node_id_) { + return LocalGetVBucketId(name); + } else { + // TODO(llogan): Add RemoteGetVBucketId + return rpc_->Call(target_node, + "RemoteGetVBucketId", + std::string(name)); + } } /** get local virtual bucket id */ VBucketID MetadataManager::LocalGetVBucketId(const char *name) { - mdm = GetMetadataManagerFromContext(context); - VBucketID result = {}; - result.as_int = LocalGet(name, kMapType_VBucket); - - return result; + return vbucket_id_map_[name]; } /** make an internal BLOB name */ -std::string MetadataManager::MakeInternalBlobName(const std::string &name, BucketID id) { +std::string MetadataManager::MakeInternalBlobName(const std::string &name, + BucketID id) { std::stringstream ss; // NOTE(chogan): Store the bytes of \p id at the beginning of the name. We @@ -173,24 +133,25 @@ BlobID MetadataManager::GetBlobId(const std::string &name, BucketID bucket_id, bool track_stats) { std::string internal_name = MakeInternalBlobName(name, bucket_id); - BlobID result = {}; - result.as_int = GetId(context, rpc, internal_name.c_str(), kMapType_BlobId); - if (!IsNullBlobId(result) && track_stats) { - IncrementBlobStats(context, rpc, result); + BlobID result; + u32 target_node = HashString(name.c_str()); + if (target_node == rpc_->node_id_) { + result = LocalGetBlobId(name); + } else { + // TODO(llogan): Add RemoteGetBlobId + result = rpc_->Call(target_node, + "RemoteGetBlobId", + std::string(name)); + } + if (!result.IsNull() && track_stats) { + IncrementBlobStats(result); } - return result; } -/** put BLOB id */ -void MetadataManager::PutId(const std::string &name, - u64 id, MapType map_type) { - u32 target_node = HashString(rpc, name.c_str()); - if (target_node == rpc_->node_id_) { - LocalPut(name.c_str(), id, map_type); - } else { - RpcCall(rpc, target_node, "RemotePut", name, id, map_type); - } +/** get local BLOB id */ +BlobID MetadataManager::LocalGetBlobId(const std::string &name) { + return blob_id_map_[name]; } /** put bucket id */ diff --git a/src/metadata_management.h b/src/metadata_management.h index d3589bc0d..5507b15ee 100644 --- a/src/metadata_management.h +++ b/src/metadata_management.h @@ -56,15 +56,6 @@ struct ShmemString { ShmemString &operator=(const ShmemString &&) = delete; }; -/** map type */ -enum MapType { - kMapType_Bucket, - kMapType_VBucket, - kMapType_BlobId, - kMapType_BlobInfo, - kMapType_Count -}; - /** min/max threshold violation */ enum class ThresholdViolation { kMin, kMax }; @@ -229,39 +220,26 @@ class MetadataManager { ptrdiff_t id_heap_offset; /**< ID heap */ ptrdiff_t map_heap_offset; /**< map heap */ - ptrdiff_t bucket_map_offset; /**< bucket map */ - ptrdiff_t vbucket_map_offset; /**< virtual bucket map */ - ptrdiff_t blob_id_map_offset; /**< BLOB ID map */ - ptrdiff_t blob_info_map_offset; /**< BLOB information map */ - ptrdiff_t swap_filename_prefix_offset; /**< swap file name prefix */ ptrdiff_t swap_filename_suffix_offset; /**< swap file name suffix */ // TODO(chogan): @optimization Should the mutexes here be reader/writer // locks? - lipc::unordered_map blob_id_map_; - lipc::unordered_map blob_info_map_; - lipc::unordered_map bucket_map_; - lipc::unordered_map vbucket_map_; - - /** Lock for accessing `BucketInfo` structures located at - * `bucket_info_offset` */ - labstor::Mutex bucket_mutex; - labstor::RwLock bucket_delete_lock; /**< lock for bucket deletion */ - - /** Lock for accessing `VBucketInfo` structures located at - * `vbucket_info_offset` */ - labstor::Mutex vbucket_mutex; - - /** Lock for accessing the `IdMap` located at `bucket_map_offset` */ - labstor::Mutex bucket_map_mutex; - /** Lock for accessing the `IdMap` located at `vbucket_map_offset` */ - labstor::Mutex vbucket_map_mutex; - /** Lock for accessing the `IdMap` located at `blob_id_map_offset` */ - labstor::Mutex blob_id_map_mutex; - /** Lock for accessing the `BlobInfoMap` located at `blob_info_map_offset` */ - labstor::Mutex blob_info_map_mutex; + lipc::unordered_map + blob_id_map_; /**< BLOB ID map */ + lipc::unordered_map + bucket_id_map_; /**< Bucket ID map */ + lipc::unordered_map + vbucket_id_map_; /**< VBucket ID map */ + + lipc::unordered_map + blob_info_map_; /**< BLOB information map */ + lipc::unordered_map + bucket_map_; /**< bucket map */ + lipc::unordered_map + vbucket_map_; /**< virtual bucket map */ + /** Lock for accessing `IdList`s and `ChunkedIdList`s */ labstor::Mutex id_mutex; @@ -362,30 +340,9 @@ class MetadataManager { /** is vBucket's \a name too long for kMaxVBucketNameSize? */ bool IsVBucketNameTooLong(const std::string &name); - /** put \a key, \a value, and \a map_type locally */ - void LocalPut(const char *key, u64 val, MapType map_type); - - /** put \a key and \a value locally */ - void LocalPut(BlobID key, const BlobInfo &value); - - /** get the value of \a key and \a map_type locally */ - u64 LocalGet(const char *key, MapType map_type); - - /** delete \a key locally */ - void LocalDelete(BlobID key); - - /** delete \a map_type locally */ - void LocalDelete(const char *key, MapType map_type); - - /** log error when metadata arena capacity is full */ - static void MetadataArenaErrorHandler(); - /** get hash string for metadata storage */ u32 HashString(const char *str); - /** get id */ - u64 GetId(const char *name, MapType map_type); - /** get bucket id */ BucketID GetBucketId(const char *name); @@ -405,6 +362,9 @@ class MetadataManager { BlobID GetBlobId(const std::string &name, BucketID bucket_id, bool track_stats); + /** get local BLOB id */ + BlobID LocalGetBlobId(const std::string &name); + /** put BLOB id */ void PutId(const std::string &name, u64 id, MapType map_type); @@ -638,13 +598,16 @@ class MetadataManager { std::string GetSwapFilename(u32 node_id); /** swap BLOB to vector */ - std::vector SwapBlobToVec(SwapBlob swap_blob)l + std::vector SwapBlobToVec(SwapBlob swap_blob); /** vector to swap BLOB */ - SwapBlob VecToSwapBlob(std::vector &vec)l + SwapBlob VecToSwapBlob(std::vector &vec); /** ID array to swap BLOB */ - SwapBlob IdArrayToSwapBlob(BufferIdArray ids)l + SwapBlob IdArrayToSwapBlob(BufferIdArray ids); + +#define RPC_METADATA_MANAGER_RPC +#undef RPC_METADATA_MANAGER_RPC }; /** log error when metadata arena capacity is full */ diff --git a/src/metadata_storage_stb_ds.cc b/src/metadata_storage_stb_ds.cc deleted file mode 100644 index 12c6b6901..000000000 --- a/src/metadata_storage_stb_ds.cc +++ /dev/null @@ -1,1099 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define STBDS_REALLOC(heap, ptr, size) hermes::HeapRealloc(heap, ptr, size) -#define STBDS_FREE(heap, ptr) hermes::HeapFree(heap, ptr) - -#define STBDS_ASSERT(x) assert((x)) - -#define STB_DS_IMPLEMENTATION -#include "stb_ds.h" -#include "buffer_pool_internal.h" - -namespace hermes { - -/** - A structure to represent ID map -*/ -struct IdMap { - char *key; /**< ID string as key */ - u64 value; /**< ID value */ -}; - -/** - A structure to represent BLOB information map -*/ -struct BlobInfoMap { - BlobID key; /**< BLOB ID as key */ - BlobInfo value; /**< BLOB information value */ -}; - -/** get map by offset */ -static IdMap *GetMapByOffset(MetadataManager *mdm, u32 offset) { - IdMap *result =(IdMap *)((u8 *)mdm + offset); - - return result; -} - -/** get bucket map */ -static IdMap *GetBucketMap(MetadataManager *mdm) { - IdMap *result = GetMapByOffset(mdm, mdm->bucket_map_offset); - - return result; -} - -/** get virtual bucket map */ -static IdMap *GetVBucketMap(MetadataManager *mdm) { - IdMap *result = GetMapByOffset(mdm, mdm->vbucket_map_offset); - - return result; -} - -/** get BLOB ID map */ -static IdMap *GetBlobIdMap(MetadataManager *mdm) { - IdMap *result = GetMapByOffset(mdm, mdm->blob_id_map_offset); - - return result; -} - -/** get map heap */ -Heap *GetMapHeap(MetadataManager *mdm) { - Heap *result = (Heap *)((u8 *)mdm + mdm->map_heap_offset); - - return result; -} - -/** get ID heap */ -Heap *GetIdHeap(MetadataManager *mdm) { - Heap *result = (Heap *)((u8 *)mdm + mdm->id_heap_offset); - - return result; -} - -/** check if heap overlaps */ -void CheckHeapOverlap(MetadataManager *mdm) { - Heap *map_heap = GetMapHeap(mdm); - Heap *id_heap = GetIdHeap(mdm); - - u8 *map_heap_end = HeapExtentToPtr(map_heap); - u8 *id_heap_start = HeapExtentToPtr(id_heap); - - if (map_heap_end >= id_heap_start) { - LOG(FATAL) << "Metadata Heaps have overlapped. Please increase " - << "metadata_arena_percentage in Hermes configuration." - << std::endl; - } -} - -/** get ticket mutex based on \a map_type */ -labstor::Mutex& GetMapMutex(MetadataManager *mdm, MapType map_type) { - switch (map_type) { - case kMapType_Bucket: { - return mdm->bucket_map_mutex; - } - case kMapType_VBucket: { - return mdm->vbucket_map_mutex; - } - case kMapType_BlobId: { - return mdm->blob_id_map_mutex; - break; - } - case kMapType_BlobInfo: { - return mdm->blob_info_map_mutex; - } - default: { - HERMES_INVALID_CODE_PATH; - } - } -} - -/** - * Get a pointer to an IdMap in shared memory. - * - * This function acquires a lock because it's pointing to a shared data - * structure. Make sure to call `ReleaseMap` when you're finished with the - * IdMap. - */ -IdMap *GetMap(MetadataManager *mdm, MapType map_type) { - IdMap *result = 0; - labstor::Mutex &mutex = GetMapMutex(mdm, map_type); - mutex.Lock(); - switch (map_type) { - case kMapType_Bucket: { - result = GetBucketMap(mdm); - break; - } - case kMapType_VBucket: { - result = GetVBucketMap(mdm); - break; - } - case kMapType_BlobId: { - result = GetBlobIdMap(mdm); - break; - } - default: - HERMES_INVALID_CODE_PATH; - } - - return result; -} - -/** get BLOB information map without mutex locking */ -BlobInfoMap *GetBlobInfoMapNoLock(MetadataManager *mdm) { - BlobInfoMap *result = (BlobInfoMap *)((u8 *)mdm + mdm->blob_info_map_offset); - - return result; -} - -/** get BLOB information map */ -BlobInfoMap *GetBlobInfoMap(MetadataManager *mdm) { - labstor::Mutex &mutex = GetMapMutex(mdm, kMapType_BlobInfo); - mutex.Lock(); - BlobInfoMap *result = GetBlobInfoMapNoLock(mdm); - - return result; -} - -/** - * Releases the lock acquired by `GetMap`. - */ -void ReleaseMap(MetadataManager *mdm, MapType map_type) { - switch (map_type) { - case kMapType_Bucket: { - mdm->bucket_map_mutex.Unlock(); - break; - } - case kMapType_VBucket: { - mdm->vbucket_map_mutex.Unlock(); - break; - } - case kMapType_BlobId: { - mdm->blob_id_map_mutex.Unlock(); - break; - } - case kMapType_BlobInfo: { - mdm->blob_info_map_mutex.Unlock(); - break; - } - default: { - HERMES_INVALID_CODE_PATH; - } - } -} - -/** - * Takes a lock on mdm->blob_info_map_mutex. Requires a corresponding - * ReleaseBlobInfoPtr call. - */ -BlobInfo *GetBlobInfoPtr(MetadataManager *mdm, BlobID blob_id) { - Heap *map_heap = GetMapHeap(mdm); - BlobInfoMap *map = GetBlobInfoMap(mdm); - BlobInfoMap *element = hmgetp_null(map, blob_id, map_heap); - - BlobInfo *result = 0; - if (element) { - result = &element->value; - } - - return result; -} - -/** release pointer to BLOB information */ -void ReleaseBlobInfoPtr(MetadataManager *mdm) { - mdm->blob_info_map_mutex.Unlock(); -} - -/** get BLOB stats locally */ -Stats LocalGetBlobStats(SharedMemoryContext *context, BlobID blob_id) { - Stats result = {}; - MetadataManager *mdm = GetMetadataManagerFromContext(context); - Heap *map_heap = GetMapHeap(mdm); - BlobInfoMap *map = GetBlobInfoMap(mdm); - BlobInfoMap *info = hmgetp_null(map, blob_id, map_heap); - if (info) { - result = info->value.stats; - } - ReleaseMap(mdm, kMapType_BlobInfo); - - return result; -} - -/** - * Return a pointer to the internal array of IDs that the `id_list` - * represents. - * - * This call acquires a lock, and must be paired with a corresponding call to - * `ReleaseIdsPtr` to release the lock. - */ -u64 *GetIdsPtr(MetadataManager *mdm, IdList id_list) { - Heap *id_heap = GetIdHeap(mdm); - mdm->id_mutex.Lock(); - u64 *result = (u64 *)HeapOffsetToPtr(id_heap, id_list.head_offset); - - return result; -} - -/** - get pointer to the internal array of IDs that the chucked \a id_list - represents -*/ -u64 *GetIdsPtr(MetadataManager *mdm, ChunkedIdList id_list) { - Heap *id_heap = GetIdHeap(mdm); - mdm->id_mutex.Lock(); - u64 *result = (u64 *)HeapOffsetToPtr(id_heap, id_list.head_offset); - - return result; -} - -/** - * Returns a copy of an embedded `IdList`. - * - * An `IdList` that consists of `BufferID`s contains an embedded `IdList` as the - * first element of the list. This is so the `BlobID` can find information about - * its buffers from a single offset. If you want a pointer to the `BufferID`s in - * an `IdList`, then you have to first retrieve the embedded `IdList` using this - * function, and then use the resulting `IdList` in `GetIdsPtr`. - */ -IdList GetEmbeddedIdList(MetadataManager *mdm, u32 offset) { - Heap *id_heap = GetIdHeap(mdm); - &mdm->id_mutex.Lock(); - IdList *embedded_id_list = (IdList *)HeapOffsetToPtr(id_heap, offset); - IdList result = *embedded_id_list; - mdm->id_mutex.Unlock(); - return result; -} - -/** - * Return a pointer to the internal array of `BufferID`s associated with the - * `blob_id`. - * - * Acquires a lock, and must be paired with a call to `ReleaseIdsPtr` to release - * the lock. The length of the array is returned in the `length` parameter. - */ -BufferID *GetBufferIdsPtrFromBlobId(MetadataManager *mdm, BlobID blob_id, - size_t &length) { - IdList id_list = GetEmbeddedIdList(mdm, blob_id.bits.buffer_ids_offset); - length = id_list.length; - BufferID *result = (BufferID *)GetIdsPtr(mdm, id_list); - - return result; -} - -/** release IDs pointer */ -void ReleaseIdsPtr(MetadataManager *mdm) { - mdm->id_mutex.Unlock(); -} - -/** Convert a key offset into the pointer where the string is stored. - * - * Even though our maps are char* -> u64, the keys are not actually pointers to - * strings, but rather offsets into the shared memory Heap where the strings are - * stored. This function converts the key at @p index from an offset to a char*. - * This produces the equivalent of: - * char *result = map[index].key; - */ -static char *GetKey(MetadataManager *mdm, IdMap *map, u32 index) { - u32 key_offset = (u64)map[index].key; - Heap *map_heap = GetMapHeap(mdm); - char *result = (char *)HeapOffsetToPtr(map_heap, key_offset); - - return result; -} - -/** free ID list */ -template -void FreeIdList(MetadataManager *mdm, T id_list) { - Heap *id_heap = GetIdHeap(mdm); - mdm->id_mutex.Lock(); - u8 *ptr = HeapOffsetToPtr(id_heap, id_list.head_offset); - HeapFree(id_heap, ptr); - mdm->id_mutex.Unlock(); -} - -/** free \a id_list ID list */ -void FreeIdList(MetadataManager *mdm, IdList id_list) { - Heap *id_heap = GetIdHeap(mdm); - mdm->id_mutex.Lock(); - u8 *ptr = HeapOffsetToPtr(id_heap, id_list.head_offset); - HeapFree(id_heap, ptr); - mdm->id_mutex.Unlock(); -} - -/** free embedded ID list */ -void FreeEmbeddedIdList(MetadataManager *mdm, u32 offset) { - Heap *id_heap = GetIdHeap(mdm); - mdm->id_mutex.Lock(); - u8 *to_free = HeapOffsetToPtr(id_heap, offset); - HeapFree(id_heap, to_free); - mdm->id_mutex.Unlock(); -} - -/** - * Assumes the caller has protected @p id_list with a lock. - */ -void AllocateOrGrowIdList(MetadataManager *mdm, ChunkedIdList *id_list) { - Heap *id_heap = GetIdHeap(mdm); - // NOTE(chogan): grow capacity by kIdListChunkSize IDs - size_t new_capacity = id_list->capacity + kIdListChunkSize; - u64 *new_ids = HeapPushArray(id_heap, new_capacity); - - if (id_list->capacity != 0) { - // NOTE(chogan): Copy over old ids and then free them - u64 *ids = GetIdsPtr(mdm, *id_list); - CopyIds(new_ids, ids, id_list->length); - ReleaseIdsPtr(mdm); - FreeIdList(mdm, *id_list); - } else { - // NOTE(chogan): This is the initial allocation so initialize length - id_list->length = 0; - } - - id_list->capacity = new_capacity; - id_list->head_offset = GetHeapOffset(id_heap, (u8 *)new_ids); -} - -/** - * Assumes the caller has protected @p id_list with a lock. - * - * @return The index of the appended @p id. - */ -u32 AppendToChunkedIdList(MetadataManager *mdm, ChunkedIdList *id_list, - u64 id) { - if (id_list->length >= id_list->capacity) { - AllocateOrGrowIdList(mdm, id_list); - } - - u64 *head = GetIdsPtr(mdm, *id_list); - u32 result = id_list->length; - head[id_list->length++] = id; - ReleaseIdsPtr(mdm); - - return result; -} - -/** - * Assumes the caller has protected @p id_list with a lock. - * - * @return A vector of the IDs. - */ -std::vector GetChunkedIdList(MetadataManager *mdm, ChunkedIdList id_list) { - std::vector result(id_list.length); - if (id_list.length > 0) { - u64 *head = GetIdsPtr(mdm, id_list); - for (u32 i = 0; i < id_list.length; ++i) { - result[i] = head[i]; - } - ReleaseIdsPtr(mdm); - } - - return result; -} - -/** get chuncked ID list element */ -u64 GetChunkedIdListElement(MetadataManager *mdm, ChunkedIdList *id_list, - u32 index) { - u64 result = 0; - if (id_list->length && index < id_list->length) { - u64 *head = GetIdsPtr(mdm, *id_list); - result = head[index]; - ReleaseIdsPtr(mdm); - } - - return result; -} - -/** set chuncked ID list element */ -void SetChunkedIdListElement(MetadataManager *mdm, ChunkedIdList *id_list, - u32 index, u64 value) { - if (id_list->length && index >= id_list->length) { - LOG(WARNING) << "Attempting to set index " << index - << " on a ChunkedIdList of length " << id_list->length - << std::endl; - } else { - u64 *head = GetIdsPtr(mdm, *id_list); - head[index] = value; - ReleaseIdsPtr(mdm); - } -} - -void LocalIncrementBlobStats(MetadataManager *mdm, BlobID blob_id) { - BlobInfo *info = GetBlobInfoPtr(mdm, blob_id); - if (info) { - info->stats.frequency++; - info->stats.recency = mdm->clock++; - } - ReleaseBlobInfoPtr(mdm); -} - -void IncrementBlobStats(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id) { - u32 target_node = blob_id.GetNodeId(); - if (target_node == rpc->node_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalIncrementBlobStats(mdm, blob_id); - } else { - RpcCall(rpc, target_node, "RemoteIncrementBlobStats", blob_id); - } -} - -/** get index of ID */ -i64 GetIndexOfId(MetadataManager *mdm, ChunkedIdList *id_list, u64 id) { - i64 result = -1; - - u64 *head = GetIdsPtr(mdm, *id_list); - for (i64 i = 0; i < id_list->length; ++i) { - if (head[i] == id) { - result = i; - break; - } - } - ReleaseIdsPtr(mdm); - - return result; -} - -void LocalReplaceBlobIdInBucket(SharedMemoryContext *context, - BucketID bucket_id, BlobID old_blob_id, - BlobID new_blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - mdm->bucket_mutex.Lock(); - BucketInfo *info = LocalGetBucketInfoById(mdm, bucket_id); - - if (info && info->active) { - ChunkedIdList *blobs = &info->blobs; - - BlobID *blobs_arr = (BlobID *)GetIdsPtr(mdm, *blobs); - for (u32 i = 0; i < blobs->length; ++i) { - if (blobs_arr[i].as_int == old_blob_id.as_int) { - blobs_arr[i] = new_blob_id; - break; - } - } - ReleaseIdsPtr(mdm); - } - - mdm->bucket_mutex.Unlock(); -} - -/** add BLOB ID to bucket locally */ -void LocalAddBlobIdToBucket(MetadataManager *mdm, BucketID bucket_id, - BlobID blob_id, bool track_stats) { - mdm->bucket_mutex.Lock(); - BucketInfo *info = LocalGetBucketInfoById(mdm, bucket_id); - AppendToChunkedIdList(mdm, &info->blobs, blob_id.as_int); - if (track_stats) { - LocalIncrementBlobStats(mdm, blob_id); - } - mdm->bucket_mutex.Unlock(); - - CheckHeapOverlap(mdm); -} - -/** add BLOB ID to virtual bucket locally */ -void LocalAddBlobIdToVBucket(MetadataManager *mdm, VBucketID vbucket_id, - BlobID blob_id) { - mdm->vbucket_mutex.Lock(); - VBucketInfo *info = LocalGetVBucketInfoById(mdm, vbucket_id); - AppendToChunkedIdList(mdm, &info->blobs, blob_id.as_int); - mdm->vbucket_mutex.Unlock(); - - CheckHeapOverlap(mdm); -} - -/** allocate ID list */ -IdList AllocateIdList(MetadataManager *mdm, u32 length) { - static_assert(sizeof(IdList) == sizeof(u64)); - Heap *id_heap = GetIdHeap(mdm); - mdm->id_mutex.Lock(); - u64 *id_list_memory = HeapPushArray(id_heap, length); - IdList result = {}; - result.length = length; - result.head_offset = GetHeapOffset(id_heap, (u8 *)(id_list_memory)); - mdm->id_mutex.Unlock(); - CheckHeapOverlap(mdm); - - return result; -} - -/** allocate embedded ID list */ -u32 AllocateEmbeddedIdList(MetadataManager *mdm, u32 length) { - static_assert(sizeof(IdList) == sizeof(u64)); - Heap *id_heap = GetIdHeap(mdm); - mdm->id_mutex.Lock(); - // NOTE(chogan): Add 1 extra for the embedded IdList - u64 *id_list_memory = HeapPushArray(id_heap, length + 1); - IdList *embedded_id_list = (IdList *)id_list_memory; - embedded_id_list->length = length; - embedded_id_list->head_offset = - GetHeapOffset(id_heap, (u8 *)(embedded_id_list + 1)); - u32 result = GetHeapOffset(id_heap, (u8 *)embedded_id_list); - mdm->id_mutex.Unlock(); - CheckHeapOverlap(mdm); - - return result; -} - -/** get BLOB IDs locally */ -std::vector LocalGetBlobIds(SharedMemoryContext *context, - BucketID bucket_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - mdm->bucket_mutex.Lock(); - BucketInfo *info = LocalGetBucketInfoById(mdm, bucket_id); - u32 num_blobs = info->blobs.length; - std::vector result(num_blobs); - - BlobID *blob_ids = (BlobID *)GetIdsPtr(mdm, info->blobs); - for (u32 i = 0; i < num_blobs; ++i) { - result[i] = blob_ids[i]; - } - ReleaseIdsPtr(mdm); - mdm->bucket_mutex.Unlock(); - - return result; -} - -/** allocate buffer ID list locally */ -u32 LocalAllocateBufferIdList(MetadataManager *mdm, - const std::vector &buffer_ids) { - static_assert(sizeof(IdList) == sizeof(BufferID)); - u32 length = (u32)buffer_ids.size(); - u32 id_list_offset = AllocateEmbeddedIdList(mdm, length); - IdList id_list = GetEmbeddedIdList(mdm, id_list_offset); - u64 *ids = (u64 *)GetIdsPtr(mdm, id_list); - CopyIds(ids, (u64 *)buffer_ids.data(), length); - ReleaseIdsPtr(mdm); - - u32 result = id_list_offset; - - return result; -} - -/** get buffer ID list locally */ -std::vector LocalGetBufferIdList(MetadataManager *mdm, - BlobID blob_id) { - size_t length = 0; - BufferID *ids = GetBufferIdsPtrFromBlobId(mdm, blob_id, length); - std::vector result(length); - CopyIds((u64 *)result.data(), (u64 *)ids, length); - ReleaseIdsPtr(mdm); - - return result; -} - -/** get buffer ID list into \a buffer_ids locally */ -void LocalGetBufferIdList(MetadataManager *mdm, BlobID blob_id, - BufferIdArray *buffer_ids) { - size_t length = 0; - BufferID *ids = GetBufferIdsPtrFromBlobId(mdm, blob_id, length); - buffer_ids->ids = PushArray(arena, length); - buffer_ids->length = length; - CopyIds((u64 *)buffer_ids->ids, (u64 *)ids, length); - ReleaseIdsPtr(mdm); -} - -/** free buffer ID list locally */ -void LocalFreeBufferIdList(SharedMemoryContext *context, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - FreeEmbeddedIdList(mdm, blob_id.bits.buffer_ids_offset); - CheckHeapOverlap(mdm); -} - -/** remove BLOB from bucket locally */ -void LocalRemoveBlobFromBucketInfo(SharedMemoryContext *context, - BucketID bucket_id, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - mdm->bucket_mutex.Lock(); - BucketInfo *info = LocalGetBucketInfoById(mdm, bucket_id); - ChunkedIdList *blobs = &info->blobs; - - BlobID *blobs_arr = (BlobID *)GetIdsPtr(mdm, *blobs); - for (u32 i = 0; i < blobs->length; ++i) { - if (blobs_arr[i].as_int == blob_id.as_int) { - blobs_arr[i] = blobs_arr[--blobs->length]; - break; - } - } - ReleaseIdsPtr(mdm); - - mdm->bucket_mutex.Unlock(); -} - -/** does \a bucket_id contain \a blob_id BLOB locally? */ -bool LocalContainsBlob(SharedMemoryContext *context, BucketID bucket_id, - BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - mdm->bucket_mutex.Lock(); - BucketInfo *info = LocalGetBucketInfoById(mdm, bucket_id); - ChunkedIdList *blobs = &info->blobs; - BlobID *blob_id_arr = (BlobID *)GetIdsPtr(mdm, *blobs); - - bool result = false; - for (u32 i = 0; i < blobs->length; ++i) { - if (blob_id_arr[i].as_int == blob_id.as_int) { - result = true; - break; - } - } - ReleaseIdsPtr(mdm); - mdm->bucket_mutex.Unlock(); - - return result; -} - -/** is \a list's capacity greater than 0? */ -static inline bool HasAllocated(ChunkedIdList *list) { - bool result = list->capacity > 0; - - return result; -} - -/** Has virtual bucket \a info allocated BLOBS? */ -static inline bool HasAllocatedBlobs(VBucketInfo *info) { - bool result = HasAllocated(&info->blobs); - - return result; -} - -/** Has bucket \a info allocated BLOBS? */ -static inline bool HasAllocatedBlobs(BucketInfo *info) { - bool result = HasAllocated(&info->blobs); - - return result; -} - -/** destroy bucket locally */ -bool LocalDestroyBucket(SharedMemoryContext *context, RpcContext *rpc, - const char *bucket_name, BucketID bucket_id) { - bool destroyed = false; - MetadataManager *mdm = GetMetadataManagerFromContext(context); - BeginWriterLock(&mdm->bucket_delete_lock); - mdm->bucket_mutex.Lock(); - BucketInfo *info = LocalGetBucketInfoById(mdm, bucket_id); - - int ref_count = info->ref_count.load(); - if (ref_count == 1) { - if (HasAllocatedBlobs(info)) { - // NOTE(chogan): Collecting the blobs to destroy first and destroying them - // later avoids locking complications - std::vector blobs_to_destroy; - blobs_to_destroy.reserve(info->blobs.length); - BlobID *blobs = (BlobID *)GetIdsPtr(mdm, info->blobs); - for (u32 i = 0; i < info->blobs.length; ++i) { - BlobID blob_id = *(blobs + i); - blobs_to_destroy.push_back(blob_id); - } - ReleaseIdsPtr(mdm); - - for (auto blob_id : blobs_to_destroy) { - DestroyBlobById(context, rpc, blob_id, bucket_id); - } - - // Delete BlobId list - FreeIdList(mdm, info->blobs); - } - - info->blobs.length = 0; - info->blobs.capacity = 0; - info->blobs.head_offset = 0; - - // Reset BucketInfo to initial values - info->ref_count.store(0); - info->active = false; - - mdm->num_buckets--; - info->next_free = mdm->first_free_bucket; - mdm->first_free_bucket = bucket_id; - - // Remove (name -> bucket_id) map entry - LocalDelete(mdm, bucket_name, kMapType_Bucket); - destroyed = true; - } else { - LOG(INFO) << "Cannot destroy bucket " << bucket_name - << ". It's refcount is " << ref_count << std::endl; - } - mdm->bucket_mutex.Unlock(); - EndWriterLock(&mdm->bucket_delete_lock); - - return destroyed; -} - -/** destroy virtual bucket locally */ -bool LocalDestroyVBucket(SharedMemoryContext *context, const char *vbucket_name, - VBucketID vbucket_id) { - bool destroyed = false; - MetadataManager *mdm = GetMetadataManagerFromContext(context); - mdm->vbucket_mutex.Lock(); - VBucketInfo *info = LocalGetVBucketInfoById(mdm, vbucket_id); - - // TODO(chogan): @optimization Lock granularity can probably be relaxed if - // this is slow - int ref_count = info->ref_count.load(); - if (ref_count == 1) { - if (HasAllocatedBlobs(info)) { - FreeIdList(mdm, info->blobs); - } - - info->blobs.length = 0; - info->blobs.capacity = 0; - info->blobs.head_offset = 0; - - // Reset VBucketInfo to initial values - info->ref_count.store(0); - info->async_flush_count.store(0); - info->active = false; - - mdm->num_vbuckets--; - info->next_free = mdm->first_free_vbucket; - mdm->first_free_vbucket = vbucket_id; - - // Remove (name -> vbucket_id) map entry - LocalDelete(mdm, vbucket_name, kMapType_VBucket); - destroyed = true; - } else { - LOG(INFO) << "Cannot destroy vbucket " << vbucket_name - << ". It's refcount is " << ref_count << std::endl; - } - mdm->vbucket_mutex.Unlock(); - return destroyed; -} - -/** get targets locally */ -std::vector LocalGetTargets(SharedMemoryContext *context, - IdList target_list) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - u32 length = target_list.length; - std::vector result; - result.reserve(length); - - u64 *target_ids = GetIdsPtr(mdm, target_list); - for (u32 i = 0; i < length; ++i) { - TargetID id = {}; - id.as_int = target_ids[i]; - u64 remaining_capacity = LocalGetRemainingTargetCapacity(context, id); - if (remaining_capacity) { - result.push_back(id); - } - } - ReleaseIdsPtr(mdm); - - return result; -} - -/** get node targets locally */ -std::vector LocalGetNodeTargets(SharedMemoryContext *context) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - std::vector result = LocalGetTargets(context, mdm->node_targets); - - return result; -} - -/** get neighborhood targets locally */ -std::vector -LocalGetNeighborhoodTargets(SharedMemoryContext *context) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - std::vector result = LocalGetTargets(context, - mdm->neighborhood_targets); - - return result; -} - -/** put to storage */ -void PutToStorage(MetadataManager *mdm, BlobID key, const BlobInfo &val) { - Heap *heap = GetMapHeap(mdm); - BlobInfoMap *map = GetBlobInfoMap(mdm); - hmput(map, key, val, heap); - ReleaseMap(mdm, kMapType_BlobInfo); - - CheckHeapOverlap(mdm); -} - -/** put \a map_type to storage */ -void PutToStorage(MetadataManager *mdm, const char *key, u64 val, - MapType map_type) { - Heap *heap = GetMapHeap(mdm); - IdMap *map = GetMap(mdm, map_type); - shput(map, key, val, heap); - ReleaseMap(mdm, map_type); - - // TODO(chogan): Maybe wrap this in a DEBUG only macro? - CheckHeapOverlap(mdm); -} - -/** get from storage */ -u64 GetFromStorage(MetadataManager *mdm, const char *key, MapType map_type) { - Heap *heap = GetMapHeap(mdm); - IdMap *map = GetMap(mdm, map_type); - u64 result = shget(map, key, heap); - ReleaseMap(mdm, map_type); - - return result; -} - -/** reverse the get from storage operation */ -std::string ReverseGetFromStorage(MetadataManager *mdm, u64 id, - MapType map_type) { - std::string result; - IdMap *map = GetMap(mdm, map_type); - size_t map_size = shlen(map); - - // TODO(chogan): @optimization This could be more efficient if necessary - for (size_t i = 0; i < map_size; ++i) { - if (map[i].value == id) { - char *key = GetKey(mdm, map, i); - if (key) { - result = key; - } - break; - } - } - ReleaseMap(mdm, map_type); - - return result; -} - -/** delete from storage */ -void DeleteFromStorage(MetadataManager *mdm, BlobID key, bool lock) { - Heap *heap = GetMapHeap(mdm); - BlobInfoMap *map = 0; - - if (lock) { - map = GetBlobInfoMap(mdm); - } else { - map = GetBlobInfoMapNoLock(mdm); - } - - hmdel(map, key, heap); - - if (lock) { - ReleaseMap(mdm, kMapType_BlobInfo); - } -} - -/** delete \a map_type from storage */ -void DeleteFromStorage(MetadataManager *mdm, const char *key, - MapType map_type) { - Heap *heap = GetMapHeap(mdm); - IdMap *map = GetMap(mdm, map_type); - shdel(map, key, heap); - ReleaseMap(mdm, map_type); - - // TODO(chogan): Maybe wrap this in a DEBUG only macro? - CheckHeapOverlap(mdm); -} - -/** get the size of stored map */ -size_t GetStoredMapSize(MetadataManager *mdm, MapType map_type) { - IdMap *map = GetMap(mdm, map_type); - size_t result = shlen(map); - ReleaseMap(mdm, map_type); - - return result; -} - -/** generate hash string for storage */ -u32 HashStringForStorage(MetadataManager *mdm, RpcContext *rpc, - const char *str) { - int result = - (stbds_hash_string((char *)str, mdm->map_seed) % rpc->num_nodes) + 1; - - return result; -} - -/** seed hash for storage */ -void SeedHashForStorage(size_t seed) { - stbds_rand_seed(seed); -} - -/** initialize swap space file name */ -void InitSwapSpaceFilename(MetadataManager *mdm, Config *config) { - std::string swap_filename_prefix("swap"); - size_t swap_mount_length = config->swap_mount.size(); - bool ends_in_slash = config->swap_mount[swap_mount_length - 1] == '/'; - std::string full_swap_path = (config->swap_mount + (ends_in_slash ? "" : "/") - + swap_filename_prefix); - size_t full_swap_path_size = full_swap_path.size() + 1; - - char *swap_filename_memory = PushArray(arena, full_swap_path_size); - memcpy(swap_filename_memory, full_swap_path.c_str(), full_swap_path.size()); - swap_filename_memory[full_swap_path.size()] = '\0'; - mdm->swap_filename_prefix_offset = - GetOffsetFromMdm(mdm, swap_filename_memory); - - const char swap_file_suffix[] = ".hermes"; - char *swap_file_suffix_memory = PushArray(arena, - sizeof(swap_file_suffix)); - memcpy(swap_file_suffix_memory, swap_file_suffix, - sizeof(swap_file_suffix)); - mdm->swap_filename_suffix_offset = - GetOffsetFromMdm(mdm, swap_file_suffix_memory); -} - -/** initialize neighborhood targets */ -void InitNeighborhoodTargets(SharedMemoryContext *context, RpcContext *rpc) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - std::vector neighborhood_targets = - GetNeighborhoodTargets(context, rpc); - size_t num_targets = neighborhood_targets.size(); - IdList targets = AllocateIdList(mdm, num_targets); - TargetID *ids = (TargetID *)GetIdsPtr(mdm, targets); - for (size_t i = 0; i < num_targets; ++i) { - ids[i] = neighborhood_targets[i]; - } - ReleaseIdsPtr(mdm); - - mdm->neighborhood_targets = targets; -} - -/** initialize metadata storage */ -void InitMetadataStorage(SharedMemoryContext *context, MetadataManager *mdm, - Config *config) { - InitSwapSpaceFilename(mdm, arena, config); - - // Heaps - - u32 heap_alignment = 8; - Heap *map_heap = InitHeapInArena(arena, true, heap_alignment); - mdm->map_heap_offset = GetOffsetFromMdm(mdm, map_heap); - - // NOTE(chogan): This Heap is constructed at the end of the Metadata Arena and - // will grow towards smaller addresses. - Heap *id_heap = InitHeapInArena(arena, false, heap_alignment); - mdm->id_heap_offset = GetOffsetFromMdm(mdm, id_heap); - - // NOTE(chogan): Local Targets default to one Target per Device - IdList node_targets = AllocateIdList(mdm, config->num_devices); - TargetID *target_ids = (TargetID *)GetIdsPtr(mdm, node_targets); - for (u32 i = 0; i < node_targets.length; ++i) { - Target *target = GetTarget(context, i); - target_ids[i] = target->id; - } - ReleaseIdsPtr(mdm); - mdm->node_targets = node_targets; - - // Maps - - i64 remaining_map_capacity = GetHeapFreeList(map_heap)->size / 3; - - IdMap *bucket_map = 0; - // TODO(chogan): We can either calculate an average expected size here, or - // make HeapRealloc actually use realloc semantics so it can grow as big as - // needed. But that requires updating offsets for the map and the heap's free - // list - - // NOTE(chogan): Make the capacity one larger than necessary because the - // stb_ds map tries to grow when it reaches capacity. - u32 max_buckets = config->max_buckets_per_node + 1; - u32 max_vbuckets = config->max_vbuckets_per_node + 1; - - // Create Bucket name -> BucketID map - sh_new_strdup(bucket_map, max_buckets, map_heap); - shdefault(bucket_map, 0, map_heap); - mdm->bucket_map_offset = GetOffsetFromMdm(mdm, bucket_map); - u32 bucket_map_num_bytes = map_heap->extent; - remaining_map_capacity -= bucket_map_num_bytes; - assert(remaining_map_capacity > 0); - - // Create VBucket name -> VBucketID map - IdMap *vbucket_map = 0; - sh_new_strdup(vbucket_map, max_vbuckets, map_heap); - shdefault(vbucket_map, 0, map_heap); - mdm->vbucket_map_offset = GetOffsetFromMdm(mdm, vbucket_map); - u32 vbucket_map_num_bytes = map_heap->extent - bucket_map_num_bytes; - remaining_map_capacity -= vbucket_map_num_bytes; - assert(remaining_map_capacity > 0); - - // NOTE(chogan): Each map element requires twice its size for storage. - size_t id_map_element_size = 2 * sizeof(IdMap); - size_t blob_info_map_element_size = 2 * sizeof(BlobInfoMap); - size_t bytes_per_blob = id_map_element_size + blob_info_map_element_size; - size_t num_blobs_supported = remaining_map_capacity / bytes_per_blob; - LOG(INFO) << "Metadata can support " << num_blobs_supported - << " Blobs per node\n"; - - // Create Blob name -> BlobID map - IdMap *blob_map = 0; - sh_new_strdup(blob_map, num_blobs_supported, map_heap); - shdefault(blob_map, 0, map_heap); - mdm->blob_id_map_offset = GetOffsetFromMdm(mdm, blob_map); - - // Create BlobID -> BlobInfo map - BlobInfoMap *blob_info_map = 0; - blob_info_map = - (BlobInfoMap *)stbds_arrgrowf(blob_info_map, sizeof(*blob_info_map), 0, - num_blobs_supported, map_heap); - blob_info_map = - (BlobInfoMap *)STBDS_ARR_TO_HASH(blob_info_map, sizeof(*blob_info_map)); - BlobInfo default_blob_info = {}; - hmdefault(blob_info_map, default_blob_info, map_heap); - mdm->blob_info_map_offset = GetOffsetFromMdm(mdm, blob_info_map); -} - -/** get BLOBs from virtual bucket information locally */ -std::vector LocalGetBlobsFromVBucketInfo(SharedMemoryContext *context, - VBucketID vbucket_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - mdm->vbucket_mutex.Lock(); - VBucketInfo *info = LocalGetVBucketInfoById(mdm, vbucket_id); - ChunkedIdList *blobs = &info->blobs; - BlobID *blobs_arr = (BlobID *)GetIdsPtr(mdm, *blobs); - std::vector blobids(blobs_arr, blobs_arr + blobs->length); - ReleaseIdsPtr(mdm); - mdm->vbucket_mutex.Unlock(); - return blobids; -} - -/** remove BLOB from virtual bucket locally */ -void LocalRemoveBlobFromVBucketInfo(SharedMemoryContext *context, - VBucketID vbucket_id, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - mdm->vbucket_mutex.Lock(); - VBucketInfo *info = LocalGetVBucketInfoById(mdm, vbucket_id); - ChunkedIdList *blobs = &info->blobs; - BlobID *blobs_arr = (BlobID *)GetIdsPtr(mdm, *blobs); - for (u32 i = 0; i < blobs->length; ++i) { - if (blobs_arr[i].as_int == blob_id.as_int) { - blobs_arr[i] = blobs_arr[--blobs->length]; - break; - } - } - ReleaseIdsPtr(mdm); - mdm->vbucket_mutex.Unlock(); -} - -/** get BLOB's importance score locally */ -f32 LocalGetBlobImportanceScore(SharedMemoryContext *context, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - Stats stats = LocalGetBlobStats(context, blob_id); - - f32 result = ScoringFunction(mdm, &stats); - - return result; -} - -/** - Get the importance score of \a blob_id BLOB. - */ -f32 GetBlobImportanceScore(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id) { - f32 result = 0; - u32 target_node = blob_id.GetNodeId(); - if (target_node == rpc->node_id) { - result = LocalGetBlobImportanceScore(context, blob_id); - } else { - result = RpcCall(rpc, target_node, "RemoteGetBlobImportanceScore", - blob_id); - } - - return result; -} - -} // namespace hermes diff --git a/src/rpc_generator/metadata_management.py b/src/rpc_generator/metadata_management.py new file mode 100644 index 000000000..c966b1c9c --- /dev/null +++ b/src/rpc_generator/metadata_management.py @@ -0,0 +1,6 @@ + +from rpc_generator.rpc_generator import RpcGenerator + +gen = RpcGenerator() +gen.SetFile("metadata_management.h") +gen.Add("BucketID LocalGetOrCreateBucketId(const std::string &name);") \ No newline at end of file diff --git a/src/rpc_generator/rpc_generator/rpc_generator.py b/src/rpc_generator/rpc_generator/rpc_generator.py new file mode 100644 index 000000000..989eadcd7 --- /dev/null +++ b/src/rpc_generator/rpc_generator/rpc_generator.py @@ -0,0 +1,114 @@ +import sys, os, re + +rpc_func_text = """ +u32 target_node = vbucket_id.bits.node_id; +if (target_node == rpc_->node_id_) { + LocalAddBlobIdToVBucket(vbucket_id, blob_id); +} else { + RpcCall(rpc, target_node, "RemoteAddBlobIdToVBucket", vbucket_id, + blob_id); +} +""" + +rpc_lambda_text = """ +auto rpc_unlock_blob = [context](const request &req, BlobID id) { + bool result = LocalUnlockBlob(context, id); + req.respond(result); +}; +rpc_server->define("GetBuffers", rpc_get_buffers); +""" + +class Api: + def __init__(self, api_str, target_node, macro): + self.api_str = api_str + self.macro = macro + self.target_node = target_node + self.name = None # The name of the API + self.global_name = None # Name of API without "Local" + self.ret = None # Return value of the API + self.var_defs = None # The variables in the API + self.decompose_prototype(api_str) + + def _is_text(self, tok): + first_is_text = re.match("[_a-zA-Z]", tok[0]) is not None + if not first_is_text: + return False + return re.match("[_a-zA-Z0-9]+", tok) is not None + + def _clean(self, toks): + return [tok for tok in toks if tok is not None and len(tok) > 0] + + def get_arg_tuple(self, arg): + arg_toks = self._clean(re.split("[ ]|(\*+)", arg)) + if len(arg_toks) == 1: + if arg_toks[0] == '...': + type = "" + name = "..." + return (type, name) + type = " ".join(arg_toks[:-1]) + name = arg_toks[-1] + return (type, name) + + def decompose_prototype(self, api_str): + toks = self._clean(re.split("[()]", api_str)) + proto, args = toks[0], toks[1] + + try: + proto = self._clean(re.split("[ ]|(\*+)", proto)) + self.name = proto[-1] + self.global_name = self.name.replace("Local") + self.ret = " ".join(proto[:-1]) + except: + print(f"Failed to decompose proto name: {proto}") + exit() + + try: + self.var_defs = [] + args = args.split(',') + for arg in args: + self.var_defs.append(self.get_arg_tuple(arg)) + except: + print(f"Failed to decompose proto args: {args}") + exit(1) + + def get_args(self): + if len(self.var_defs) == 0: + return "" + try: + args = [" ".join(arg_tuple) for arg_tuple in self.var_defs] + except: + print(f"Failed to get arg list: {self.var_defs}") + exit(1) + return ", ".join(args) + + def pass_args(self): + if self.var_defs is None: + return "" + args = [arg[-1] for arg in self.var_defs if arg[0] != ''] + return ", ".join(args) + +class RpcGenerator: + def __init__(self): + self.path = None + self.rpcs = {} + + def set_file(self, path, macro): + self.path = path + self.macro = macro + + def add(self, prototype, target_node): + if self.path not in self.rpcs: + self.rpcs[self.path] = [] + self.rpcs[self.path].append(Api(prototype, target_node, self.macro)) + + def generate(self): + for path, rpc in self.rpcs.items(): + + + def create_rpc_func(self, name): + pass + + def create_rpc_lambda(self, lines): + self.lines.append("[]() {") + pass + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cafe28135..61654d4b4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -96,14 +96,6 @@ add_test(NAME TestMemoryManagement COMMAND mem) target_compile_definitions(mem PRIVATE $<$:HERMES_RPC_THALLIUM>) -add_executable(stb_map stb_map_test.cc) -target_link_libraries(stb_map hermes ${LIBRT} - $<$:thallium> glog::glog MPI::MPI_CXX) -target_compile_definitions(stb_map - PRIVATE $<$:HERMES_DEBUG_HEAP> - PRIVATE $<$:HERMES_RPC_THALLIUM>) -add_test(NAME TestSTBMapWithHeap COMMAND stb_map) - #------------------------------------------------------------------------------ # Metadata Manager tests #------------------------------------------------------------------------------ From 97bf80c9085f0ac035a1e822253992e235b80629 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 1 Dec 2022 09:16:08 -0600 Subject: [PATCH 036/511] RPC generator --- .../rpc_generator/rpc_generator.py | 102 +++++++++++++----- 1 file changed, 77 insertions(+), 25 deletions(-) diff --git a/src/rpc_generator/rpc_generator/rpc_generator.py b/src/rpc_generator/rpc_generator/rpc_generator.py index 989eadcd7..0d213dc40 100644 --- a/src/rpc_generator/rpc_generator/rpc_generator.py +++ b/src/rpc_generator/rpc_generator/rpc_generator.py @@ -1,30 +1,34 @@ import sys, os, re rpc_func_text = """ -u32 target_node = vbucket_id.bits.node_id; -if (target_node == rpc_->node_id_) { - LocalAddBlobIdToVBucket(vbucket_id, blob_id); -} else { - RpcCall(rpc, target_node, "RemoteAddBlobIdToVBucket", vbucket_id, - blob_id); -} +{RET} {GLOBAL_NAME}({PARAMS}) {{ + u32 target_node = {TARGET_NODE}; + if (target_node == rpc_->node_id_) {{ + LocalAddBlobIdToVBucket( + {PASS_PARAMS}); + }} else {{ + RpcCall(rpc, target_node, "{GLOBAL_NAME}", + {PASS_PARAMS}); + }} +}} """ rpc_lambda_text = """ -auto rpc_unlock_blob = [context](const request &req, BlobID id) { - bool result = LocalUnlockBlob(context, id); +auto {LAMBDA_NAME} = [{CONTEXT}](const request &req, {PARAMS}) {{ + auto result = {CONTEXT}->{LOCAL_NAME}({PASS_PARAMS}); req.respond(result); -}; -rpc_server->define("GetBuffers", rpc_get_buffers); +}}; +rpc_server->define("{GLOBAL_NAME}", rpc_get_buffers); """ class Api: - def __init__(self, api_str, target_node, macro): + def __init__(self, api_str, target_node, context): self.api_str = api_str - self.macro = macro self.target_node = target_node + self.context = context self.name = None # The name of the API self.global_name = None # Name of API without "Local" + self.lambda_name = None # Name of lambda caller of API (rpc_{name}) self.ret = None # Return value of the API self.var_defs = None # The variables in the API self.decompose_prototype(api_str) @@ -57,6 +61,7 @@ def decompose_prototype(self, api_str): proto = self._clean(re.split("[ ]|(\*+)", proto)) self.name = proto[-1] self.global_name = self.name.replace("Local") + self.lambda_name = f"Rpc{self.global_name}" self.ret = " ".join(proto[:-1]) except: print(f"Failed to decompose proto name: {proto}") @@ -96,19 +101,66 @@ def set_file(self, path, macro): self.path = path self.macro = macro - def add(self, prototype, target_node): + def add(self, prototype, target_node, context): if self.path not in self.rpcs: - self.rpcs[self.path] = [] - self.rpcs[self.path].append(Api(prototype, target_node, self.macro)) + self.rpcs[self.path] = {} + if self.macro not in self.rpcs[self.path]: + self.rpcs[self.path][self.macro] = [] + self.rpcs[self.path][self.macro].append( + Api(prototype, target_node, context)) def generate(self): - for path, rpc in self.rpcs.items(): - - - def create_rpc_func(self, name): - pass - - def create_rpc_lambda(self, lines): - self.lines.append("[]() {") - pass + for path, macro_rpcs in self.rpcs.items(): + class_lines = [] + with open(path) as fp: + class_lines = fp.read().splitlines() + + rpc_lambdas = [] + for macro, rpcs in macro_rpcs.items(): + global_rpc_funcs = [] + i = self.find_macro(macro, class_lines) + space = self.get_macro_space(i, class_lines) + + for rpc in rpcs: + self.create_global_rpc_func(rpc, space, global_rpc_funcs) + self.create_rpc_lambda(rpc, space, rpc_lambdas) + + class_lines = class_lines[:i+1] + \ + global_rpc_funcs + \ + class_lines[i:] + class_text = "\n".join(class_lines) + + def find_macro(self, macro, lines): + for i, line in enumerate(lines): + if macro in line: + return i + + def get_macro_space(self, i, lines): + return len(lines[i]) - len(lines[i].lstrip()) + + def add_space(self, space, text): + lines = text.splitlines() + for j, line in enumerate(lines): + lines[j] = f"{space}{line}" + return "\n".join(lines) + + def create_global_rpc_func(self, rpc, space, lines): + lines.append(rpc_func_text.format( + RET=rpc.ret, + GLOBAL_NAME=rpc.global_name, + PARAMS=rpc.get_args(), + PASS_PARAMS=rpc.pass_params(), + TARGET_NODE=rpc.target_node + )) + self.add_space(space, lines[-1]) + + def create_rpc_lambda(self, rpc, space, lines): + lines.append(rpc_lambda_text.format( + LAMBDA_NAME=rpc.lambda_name, + CONTEXT=rpc.context, + PARAMS=rpc.get_params(), + PASS_PARAMS=rpc.pass_params(), + LOCAL_NAME=rpc.name + )) + self.add_space(space, lines[-1]) From a3a278b379cffc5cc35a8ebce020dc7a025e22eb Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 1 Dec 2022 20:25:56 -0600 Subject: [PATCH 037/511] RPC generator produces reasonable looking code --- src/buffer_organizer.cc | 4 +- src/buffer_organizer.h | 31 +- src/metadata_storage.h | 102 ----- src/rpc_generator/generate.py | 26 ++ src/rpc_generator/metadata_management.py | 6 - .../rpc_generator/rpc_generator.py | 109 +++-- src/rpc_thallium.cc | 391 +++++++++--------- 7 files changed, 321 insertions(+), 348 deletions(-) delete mode 100644 src/metadata_storage.h create mode 100644 src/rpc_generator/generate.py delete mode 100644 src/rpc_generator/metadata_management.py diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 015864d34..cabfaa2ef 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -435,7 +435,7 @@ void BufferOrganizer::OrganizeBlob(BucketID bucket_id, f32 epsilon, f32 importance_score) { MetadataManager *mdm = GetMetadataManagerFromContext(context); std::string internal_name = MakeInternalBlobName(blob_name, bucket_id); - u32 target_node = HashString(mdm, rpc, internal_name.c_str()); + u32 target_node = HashString(internal_name.c_str()); if (target_node == rpc->node_id) { LocalOrganizeBlob(context, rpc, internal_name, bucket_id, epsilon, @@ -799,7 +799,7 @@ void BufferOrganizer::LocalDecrementFlushCount(const std::string &vbkt_name) { void BufferOrganizer::IncrementFlushCount(const std::string &vbkt_name) { MetadataManager *mdm = GetMetadataManagerFromContext(context); - u32 target_node = HashString(mdm, rpc, vbkt_name.c_str()); + u32 target_node = HashString(vbkt_name.c_str()); if (target_node == rpc->node_id) { LocalIncrementFlushCount(context, vbkt_name); diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index edf033884..d136c1569 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -15,6 +15,7 @@ #include "thread_pool.h" #include "hermes_status.h" +#include "rpc_decorator.h" namespace hermes { @@ -102,7 +103,7 @@ class BufferOrganizer { RpcContext *rpc, int num_threads); /** get buffer information locally */ - BufferInfo LocalGetBufferInfo(BufferID buffer_id); + RPC BufferInfo LocalGetBufferInfo(BufferID buffer_id); /** get buffer information */ BufferInfo GetBufferInfo(BufferID buffer_id); @@ -124,10 +125,10 @@ class BufferOrganizer { void SortTargetInfo(std::vector &target_info, bool increasing); /** Local enqueue of buffer information */ - void LocalEnqueueBoMove(const BoMoveList &moves, BlobID blob_id, - BucketID bucket_id, - const std::string &internal_blob_name, - BoPriority priority); + RPC void LocalEnqueueBoMove(const BoMoveList &moves, BlobID blob_id, + BucketID bucket_id, + const std::string &internal_blob_name, + BoPriority priority); /** enqueue a move operation */ void EnqueueBoMove(const BoMoveList &moves, BlobID blob_id, @@ -143,9 +144,9 @@ class BufferOrganizer { const std::string &internal_blob_name); /** change the composition of a blob based on importance locally */ - void LocalOrganizeBlob(const std::string &internal_blob_name, - BucketID bucket_id, f32 epsilon, - f32 explicit_importance_score); + RPC void LocalOrganizeBlob(const std::string &internal_blob_name, + BucketID bucket_id, f32 epsilon, + f32 explicit_importance_score); /** change the composition of a blob */ void OrganizeBlob(BucketID bucket_id, const std::string &blob_name, @@ -153,22 +154,26 @@ class BufferOrganizer { void EnforceCapacityThresholds(ViolationInfo info); - void LocalEnforceCapacityThresholds(ViolationInfo info); + RPC void LocalEnforceCapacityThresholds(ViolationInfo info); void LocalShutdownBufferOrganizer(); void FlushBlob(BlobID blob_id, const std::string &filename, u64 offset, bool async); bool EnqueueFlushingTask(BlobID blob_id, const std::string &filename, u64 offset); - bool LocalEnqueueFlushingTask(BlobID blob_id, const std::string &filename, - u64 offset); + RPC bool LocalEnqueueFlushingTask(BlobID blob_id, const std::string &filename, + u64 offset); api::Status PlaceInHierarchy(SwapBlob swap_blob, const std::string &name, const api::Context &ctx); void LocalAdjustFlushCount(const std::string &vbkt_name, int adjustment); - void LocalIncrementFlushCount(const std::string &vbkt_name); - void LocalDecrementFlushCount(const std::string &vbkt_name); + RPC void LocalIncrementFlushCount(const std::string &vbkt_name); + RPC void LocalDecrementFlushCount(const std::string &vbkt_name); void IncrementFlushCount(const std::string &vbkt_name); void DecrementFlushCount(const std::string &vbkt_name); void AwaitAsyncFlushingTasks(VBucketID id); + + /** Automatically Generate RPCs */ + RPC_AUTOGEN_START + RPC_AUTOGEN_END }; static inline f32 BytesToMegabytes(size_t bytes) { diff --git a/src/metadata_storage.h b/src/metadata_storage.h deleted file mode 100644 index 1d219a60c..000000000 --- a/src/metadata_storage.h +++ /dev/null @@ -1,102 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_METADATA_STORAGE_H_ -#define HERMES_METADATA_STORAGE_H_ - -namespace hermes { - -/** - * - */ -void PutToStorage(MetadataManager *mdm, const char *key, u64 val, - MapType map_type); - -/** - * - */ -void PutToStorage(MetadataManager *mdm, BlobID key, const BlobInfo &val); - -/** - * - */ -u64 GetFromStorage(MetadataManager *mdm, const char *key, MapType map_type); - -/** - * - */ -std::string ReverseGetFromStorage(MetadataManager *mdm, u64 id, - MapType map_type); - -/** - * - */ -void DeleteFromStorage(MetadataManager *mdm, BlobID key, bool lock); - -/** - * - */ -void DeleteFromStorage(MetadataManager *mdm, const char *key, MapType map_type); - -/** - * - */ -u32 HashStringForStorage(MetadataManager *mdm, RpcContext *rpc, - const char *str); - -/** - * - */ -void SeedHashForStorage(size_t seed); - -/** - * - */ -size_t GetStoredMapSize(MetadataManager *mdm, MapType map_type); - -/** - * - */ -std::vector LocalGetNodeTargets(SharedMemoryContext *context); - -/** - * - */ -std::vector LocalGetNeighborhoodTargets(SharedMemoryContext *context); - -/** - * - */ -std::vector LocalGetBlobIds(SharedMemoryContext *context, - BucketID bucket_id); -/** - * - */ -BlobInfo *GetBlobInfoPtr(MetadataManager *mdm, BlobID blob_id); - -/** - * - */ -void ReleaseBlobInfoPtr(MetadataManager *mdm); - -u64 *GetIdsPtr(MetadataManager *mdm, IdList id_list); -u64 *GetIdsPtr(MetadataManager *mdm, ChunkedIdList id_list); -void ReleaseIdsPtr(MetadataManager *mdm); - -/** - * - */ -std::vector GetChunkedIdList(MetadataManager *mdm, ChunkedIdList id_list); - -} // namespace hermes - -#endif // HERMES_METADATA_STORAGE_H_ diff --git a/src/rpc_generator/generate.py b/src/rpc_generator/generate.py new file mode 100644 index 000000000..921b2b066 --- /dev/null +++ b/src/rpc_generator/generate.py @@ -0,0 +1,26 @@ + +""" +Automatically generate the RPCs for a series of Local functions + +USAGE: + cd /path/to/rpc_generator + python3 generate.py +""" + +from rpc_generator.rpc_generator import RpcGenerator + +gen = RpcGenerator() + +gen.set_file("../buffer_organizer.h", "BufferOrganizer", "borg") +gen.add("LocalGetBufferInfo", "buffer_id.bits.node_id") +gen.add("LocalEnqueueBoMove", "rpc_->node_id_") +gen.add("LocalOrganizeBlob", "HashString(internal_name.c_str())") +gen.add("LocalEnforceCapacityThresholds", "info.target_id.bits.node_id") +gen.add("LocalEnqueueFlushingTask", "rpc->node_id_") +gen.add("LocalIncrementFlushCount", "HashString(vbkt_name.c_str())") +gen.add("LocalDecrementFlushCount", "HashString(vbkt_name.c_str())") + +# gen.set_file("metadata_management.h", "METADTA_MANAGER_RPC", "mdm") +# gen.add("LocalGetVBucketInfoById", "HashString(name)") + +gen.generate() \ No newline at end of file diff --git a/src/rpc_generator/metadata_management.py b/src/rpc_generator/metadata_management.py deleted file mode 100644 index c966b1c9c..000000000 --- a/src/rpc_generator/metadata_management.py +++ /dev/null @@ -1,6 +0,0 @@ - -from rpc_generator.rpc_generator import RpcGenerator - -gen = RpcGenerator() -gen.SetFile("metadata_management.h") -gen.Add("BucketID LocalGetOrCreateBucketId(const std::string &name);") \ No newline at end of file diff --git a/src/rpc_generator/rpc_generator/rpc_generator.py b/src/rpc_generator/rpc_generator/rpc_generator.py index 0d213dc40..a0bae063b 100644 --- a/src/rpc_generator/rpc_generator/rpc_generator.py +++ b/src/rpc_generator/rpc_generator/rpc_generator.py @@ -7,7 +7,7 @@ LocalAddBlobIdToVBucket( {PASS_PARAMS}); }} else {{ - RpcCall(rpc, target_node, "{GLOBAL_NAME}", + rpc_->Call(rpc, target_node, "{GLOBAL_NAME}", {PASS_PARAMS}); }} }} @@ -22,10 +22,8 @@ """ class Api: - def __init__(self, api_str, target_node, context): + def __init__(self, api_str): self.api_str = api_str - self.target_node = target_node - self.context = context self.name = None # The name of the API self.global_name = None # Name of API without "Local" self.lambda_name = None # Name of lambda caller of API (rpc_{name}) @@ -54,13 +52,13 @@ def get_arg_tuple(self, arg): return (type, name) def decompose_prototype(self, api_str): - toks = self._clean(re.split("[()]", api_str)) + toks = self._clean(re.split("[()]|;", api_str)) proto, args = toks[0], toks[1] try: proto = self._clean(re.split("[ ]|(\*+)", proto)) self.name = proto[-1] - self.global_name = self.name.replace("Local") + self.global_name = self.name.replace("Local", "") self.lambda_name = f"Rpc{self.global_name}" self.ret = " ".join(proto[:-1]) except: @@ -95,48 +93,96 @@ def pass_args(self): class RpcGenerator: def __init__(self): self.path = None + self.macro = None + self.context = None self.rpcs = {} - def set_file(self, path, macro): + def set_file(self, path, class_name, context): self.path = path - self.macro = macro + self.class_name = class_name + self.context = context - def add(self, prototype, target_node, context): + def add(self, local_rpc_name, target_node): if self.path not in self.rpcs: self.rpcs[self.path] = {} - if self.macro not in self.rpcs[self.path]: - self.rpcs[self.path][self.macro] = [] - self.rpcs[self.path][self.macro].append( - Api(prototype, target_node, context)) + if self.class_name not in self.rpcs[self.path]: + self.rpcs[self.path][self.class_name] = [] + self.rpcs[self.path][self.class_name].append( + (local_rpc_name, target_node, self.context)) def generate(self): - for path, macro_rpcs in self.rpcs.items(): + for path, class_rpcs in self.rpcs.items(): class_lines = [] with open(path) as fp: class_lines = fp.read().splitlines() + rpc_map = self.get_rpcs_from_class(class_lines) rpc_lambdas = [] - for macro, rpcs in macro_rpcs.items(): + for class_name, rpcs in class_rpcs.items(): + i = rpc_map[class_name]['macro'] + space = self.get_macro_space(class_lines[i]) + print(space) global_rpc_funcs = [] - i = self.find_macro(macro, class_lines) - space = self.get_macro_space(i, class_lines) - for rpc in rpcs: - self.create_global_rpc_func(rpc, space, global_rpc_funcs) - self.create_rpc_lambda(rpc, space, rpc_lambdas) + local_rpc_name = rpc[0] + target_node = rpc[1] + context = rpc[2] + local_rpc_api = rpc_map[class_name]['apis'][local_rpc_name] + self.create_global_rpc_func(local_rpc_api, target_node, + space, global_rpc_funcs) + self.create_rpc_lambda(local_rpc_api, context, + space, rpc_lambdas) class_lines = class_lines[:i+1] + \ global_rpc_funcs + \ - class_lines[i:] - class_text = "\n".join(class_lines) + class_lines[i+1:] + + with open(path, 'w'): + fp.writelines(class_lines) + + + + def get_rpcs_from_class(self, class_lines): + cur_class = None + rpc_map = {} + for i, line in enumerate(class_lines): + if "class" == line.strip()[0:5]: + cur_class = self.get_class_name(line) + rpc_map[cur_class] = {'apis': {}, 'macro': None} + elif "RPC_AUTOGEN_START" in line: + rpc_map[cur_class]['macro'] = i + elif "RPC_AUTOGEN_END" in line: + pass + elif "RPC" == line.strip()[0:3]: + text_proto = self.get_rpc_prototype(class_lines[i:]) + api = Api(text_proto) + local_rpc_name = api.name + rpc_map[cur_class]['apis'][local_rpc_name] = api + return rpc_map + + def get_class_name(self, line): + toks = re.split("[\:\*+ ]", line) + toks = [tok.strip() for tok in toks if tok is not None and len(tok)] + class_name = toks[1] + return class_name + + def get_rpc_prototype(self, lines): + proto_toks = [] + for line in lines: + proto_toks.append(line.strip()) + if ';' in line: + break + proto = " ".join(proto_toks) + return proto def find_macro(self, macro, lines): for i, line in enumerate(lines): if macro in line: return i - def get_macro_space(self, i, lines): - return len(lines[i]) - len(lines[i].lstrip()) + def get_macro_space(self, line): + space_len = len(line) - len(line.lstrip()) + return " " * space_len def add_space(self, space, text): lines = text.splitlines() @@ -144,22 +190,23 @@ def add_space(self, space, text): lines[j] = f"{space}{line}" return "\n".join(lines) - def create_global_rpc_func(self, rpc, space, lines): + def create_global_rpc_func(self, rpc, target_node, space, lines): lines.append(rpc_func_text.format( RET=rpc.ret, GLOBAL_NAME=rpc.global_name, PARAMS=rpc.get_args(), - PASS_PARAMS=rpc.pass_params(), - TARGET_NODE=rpc.target_node + PASS_PARAMS=rpc.pass_args(), + TARGET_NODE=target_node )) self.add_space(space, lines[-1]) - def create_rpc_lambda(self, rpc, space, lines): + def create_rpc_lambda(self, rpc, context, space, lines): lines.append(rpc_lambda_text.format( + GLOBAL_NAME=rpc.global_name, LAMBDA_NAME=rpc.lambda_name, - CONTEXT=rpc.context, - PARAMS=rpc.get_params(), - PASS_PARAMS=rpc.pass_params(), + CONTEXT=context, + PARAMS=rpc.get_args(), + PASS_PARAMS=rpc.pass_args(), LOCAL_NAME=rpc.name )) self.add_space(space, lines[-1]) diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 46a424acd..cd3763aea 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -14,7 +14,6 @@ #include "rpc.h" #include "buffer_organizer.h" -#include "metadata_management_internal.h" #include "prefetcher.h" #include "singleton.h" @@ -190,6 +189,198 @@ size_t ThalliumRpc::BulkRead(u32 node_id, const char *func_name, return result; } +/** start buffer organizer */ +void ThalliumRpc::StartBufferOrganizer(const char *addr, int num_threads, + int port) { + context->bo = PushStruct(arena); + new(context->bo) BufferOrganizer(num_threads); + + ThalliumState *state = GetThalliumState(rpc); + + int num_bo_rpc_threads = 1; + bo_engine = new tl::engine(addr, THALLIUM_SERVER_MODE, true, + num_bo_rpc_threads); + tl::engine *rpc_server = bo_engine; + + std::string rpc_server_name = rpc_server->self(); + LOG(INFO) << "Buffer organizer serving at " << rpc_server_name << " with " + << num_bo_rpc_threads << " RPC threads and " << num_threads + << " BO worker threads" << std::endl; + + std::string server_name_postfix = ":" + std::to_string(port); + CopyStringToCharArray(server_name_postfix, bo_server_name_postfix, + kMaxServerNamePostfix); + + auto rpc_place_in_hierarchy = [context, rpc](const tl::request &req, + SwapBlob swap_blob, + const std::string name, + api::Context ctx) { + (void)req; + for (int i = 0; i < ctx.buffer_organizer_retries; ++i) { + LOG(INFO) << "Buffer Organizer placing blob '" << name + << "' in hierarchy. Attempt " << i + 1 << " of " + << ctx.buffer_organizer_retries << std::endl; + api::Status result = PlaceInHierarchy(context, rpc, swap_blob, name, ctx); + if (result.Succeeded()) { + break; + } else { + ThalliumState *state = GetThalliumState(rpc); + + if (state && bo_engine) { + // TODO(chogan): We probably don't want to sleep here, but for now + // this enables testing. + double sleep_ms = 2000; + tl::thread::self().sleep(*bo_engine, sleep_ms); + } + } + } + }; + + auto rpc_move_to_target = [context, rpc](const tl::request &req, + SwapBlob swap_blob, + TargetID target_id, int retries) { + (void)req; + (void)swap_blob; + (void)target_id; + for (int i = 0; i < retries; ++i) { + // TODO(chogan): MoveToTarget(context, rpc, target_id, swap_blob); + HERMES_NOT_IMPLEMENTED_YET; + } + }; + + auto rpc_enqueue_flushing_task = + [context, rpc](const tl::request &req, BlobID blob_id, + const std::string &filename, u64 offset) { + bool result = LocalEnqueueFlushingTask(context, rpc, blob_id, filename, + offset); + + req.respond(result); + }; + + auto rpc_enqueue_bo_move = [context, rpc](const tl::request &req, + const BoMoveList &moves, + BlobID blob_id, + BucketID bucket_id, + const std::string &internal_name, + BoPriority priority) { + LocalEnqueueBoMove(context, rpc, moves, blob_id, bucket_id, internal_name, + priority); + + req.respond(true); + }; + + auto rpc_organize_blob = [context, rpc](const tl::request &req, + const std::string &internal_blob_name, + BucketID bucket_id, f32 epsilon, + f32 importance_score) { + LocalOrganizeBlob(context, rpc, internal_blob_name, bucket_id, epsilon, + importance_score); + + req.respond(true); + }; + + rpc_server->define("PlaceInHierarchy", + rpc_place_in_hierarchy).disable_response(); + rpc_server->define("MoveToTarget", + rpc_move_to_target).disable_response(); + rpc_server->define("EnqueueFlushingTask", rpc_enqueue_flushing_task); + rpc_server->define("EnqueueBoMove", rpc_enqueue_bo_move); + rpc_server->define("OrganizeBlob", rpc_organize_blob); +} + +/** start prefetcher */ +void ThalliumRpc::StartPrefetcher(double sleep_ms) { + tl::engine *rpc_server = engine; + using tl::request; + + // Create the LogIoStat RPC + auto rpc_log_io_stat = [context](const request &req, IoLogEntry &entry) { + (void) context; + auto prefetcher = Singleton::GetInstance(); + prefetcher->Log(entry); + req.respond(true); + }; + rpc_server->define("LogIoStat", rpc_log_io_stat); + + // Prefetcher thread args + struct PrefetcherThreadArgs { + SharedMemoryContext *context; + RpcContext *rpc; + double sleep_ms; + bool init_; + }; + + // Create the prefetcher thread lambda + auto prefetch = [](void *args) { + PrefetcherThreadArgs targs = *((PrefetcherThreadArgs*)args); + ThalliumState *state = GetThalliumState(targs.rpc); + LOG(INFO) << "Prefetching thread started" << std::endl; + auto prefetcher = Singleton::GetInstance(); + while (!kill_requested.load()) { + prefetcher->Process(); + tl::thread::self().sleep(*engine, targs.sleep_ms); + } + LOG(INFO) << "Finished prefetcher" << std::endl; + }; + + // Create prefetcher thread + PrefetcherThreadArgs *args = PushStruct(arena); + args->context = context; + args->rpc = rpc; + args->sleep_ms = sleep_ms; + args->init_ = false; + + ABT_xstream_create(ABT_SCHED_NULL, &execution_stream); + ABT_thread_create_on_xstream(execution_stream, + prefetch, args, + ABT_THREAD_ATTR_NULL, NULL); +} + +/** stop prefetcher */ +void ThalliumRpc::StopPrefetcher() { + kill_requested.store(true); + ABT_xstream_join(execution_stream); + ABT_xstream_free(&execution_stream); +} + +/** start global system view state update thread */ +void ThalliumRpc::StartGlobalSystemViewStateUpdateThread(double sleep_ms) { + struct ThreadArgs { + SharedMemoryContext *context; + RpcContext *rpc; + double sleep_ms; + }; + + auto update_global_system_view_state = [](void *args) { + ThreadArgs *targs = (ThreadArgs *)args; + ThalliumState *state = GetThalliumState(targs->rpc); + LOG(INFO) << "Update global system view state start" << std::endl; + while (!kill_requested.load()) { + UpdateGlobalSystemViewState(targs->context, targs->rpc); + tl::thread::self().sleep(*engine, targs->sleep_ms); + } + LOG(INFO) << "Finished global system view update thread" << std::endl; + }; + + ThreadArgs *args = PushStruct(arena); + args->context = context; + args->rpc = rpc; + args->sleep_ms = sleep_ms; + + ThalliumState *state = GetThalliumState(rpc); + ABT_thread_create_on_xstream(execution_stream, + update_global_system_view_state, args, + ABT_THREAD_ATTR_NULL, NULL); +} + +/** stop global system view state update thread */ +void ThalliumRpc::StopGlobalSystemViewStateUpdateThread() { + ThalliumState *state = GetThalliumState(rpc); + kill_requested.store(true); + ABT_xstream_join(execution_stream); + ABT_xstream_free(&execution_stream); +} + /** start Thallium RPC server */ void ThalliumRpc::StartServer(const char *addr, i32 num_rpc_threads) { @@ -218,6 +409,10 @@ void ThalliumRpc::StartServer(const char *addr, using std::vector; using tl::request; + RPC_AUTOGEN_START + RPC_AUTOGEN_END + + // BufferPool requests auto rpc_get_buffers = @@ -583,7 +778,7 @@ void ThalliumRpc::StartServer(const char *addr, auto rpc_enforce_capacity_thresholds = [context, rpc](const request &req, ViolationInfo info) { - LocalEnforceCapacityThresholds(context, rpc, info); + LocalEnforceCapacityThresholds(info); // TODO(chogan): Can this be async? req.respond(true); }; @@ -657,196 +852,4 @@ void ThalliumRpc::StartServer(const char *addr, rpc_enforce_capacity_thresholds); } -/** start buffer organizer */ -void ThalliumRpc::StartBufferOrganizer(const char *addr, int num_threads, - int port) { - context->bo = PushStruct(arena); - new(context->bo) BufferOrganizer(num_threads); - - ThalliumState *state = GetThalliumState(rpc); - - int num_bo_rpc_threads = 1; - bo_engine = new tl::engine(addr, THALLIUM_SERVER_MODE, true, - num_bo_rpc_threads); - tl::engine *rpc_server = bo_engine; - - std::string rpc_server_name = rpc_server->self(); - LOG(INFO) << "Buffer organizer serving at " << rpc_server_name << " with " - << num_bo_rpc_threads << " RPC threads and " << num_threads - << " BO worker threads" << std::endl; - - std::string server_name_postfix = ":" + std::to_string(port); - CopyStringToCharArray(server_name_postfix, bo_server_name_postfix, - kMaxServerNamePostfix); - - auto rpc_place_in_hierarchy = [context, rpc](const tl::request &req, - SwapBlob swap_blob, - const std::string name, - api::Context ctx) { - (void)req; - for (int i = 0; i < ctx.buffer_organizer_retries; ++i) { - LOG(INFO) << "Buffer Organizer placing blob '" << name - << "' in hierarchy. Attempt " << i + 1 << " of " - << ctx.buffer_organizer_retries << std::endl; - api::Status result = PlaceInHierarchy(context, rpc, swap_blob, name, ctx); - if (result.Succeeded()) { - break; - } else { - ThalliumState *state = GetThalliumState(rpc); - - if (state && bo_engine) { - // TODO(chogan): We probably don't want to sleep here, but for now - // this enables testing. - double sleep_ms = 2000; - tl::thread::self().sleep(*bo_engine, sleep_ms); - } - } - } - }; - - auto rpc_move_to_target = [context, rpc](const tl::request &req, - SwapBlob swap_blob, - TargetID target_id, int retries) { - (void)req; - (void)swap_blob; - (void)target_id; - for (int i = 0; i < retries; ++i) { - // TODO(chogan): MoveToTarget(context, rpc, target_id, swap_blob); - HERMES_NOT_IMPLEMENTED_YET; - } - }; - - auto rpc_enqueue_flushing_task = - [context, rpc](const tl::request &req, BlobID blob_id, - const std::string &filename, u64 offset) { - bool result = LocalEnqueueFlushingTask(context, rpc, blob_id, filename, - offset); - - req.respond(result); - }; - - auto rpc_enqueue_bo_move = [context, rpc](const tl::request &req, - const BoMoveList &moves, - BlobID blob_id, - BucketID bucket_id, - const std::string &internal_name, - BoPriority priority) { - LocalEnqueueBoMove(context, rpc, moves, blob_id, bucket_id, internal_name, - priority); - - req.respond(true); - }; - - auto rpc_organize_blob = [context, rpc](const tl::request &req, - const std::string &internal_blob_name, - BucketID bucket_id, f32 epsilon, - f32 importance_score) { - LocalOrganizeBlob(context, rpc, internal_blob_name, bucket_id, epsilon, - importance_score); - - req.respond(true); - }; - - rpc_server->define("PlaceInHierarchy", - rpc_place_in_hierarchy).disable_response(); - rpc_server->define("MoveToTarget", - rpc_move_to_target).disable_response(); - rpc_server->define("EnqueueFlushingTask", rpc_enqueue_flushing_task); - rpc_server->define("EnqueueBoMove", rpc_enqueue_bo_move); - rpc_server->define("OrganizeBlob", rpc_organize_blob); -} - -/** start prefetcher */ -void ThalliumRpc::StartPrefetcher(double sleep_ms) { - tl::engine *rpc_server = engine; - using tl::request; - - // Create the LogIoStat RPC - auto rpc_log_io_stat = [context](const request &req, IoLogEntry &entry) { - (void) context; - auto prefetcher = Singleton::GetInstance(); - prefetcher->Log(entry); - req.respond(true); - }; - rpc_server->define("LogIoStat", rpc_log_io_stat); - - // Prefetcher thread args - struct PrefetcherThreadArgs { - SharedMemoryContext *context; - RpcContext *rpc; - double sleep_ms; - bool init_; - }; - - // Create the prefetcher thread lambda - auto prefetch = [](void *args) { - PrefetcherThreadArgs targs = *((PrefetcherThreadArgs*)args); - ThalliumState *state = GetThalliumState(targs.rpc); - LOG(INFO) << "Prefetching thread started" << std::endl; - auto prefetcher = Singleton::GetInstance(); - while (!kill_requested.load()) { - prefetcher->Process(); - tl::thread::self().sleep(*engine, targs.sleep_ms); - } - LOG(INFO) << "Finished prefetcher" << std::endl; - }; - - // Create prefetcher thread - PrefetcherThreadArgs *args = PushStruct(arena); - args->context = context; - args->rpc = rpc; - args->sleep_ms = sleep_ms; - args->init_ = false; - - ABT_xstream_create(ABT_SCHED_NULL, &execution_stream); - ABT_thread_create_on_xstream(execution_stream, - prefetch, args, - ABT_THREAD_ATTR_NULL, NULL); -} - -/** stop prefetcher */ -void ThalliumRpc::StopPrefetcher() { - kill_requested.store(true); - ABT_xstream_join(execution_stream); - ABT_xstream_free(&execution_stream); -} - -/** start global system view state update thread */ -void ThalliumRpc::StartGlobalSystemViewStateUpdateThread(double sleep_ms) { - struct ThreadArgs { - SharedMemoryContext *context; - RpcContext *rpc; - double sleep_ms; - }; - - auto update_global_system_view_state = [](void *args) { - ThreadArgs *targs = (ThreadArgs *)args; - ThalliumState *state = GetThalliumState(targs->rpc); - LOG(INFO) << "Update global system view state start" << std::endl; - while (!kill_requested.load()) { - UpdateGlobalSystemViewState(targs->context, targs->rpc); - tl::thread::self().sleep(*engine, targs->sleep_ms); - } - LOG(INFO) << "Finished global system view update thread" << std::endl; - }; - - ThreadArgs *args = PushStruct(arena); - args->context = context; - args->rpc = rpc; - args->sleep_ms = sleep_ms; - - ThalliumState *state = GetThalliumState(rpc); - ABT_thread_create_on_xstream(execution_stream, - update_global_system_view_state, args, - ABT_THREAD_ATTR_NULL, NULL); -} - -/** stop global system view state update thread */ -void ThalliumRpc::StopGlobalSystemViewStateUpdateThread() { - ThalliumState *state = GetThalliumState(rpc); - kill_requested.store(true); - ABT_xstream_join(execution_stream); - ABT_xstream_free(&execution_stream); -} - } // namespace hermes From 9707bdc597d7c996ca4516df289c48adc1243fc7 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 1 Dec 2022 20:41:32 -0600 Subject: [PATCH 038/511] RPC generator produces proper output --- .../rpc_generator/rpc_generator.py | 75 +++++++++++-------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/src/rpc_generator/rpc_generator/rpc_generator.py b/src/rpc_generator/rpc_generator/rpc_generator.py index a0bae063b..b5a673da4 100644 --- a/src/rpc_generator/rpc_generator/rpc_generator.py +++ b/src/rpc_generator/rpc_generator/rpc_generator.py @@ -111,36 +111,45 @@ def add(self, local_rpc_name, target_node): (local_rpc_name, target_node, self.context)) def generate(self): + rpc_lambdas = [] for path, class_rpcs in self.rpcs.items(): - class_lines = [] - with open(path) as fp: - class_lines = fp.read().splitlines() - rpc_map = self.get_rpcs_from_class(class_lines) - - rpc_lambdas = [] - for class_name, rpcs in class_rpcs.items(): - i = rpc_map[class_name]['macro'] - space = self.get_macro_space(class_lines[i]) - print(space) - global_rpc_funcs = [] - for rpc in rpcs: - local_rpc_name = rpc[0] - target_node = rpc[1] - context = rpc[2] - local_rpc_api = rpc_map[class_name]['apis'][local_rpc_name] - self.create_global_rpc_func(local_rpc_api, target_node, - space, global_rpc_funcs) - self.create_rpc_lambda(local_rpc_api, context, - space, rpc_lambdas) - - class_lines = class_lines[:i+1] + \ - global_rpc_funcs + \ - class_lines[i+1:] - - with open(path, 'w'): - fp.writelines(class_lines) - - + self.generate_class_file(path, class_rpcs, rpc_lambdas) + self.generate_rpc_file(rpc_lambdas) + + def generate_class_file(self, path, class_rpcs, rpc_lambdas): + with open(path) as fp: + class_lines = fp.read().splitlines() + rpc_map = self.get_rpcs_from_class(class_lines) + for class_name, rpcs in class_rpcs.items(): + i = rpc_map[class_name]['macro'] + space = self.get_macro_space(class_lines[i]) + print(space) + global_rpc_funcs = [] + for rpc in rpcs: + local_rpc_name = rpc[0] + target_node = rpc[1] + context = rpc[2] + local_rpc_api = rpc_map[class_name]['apis'][local_rpc_name] + self.create_global_rpc_func(local_rpc_api, target_node, + space, global_rpc_funcs) + self.create_rpc_lambda(local_rpc_api, context, + space, rpc_lambdas) + + class_lines = class_lines[:i + 1] + \ + global_rpc_funcs + \ + class_lines[i + 1:] + + with open("tmp", 'w') as fp: + fp.write("\n".join(class_lines)) + + def generate_rpc_file(self, rpc_lambdas): + path = "../rpc_thallium.cc" + with open(path) as fp: + rpc_lines = fp.read().splitlines() + i = self.find_macro("RPC_AUTOGEN_START", rpc_lines) + rpc_lines = rpc_lines[:i+1] + rpc_lambdas + rpc_lines[i+1:] + with open("tmp2", 'w') as fp: + fp.write("\n".join(rpc_lines)) def get_rpcs_from_class(self, class_lines): cur_class = None @@ -197,8 +206,8 @@ def create_global_rpc_func(self, rpc, target_node, space, lines): PARAMS=rpc.get_args(), PASS_PARAMS=rpc.pass_args(), TARGET_NODE=target_node - )) - self.add_space(space, lines[-1]) + ).strip()) + lines[-1] = self.add_space(space, lines[-1]) def create_rpc_lambda(self, rpc, context, space, lines): lines.append(rpc_lambda_text.format( @@ -208,6 +217,6 @@ def create_rpc_lambda(self, rpc, context, space, lines): PARAMS=rpc.get_args(), PASS_PARAMS=rpc.pass_args(), LOCAL_NAME=rpc.name - )) - self.add_space(space, lines[-1]) + ).strip()) + lines[-1] = self.add_space(space, lines[-1]) From 9f25c52d2b149e4abba23298ff1697a077829711 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 1 Dec 2022 20:47:40 -0600 Subject: [PATCH 039/511] Ensure RPC generator removes everything between START and END --- src/buffer_organizer.h | 2 ++ src/rpc_decorator.h | 12 +++++++++ .../rpc_generator/rpc_generator.py | 27 ++++++++++++------- 3 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 src/rpc_decorator.h diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index d136c1569..332cf743e 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -173,6 +173,8 @@ class BufferOrganizer { /** Automatically Generate RPCs */ RPC_AUTOGEN_START + //hello + //hello RPC_AUTOGEN_END }; diff --git a/src/rpc_decorator.h b/src/rpc_decorator.h new file mode 100644 index 000000000..9916e3ddf --- /dev/null +++ b/src/rpc_decorator.h @@ -0,0 +1,12 @@ +// +// Created by lukemartinlogan on 12/1/22. +// + +#ifndef HERMES_SRC_RPC_GENERATOR_DECORATOR_H_ +#define HERMES_SRC_RPC_GENERATOR_DECORATOR_H_ + +#define RPC +#define RPC_AUTOGEN_START +#define RPC_AUTOGEN_END + +#endif // HERMES_SRC_RPC_GENERATOR_DECORATOR_H_ diff --git a/src/rpc_generator/rpc_generator/rpc_generator.py b/src/rpc_generator/rpc_generator/rpc_generator.py index b5a673da4..ad94c26ad 100644 --- a/src/rpc_generator/rpc_generator/rpc_generator.py +++ b/src/rpc_generator/rpc_generator/rpc_generator.py @@ -121,9 +121,9 @@ def generate_class_file(self, path, class_rpcs, rpc_lambdas): class_lines = fp.read().splitlines() rpc_map = self.get_rpcs_from_class(class_lines) for class_name, rpcs in class_rpcs.items(): - i = rpc_map[class_name]['macro'] - space = self.get_macro_space(class_lines[i]) - print(space) + gen_start = rpc_map[class_name]['gen_start'] + gen_end = rpc_map[class_name]['gen_end'] + space = self.get_macro_space(class_lines[gen_start]) global_rpc_funcs = [] for rpc in rpcs: local_rpc_name = rpc[0] @@ -135,9 +135,10 @@ def generate_class_file(self, path, class_rpcs, rpc_lambdas): self.create_rpc_lambda(local_rpc_api, context, space, rpc_lambdas) - class_lines = class_lines[:i + 1] + \ + class_lines = class_lines[:gen_start+1] + class_lines[gen_end:] + class_lines = class_lines[:gen_start + 1] + \ global_rpc_funcs + \ - class_lines[i + 1:] + class_lines[gen_start + 1:] with open("tmp", 'w') as fp: fp.write("\n".join(class_lines)) @@ -146,8 +147,12 @@ def generate_rpc_file(self, rpc_lambdas): path = "../rpc_thallium.cc" with open(path) as fp: rpc_lines = fp.read().splitlines() - i = self.find_macro("RPC_AUTOGEN_START", rpc_lines) - rpc_lines = rpc_lines[:i+1] + rpc_lambdas + rpc_lines[i+1:] + gen_start = self.find_macro("RPC_AUTOGEN_START", rpc_lines) + gen_end = self.find_macro("RPC_AUTOGEN_END", rpc_lines) + rpc_lines = rpc_lines[:gen_start+1] + rpc_lines[gen_end:] + rpc_lines = rpc_lines[:gen_start+1] + \ + rpc_lambdas + \ + rpc_lines[gen_start+1:] with open("tmp2", 'w') as fp: fp.write("\n".join(rpc_lines)) @@ -157,11 +162,13 @@ def get_rpcs_from_class(self, class_lines): for i, line in enumerate(class_lines): if "class" == line.strip()[0:5]: cur_class = self.get_class_name(line) - rpc_map[cur_class] = {'apis': {}, 'macro': None} + rpc_map[cur_class] = {'apis': {}, + 'gen_start': None, + 'gen_end': None} elif "RPC_AUTOGEN_START" in line: - rpc_map[cur_class]['macro'] = i + rpc_map[cur_class]['gen_start'] = i elif "RPC_AUTOGEN_END" in line: - pass + rpc_map[cur_class]['gen_end'] = i elif "RPC" == line.strip()[0:3]: text_proto = self.get_rpc_prototype(class_lines[i:]) api = Api(text_proto) From 1cfddd7851e11d744d0cba18f7275408ef95099b Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 2 Dec 2022 00:21:30 -0600 Subject: [PATCH 040/511] Add conditional modify to rpc gen --- src/buffer_organizer.h | 74 ++++++++++++++++++- src/rpc_generator/generate.py | 8 +- .../rpc_generator/rpc_generator.py | 25 +++++-- src/rpc_thallium.cc | 40 +++++++++- 4 files changed, 134 insertions(+), 13 deletions(-) diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index 332cf743e..63e328872 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -173,8 +173,76 @@ class BufferOrganizer { /** Automatically Generate RPCs */ RPC_AUTOGEN_START - //hello - //hello + RPC BufferInfo GetBufferInfo(BufferID buffer_id) { + u32 target_node = buffer_id.bits.node_id; + if (target_node == rpc_->node_id_) { + LocalAddBlobIdToVBucket( + buffer_id); + } else { + rpc_->Call(rpc, target_node, "GetBufferInfo", + buffer_id); + } + } + RPC void EnqueueBoMove(const BoMoveList &moves, BlobID blob_id, BucketID bucket_id, const std::string &internal_blob_name, BoPriority priority) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + LocalAddBlobIdToVBucket( + &moves, blob_id, bucket_id, &internal_blob_name, priority); + } else { + rpc_->Call(rpc, target_node, "EnqueueBoMove", + &moves, blob_id, bucket_id, &internal_blob_name, priority); + } + } + RPC void OrganizeBlob(const std::string &internal_blob_name, BucketID bucket_id, f32 epsilon, f32 explicit_importance_score) { + u32 target_node = HashString(internal_name.c_str()); + if (target_node == rpc_->node_id_) { + LocalAddBlobIdToVBucket( + &internal_blob_name, bucket_id, epsilon, explicit_importance_score); + } else { + rpc_->Call(rpc, target_node, "OrganizeBlob", + &internal_blob_name, bucket_id, epsilon, explicit_importance_score); + } + } + RPC void EnforceCapacityThresholds(ViolationInfo info) { + u32 target_node = info.target_id.bits.node_id; + if (target_node == rpc_->node_id_) { + LocalAddBlobIdToVBucket( + info); + } else { + rpc_->Call(rpc, target_node, "EnforceCapacityThresholds", + info); + } + } + RPC bool EnqueueFlushingTask(BlobID blob_id, const std::string &filename, u64 offset) { + u32 target_node = rpc->node_id_; + if (target_node == rpc_->node_id_) { + LocalAddBlobIdToVBucket( + blob_id, &filename, offset); + } else { + rpc_->Call(rpc, target_node, "EnqueueFlushingTask", + blob_id, &filename, offset); + } + } + RPC void IncrementFlushCount(const std::string &vbkt_name) { + u32 target_node = HashString(vbkt_name.c_str()); + if (target_node == rpc_->node_id_) { + LocalAddBlobIdToVBucket( + &vbkt_name); + } else { + rpc_->Call(rpc, target_node, "IncrementFlushCount", + &vbkt_name); + } + } + RPC void DecrementFlushCount(const std::string &vbkt_name) { + u32 target_node = HashString(vbkt_name.c_str()); + if (target_node == rpc_->node_id_) { + LocalAddBlobIdToVBucket( + &vbkt_name); + } else { + rpc_->Call(rpc, target_node, "DecrementFlushCount", + &vbkt_name); + } + } RPC_AUTOGEN_END }; @@ -186,4 +254,4 @@ static inline f32 BytesToMegabytes(size_t bytes) { } // namespace hermes -#endif // HERMES_BUFFER_ORGANIZER_H_ +#endif // HERMES_BUFFER_ORGANIZER_H_ \ No newline at end of file diff --git a/src/rpc_generator/generate.py b/src/rpc_generator/generate.py index 921b2b066..8770209b1 100644 --- a/src/rpc_generator/generate.py +++ b/src/rpc_generator/generate.py @@ -4,12 +4,16 @@ USAGE: cd /path/to/rpc_generator - python3 generate.py + python3 generate.py [whether or not to modify path or make tmpfiles] """ +import sys from rpc_generator.rpc_generator import RpcGenerator -gen = RpcGenerator() +if len(sys.argv) < 2: + gen = RpcGenerator(False) +else: + gen = RpcGenerator(sys.argv[1]) gen.set_file("../buffer_organizer.h", "BufferOrganizer", "borg") gen.add("LocalGetBufferInfo", "buffer_id.bits.node_id") diff --git a/src/rpc_generator/rpc_generator/rpc_generator.py b/src/rpc_generator/rpc_generator/rpc_generator.py index ad94c26ad..d1c3f40d1 100644 --- a/src/rpc_generator/rpc_generator/rpc_generator.py +++ b/src/rpc_generator/rpc_generator/rpc_generator.py @@ -13,6 +13,7 @@ }} """ +# Will add this to rpc_thallium.cc rpc_lambda_text = """ auto {LAMBDA_NAME} = [{CONTEXT}](const request &req, {PARAMS}) {{ auto result = {CONTEXT}->{LOCAL_NAME}({PASS_PARAMS}); @@ -91,7 +92,11 @@ def pass_args(self): return ", ".join(args) class RpcGenerator: - def __init__(self): + def __init__(self, modify): + if modify != "True": + self.modify = False + else: + self.modify = True self.path = None self.macro = None self.context = None @@ -140,8 +145,13 @@ def generate_class_file(self, path, class_rpcs, rpc_lambdas): global_rpc_funcs + \ class_lines[gen_start + 1:] - with open("tmp", 'w') as fp: - fp.write("\n".join(class_lines)) + if self.modify: + with open(path, 'w') as fp: + fp.write("\n".join(class_lines)) + else: + tmp_path = os.path.basename(path) + with open(f"tmp_{tmp_path}", 'w') as fp: + fp.write("\n".join(class_lines)) def generate_rpc_file(self, rpc_lambdas): path = "../rpc_thallium.cc" @@ -153,8 +163,13 @@ def generate_rpc_file(self, rpc_lambdas): rpc_lines = rpc_lines[:gen_start+1] + \ rpc_lambdas + \ rpc_lines[gen_start+1:] - with open("tmp2", 'w') as fp: - fp.write("\n".join(rpc_lines)) + if self.modify: + with open(path, 'w') as fp: + fp.write("\n".join(rpc_lines)) + else: + tmp_path = os.path.basename(path) + with open(tmp_path, 'w') as fp: + fp.write("\n".join(rpc_lines)) def get_rpcs_from_class(self, class_lines): cur_class = None diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index cd3763aea..e991b03c7 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -294,8 +294,7 @@ void ThalliumRpc::StartPrefetcher(double sleep_ms) { using tl::request; // Create the LogIoStat RPC - auto rpc_log_io_stat = [context](const request &req, IoLogEntry &entry) { - (void) context; + auto rpc_log_io_stat = [](const request &req, IoLogEntry &entry) { auto prefetcher = Singleton::GetInstance(); prefetcher->Log(entry); req.respond(true); @@ -410,6 +409,41 @@ void ThalliumRpc::StartServer(const char *addr, using tl::request; RPC_AUTOGEN_START + auto RpcGetBufferInfo = [borg](const request &req, BufferID buffer_id) { + auto result = borg->LocalGetBufferInfo(buffer_id); + req.respond(result); + }; + rpc_server->define("GetBufferInfo", rpc_get_buffers); + auto RpcEnqueueBoMove = [borg](const request &req, const BoMoveList &moves, BlobID blob_id, BucketID bucket_id, const std::string &internal_blob_name, BoPriority priority) { + auto result = borg->LocalEnqueueBoMove(&moves, blob_id, bucket_id, &internal_blob_name, priority); + req.respond(result); + }; + rpc_server->define("EnqueueBoMove", rpc_get_buffers); + auto RpcOrganizeBlob = [borg](const request &req, const std::string &internal_blob_name, BucketID bucket_id, f32 epsilon, f32 explicit_importance_score) { + auto result = borg->LocalOrganizeBlob(&internal_blob_name, bucket_id, epsilon, explicit_importance_score); + req.respond(result); + }; + rpc_server->define("OrganizeBlob", rpc_get_buffers); + auto RpcEnforceCapacityThresholds = [borg](const request &req, ViolationInfo info) { + auto result = borg->LocalEnforceCapacityThresholds(info); + req.respond(result); + }; + rpc_server->define("EnforceCapacityThresholds", rpc_get_buffers); + auto RpcEnqueueFlushingTask = [borg](const request &req, BlobID blob_id, const std::string &filename, u64 offset) { + auto result = borg->LocalEnqueueFlushingTask(blob_id, &filename, offset); + req.respond(result); + }; + rpc_server->define("EnqueueFlushingTask", rpc_get_buffers); + auto RpcIncrementFlushCount = [borg](const request &req, const std::string &vbkt_name) { + auto result = borg->LocalIncrementFlushCount(&vbkt_name); + req.respond(result); + }; + rpc_server->define("IncrementFlushCount", rpc_get_buffers); + auto RpcDecrementFlushCount = [borg](const request &req, const std::string &vbkt_name) { + auto result = borg->LocalDecrementFlushCount(&vbkt_name); + req.respond(result); + }; + rpc_server->define("DecrementFlushCount", rpc_get_buffers); RPC_AUTOGEN_END @@ -852,4 +886,4 @@ void ThalliumRpc::StartServer(const char *addr, rpc_enforce_capacity_thresholds); } -} // namespace hermes +} // namespace hermes \ No newline at end of file From f52721df80fab2fdff0bd4549c0437afe72631e6 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 2 Dec 2022 15:59:47 -0600 Subject: [PATCH 041/511] Autogeneration for config default --- CMakeLists.txt | 16 +- adapter/interceptor.cc | 2 +- adapter/interceptor.h | 1 - adapter/test/CMakeLists.txt | 2 +- config/default_config_gen/generate.py | 53 + config/hermes_client_default.yaml | 2 + config/hermes_server_default.yaml | 136 ++ src/CMakeLists.txt | 25 +- src/api/bucket.cc | 444 ---- src/api/bucket.h | 574 ----- src/api/hermes.cc | 447 ---- src/api/hermes.h | 317 +-- src/api/traits.cc | 146 -- src/api/traits.h | 152 -- src/api/vbucket.cc | 407 ---- src/api/vbucket.h | 264 --- src/buffer_organizer.cc | 841 ------- src/buffer_organizer.h | 257 -- src/buffer_pool.cc | 2061 ----------------- src/buffer_pool.h | 559 ----- src/buffer_pool_internal.h | 221 -- src/buffer_pool_visualizer/CMakeLists.txt | 18 - src/buffer_pool_visualizer/README.md | 41 - src/buffer_pool_visualizer/asan.supp | 4 - .../buffer_pool_visualizer.cc | 1069 --------- src/communication.h | 45 +- src/communication_factory.h | 34 - ...mmunication_mpi.cc => communication_mpi.h} | 9 +- src/config.h | 255 ++ src/config_client.cc | 14 + src/config_client_default.h | 6 + src/config_parser.cc | 556 ----- src/config_parser.h | 30 - src/config_server.cc | 367 +++ src/config_server_default.h | 140 ++ src/data_placement_engine.cc | 173 -- src/data_placement_engine.h | 69 - src/data_placement_engine_factory.h | 60 - src/dpe/linprog.h | 163 -- src/dpe/minimize_io_time.cc | 179 -- src/dpe/minimize_io_time.h | 48 - src/dpe/random.cc | 95 - src/dpe/random.h | 46 - src/dpe/round_robin.cc | 142 -- src/dpe/round_robin.h | 73 - {adapter/test => src}/hermes_daemon.cc | 16 +- src/hermes_types.h | 141 +- src/metadata_management.cc | 1502 ------------ src/metadata_management.h | 622 ----- src/prefetcher.cc | 226 -- src/prefetcher.h | 268 --- src/prefetcher_factory.h | 48 - src/prefetchers/apriori.cc | 13 - src/prefetchers/apriori.h | 28 - src/prefetchers/sequential.cc | 145 -- src/prefetchers/sequential.h | 52 - src/rpc.h | 11 +- src/rpc_factory.h | 37 - src/rpc_generator/generate.py | 30 - .../rpc_generator/rpc_generator.py | 244 -- src/rpc_thallium.cc | 759 +----- src/rpc_thallium.h | 117 +- test/CMakeLists.txt | 2 +- test/bucket_test.cc | 280 --- test/buffer_organizer_test.cc | 388 ---- test/buffer_pool_client_test.cc | 371 --- test/buffer_pool_test.cc | 336 --- test/catch_config.h | 43 - test/clear_cache.sh | 3 - test/config_parser_test.cc | 271 --- test/data/ares.yaml | 52 - test/data/bucket_test.yaml | 53 - test/data/hermes.yaml | 140 -- test/data/hermes_client.yaml | 2 + test/data/hermes_server.yaml | 136 ++ test/data/local.yaml | 140 -- test/data/prefetch.yaml | 134 -- test/data/prefetch_ares.yaml | 134 -- test/data/prefetch_ares_ram.yaml | 131 -- test/data/prefetch_ram.yaml | 131 -- test/data/staging.yaml | 195 -- test/dpe_optimization_test.cc | 93 - test/dpe_random_test.cc | 80 - test/dpe_roundrobin_test.cc | 83 - test/end_to_end_test.cc | 136 -- test/mdm_test.cc | 464 ---- test/memory_test.cc | 96 - test/mpi_test.c | 37 - test/prefetch_test.cc | 117 - test/stdio_test.c | 28 - test/test_rpc.cc | 6 + test/test_utils.h | 98 - test/timer.h | 201 -- test/trait_test.cc | 144 -- test/vbucket_test.cc | 105 - 95 files changed, 1282 insertions(+), 18170 deletions(-) create mode 100644 config/default_config_gen/generate.py create mode 100644 config/hermes_client_default.yaml create mode 100644 config/hermes_server_default.yaml delete mode 100644 src/api/bucket.cc delete mode 100644 src/api/bucket.h delete mode 100644 src/api/hermes.cc delete mode 100644 src/api/traits.cc delete mode 100644 src/api/traits.h delete mode 100644 src/api/vbucket.cc delete mode 100644 src/api/vbucket.h delete mode 100644 src/buffer_organizer.cc delete mode 100644 src/buffer_organizer.h delete mode 100644 src/buffer_pool.cc delete mode 100644 src/buffer_pool.h delete mode 100644 src/buffer_pool_internal.h delete mode 100644 src/buffer_pool_visualizer/CMakeLists.txt delete mode 100644 src/buffer_pool_visualizer/README.md delete mode 100644 src/buffer_pool_visualizer/asan.supp delete mode 100644 src/buffer_pool_visualizer/buffer_pool_visualizer.cc delete mode 100644 src/communication_factory.h rename src/{communication_mpi.cc => communication_mpi.h} (97%) create mode 100644 src/config.h create mode 100644 src/config_client.cc create mode 100644 src/config_client_default.h delete mode 100644 src/config_parser.cc delete mode 100644 src/config_parser.h create mode 100644 src/config_server.cc create mode 100644 src/config_server_default.h delete mode 100644 src/data_placement_engine.cc delete mode 100644 src/data_placement_engine.h delete mode 100644 src/data_placement_engine_factory.h delete mode 100644 src/dpe/linprog.h delete mode 100644 src/dpe/minimize_io_time.cc delete mode 100644 src/dpe/minimize_io_time.h delete mode 100644 src/dpe/random.cc delete mode 100644 src/dpe/random.h delete mode 100644 src/dpe/round_robin.cc delete mode 100644 src/dpe/round_robin.h rename {adapter/test => src}/hermes_daemon.cc (80%) delete mode 100644 src/metadata_management.cc delete mode 100644 src/metadata_management.h delete mode 100644 src/prefetcher.cc delete mode 100644 src/prefetcher.h delete mode 100644 src/prefetcher_factory.h delete mode 100644 src/prefetchers/apriori.cc delete mode 100644 src/prefetchers/apriori.h delete mode 100644 src/prefetchers/sequential.cc delete mode 100644 src/prefetchers/sequential.h delete mode 100644 src/rpc_factory.h delete mode 100644 src/rpc_generator/generate.py delete mode 100644 src/rpc_generator/rpc_generator/rpc_generator.py delete mode 100644 test/bucket_test.cc delete mode 100644 test/buffer_organizer_test.cc delete mode 100644 test/buffer_pool_client_test.cc delete mode 100644 test/buffer_pool_test.cc delete mode 100644 test/catch_config.h delete mode 100644 test/clear_cache.sh delete mode 100644 test/config_parser_test.cc delete mode 100644 test/data/ares.yaml delete mode 100644 test/data/bucket_test.yaml delete mode 100644 test/data/hermes.yaml create mode 100644 test/data/hermes_client.yaml create mode 100644 test/data/hermes_server.yaml delete mode 100644 test/data/local.yaml delete mode 100644 test/data/prefetch.yaml delete mode 100644 test/data/prefetch_ares.yaml delete mode 100644 test/data/prefetch_ares_ram.yaml delete mode 100644 test/data/prefetch_ram.yaml delete mode 100644 test/data/staging.yaml delete mode 100644 test/dpe_optimization_test.cc delete mode 100644 test/dpe_random_test.cc delete mode 100644 test/dpe_roundrobin_test.cc delete mode 100644 test/end_to_end_test.cc delete mode 100644 test/mdm_test.cc delete mode 100644 test/memory_test.cc delete mode 100644 test/mpi_test.c delete mode 100644 test/prefetch_test.cc delete mode 100644 test/stdio_test.c create mode 100644 test/test_rpc.cc delete mode 100644 test/test_utils.h delete mode 100644 test/timer.h delete mode 100644 test/trait_test.cc delete mode 100644 test/vbucket_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 161a0b995..18e7d0288 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -395,18 +395,18 @@ endif() add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src) if(HERMES_HAVE_GOTCHA) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/gotcha_intercept) + # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/gotcha_intercept) endif() if(HERMES_ENABLE_WRAPPER) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/wrapper) + # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/wrapper) endif() if(HERMES_BUILD_BUFFER_POOL_VISUALIZER AND SDL2_FOUND) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/buffer_pool_visualizer) + # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/buffer_pool_visualizer) endif() -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/data_stager) +# add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/data_stager) #----------------------------------------------------------------------------- # Testing @@ -423,14 +423,14 @@ if(CMAKE_PROJECT_NAME STREQUAL HERMES AND BUILD_TESTING) set(HERMES_HAVE_IOR "NO") endif() enable_testing() - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/data_stager/test) + # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test) + # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/data_stager/test) endif() if(HERMES_ENABLE_STDIO_ADAPTER OR HERMES_ENABLE_POSIX_ADAPTER OR HERMES_ENABLE_MPIIO_ADAPTER OR HERMES_ENABLE_PUBSUB_ADAPTER OR HERMES_ENABLE_VFD) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/adapter) + # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/adapter) endif() #----------------------------------------------------------------------------- @@ -484,7 +484,7 @@ install( install( FILES - test/data/hermes.yaml + test/data/hermes_server.yaml TYPE DATA RENAME diff --git a/adapter/interceptor.cc b/adapter/interceptor.cc index 8a845b413..fb28f5f73 100644 --- a/adapter/interceptor.cc +++ b/adapter/interceptor.cc @@ -18,7 +18,7 @@ #include #include #include "adapter_utils.h" -#include "config_parser.h" +#include "config.h" namespace stdfs = std::experimental::filesystem; const char* kPathExclusions[] = {"/bin/", "/boot/", "/dev/", "/etc/", diff --git a/adapter/interceptor.h b/adapter/interceptor.h index 847a6cedb..9ed25463f 100644 --- a/adapter/interceptor.h +++ b/adapter/interceptor.h @@ -23,7 +23,6 @@ #include #include "adapter_utils.h" -#include "buffer_pool_internal.h" #include "constants.h" #include "enumerations.h" #include "singleton.h" diff --git a/adapter/test/CMakeLists.txt b/adapter/test/CMakeLists.txt index 2ee65699f..4f38bb8b2 100644 --- a/adapter/test/CMakeLists.txt +++ b/adapter/test/CMakeLists.txt @@ -3,7 +3,7 @@ set(ADAPTER_COMMON ${CMAKE_CURRENT_SOURCE_DIR}/catch_config.h) set(HERMES_ADAPTER_TEST_DIR ${HERMES_ADAPTER_DIR}/test) find_package(Catch2 REQUIRED) -add_executable(hermes_daemon hermes_daemon.cc) +add_executable(hermes_daemon ../../src/hermes_daemon.cc) target_link_libraries(hermes_daemon -ldl -lc MPI::MPI_CXX glog::glog) target_link_libraries(hermes_daemon hermes) add_dependencies(hermes_daemon hermes) diff --git a/config/default_config_gen/generate.py b/config/default_config_gen/generate.py new file mode 100644 index 000000000..10fcd17d5 --- /dev/null +++ b/config/default_config_gen/generate.py @@ -0,0 +1,53 @@ +""" +USAGE: + cd /path/to/default_config_gen + ./config_gen [client/server] + +OUTPUT: + ../../config_client_default.h (if client) + ../../config_server_default.h (if server) +""" + +import sys, os + +if len(sys.argv) != 2: + print("USAGE: ./config_gen [client/server]") + exit(1) + +config_type = sys.argv[1] +if config_type == 'client': + path = "../hermes_client_default.yaml" + var_name = "kClientDefaultConfigStr" + config_path = "../../src/config_client_default.h" + macro_name = "CLIENT" +elif config_type == 'server': + path = "../hermes_server_default.yaml" + var_name = "kServerDefaultConfigStr" + config_path = "../../src/config_server_default.h" + macro_name = "SERVER" +else: + print(f"{config_type} is not either \"client\" or \"server\"") + exit(1) + +with open(path) as fp: + yaml_config_lines = fp.read().splitlines() + +# Create the hermes config string +string_lines = [] +string_lines.append(f"const char* {var_name} = ") +for line in yaml_config_lines: + line = line.replace('\"', '\\\"') + line = line.replace('\'', '\\\'') + string_lines.append(f"\"{line}\"") +string_lines[-1] = string_lines[-1] + ';' +final_string = "\n".join(string_lines) + +# Create the configuration +config_lines = [] +config_lines.append(f"#ifndef HERMES_SRC_CONFIG_{macro_name}_DEFAULT_H_") +config_lines.append(f"#define HERMES_SRC_CONFIG_{macro_name}_DEFAULT_H_") +config_lines.append(final_string) +config_lines.append(f"#endif // HERMES_SRC_CONFIG_{macro_name}_DEFAULT_H_") +config = "\n".join(config_lines) +with open(config_path, 'w') as fp: + fp.write(config) \ No newline at end of file diff --git a/config/hermes_client_default.yaml b/config/hermes_client_default.yaml new file mode 100644 index 000000000..61f5a6146 --- /dev/null +++ b/config/hermes_client_default.yaml @@ -0,0 +1,2 @@ +stop_daemon: true +file_page_size_kb: 1024 \ No newline at end of file diff --git a/config/hermes_server_default.yaml b/config/hermes_server_default.yaml new file mode 100644 index 000000000..09e27c1e7 --- /dev/null +++ b/config/hermes_server_default.yaml @@ -0,0 +1,136 @@ +# Example Hermes configuration file + +### Define properties of the storage devices +devices: + # The name of the device. + # It can be whatever the user wants, there are no special names + ram: + # The mount point of each device. RAM should be the empty string. For block + # devices, this is the directory where Hermes will create buffering files. For + # object storage or cloud targets, this will be a url. + mount_point: "" + + # The maximum buffering capacity in MiB of each device. Here we say that all 4 + # devices get 50 MiB of buffering capacity. + capacity_mb: 50 + + # The size of the smallest available buffer in KiB. In general this should be + # the page size of your system for byte addressable storage, and the block size + # of the storage device for block addressable storage. + block_size_kb: 4 + + # The number of blocks (the size of which is chosen in block_sizes_kb) that each + # device should contain for each slab (controlled by num_slabs). This allows for + # precise control of the distibution of buffer sizes. + slab_units: [1, 4, 16, 32] + + # The maximum theoretical bandwidth (as advertised by the manufacturer) in + # MiB/sec. of each device. + bandwidth_mbps: 6000 + + # The latency in microseconds of each device (as advertised by the manufacturer). + latencies_us: 15 + + # For each device, indicate '1' if it is shared among nodes (e.g., burst + # buffers), or '0' if it is per node (e.g., local NVMe). + is_shared_device: 0 + + nvme: + mount_point: "./" + capacity_mb: 50 + block_size_kb: 4 + slab_units: [1, 4, 16, 32] + is_shared_device: 0 + + ssd: + mount_point: "./" + capacity_mb: 50 + block_size_kb: 4 + slab_units: [ 1, 4, 16, 32 ] + is_shared_device: 0 + + pfs: + mount_point: "./" + capacity_mb: inf + block_size_kb: 64 # Assume 64KB strip size + slab_units: [1, 4, 16, 32] + +### Define the network communication protocol +rpc: + # A path to a file containing a list of server names, 1 per line. If your + # servers are named according to a pattern (e.g., server-1, server-2, etc.), + # prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this + # option is not empty, it will override anything in `rpc_server_base_name`. + host_file: "" + + # Host names are constructed as "base_name + + # host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list + # can be either a single number, or a range, which is 2 numbers separated by a + # hyphen (-). For example the list {01, 03-05, 07, 08-10} will be expanded to + # {01, 03, 04, 05, 07, 08, 09, 10}. + server_base_name: "localhost" + server_host_number_range: [] + server_suffix: "" + + # The RPC protocol. This must come from the documentation of the specific RPC + # library in use. + protocol: "ofi+sockets" + + # RPC domain name for verbs transport. Blank for tcp. + domain: "" + + # Desired RPC port number. + port: 8080 + + # Desired RPC port number for buffer organizer. + buffer_organizer_port: 8081 + + # The number of handler threads for each RPC server. + num_threads: 1 + +### Define properties of the BORG +buffer_organizer: + # The number of threads used in the background organization of internal Hermes buffers. + num_threads: 4 + + # For each device, the minimum and maximum percent capacity threshold at which + # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause + # the BufferOrganizer to move data to lower devices, making more room in faster + # devices (ideal for write-heavy workloads). Conversely, increasing the minimum + # threshold will cause data to be moved from slower devices into faster devices + # (ideal for read-heavy workloads). For example, a maximum capacity threshold of + # 0.8 would have the effect of always keeping 20% of the device's space free for + # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure + # that the device is always at least 30% occupied. + capacity_thresholds: [ + [ 0.0, 1.0 ], + [ 0.0, 1.0 ], + [ 0.0, 1.0 ], + [ 0.0, 1.0 ] + ] + +### Define the default data placement policy +dpe: + # Choose Random, RoundRobin, or MinimizeIoTime + default_placement_policy: "MinimizeIoTime" + + # If true (1) the RoundRobin placement policy algorithm will split each Blob + # into a random number of smaller Blobs. + default_rr_split: 0 + +# The shared memory prefix for the hermes shared memory segment. A user name +# will be automatically appended. +shmem_name: "/hermes_shm_" +# The interval in milliseconds at which to update the global system view. +system_view_state_update_interval_ms: 1000 + +#Paths which are ignored when buffering data +path_exclusions: [ + "/bin/", "/boot/", "/dev/", "/etc/", + "/lib/", "/opt/", "/proc/", "/sbin/", + "/sys/", "/usr/", "/var/", "/run/", + "pipe", "socket:", "anon_inode:" +] +#Paths which are never ignored when buffering data +path_inclusions: ["/var/opt/cray/dws/mounts/"] + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6c51d8a5c..51c7ae975 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,17 +23,20 @@ endif() # Set sources #------------------------------------------------------------------------------ set(HERMES_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/api/bucket.cc - ${CMAKE_CURRENT_SOURCE_DIR}/api/hermes.cc - ${CMAKE_CURRENT_SOURCE_DIR}/api/vbucket.cc - ${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cc - ${CMAKE_CURRENT_SOURCE_DIR}/prefetcher.cc - ${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/sequential.cc - ${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/apriori.cc - ${CMAKE_CURRENT_SOURCE_DIR}/data_placement_engine.cc - ${CMAKE_CURRENT_SOURCE_DIR}/dpe/random.cc - ${CMAKE_CURRENT_SOURCE_DIR}/dpe/round_robin.cc - ${CMAKE_CURRENT_SOURCE_DIR}/dpe/minimize_io_time.cc + #${CMAKE_CURRENT_SOURCE_DIR}/api/bucket.cc + #${CMAKE_CURRENT_SOURCE_DIR}/api/hermes.cc + #${CMAKE_CURRENT_SOURCE_DIR}/api/vbucket.cc + #${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cc + #${CMAKE_CURRENT_SOURCE_DIR}/prefetcher.cc + #${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/sequential.cc + #${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/apriori.cc + #${CMAKE_CURRENT_SOURCE_DIR}/data_placement_engine.cc + #${CMAKE_CURRENT_SOURCE_DIR}/dpe/random.cc + #${CMAKE_CURRENT_SOURCE_DIR}/dpe/round_robin.cc + #${CMAKE_CURRENT_SOURCE_DIR}/dpe/minimize_io_time.cc + ${CMAKE_CURRENT_SOURCE_DIR}/config_parser.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rpc_thallium.cc + ${CMAKE_CURRENT_SOURCE_DIR}/hermes_daemon.cc ) #------------------------------------------------------------------------------ diff --git a/src/api/bucket.cc b/src/api/bucket.cc deleted file mode 100644 index ea7a8c32d..000000000 --- a/src/api/bucket.cc +++ /dev/null @@ -1,444 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "bucket.h" -#include "prefetcher.h" - -#include -#include - -#include "utils.h" -#include "buffer_pool.h" -#include "metadata_management.h" - -namespace hermes { - -namespace api { - -Bucket::Bucket(const std::string &initial_name, - const std::shared_ptr &h, Context ctx) - : name_(initial_name), hermes_(h), ctx_(ctx) { - if (IsBucketNameTooLong(name_)) { - id_.as_int = 0; - throw std::length_error("Bucket name is too long: " + - std::to_string(kMaxBucketNameSize)); - } else { - id_ = GetOrCreateBucketId(&hermes_->context_, &hermes_->rpc_, name_); - if (!IsValid()) { - throw std::runtime_error("Bucket id is invalid."); - } - } -} - -Bucket::~Bucket() { - if (IsValid()) { - Context ctx; - Release(ctx); - } -} - -std::string Bucket::GetName() const { - return name_; -} - -u64 Bucket::GetId() const { - return id_.as_int; -} - -bool Bucket::IsValid() const { - return !IsNullBucketId(id_); -} - -Status Bucket::Put(const std::string &name, const u8 *data, size_t size, - const Context &ctx) { - Status result; - - if (size > 0 && nullptr == data) { - result = INVALID_BLOB; - LOG(ERROR) << result.Msg(); - } - - if (result.Succeeded()) { - std::vector names{name}; - // TODO(chogan): Create a PreallocatedMemory allocator for std::vector so - // that a single-blob-Put doesn't perform a copy - std::vector blobs{Blob{data, data + size}}; - result = Put(names, blobs, ctx); - } - - return result; -} - -Status Bucket::Put(const std::string &name, const u8 *data, size_t size) { - Status result = Put(name, data, size, ctx_); - - return result; -} - -size_t Bucket::GetTotalBlobSize() { - std::vector blob_ids = hermes::GetBlobIds(&hermes_->context_, - &hermes_->rpc_, id_); - api::Context ctx; - size_t result = 0; - for (size_t i = 0; i < blob_ids.size(); ++i) { - ScopedTemporaryMemory scratch(&hermes_->trans_arena_); - result += hermes::GetBlobSizeById(&hermes_->context_, &hermes_->rpc_, - scratch, blob_ids[i]); - } - - return result; -} - -size_t Bucket::GetBlobSize(const std::string &name, const Context &ctx) { - ScopedTemporaryMemory scratch(&hermes_->trans_arena_); - size_t result = GetBlobSize(scratch, name, ctx); - - return result; -} - -size_t Bucket::GetBlobSize(const std::string &name, - const Context &ctx) { - (void)ctx; - size_t result = 0; - - if (IsValid()) { - LOG(INFO) << "Getting Blob " << name << " size from bucket " - << name_ << '\n'; - BlobID blob_id = GetBlobId(&hermes_->context_, &hermes_->rpc_, name, - id_, false); - if (!IsNullBlobId(blob_id)) { - result = GetBlobSizeById(&hermes_->context_, &hermes_->rpc_, arena, - blob_id); - } - } - - return result; -} - -size_t Bucket::Get(const std::string &name, Blob &user_blob, - const Context &ctx) { - size_t ret = Get(name, user_blob.data(), user_blob.size(), ctx); - - return ret; -} - -size_t Bucket::Get(const std::string &name, Blob &user_blob) { - size_t result = Get(name, user_blob, ctx_); - - return result; -} - -size_t Bucket::Get(const std::string &name, void *user_blob, size_t blob_size, - const Context &ctx) { - (void)ctx; - - size_t ret = 0; - - if (IsValid()) { - // TODO(chogan): Assumes scratch is big enough to hold buffer_ids - ScopedTemporaryMemory scratch(&hermes_->trans_arena_); - - if (user_blob && blob_size != 0) { - hermes::Blob blob = {}; - blob.data = (u8 *)user_blob; - blob.size = blob_size; - LOG(INFO) << "Getting Blob " << name << " from bucket " << name_ << '\n'; - BlobID blob_id = GetBlobId(&hermes_->context_, &hermes_->rpc_, - name, id_); - - // Upload statistic to prefetcher - if (ctx.pctx_.hint_ != PrefetchHint::kNone) { - IoLogEntry entry; - entry.vbkt_id_ = ctx.vbkt_id_; - entry.bkt_id_ = id_; - entry.blob_id_ = blob_id; - entry.type_ = IoType::kGet; - entry.off_ = 0; - entry.size_ = blob_size; - entry.pctx_ = ctx.pctx_; - entry.tid_ = GlobalThreadID(hermes_->comm_.world_proc_id); - entry.historical_ = false; - Prefetcher::LogIoStat(hermes_.get(), entry); - } - LockBlob(&hermes_->context_, &hermes_->rpc_, blob_id); - ret = ReadBlobById(&hermes_->context_, &hermes_->rpc_, - &hermes_->trans_arena_, blob, blob_id); - UnlockBlob(&hermes_->context_, &hermes_->rpc_, blob_id); - } else { - ret = GetBlobSize(scratch, name, ctx); - } - } - - return ret; -} - -std::vector Bucket::Get(const std::vector &names, - std::vector &blobs, const Context &ctx) { - std::vector result(names.size(), 0); - if (names.size() == blobs.size()) { - for (size_t i = 0; i < result.size(); ++i) { - result[i] = Get(names[i], blobs[i], ctx); - } - } else { - LOG(ERROR) << "names.size() != blobs.size() in Bucket::Get (" - << names.size() << " != " << blobs.size() << ")" - << std::endl; - } - - return result; -} - -size_t Bucket::GetNext(u64 blob_index, Blob &user_blob, - const Context &ctx) { - size_t ret = GetNext(blob_index, user_blob.data(), user_blob.size(), ctx); - - return ret; -} - -size_t Bucket::GetNext(u64 blob_index, Blob &user_blob) { - size_t result = GetNext(blob_index, user_blob, ctx_); - - return result; -} - -size_t Bucket::GetNext(u64 blob_index, void *user_blob, size_t blob_size, - const Context &ctx) { - (void)ctx; - size_t ret = 0; - - if (IsValid()) { - std::vector blob_ids = GetBlobIds(&hermes_->context_, - &hermes_->rpc_, - this->id_); - if (blob_index > blob_ids.size()) { - LOG(INFO) << "Already on the tail for bucket " << name_ << '\n'; - return ret; - } - BlobID next_blob_id = blob_ids.at(blob_index); - if (user_blob && blob_size != 0) { - hermes::Blob blob = {}; - blob.data = (u8 *)user_blob; - blob.size = blob_size; - LOG(INFO) << "Getting Blob " << next_blob_id.as_int << " from bucket " - << name_ << '\n'; - ret = ReadBlobById(&hermes_->context_, &hermes_->rpc_, - &hermes_->trans_arena_, blob, next_blob_id); - } else { - LOG(INFO) << "Getting Blob " << next_blob_id.as_int << - " size from bucket " << name_ << '\n'; - ScopedTemporaryMemory scratch(&hermes_->trans_arena_); - if (!IsNullBlobId(next_blob_id)) { - ret = GetBlobSizeById(&hermes_->context_, &hermes_->rpc_, scratch, - next_blob_id); - } - } - } - - return ret; -} - -std::vector Bucket::GetNext(u64 blob_index, u64 count, - std::vector &blobs, - const Context &ctx) { - std::vector result(count, 0); - - if (IsValid()) { - if (count == blobs.size()) { - for (size_t i = 0; i < result.size(); ++i) { - result[i] = GetNext(blob_index + i, blobs[i], ctx); - } - } else { - LOG(ERROR) << "names.size() != blobs.size() in Bucket::Get (" << count - << " != " << blobs.size() << ")" << std::endl; - } - } - - return result; -} - -template -Status Bucket::GetV(void *user_blob, Predicate pred, Context &ctx) { - (void)user_blob; - (void)ctx; - Status ret; - - LOG(INFO) << "Getting blobs by predicate from bucket " << name_ << '\n'; - - HERMES_NOT_IMPLEMENTED_YET; - - return ret; -} - -Status Bucket::DeleteBlob(const std::string &name) { - Status result = DeleteBlob(name, ctx_); - - return result; -} - -Status Bucket::DeleteBlob(const std::string &name, const Context &ctx) { - (void)ctx; - Status ret; - - LOG(INFO) << "Deleting Blob " << name << " from bucket " << name_ << '\n'; - DestroyBlobByName(&hermes_->context_, &hermes_->rpc_, id_, name); - - return ret; -} - -Status Bucket::RenameBlob(const std::string &old_name, - const std::string &new_name) { - Status result = RenameBlob(old_name, new_name, ctx_); - - return result; -} - -Status Bucket::RenameBlob(const std::string &old_name, - const std::string &new_name, - const Context &ctx) { - (void)ctx; - Status ret; - - if (IsBlobNameTooLong(new_name)) { - ret = BLOB_NAME_TOO_LONG; - LOG(ERROR) << ret.Msg(); - return ret; - } else { - LOG(INFO) << "Renaming Blob " << old_name << " to " << new_name << '\n'; - hermes::RenameBlob(&hermes_->context_, &hermes_->rpc_, old_name, - new_name, id_); - } - - return ret; -} - -bool Bucket::ContainsBlob(const std::string &name) { - bool result = hermes::ContainsBlob(&hermes_->context_, &hermes_->rpc_, id_, - name); - - return result; -} - -bool Bucket::BlobIsInSwap(const std::string &name) { - BlobID blob_id = GetBlobId(&hermes_->context_, &hermes_->rpc_, name, - id_); - bool result = hermes::BlobIsInSwap(blob_id); - - return result; -} - -template -std::vector Bucket::GetBlobNames(Predicate pred, - Context &ctx) { - (void)ctx; - - LOG(INFO) << "Getting blob names by predicate from bucket " << name_ << '\n'; - - HERMES_NOT_IMPLEMENTED_YET; - - return std::vector(); -} - -Status Bucket::Rename(const std::string &new_name) { - Status result = Rename(new_name, ctx_); - - return result; -} - -Status Bucket::Rename(const std::string &new_name, const Context &ctx) { - (void)ctx; - Status ret; - - if (IsBucketNameTooLong(new_name)) { - ret = BUCKET_NAME_TOO_LONG; - LOG(ERROR) << ret.Msg(); - return ret; - } else { - LOG(INFO) << "Renaming a bucket to" << new_name << '\n'; - RenameBucket(&hermes_->context_, &hermes_->rpc_, id_, name_, new_name); - } - - return ret; -} - -Status Bucket::Persist(const std::string &file_name) { - Status result = Persist(file_name, ctx_); - - return result; -} - -Status Bucket::Persist(const std::string &file_name, const Context &ctx) { - (void)ctx; - // TODO(chogan): Once we have Traits, we need to let users control the mode - // when we're, for example, updating an existing file. For now we just assume - // we're always creating a new file. - std::string open_mode = "w"; - - // TODO(chogan): Support other storage backends - Status result = StdIoPersistBucket(&hermes_->context_, &hermes_->rpc_, - &hermes_->trans_arena_, id_, file_name, - open_mode); - - return result; -} - -void Bucket::OrganizeBlob(const std::string &blob_name, f32 epsilon, - f32 custom_importance) { - hermes::OrganizeBlob(&hermes_->context_, &hermes_->rpc_, id_, blob_name, - epsilon, custom_importance); -} - -Status Bucket::Release() { - Status result = Release(ctx_); - - return result; -} - -Status Bucket::Release(const Context &ctx) { - (void)ctx; - Status ret; - - if (IsValid() && hermes_->is_initialized) { - LOG(INFO) << "Closing bucket '" << name_ << "'" << std::endl; - DecrementRefcount(&hermes_->context_, &hermes_->rpc_, id_); - id_.as_int = 0; - } - - return ret; -} - -Status Bucket::Destroy() { - Status result = Destroy(ctx_); - - return result; -} - -Status Bucket::Destroy(const Context &ctx) { - (void)ctx; - Status result; - - if (IsValid()) { - LOG(INFO) << "Destroying bucket '" << name_ << "'" << std::endl; - bool destroyed = DestroyBucket(&hermes_->context_, &hermes_->rpc_, - name_.c_str(), id_); - if (destroyed) { - id_.as_int = 0; - } else { - result = BUCKET_IN_USE; - LOG(ERROR) << result.Msg(); - } - } - - return result; -} - -} // namespace api -} // namespace hermes diff --git a/src/api/bucket.h b/src/api/bucket.h deleted file mode 100644 index c4ee0bc63..000000000 --- a/src/api/bucket.h +++ /dev/null @@ -1,574 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef BUCKET_H_ -#define BUCKET_H_ - -#include - -#include -#include -#include -#include - -#include "dpe/round_robin.h" -#include "hermes.h" -#include "metadata_management.h" -#include "utils.h" - -/** \file bucket.h */ - -namespace hermes { - -namespace api { - -/** \brief A container for Blob%s - * - */ -class Bucket { - private: - /** The user-facing descriptor of this Bucket. */ - std::string name_; - /** The internal descriptor of this Bucket. */ - hermes::BucketID id_; - - public: - /** The internal Hermes instance within which to create this Bucket. */ - std::shared_ptr hermes_; - /** The api::Context that controls all operations on this Bucket. */ - Context ctx_; - - // TODO(chogan): Think about copy/move constructor/assignment operators - - /** \brief Default constructor. - * - * Creates the "NULL" Bucket. - */ - Bucket() : name_(""), id_{0, 0}, hermes_(nullptr) { - LOG(INFO) << "Create NULL Bucket " << std::endl; - } - - /** \brief Constructor. - * - * Create a Bucket with name \p initial_name, backed by Hermes instance \p h, - * with optional Context \p ctx. - * - * \param initial_name The name of this Bucket. - * \param h An initialized Hermes instance. - * \param ctx An optional Context that controls the behavior of this Bucket. - */ - Bucket(const std::string &initial_name, std::shared_ptr const &h, - Context ctx = Context()); - - /** \brief Releases the Bucket, decrementing its reference count. - * - * This does not free any resources. To remove the Bucket%'s metadata and free - * its stored Blob%s, see Bucket::Destroy. - */ - ~Bucket(); - - /** \brief Get the user-facing name of the Bucket. - * - * \return The name of this Bucket. - */ - std::string GetName() const; - - /** \brief Get the internal ID of the bucket. - * - * The ID is the internal representation of the Bucket%'s name. - * - * \return The internal Bucket ID. - */ - u64 GetId() const; - - /** \brief Return true if the Bucket is valid. - * - * A valid Bucket is one that was successfully created, contains metadata - * entries, has a valid ID, and has not been destroyed. An invalid Bucket - * cannot be used. - * - * \return \bool{the Bucket is valid} - */ - bool IsValid() const; - - /** \brief Return the total size in bytes of all Blob%s in this Bucket. - * - * \return The total size in bytes of all Blob%s in this Bucket. - */ - size_t GetTotalBlobSize(); - - /** \brief Put a Blob in this Bucket. - * - * Uses the Bucket's saved Context. - * - * \param name The name of the Blob to put. - * \param data The Blob data. - * - * \return \status - */ - template - Status Put(const std::string &name, const std::vector &data); - - /** \brief Put a Blob in this Bucket using context. - * - * \param name BLOB name - * \param data BLOB data - * \param ctx context - */ - template - Status Put(const std::string &name, const std::vector &data, Context &ctx); - - /** - * \brief Put a Blob in this Bucket. - * - * \param name The name of the Blob to Put - * \param data The Blob's data. - * \param size The size of the Blob in bytes. - * - * \return \status - * - * \pre The Bucket must be valid. - * \pre The length of \p name in bytes must not exceed - * hermes::api::kMaxBlobNameSize. - * \pre The Blob buffer \p data must not be \c nullptr unless \p size is 0. - * - * \return \status - */ - Status Put(const std::string &name, const u8 *data, size_t size); - - /** - * \overload - * \param name BLOB name - * \param data BLOB data - * \param size BLOB size - * \param ctx context - */ - Status Put(const std::string &name, const u8 *data, size_t size, - const Context &ctx); - - /** \brief Put a vector of Blob%s. - * - * \param names 1 or more names, each of which is no longer than - * kMaxBlobNameSize bytes. - * \param blobs 1 or more Blob%s. - * - * \pre The length of \p names and \p blobs should be equal. - * - * \return \status - */ - template - Status Put(const std::vector &names, - const std::vector> &blobs); - - /** \overload - * - * \param names BLOB names - * \param blobs BLOB data - * \param ctx context - */ - template - Status Put(const std::vector &names, - const std::vector> &blobs, const Context &ctx); - - /** \brief Get the size in bytes of the Blob referred to by \p name. - * - * \param name The name of the Blob to query. - * \param ctx context - */ - size_t GetBlobSize(const std::string &name, const Context &ctx); - - /** \overload - * - * \param arena An Arena backed by allocated memory. - * \param name The name of the Blob to query. - * \param ctx context - */ - size_t GetBlobSize(const std::string &name, const Context &ctx); - - /** \brief Get a blob from this Bucket. - * - * If if the size of \p user_blob is 0, return the minimum buffer size needed - * to contain the Blob \p name, otherwise copy \p user_blob.size() bytes to \p - * user_blob and return the number of bytes copied. - * - * \param name The name of the Blob to get. - * \param user_blob User-provided storage for the retrieved Blob. - * - * \return The size in bytes of the Blob. - */ - size_t Get(const std::string &name, Blob &user_blob); - - /** \overload - * - * \param name The name of the Blob to get. - * \param user_blob User-provided storage for the retrieved Blob. - * \param ctx context - */ - size_t Get(const std::string &name, Blob &user_blob, const Context &ctx); - - /** \brief Retrieve multiple Blob%s in one call. - * - * \param names A list of names of the Blob%s to get. - * \param blobs User-provided storage for the retrieved Blob%s. - * \param \ctx{Get} - * - * \return The sizes in bytes of the Blob%s. - * - */ - std::vector Get(const std::vector &names, - std::vector &blobs, const Context &ctx); - - /** \overload - * - */ - size_t Get(const std::string &name, void *user_blob, size_t blob_size, - const Context &ctx); - - /** \brief Given an ordering of Blob%s, retrieves the Blob at index \p - * blob_index + 1. - * - * By default Blob%s are arranged in the order in which they were Put. If - * user_blob.size() == 0, return the minimum buffer size needed. If - * user_blob.size() > 0, copy user_blob.size() bytes to user_blob and return - * user_blob.size() - * - * \param blob_index The starting index. - * \param user_blob User-provided memory for the Blob. - * - * \return The size in bytes of the retrieved Blob. - */ - size_t GetNext(u64 blob_index, Blob &user_blob); - - /** \overload - * - * \param blob_index The starting index. - * \param user_blob User-provided memory for the Blob. - * \param ctx context - */ - size_t GetNext(u64 blob_index, Blob &user_blob, const Context &ctx); - - /** \overload - * - * \param blob_index The starting index. - * \param user_blob User-provided memory for the Blob. - * \param blob_size Blob size - * \param ctx context - */ - size_t GetNext(u64 blob_index, void *user_blob, size_t blob_size, - const Context &ctx); - - // TODO(chogan): - /** \brief Retrieves multiple blobs from the Bucket. - * - * The Blobs retrieved are the next ones from the passed blob_index - */ - std::vector GetNext(u64 blob_index, u64 count, - std::vector &blobs, const Context &ctx); - - /** \brief Get Blob%(s) from this Bucket according to a predicate. - * - * \todo Not implemented yet. - * - * \return \status - */ - template - Status GetV(void *user_blob, Predicate pred, Context &ctx); - - /** \brief Delete a Blob from this Bucket. - * - * \param name The name of the Blob to delete. - * - * \return \status - */ - Status DeleteBlob(const std::string &name); - - /** \overload - * - * \param name The name of the Blob to delete. - * \param ctx context - */ - Status DeleteBlob(const std::string &name, const Context &ctx); - - /** \brief Rename a Blob in this Bucket. - * - * \param old_name The Blob to rename. - * \param new_name The desired new name of the Blob. - * - * \pre The size in bytes of \p new_name must be <= to kMaxBlobNameSize. - * - * \return \status - */ - Status RenameBlob(const std::string &old_name, const std::string &new_name); - - /** \overload - * - * \param old_name The Blob to rename. - * \param new_name The desired new name of the Blob. - * \param ctx context - */ - Status RenameBlob(const std::string &old_name, const std::string &new_name, - const Context &ctx); - - /** \brief Returns true if the Bucket contains a Blob called \p name. - * - * \param name The name of the Blob to check. - * - * \return \bool{the Blob \p name is in this Bucket} - */ - bool ContainsBlob(const std::string &name); - - /** \brief Return true if the Blob \p name is in swap space. - * - * \param name The name of the Blob to check. - * - * \return \bool{the Blob called \p name in this Bucket is in swap space} - */ - bool BlobIsInSwap(const std::string &name); - - /** \brief Get a list of blob names filtered by \p pred. - * - * \todo Not implemented yet. - */ - template - std::vector GetBlobNames(Predicate pred, Context &ctx); - - /** \brief Rename this Bucket. - * - * \param new_name A new name for the Bucket. - * - * \pre The length of \p new_name in bytes should be less than - * #kMaxBucketNameSize. - * - * \return \status - */ - Status Rename(const std::string &new_name); - - /** \overload - * - * \param new_name A new name for the Bucket. - * \param ctx context - */ - Status Rename(const std::string &new_name, const Context &ctx); - - /** \brief Save this Bucket%'s Blob%s to persistent storage. - * - * The blobs are written in the same order in which they were \p Put. - * - * \param file_name The name of the file to persist the Blob's to. - * - * \return \status - */ - Status Persist(const std::string &file_name); - - /** \overload - * \param file_name The name of the file to persist the Blob's to. - * \param ctx context - */ - Status Persist(const std::string &file_name, const Context &ctx); - - /** - * \brief Allign blob_name's access speed to its importance. - * - * \param blob_name The name of the Blob to organize. - * - * \param epsilon - * The threshold within which the Blob's access time should match its - * importance. Constraint: 0 < epsilon <= 1. - * - * \param custom_importance - * A measure of importance that overrides the internal importance of a Blob. - * Constraint: 0 <= custom_importance <= 1, where 1 signifies the most - * important Blob. By default the internal, statistics-based measure of - * importance is used. - */ - void OrganizeBlob(const std::string &blob_name, f32 epsilon, - f32 custom_importance = -1.f); - - /** \brief Release this Bucket. - * - * This function simply decrements the refcount to this Bucket in the Hermes - * metadata. To free resources associated with this Bucket, call - * Bucket::Destroy. - * - * \return \status - */ - Status Release(); - - /** \overload - * - * \param \ctx{call} - */ - Status Release(const Context &ctx); - - /** \brief Destroy this Bucket. - * - * Deletes all metadata and Blob's associated with this Bucket. - * - * \pre The Bucket must have a reference count of 1. Other ranks must first - * Bucket::Close the Bucket. - * - * \return \status - */ - Status Destroy(); - - /** \overload - * - * \param \ctx{call}. - */ - Status Destroy(const Context &ctx); - - private: - /** \brief Internal version of Put, called by all overloads. - * - * \return \status - */ - template - Status PutInternal(const std::vector &names, - const std::vector &sizes, - const std::vector> &blobs, - const Context &ctx); - /** \brief Low-level version of Put. - * - * \return \status - */ - template - Status PlaceBlobs(std::vector &schemas, - const std::vector> &blobs, - const std::vector &names, const Context &ctx); -}; - -template -Status Bucket::Put(const std::string &name, const std::vector &data, - Context &ctx) { - Status result = Put(name, (u8 *)data.data(), data.size() * sizeof(T), ctx); - - return result; -} - -template -Status Bucket::Put(const std::string &name, const std::vector &data) { - Status result = Put(name, data, ctx_); - - return result; -} - -template -Status Bucket::PlaceBlobs(std::vector &schemas, - const std::vector> &blobs, - const std::vector &names, - const Context &ctx) { - Status result; - - for (size_t i = 0; i < schemas.size(); ++i) { - PlacementSchema &schema = schemas[i]; - hermes::Blob blob = {}; - blob.data = (u8 *)blobs[i].data(); - blob.size = blobs[i].size() * sizeof(T); - LOG(INFO) << "Attaching blob '" << names[i] << "' to Bucket '" << name_ - << "'" << std::endl; - result = PlaceBlob(&hermes_->context_, &hermes_->rpc_, schema, blob, - names[i], id_, ctx); - if (result.Failed()) { - // TODO(chogan): Need to return a std::vector - break; - } - } - - return result; -} - -template -Status Bucket::Put(const std::vector &names, - const std::vector> &blobs) { - Status result = Put(names, blobs, ctx_); - - return result; -} - -template -Status Bucket::PutInternal(const std::vector &names, - const std::vector &sizes, - const std::vector> &blobs, - const Context &ctx) { - std::vector schemas; - HERMES_BEGIN_TIMED_BLOCK("CalculatePlacement"); - Status result = CalculatePlacement(&hermes_->context_, &hermes_->rpc_, sizes, - schemas, ctx); - HERMES_END_TIMED_BLOCK(); - - if (result.Succeeded()) { - result = PlaceBlobs(schemas, blobs, names, ctx); - } else { - LOG(ERROR) << result.Msg(); - } - - return result; -} - -template -Status Bucket::Put(const std::vector &names, - const std::vector> &blobs, - const Context &ctx) { - Status ret; - - for (auto &name : names) { - if (IsBlobNameTooLong(name)) { - ret = BLOB_NAME_TOO_LONG; - LOG(ERROR) << ret.Msg(); - return ret; - } - } - - if (blobs.size() == 0) { - ret = INVALID_BLOB; - LOG(ERROR) << ret.Msg(); - return ret; - } - - if (IsValid()) { - size_t num_blobs = blobs.size(); - std::vector sizes_in_bytes(num_blobs); - for (size_t i = 0; i < num_blobs; ++i) { - sizes_in_bytes[i] = blobs[i].size() * sizeof(T); - } - - if (ctx.rr_retry) { - int num_devices = - GetLocalSystemViewState(&hermes_->context_)->num_devices; - - for (int i = 0; i < num_devices; ++i) { - ret = PutInternal(names, sizes_in_bytes, blobs, ctx); - - if (ret.Failed()) { - RoundRobin rr_state; - int current = rr_state.GetCurrentDeviceIndex(); - rr_state.SetCurrentDeviceIndex((current + 1) % num_devices); - } else { - break; - } - } - } else { - ret = PutInternal(names, sizes_in_bytes, blobs, ctx); - } - } else { - ret = INVALID_BUCKET; - LOG(ERROR) << ret.Msg(); - return ret; - } - - return ret; -} - -} // namespace api -} // namespace hermes - -#endif // BUCKET_H_ diff --git a/src/api/hermes.cc b/src/api/hermes.cc deleted file mode 100644 index 3d8ef1fdb..000000000 --- a/src/api/hermes.cc +++ /dev/null @@ -1,447 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -#include -#include - -#include - -#include "utils.h" -#include "hermes.h" -#include "bucket.h" -#include "buffer_pool.h" -#include "buffer_pool_internal.h" -#include "metadata_management_internal.h" -#include "config_parser.h" -#include "prefetcher.h" -#include "singleton.h" -#include "communication_factory.h" -#include "rpc_factory.h" - -namespace hermes { - -namespace api { - -std::string GetVersion() { - std::string result(HERMES_VERSION_STRING); - - return result; -} - -int Context::default_buffer_organizer_retries; -PlacementPolicy Context::default_placement_policy; -bool Context::default_rr_split; - -Status RenameBucket(const std::string &old_name, - const std::string &new_name, - Context &ctx) { - (void)ctx; - Status ret; - - LOG(INFO) << "Renaming Bucket from " << old_name << " to " - << new_name << '\n'; - - return ret; -} - -Status TransferBlob(const Bucket &src_bkt, - const std::string &src_blob_name, - Bucket &dst_bkt, - const std::string &dst_blob_name, - Context &ctx) { - (void)src_bkt; - (void)dst_bkt; - (void)ctx; - Status ret; - - LOG(INFO) << "Transferring Blob from " << src_blob_name << " to " - << dst_blob_name << '\n'; - - HERMES_NOT_IMPLEMENTED_YET; - - return ret; -} - -bool Hermes::IsApplicationCore() { - bool result = comm_.proc_kind == ProcessKind::kApp; - - return result; -} - -bool Hermes::IsFirstRankOnNode() { - bool result = comm_.first_on_node; - - return result; -} - -void Hermes::AppBarrier() { - hermes::SubBarrier(&comm_); -} - -bool Hermes::BucketContainsBlob(const std::string &bucket_name, - const std::string &blob_name) { - BucketID bucket_id = GetBucketId(&context_, &rpc_, bucket_name.c_str()); - bool result = hermes::ContainsBlob(&context_, &rpc_, bucket_id, blob_name); - - return result; -} - -bool Hermes::BucketExists(const std::string &bucket_name) { - BucketID id = hermes::GetBucketId(&context_, &rpc_, bucket_name.c_str()); - bool result = !IsNullBucketId(id); - - return result; -} - -int Hermes::GetProcessRank() { - int result = comm_.sub_proc_id; - - return result; -} - -int Hermes::GetNodeId() { - int result = comm_.node_id; - - return result; -} - -int Hermes::GetNumProcesses() { - int result = comm_.app_size; - - return result; -} - -void *Hermes::GetAppCommunicator() { - void *result = hermes::GetAppCommunicator(&comm_); - - return result; -} - -void Hermes::Finalize(bool force_rpc_shutdown) { - hermes::Finalize(&context_, &comm_, &rpc_, shmem_name_.c_str(), &trans_arena_, - IsApplicationCore(), force_rpc_shutdown); - is_initialized = false; -} - -void Hermes::FinalizeClient(bool stop_daemon) { - hermes::FinalizeClient(&context_, &rpc_, &comm_, &trans_arena_, stop_daemon); -} - -void Hermes::RemoteFinalize() { - hermes::RpcCall(&rpc_, rpc_.node_id, "RemoteFinalize"); -} - -void Hermes::RunDaemon() { - hermes::RunDaemon(&context_, &rpc_, &comm_, &trans_arena_, - shmem_name_.c_str()); -} - -} // namespace api - -/** get hosts from \a host_file file */ -std::vector GetHostsFromFile(const std::string &host_file) { - std::vector result; - std::fstream file; - LOG(INFO) << "Reading hosts from " << host_file; - - file.open(host_file.c_str(), std::ios::in); - if (file.is_open()) { - std::string file_line; - while (getline(file, file_line)) { - if (!file_line.empty()) { - result.emplace_back(file_line); - } - } - } else { - LOG(FATAL) << "Failed to open host file " << host_file; - } - file.close(); - - return result; -} - -/** push host names */ -void PushHostNames(Arena *arenas, RpcContext *rpc, - const std::vector &host_names, - MetadataManager *mdm, u8 *shmem_base) { - rpc->host_names = PushArray(&arenas[kArenaType_MetaData], - host_names.size()); - for (size_t i = 0; i < host_names.size(); ++i) { - char *host_name_mem = PushArray(&arenas[kArenaType_MetaData], - host_names[i].size()); - MakeShmemString(&rpc->host_names[i], (u8 *)host_name_mem, host_names[i]); - } - mdm->host_names_offset = (u8 *)rpc->host_names - (u8 *)shmem_base; -} - -/** initialize Hermes core */ -SharedMemoryContext InitHermesCore(Config *config, CommunicationContext *comm, - ArenaInfo *arena_info, Arena *arenas, - RpcContext *rpc) { - size_t shmem_size = (arena_info->total - - arena_info->sizes[kArenaType_Transient]); - u8 *shmem_base = InitSharedMemory(config->buffer_pool_shmem_name, shmem_size); - LOG(INFO) << "HERMES CORE" << std::endl; - - // NOTE(chogan): Initialize shared arenas - ptrdiff_t base_offset = 0; - for (int i = 0; i < kArenaType_Count; ++i) { - if (i == kArenaType_Transient) { - // NOTE(chogan): Transient arena exists per rank, not in shared memory - continue; - } - size_t arena_size = arena_info->sizes[i]; - InitArena(&arenas[i], arena_size, shmem_base + base_offset); - base_offset += arena_size; - } - - SharedMemoryContext context = {}; - context.shm_base = shmem_base; - context.shm_size = shmem_size; - context.buffer_pool_offset = InitBufferPool(context.shm_base, - &arenas[kArenaType_BufferPool], - &arenas[kArenaType_Transient], - comm->node_id, config); - - MetadataManager *mdm = - PushClearedStruct(&arenas[kArenaType_MetaData]); - context.metadata_manager_offset = (u8 *)mdm - (u8 *)shmem_base; - - rpc->state = CreateRpcState(&arenas[kArenaType_MetaData]); - mdm->rpc_state_offset = (u8 *)rpc->state - shmem_base; - - if (rpc->use_host_file) { - std::vector host_names = - GetHostsFromFile(config->rpc_server_host_file); - CHECK_EQ(host_names.size(), rpc->num_nodes); - PushHostNames(arenas, rpc, host_names, mdm, shmem_base); - } else { - PushHostNames(arenas, rpc, config->host_names, mdm, shmem_base); - } - InitMetadataManager(mdm, rpc, &arenas[kArenaType_MetaData], config); - InitMetadataStorage(&context, mdm, &arenas[kArenaType_MetaData], config); - - ShmemClientInfo *client_info = (ShmemClientInfo *)shmem_base; - client_info->mdm_offset = context.metadata_manager_offset; - - return context; -} - -// TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 -#if 0 -static void InitGlog() { - FLAGS_logtostderr = 1; - const char kMinLogLevel[] = "GLOG_minloglevel"; - char *min_log_level = getenv(kMinLogLevel); - - if (!min_log_level) { - FLAGS_minloglevel = 0; - } - - FLAGS_v = 0; - - google::InitGoogleLogging("hermes"); -} -#endif - -namespace api { - -/** get arena information from \a config configuration */ -ArenaInfo GetArenaInfo(Config *config) { - size_t page_size = sysconf(_SC_PAGESIZE); - // NOTE(chogan): Assumes first Device is RAM - size_t total_hermes_memory = RoundDownToMultiple(config->capacities[0], - page_size); - size_t total_pages = total_hermes_memory / page_size; - size_t pages_left = total_pages; - - ArenaInfo result = {}; - - for (int i = kArenaType_Count - 1; i > kArenaType_BufferPool; --i) { - size_t desired_pages = - std::floor(config->arena_percentages[i] * total_pages); - // NOTE(chogan): Each arena gets 1 page at minimum - size_t pages = std::max(desired_pages, 1UL); - pages_left -= pages; - size_t num_bytes = pages * page_size; - result.sizes[i] = num_bytes; - result.total += num_bytes; - } - - if (pages_left == 0) { - // TODO(chogan): @errorhandling - HERMES_NOT_IMPLEMENTED_YET; - } - - // NOTE(chogan): BufferPool Arena gets remainder of pages - result.sizes[kArenaType_BufferPool] = pages_left * page_size; - result.total += result.sizes[kArenaType_BufferPool]; - - return result; -} - -/** boostrap shared memory */ -void Hermes::BootstrapSharedMemory(bool is_daemon, bool is_adapter) { - ArenaInfo arena_info = GetArenaInfo(config); - // NOTE(chogan): The buffering capacity for the RAM Device is the size of the - // BufferPool Arena - config_->capacities[0] = arena_info.sizes[kArenaType_BufferPool]; - InitRpcContext(rpc, comm->num_nodes, comm->node_id, config); - - SharedMemoryContext result = {}; - if (comm->proc_kind == ProcessKind::kHermes && comm->first_on_node) { - result = InitHermesCore(config, comm, &arena_info, arenas, rpc); - } -} - -Hermes::Hermes(Config *config, bool is_daemon, bool is_adapter) : - config_(config) { - // TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 - // InitGlog(); - - std::string base_shmem_name(config->buffer_pool_shmem_name); - MakeFullShmemName(config->buffer_pool_shmem_name, base_shmem_name.c_str()); - - // TODO(chogan): Do we need a transfer window arena? We can probably just use - // the transient arena for this. - comm_ = CommunicationFactory::Get(CommunicationType::kMpi); - SharedMemoryContext context = - BootstrapSharedMemory(config, is_daemon, is_adapter); - rpc_ = RpcFactory::Get(RpcType::kThallium); - - WorldBarrier(comm_); - std::shared_ptr result = nullptr; - - if (comm.proc_kind == ProcessKind::kHermes) { - result = std::make_shared(context); - result->shmem_name_ = std::string(config->buffer_pool_shmem_name); - } else { - context = GetSharedMemoryContext(config->buffer_pool_shmem_name); - SubBarrier(&comm); - result = std::make_shared(context); - // NOTE(chogan): Give every App process a valid pointer to the internal RPC - // state in shared memory - MetadataManager *mdm = GetMetadataManagerFromContext(&context); - rpc.state = (void *)(context.shm_base + mdm->rpc_state_offset); - rpc.host_names = - (ShmemString *)((u8 *)context.shm_base + mdm->host_names_offset); - } - - InitFilesForBuffering(&context, comm); - - WorldBarrier(&comm); - - rpc.node_id = comm.node_id; - rpc.num_nodes = comm.num_nodes; - - result->comm_ = comm; - result->context_ = context; - result->rpc_ = rpc; - - // NOTE(chogan): The RPC servers have to be started here because they need to - // save a reference to the context and rpc instances that are members of the - // Hermes instance. - if (comm.proc_kind == ProcessKind::kHermes) { - std::string rpc_server_addr = - result->rpc_.GetRpcAddress(config, result->rpc_.node_id, - config->rpc_port); - std::string bo_address = - result->rpc_.GetRpcAddress(config, result->rpc_.node_id, - config->buffer_organizer_port); - - result->rpc_.StartServer(&result->context_, &result->rpc_, - &result->trans_arena_, rpc_server_addr.c_str(), - config->rpc_num_threads); - - StartBufferOrganizer(&result->context_, &result->rpc_, - &result->trans_arena_, bo_address.c_str(), - config->bo_num_threads, config->buffer_organizer_port); - - auto prefetcher = Singleton::GetInstance(); - prefetcher->SetHermes(result); - StartPrefetcher(&result->context_, &result->rpc_, - &result->trans_arena_, 10); - - double sleep_ms = config->system_view_state_update_interval_ms; - StartGlobalSystemViewStateUpdateThread(&result->context_, &result->rpc_, - &result->trans_arena_, sleep_ms); - } - - WorldBarrier(&comm); - - api::Context::default_buffer_organizer_retries = - config->num_buffer_organizer_retries; - api::Context::default_placement_policy = config->default_placement_policy; - api::Context::default_rr_split = config->default_rr_split; - RoundRobin::InitDevices(config, result); - - InitRpcClients(&result->rpc_); - - // NOTE(chogan): Can only initialize the neighborhood Targets once the RPC - // clients have been initialized. - InitNeighborhoodTargets(&result->context_, &result->rpc_); - - result->is_initialized = true; - - WorldBarrier(&comm); - - return result; -} - -std::shared_ptr InitHermes(const char *config_file, bool is_daemon, - bool is_adapter) { - u16 endian_test = 0x1; - char *endian_ptr = (char *)&endian_test; - if (endian_ptr[0] != 1) { - LOG(FATAL) << "Big endian machines not supported yet." << std::endl; - } - - LOG(INFO) << "Initializing hermes config" << std::endl; - - hermes::Config config = {}; - hermes::InitConfig(&config, config_file); - std::shared_ptr result = InitHermes(&config, is_daemon, is_adapter); - - LOG(INFO) << "Initialized hermes config" << std::endl; - - return result; -} - -} // namespace api - -std::shared_ptr InitHermes(Config *config, bool is_daemon, - bool is_adapter) { - return std::make_shared(config, is_daemon, is_adapter); -} - -std::shared_ptr InitHermesClient(const char *config_file) { - std::shared_ptr result = - api::InitHermes(config_file, false, true); - - return result; -} - -std::shared_ptr InitHermesDaemon(char *config_file) { - std::shared_ptr result = api::InitHermes(config_file, true); - - return result; -} - -std::shared_ptr InitHermesDaemon(Config *config) { - std::shared_ptr result = InitHermes(config, true, false); - - return result; -} - -} // namespace hermes diff --git a/src/api/hermes.h b/src/api/hermes.h index d2fe2c7b6..8011ef909 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -1,260 +1,81 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +// +// Created by lukemartinlogan on 12/2/22. +// -/** - * \mainpage Welcome to Hermes! - * - * \section sec_coordinates Important Coordinates - * - * - GitHub - * - */ +#ifndef HERMES_SRC_API_HERMES_H_ +#define HERMES_SRC_API_HERMES_H_ -#ifndef HERMES_H_ -#define HERMES_H_ +#include "config.h" -#include +namespace hermes::api { -#include -#include +const char* kHermesConf = "HERMES_CONF"; +const char* kHermesClientConf = "HERMES_CLIENT_CONF"; -#include "buffer_pool.h" -#include "hermes_types.h" -#include "metadata_management.h" -#include "rpc.h" - -/** \file hermes.h */ - -namespace hermes { -namespace api { - -/** \brief Return the (semantic versioning compatible) version of Hermes. - * - * \return A string in the form MAJOR.MINOR.PATCH - */ -std::string GetVersion(); +enum class HermesType { + kDaemon, + kClient, + kColocated +}; -/** Class representing an instance of a Hermes buffering system. */ class Hermes { public: - /** \bool{Hermes is initialized} */ - bool is_initialized; - - // TODO(chogan): Temporarily public to facilitate iterative development. - Config *config_; - hermes::SharedMemoryContext context_; /**< shared memory context */ - std::unique_ptr comm_; /**< communication context */ - std::unique_ptr rpc_; /**< remote procedure call context */ - /** The name of the shared memory segment in which all Hermes data is - * stored. - */ - std::string shmem_name_; - /** The name of the primary RPC server. */ - std::string rpc_server_name_; - - Hermes() {} - - /** - * Constructor - * */ - - Hermes(Config *config, bool is_daemon, bool is_adapter); - - /** \brief Return \bool{this rank is an application core} - * - * An application core is a core or rank on which user code runs as opposed to - * the Hermes core (or rank) which only runs Hermes services. - * - * \return \bool{this rank is an application core} - */ - bool IsApplicationCore(); - - /** \brief Returns \bool{this is the first MPI rank on this node} - * - * Hermes assigns numeric IDs to each rank. The first rank on the node is the - * lowest ID on that node. - * - * \return \bool{this is the first MPI rank on this node} - */ - bool IsFirstRankOnNode(); - - /** \brief A barrier across all application processes. - * - * Like MPI_Barrier but only involves application ranks. - */ - void AppBarrier(); - - /** \brief Returns the rank of this process. - * - * Hermes assigns each application core a unique rank. - * - * \return The rank of this process. - */ - int GetProcessRank(); - - /** \brief Return ID of the node this process is running on. - * - * Hermes assigns each node a numeric ID. - * - * \return The node's ID. - */ - int GetNodeId(); - - /** \brief Returns the total number of application processes. - * - * Does not count Hermes processes. - * - * \return The number of application processes. - */ - int GetNumProcesses(); - - /** \brief Get an application communicator handle. - * - * The handle can be cast to the appropriate type for the communication - * backend and used in the backend's API calls. For example, when using the - * MPI communication backend (the default), this function returns a pointer to - * an MPI_Comm object, which can then be used in any MPI call. - * - * \return A void pointer to a communicator handle. - */ - void *GetAppCommunicator(); + HermesType mode_; + Config config_; - /** \brief Shutdown Hermes. - * - * This should be called by every process (application and Hermes cores) - * before shutting down the communication backend (e.g., MPI_Finalize). - * - * \param force_rpc_shutdown This should be \c true if Hermes was initialized - * as a daemon. - */ - void Finalize(bool force_rpc_shutdown = false); - - /** \brief Shutdown application cores. - * - * To be called from application cores that were started separately from a - * Hermes daemon. Normally this is called from adapters. - * - * \param stop_daemon By default this function will stop the daemon this - * client is connected to. Passing \c false here will keep it alive. - */ - void FinalizeClient(bool stop_daemon = true); - - /** \todo Is this still necessary? - * - */ - void RemoteFinalize(); - - /** \brief Starts a Hermes daemon. - * - * Starts all Hermes services, then waits on the main thread to be finalized. - * - * \pre The Hermes instance must be initialized with InitHermesDaemon. - */ - void RunDaemon(); - - /** \brief Check if a given Bucket contains a Blob. - * - * \param bucket_name The name of the Bucket to check. - * \param blob_name The name of the Blob to check. - * - * \return \bool{the bucket \p bucket_name contains the Blob \p blob_name} - */ - bool BucketContainsBlob(const std::string &bucket_name, - const std::string &blob_name); - - /** \brief Returns true if \p bucket_name exists in this Hermes instance. - * - * \param bucket_name The name of the Bucket to check. - * - * \return \bool{\p bucket_name exists in this Hermes instance} - */ - bool BucketExists(const std::string &bucket_name); + public: + Hermes() = default; + + void Init(HermesType mode, std::string config_path) { + // Load the Hermes Configuration + if (config_path.size() == 0) { + config_path = getenv(kHermesConf); + } + InitConfig(&config_, config_path.c_str()); + + mode_ = mode; + switch (mode) { + case HermesType::kDaemon: { + InitDaemon(); + break; + } + case HermesType::kClient: { + InitClient(); + break; + } + case HermesType::kColocated: { + InitColocated(); + break; + } + } + } + + void Finalize() { + } + + void RunDaemon() { + } + + private: + void InitDaemon() { + } + + void InitClient() { + } + + void InitColocated() { + } + + void FinalizeDaemon() { + } + + void FinalizeClient() { + } + + void FinalizeColocated() { + } }; -class Bucket; - -/** Renames a bucket referred to by name only */ -Status RenameBucket(const std::string &old_name, const std::string &new_name, - Context &ctx); - -/** \todo Not implemented yet. */ -Status TransferBlob(const Bucket &src_bkt, const std::string &src_blob_name, - Bucket &dst_bkt, const std::string &dst_blob_name, - Context &ctx); - -/** \brief Initialize an instance of Hermes. - * - * \param config_file The (relative or absolute) path to a hermes configuration - * file - * \param is_daemon \c true if initializing this Hermes instance as a daemon. - * \param is_adapter \c true if initializing this Hermes instance as an adapter, - * or client to an existing daemon. - * - * \pre Only one of \p is_daemon and \p is_adapter can be \c true. - * - * \return An initialized Hermes instance. - */ -std::shared_ptr InitHermes(const char *config_file = NULL, - bool is_daemon = false, - bool is_adapter = false); - -} // namespace api - -/** \overload - * - * Allows programatically generating configurations. - * - * \param config a pointer to configuration - * \param is_daemon a flag to run Hermes as a daemon - * \param is_adapter a flag to run Hermes in adapter mode - * - * \return An initialized Hermes instance. - */ -std::shared_ptr InitHermes(Config *config, bool is_daemon = false, - bool is_adapter = false); - -/** \brief Initialize a Hermes instance as a daemon. - * - * A Hermes daemon is one or more processes (one per node) that handle all - * Hermes background services. This includes RPC servers, thread pools, buffer - * organization, and SystemViewState updates. A daemon is necessary in workflows - * that involve 2 or more applications sharing buffered data. Without a daemon, - * (i.e., co-deploying Hermes services with an application) the lifetime of - * Hermes is tied to the app. - * - * \param config_file The (relative or absolute) path to a hermes configuration - * file - * - * \return An initialized Hermes instance. - */ -std::shared_ptr InitHermesDaemon(char *config_file = NULL); - -/** \overload - * - * \param config A valid Config. - */ -std::shared_ptr InitHermesDaemon(Config *config); - -/** \brief Initialize a Hermes instance as a client or adapter. - * - * \param config_file The (relative or absolute) path to a hermes configuration - * file - * - * \pre An existing Hermes daemon must already be running. - * - * \return An initialized Hermes instance. - */ -std::shared_ptr InitHermesClient(const char *config_file = NULL); - -} // namespace hermes +} -#endif // HERMES_H_ +#endif // HERMES_SRC_API_HERMES_H_ diff --git a/src/api/traits.cc b/src/api/traits.cc deleted file mode 100644 index c18be8d0e..000000000 --- a/src/api/traits.cc +++ /dev/null @@ -1,146 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "traits.h" - -#include - -#include "buffer_organizer.h" -#include "metadata_management_internal.h" - -namespace hermes { -namespace api { -Trait::Trait(TraitID id, const std::vector &conflict_traits, - TraitType type) - : id(id), - conflict_traits(conflict_traits), - type(type), - onAttachFn(nullptr), - onDetachFn(nullptr), - onLinkFn(nullptr), - onUnlinkFn(nullptr) {} - -PersistTrait::PersistTrait(const std::string &filename, - const OffsetMap &offset_map, - bool synchronous) - : Trait(HERMES_PERSIST_TRAIT, std::vector(), TraitType::PERSIST), - filename(filename), offset_map(offset_map), synchronous(synchronous) { - onAttachFn = std::bind(&PersistTrait::onAttach, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3); - onDetachFn = std::bind(&PersistTrait::onDetach, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3); - onLinkFn = std::bind(&PersistTrait::onLink, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3); - onUnlinkFn = std::bind(&PersistTrait::onUnlink, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3); -} - -void PersistTrait::onAttach(HermesPtr hermes, VBucketID id, Trait *trait) { - SharedMemoryContext *context = &hermes->context_; - RpcContext *rpc = &hermes->rpc_; - - auto blob_ids = - GetBlobsFromVBucketInfo(context, rpc, id); - for (const auto& blob_id : blob_ids) { - TraitInput input; - auto bucket_id = GetBucketIdFromBlobId(context, rpc, blob_id); - input.bucket_name = GetBucketNameById(context, rpc, bucket_id); - input.blob_name = GetBlobNameFromId(context, rpc, blob_id); - onLink(hermes, input, trait); - } -} - -void PersistTrait::onDetach(HermesPtr hermes, VBucketID id, Trait *trait) { - (void)hermes; - (void)id; - (void)trait; -} - -void PersistTrait::onLink(HermesPtr hermes, TraitInput &input, Trait *trait) { - PersistTrait *persist_trait = (PersistTrait *)trait; - auto iter = persist_trait->offset_map.find(input.blob_name); - - if (iter != persist_trait->offset_map.end()) { - SharedMemoryContext *context = &hermes->context_; - RpcContext *rpc = &hermes->rpc_; - BucketID bucket_id = GetBucketId(context, rpc, input.bucket_name.c_str()); - BlobID blob_id = GetBlobId(context, rpc, input.blob_name, bucket_id, true); - std::string filename = persist_trait->filename; - u64 offset = iter->second; - - if (synchronous) { - FlushBlob(context, rpc, blob_id, filename, offset); - } else { - EnqueueFlushingTask(rpc, blob_id, filename, offset); - } - } -} - -void PersistTrait::onUnlink(HermesPtr hermes, TraitInput &input, Trait *trait) { - (void)hermes; - (void)input; - (void)trait; -} - -WriteOnlyTrait::WriteOnlyTrait() - : Trait(HERMES_WRITE_ONLY_TRAIT, std::vector(), TraitType::META) { - onAttachFn = std::bind(&WriteOnlyTrait::onAttach, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3); - onDetachFn = std::bind(&WriteOnlyTrait::onDetach, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3); - onLinkFn = std::bind(&WriteOnlyTrait::onLink, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3); - onUnlinkFn = std::bind(&WriteOnlyTrait::onUnlink, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3); -} - -void WriteOnlyTrait::onAttach(HermesPtr hermes, VBucketID id, Trait *trait) { - (void)hermes; - (void)id; - (void)trait; -} - -void WriteOnlyTrait::onDetach(HermesPtr hermes, VBucketID id, Trait *trait) { - (void)hermes; - (void)id; - (void)trait; -} - -void WriteOnlyTrait::onLink(HermesPtr hermes, TraitInput &input, Trait *trait) { - (void)trait; - - SharedMemoryContext *context = &hermes->context_; - RpcContext *rpc = &hermes->rpc_; - BucketID bucket_id = GetBucketId(context, rpc, input.bucket_name.c_str()); - f32 epsilon = 0.1; - f32 custom_importance = 0; - hermes::OrganizeBlob(context, rpc, bucket_id, input.blob_name, epsilon, - custom_importance); -} - -void WriteOnlyTrait::onUnlink(HermesPtr hermes, TraitInput &input, - Trait *trait) { - (void)hermes; - (void)input; - (void)trait; -} - -} // namespace api -} // namespace hermes diff --git a/src/api/traits.h b/src/api/traits.h deleted file mode 100644 index 2468d3d8e..000000000 --- a/src/api/traits.h +++ /dev/null @@ -1,152 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_TRAITS_H -#define HERMES_TRAITS_H - -#include - -#include "hermes.h" -#include "hermes_types.h" - -namespace hermes { -namespace api { - -#define HERMES_PERSIST_TRAIT 11 -#define HERMES_WRITE_ONLY_TRAIT 12 - -/** A blob's hosting bucket and blob names */ -struct BlobInfo { - /** The blob-hosting bucket name */ - std::string bucket_name; - /** The blob's name (in the bucket) */ - std::string blob_name; -}; - -typedef BlobInfo TraitInput; -struct Trait; -using HermesPtr = std::shared_ptr; - -// TODO(chogan): I don't think we need to pass a Trait* to these callbacks -// anymore. That is a relic of an old implementation. - -/** Callback for blob->vbucket link events */ -typedef std::function OnLinkCallback; -/** Callback for trait->vbucket attach events */ -typedef std::function OnAttachCallback; - -/** \brief Base class for Traits, which can attach functionality to VBuckets. - * - * To add functionality to a VBucket, inherit from this class and implement the - * various callbacks. - */ -struct Trait { - /** The trait's ID */ - TraitID id; - /** IDs of Traits whose functionality conflict with this Trait. */ - std::vector conflict_traits; - /** The trait's type. */ - TraitType type; - /** Callback for trait->vbucket attach events. */ - OnAttachCallback onAttachFn; - /** Callback for trait->vbucket detach events. */ - OnAttachCallback onDetachFn; - /** Callback for blob->vbucket link events. */ - OnLinkCallback onLinkFn; - /** Callback for blob- &conflict_traits, - TraitType type); -}; - -/** \brief Engable persisting a VBucket's linked Blobs to permanent - * storage. - * - */ -struct PersistTrait : public Trait { - /** The name of the file to flush the Blobs to. */ - std::string filename; - /** Maps Blob names to offsets within a file. */ - std::unordered_map offset_map; - /** \bool{flushing data should block until finished} */ - bool synchronous; - - /** offset map */ - using OffsetMap = std::unordered_map; - - /** Constructor */ - explicit PersistTrait(bool synchronous); - - /** Constructor with file name and offset map */ - explicit PersistTrait(const std::string &filename, - const OffsetMap &offset_map, bool synchronous = false); - - /** - * a binding function to run on attchment event - */ - void onAttach(HermesPtr hermes, VBucketID id, Trait *trait); - - /** \brief Currently a no-op. */ - void onDetach(HermesPtr hermes, VBucketID id, Trait *trait); - - /** - * a binding function to run on link event - */ - void onLink(HermesPtr hermes, TraitInput &input, Trait *trait); - - /** \brief Currently a no-op. */ - void onUnlink(HermesPtr hermes, TraitInput &input, Trait *trait); -}; - -/** \brief Marks the Blobs in a VBucket as write-only. - * - * If we know that certain Blobs are write-only, we can asynchronously and - * eagerly flush buffered data to the final destination. - * - */ -struct WriteOnlyTrait : public Trait { - /** */ - WriteOnlyTrait(); - - /** \brief Currently a no-op. */ - void onAttach(HermesPtr hermes, VBucketID id, Trait *trait); - - /** \brief Currently a no-op. */ - void onDetach(HermesPtr hermes, VBucketID id, Trait *trait); - - /** - * a binding function to run on link event - */ - void onLink(HermesPtr hermes, TraitInput &input, Trait *trait); - - /** \brief Currently a no-op. */ - void onUnlink(HermesPtr hermes, TraitInput &input, Trait *trait); -}; - -} // namespace api -} // namespace hermes - -#endif // HERMES_TRAITS_H diff --git a/src/api/vbucket.cc b/src/api/vbucket.cc deleted file mode 100644 index 90f1c8c3c..000000000 --- a/src/api/vbucket.cc +++ /dev/null @@ -1,407 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "vbucket.h" - -#include - -#include -#include - -#include "bucket.h" -#include "prefetcher.h" - -namespace hermes { - -namespace api { - -VBucket::VBucket(std::string initial_name, std::shared_ptr const &h, - Context ctx) - : name_(initial_name), - id_({{0, 0}}), - attached_traits_(), - hermes_(h), - ctx_(ctx) { - if (IsVBucketNameTooLong(name_)) { - id_.as_int = 0; - throw std::length_error("VBucket name exceeds maximum size of " + - std::to_string(kMaxVBucketNameSize)); - } else { - id_ = GetOrCreateVBucketId(&hermes_->context_, &hermes_->rpc_, name_); - if (!IsValid()) { - throw std::runtime_error("Could not open or create VBucket"); - } - } -} - -VBucket::~VBucket() { - if (IsValid()) { - Release(); - } -} - -bool VBucket::IsValid() const { - return !IsNullVBucketId(id_); -} - -std::string VBucket::GetName() const { - return this->name_; -} - -void VBucket::WaitForBackgroundFlush() { - AwaitAsyncFlushingTasks(&hermes_->context_, &hermes_->rpc_, id_); -} - -Status VBucket::Link(std::string blob_name, std::string bucket_name) { - Status result = Link(blob_name, bucket_name, ctx_); - - return result; -} - -Status VBucket::Link(std::string blob_name, std::string bucket_name, - Context& ctx) { - (void)ctx; - Status ret; - - LOG(INFO) << "Linking blob " << blob_name << " in bucket " << bucket_name - << " to VBucket " << name_ << '\n'; - - bool blob_exists = hermes_->BucketContainsBlob(bucket_name, blob_name); - - if (blob_exists) { - TraitInput input; - input.bucket_name = bucket_name; - input.blob_name = blob_name; - for (const auto& t : attached_traits_) { - if (t->onLinkFn != nullptr) { - t->onLinkFn(hermes_, input, t); - // TODO(hari): @errorhandling Check if linking was successful - } - } - - bool already_linked = ContainsBlob(blob_name, bucket_name); - if (!already_linked) { - AttachBlobToVBucket(&hermes_->context_, &hermes_->rpc_, blob_name.data(), - bucket_name.data(), id_); - } - } else { - ret = BLOB_NOT_IN_BUCKET; - LOG(ERROR) << ret.Msg(); - } - - return ret; -} - -Status VBucket::Unlink(std::string blob_name, std::string bucket_name) { - Status result = Unlink(blob_name, bucket_name, ctx_); - - return result; -} - -Status VBucket::Unlink(std::string blob_name, std::string bucket_name, - Context& ctx) { - (void)ctx; - Status ret; - - LOG(INFO) << "Unlinking blob " << blob_name << " in bucket " << bucket_name - << " from VBucket " << name_ << '\n'; - bool found = false; - auto blob_ids = - GetBlobsFromVBucketInfo(&hermes_->context_, &hermes_->rpc_, id_); - auto bucket_id = - GetBucketId(&hermes_->context_, &hermes_->rpc_, bucket_name.c_str()); - auto selected_blob_id = GetBlobId(&hermes_->context_, &hermes_->rpc_, - blob_name.c_str(), bucket_id); - for (hermes::BlobID& blob_id : blob_ids) { - if (selected_blob_id.as_int == blob_id.as_int) { - TraitInput input; - input.bucket_name = bucket_name; - input.blob_name = blob_name; - for (const auto& t : attached_traits_) { - if (t->onUnlinkFn != nullptr) { - t->onUnlinkFn(hermes_, input, t); - // TODO(hari): @errorhandling Check if unlinking was successful - } - } - RemoveBlobFromVBucketInfo(&hermes_->context_, &hermes_->rpc_, id_, - blob_name.c_str(), bucket_name.c_str()); - found = true; - break; - } - } - if (!found) { - ret = BLOB_NOT_LINKED_TO_VBUCKET; - LOG(ERROR) << ret.Msg(); - } - - return ret; -} - -bool VBucket::ContainsBlob(std::string blob_name, std::string bucket_name) { - bool ret = false; - - LOG(INFO) << "Checking if blob " << blob_name << " from bucket " - << bucket_name << " is in this VBucket " << name_ << '\n'; - - auto blob_ids = - GetBlobsFromVBucketInfo(&hermes_->context_, &hermes_->rpc_, id_); - auto bucket_id = - GetBucketId(&hermes_->context_, &hermes_->rpc_, bucket_name.c_str()); - auto selected_blob_id = GetBlobId(&hermes_->context_, &hermes_->rpc_, - blob_name.c_str(), bucket_id); - for (const auto& blob_id : blob_ids) { - if (selected_blob_id.as_int == blob_id.as_int) { - ret = true; - } - } - - return ret; -} - -size_t VBucket::Get(const std::string &name, Bucket &bkt, Blob &user_blob, - Context &ctx) { - size_t ret = Get(name, bkt, user_blob.data(), user_blob.size(), ctx); - - return ret; -} - -size_t VBucket::Get(const std::string &name, Bucket &bkt, Blob &user_blob) { - size_t result = Get(name, bkt, user_blob, ctx_); - - return result; -} - -size_t VBucket::Get(const std::string &name, Bucket &bkt, void *user_blob, - size_t blob_size, Context &ctx) { - bool is_size_query = false; - if (blob_size != 0) { - is_size_query = true; - } - - ctx.vbkt_id_ = id_; - size_t result = bkt.Get(name, user_blob, blob_size, ctx); - - if (!is_size_query) { - TraitInput input; - input.blob_name = name; - input.bucket_name = bkt.GetName(); - for (const auto& t : attached_traits_) { - if (t->onGetFn != nullptr) { - t->onGetFn(hermes_, input, t); - } - } - } - - return result; -} - -std::vector VBucket::GetLinks() { - Context ctx; - return GetLinks(ctx); -} - -std::vector VBucket::GetLinks(Context& ctx) { - (void)ctx; - LOG(INFO) << "Getting subset of links satisfying pred in VBucket " << name_ - << '\n'; - auto blob_ids = - GetBlobsFromVBucketInfo(&hermes_->context_, &hermes_->rpc_, id_); - auto blob_names = std::vector(); - for (const auto& blob_id : blob_ids) { - blob_names.push_back( - GetBlobNameFromId(&hermes_->context_, &hermes_->rpc_, blob_id)); - } - // TODO(hari): add filtering - return blob_names; -} - -Status VBucket::Attach(Trait* trait) { - Status result = Attach(trait, ctx_); - - return result; -} - -Status VBucket::Attach(Trait* trait, Context& ctx) { - (void)ctx; - Status ret; - - LOG(INFO) << "Attaching trait to VBucket " << name_ << '\n'; - Trait* selected_trait = NULL; - for (const auto& t : attached_traits_) { - if (t->id == trait->id) { - selected_trait = t; - break; - } - } - if (!selected_trait) { - Trait* t = static_cast(trait); - if (t->onAttachFn != nullptr) { - t->onAttachFn(hermes_, id_, trait); - // TODO(hari): @errorhandling Check if attach was successful - } - - attached_traits_.push_back(trait); - } else { - ret = TRAIT_EXISTS_ALREADY; - LOG(ERROR) << ret.Msg(); - } - - return ret; -} - -Status VBucket::Detach(Trait* trait) { - Status result = Detach(trait, ctx_); - - return result; -} - -Status VBucket::Detach(Trait* trait, Context& ctx) { - (void)ctx; - (void)trait; - Status ret; - - LOG(INFO) << "Detaching trait from VBucket " << name_ << '\n'; - - auto trait_iter = attached_traits_.begin(); - Trait* selected_trait = NULL; - auto selected_trait_iter = attached_traits_.begin(); - while (trait_iter != attached_traits_.end()) { - selected_trait = reinterpret_cast(&*trait_iter); - if (selected_trait->id == trait->id) { - selected_trait_iter = trait_iter; - break; - } else { - trait_iter++; - } - } - if (selected_trait) { - Trait* t = static_cast(trait); - if (t->onDetachFn != nullptr) { - t->onDetachFn(hermes_, id_, trait); - // TODO(hari): @errorhandling Check if detach was successful - } - - attached_traits_.erase(selected_trait_iter); - } else { - ret = TRAIT_NOT_VALID; - LOG(ERROR) << ret.Msg(); - } - - return ret; -} - -Trait *VBucket::GetTrait(TraitType type) { - Trait *result = 0; - for (Trait *trait : attached_traits_) { - if (trait && trait->type == type) { - result = trait; - break; - } - } - - return result; -} - -template -std::vector VBucket::GetTraits(Predicate pred, Context& ctx) { - (void)ctx; - - LOG(INFO) << "Getting the subset of attached traits satisfying pred in " - << "VBucket " << name_ << '\n'; - auto attached_traits = std::vector(); - // TODO(hari): add filtering based on predicate. - for (const auto& t : this->attached_traits_) { - attached_traits.push_back(t->id); - } - return attached_traits; -} - -Status VBucket::Release() { - Status result = Release(ctx_); - - return result; -} - -Status VBucket::Release(Context& ctx) { - (void)ctx; - Status ret; - - if (IsValid() && hermes_->is_initialized) { - LOG(INFO) << "Closing vbucket '" << name_ << "'" << std::endl; - DecrementRefcount(&hermes_->context_, &hermes_->rpc_, id_); - id_.as_int = 0; - } - return ret; -} - -Status VBucket::Destroy() { - Status result = Destroy(ctx_); - - return result; -} - -Status VBucket::Destroy(Context& ctx) { - (void)ctx; - Status result; - - if (IsValid()) { - // NOTE(chogan): Let all flushing tasks complete before destroying the - // VBucket. - WaitForBackgroundFlush(); - - SharedMemoryContext *context = &hermes_->context_; - RpcContext *rpc = &hermes_->rpc_; - - LOG(INFO) << "Destroying VBucket " << name_ << '\n'; - - auto blob_ids = GetBlobsFromVBucketInfo(context, rpc, id_); - - // NOTE(chogan): Call each Trait's unlink callback on each Blob - for (const auto& t : attached_traits_) { - for (const auto& blob_id : blob_ids) { - TraitInput input = {}; - BucketID bucket_id = GetBucketIdFromBlobId(context, rpc, blob_id); - if (!IsNullBucketId(bucket_id)) { - input.bucket_name = GetBucketNameById(context, rpc, bucket_id); - input.blob_name = GetBlobNameFromId(context, rpc, blob_id); - if (t->onUnlinkFn != nullptr) { - t->onUnlinkFn(hermes_, input, t); - // TODO(hari): @errorhandling Check if unlinking was successful - } - } - } - } - - // NOTE(chogan): Call each trait's onDetach callback - for (const auto& t : attached_traits_) { - if (t->onDetachFn != nullptr) { - TraitInput input = {}; - t->onDetachFn(hermes_, id_, t); - // TODO(hari): @errorhandling Check if detach was successful - } - } - - attached_traits_.clear(); - bool destroyed = DestroyVBucket(context, rpc, name_.c_str(), id_); - if (destroyed) { - id_.as_int = 0; - } else { - result = BUCKET_IN_USE; - LOG(ERROR) << result.Msg(); - } - } - - return result; -} - -} // namespace api -} // namespace hermes diff --git a/src/api/vbucket.h b/src/api/vbucket.h deleted file mode 100644 index 19974c84c..000000000 --- a/src/api/vbucket.h +++ /dev/null @@ -1,264 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef VBUCKET_H_ -#define VBUCKET_H_ - -#include - -#include -#include -#include -#include -#include - -#include "hermes.h" -#include "traits.h" - -namespace hermes { - -namespace api { - -/** - * Virtual buckets (VBucket%s) capture relationships between Blob%s - * across Bucket boundaries. - */ -class VBucket { - private: - /** The user-facing name of this VBucket. */ - std::string name_; - /** The internal ID of this VBucket. */ - VBucketID id_; - /** Traits attached to this vbucket. */ - std::list attached_traits_; - /** The Hermes instance this VBucket is stored in. */ - std::shared_ptr hermes_; - /** The Context for this VBucket. Overrides the global default Context. */ - Context ctx_; - - public: - /** \brief Create or open a VBucket. - * - * If the VBucket \p initial_name doesn't already exist, it is created and - * registered in Hermes. If it does exists, it is opened and its reference - * count is incremented. Once a VBucket is created, it can be opened on any - * rank or node. - * - * \param initial_name The desired name of the VBucket. - * \param hermes An initialized Hermes instance. - * \param \ctx{VBucket} - * - * \pre The Hermes instance \p hermes must be be initialized. - */ - VBucket(std::string initial_name, std::shared_ptr const &hermes, - Context ctx = Context()); - - /** \brief Close a VBucket. - * - * This does not delete the VBucket from Hermes, it merely decrements the - * reference count. To delete the VBucket and all associated metadata use - * VBucket::Destroy. - */ - ~VBucket(); - - /** \brief Return bool{this VBucket is valid} - * - * A VBucket is valid if it has a non-NULL ID, meaning it has been registered - * in the Hermes system. - * - * \return \bool{this VBucket is valid} - */ - bool IsValid() const; - - /** \brief Return the name of this VBucket. - * - * \return The name of this VBucket. - */ - std::string GetName() const; - - /** - * Blocks until all outstanding asynchronous flushing tasks associated with - * this VBucket are complete. - */ - void WaitForBackgroundFlush(); - - /** - * Link a Blob to this VBucket. - * - * Adds Blob \p blob_name in Bucket \p bucket_name to this VBucket's list of - * Blobs. Additional calls the Trait::OnLinkFn function on the Blob for each - * attached Trait. - * - * \param blob_name The name of the Blob to link. - * \param bucket_name The name of the Bucket containing the Blob to link. - * - * \return \status - */ - Status Link(std::string blob_name, std::string bucket_name); - - /** \overload - * - * \param blob_name The name of the Blob to link. - * \param bucket_name The name of the Bucket containing the Blob to link. - * \param ctx Currently unused. - */ - Status Link(std::string blob_name, std::string bucket_name, Context &ctx); - - /** - * Unlink a Blob from this VBucket. - * - * \param blob_name The name of the Blob to unlink. - * \param bucket_name The name of the Bucket containing the Blob to unlink. - * \param ctx context - * - * \return \status - */ - Status Unlink(std::string blob_name, std::string bucket_name, Context &ctx); - /** \todo Unlink */ - Status Unlink(std::string blob_name, std::string bucket_name); - - /** check if blob is in this vbucket */ - bool ContainsBlob(std::string blob_name, std::string bucket_name); - - /** Get a Blob, calling any OnGet callbacks of attached Traits. - * - * Exactly like Bucket::Get, except this function invokes the OnGet callback - * of any attached Traits. - */ - size_t Get(const std::string &name, Bucket &bkt, Blob &user_blob, - Context &ctx); - - /** Get a Blob without context. - */ - size_t Get(const std::string &name, Bucket &bkt, Blob &user_blob); - - /** Get a Blob with size and context. - */ - size_t Get(const std::string &name, Bucket &bkt, void *user_blob, - size_t blob_size, Context &ctx); - - /** get a blob on this bucket */ - /** - if user_blob.size() == 0 => return the minimum buffer size needed */ - /** - if user_blob.size() > 0 => copy user_blob.size() bytes */ - /** to user_blob and return user_blob.size() */ - /** use provides buffer */ - size_t Get(const std::string &name, Bucket *bkt, Blob &user_blob, - const Context &ctx); - - /** Get a blob on this bucket without context. */ - size_t Get(const std::string &name, Bucket *bkt, Blob &user_blob); - - /** - *\brief Retrieve a Blob into a user buffer. - */ - size_t Get(const std::string &name, Bucket *bkt, void *user_blob, - size_t blob_size, const Context &ctx); - - /** retrieves all blob links */ - std::vector GetLinks(); - - /** retrieves all blob links subject to a predicte in \a ctx */ - std::vector GetLinks(Context &ctx); - - /** \brief Attach a Trait to this VBucket. - * - * Calls the Trait::onAttachFn function of \p trait on each Blob that's linked - * to this VBucket. - * - * \param trait The Trait to attach. - * - * \return \status - */ - Status Attach(Trait *trait); - - /** \overload - * - * \param trait The Trait to attach. - * \param ctx Currently unused. - */ - Status Attach(Trait *trait, Context &ctx); - - /** \brief Detach a trait from this VBucket. - * - * \param trait The Trait to detach. - * - * \return \status - */ - Status Detach(Trait *trait); - - /** \overload - * - * \param trait The Trait to detach. - * \param ctx Currently unused. - */ - Status Detach(Trait *trait, Context &ctx); - - /** \brief Retrieves the subset of attached traits satisfying the Predicate \p - * pred. - * - * \todo \p pred is curently ignored and this function returns all attached - * traits. - * - * \param pred \todo - * \param ctx Currently unused; - */ - template - std::vector GetTraits(Predicate pred, Context &ctx); - - /** \brief Get's an attached Trait that matches \p type. - * - * \param type The type of Trait to retrieve. - * - * \return The first attached trait that matches \p type. - */ - Trait *GetTrait(TraitType type); - - /** \brief Release this vBucket. - * - * This function does not result in any Trait callbacks being invoked or any - * Blob links to be deleted. It simply decrements the reference count on this - * VBucket. A VBucket can only be destroyed (VBucket::Destroy) when it's - * reference count is 1. I.e., each rank that is not destroying the VBucket - * must release it. - * - * \return A Status. - */ - Status Release(); - - /** \overload - * - * \param ctx Currently unused. - */ - Status Release(Context &ctx); - - /** \brief Destroy this VBucket. - * - * Releases all resources associated with this VBucket. If it is opened again, - * it will be created from scratch. Unlinks all linked Blobs (which will - * invoke each attached Trait's Trait::onUnlinkFn function), and detaches all - * attached Traits, invoking Trait::onDetachFn. - * - * \return \status - */ - Status Destroy(); - - /** \overload - * - * \param ctx Currently unused. - */ - Status Destroy(Context &ctx); -}; // class VBucket - -} // namespace api -} // namespace hermes - -#endif // VBUCKET_H_ diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc deleted file mode 100644 index cabfaa2ef..000000000 --- a/src/buffer_organizer.cc +++ /dev/null @@ -1,841 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include "hermes.h" -#include "buffer_organizer.h" -#include "metadata_storage.h" -#include "data_placement_engine.h" - -namespace hermes { - -BufferOrganizer::BufferOrganizer(SharedMemoryContext *context, - RpcContext *rpc, int num_threads) : - context_(context), rpc_(rpc), pool(num_threads) {} - -bool operator==(const BufferInfo &lhs, const BufferInfo &rhs) { - return (lhs.id == rhs.id && lhs.size == rhs.size && - lhs.bandwidth_mbps == rhs.bandwidth_mbps); -} - -/** get buffer information locally */ -BufferInfo BufferOrganizer::LocalGetBufferInfo(BufferID buffer_id) { - BufferInfo result = {}; - - BufferHeader *header = GetHeaderByBufferId(context, buffer_id); - // TODO(chogan): Should probably use Targets to factor in remote devices. - // However, we currently don't distinguish between the bandwidth of a device - // and the same device accessed from a remote node. - Device *device = GetDeviceFromHeader(context, header); - - result.id = buffer_id; - result.bandwidth_mbps = device->bandwidth_mbps; - result.size = header->used; - - return result; -} - -/** get buffer information */ -BufferInfo BufferOrganizer::GetBufferInfo(BufferID buffer_id) { - BufferInfo result = {}; - u32 target_node = buffer_id.bits.node_id; - - if (target_node == rpc->node_id) { - result = LocalGetBufferInfo(context, buffer_id); - } else { - result = RpcCall(rpc, target_node, "RemoteGetBufferInfo", - buffer_id); - } - - return result; -} - -/** get information for multiple buffers */ -std::vector -BufferOrganizer::GetBufferInfo(const std::vector &buffer_ids) { - std::vector result(buffer_ids.size()); - - for (size_t i = 0; i < buffer_ids.size(); ++i) { - result[i] = GetBufferInfo(context, rpc, buffer_ids[i]); - } - - return result; -} - -/** normalize access score from \a raw-score using \a size_mb */ -f32 BufferOrganizer::NormalizeAccessScore(f32 raw_score, f32 size_mb) { - BufferPool *pool = GetBufferPoolFromContext(context); - - f32 min_seconds = size_mb * (1.0 / pool->max_device_bw_mbps); - f32 max_seconds = size_mb * (1.0 / pool->min_device_bw_mbps); - f32 range = max_seconds - min_seconds; - f32 adjusted_score = raw_score - min_seconds; - f32 result = 1.0 - (adjusted_score / range); - if (result < 0.0) result = 0.0; - if (result > 1.0) result = 1.0; - return result; -} - -f32 BufferOrganizer::ComputeBlobAccessScore( - const std::vector &buffer_info) { - f32 result = 0; - f32 raw_score = 0; - f32 total_blob_size_mb = 0; - - for (size_t i = 0; i < buffer_info.size(); ++i) { - f32 size_in_mb = BytesToMegabytes(buffer_info[i].size); - f32 seconds_per_mb = 1.0f / buffer_info[i].bandwidth_mbps; - f32 total_seconds = size_in_mb * seconds_per_mb; - - total_blob_size_mb += size_in_mb; - raw_score += total_seconds; - } - result = NormalizeAccessScore(context, raw_score, total_blob_size_mb); - - return result; -} - -/** sort buffer information */ -void BufferOrganizer::SortBufferInfo(std::vector &buffer_info, - bool increasing) { -#define HERMES_BUFFER_INFO_COMPARATOR(direction, comp) \ - auto direction##_buffer_info_comparator = \ - [](const BufferInfo &lhs, const BufferInfo &rhs) { \ - if (lhs.bandwidth_mbps == rhs.bandwidth_mbps) { \ - return lhs.size > rhs.size; \ - } \ - return lhs.bandwidth_mbps comp rhs.bandwidth_mbps; \ - }; - - if (increasing) { - // Sort first by bandwidth (descending), then by size (descending) - HERMES_BUFFER_INFO_COMPARATOR(increasing, >); - std::sort(buffer_info.begin(), buffer_info.end(), - increasing_buffer_info_comparator); - } else { - // Sort first by bandwidth (ascending), then by size (descending) - HERMES_BUFFER_INFO_COMPARATOR(decreasing, <); - std::sort(buffer_info.begin(), buffer_info.end(), - decreasing_buffer_info_comparator); - } - -#undef HERMES_BUFFER_INFO_COMPARATOR -} - -/** sort target information */ -void BufferOrganizer::SortTargetInfo(std::vector &target_info, - bool increasing) { - auto increasing_target_info_comparator = [](const TargetInfo &lhs, - const TargetInfo &rhs) { - return lhs.bandwidth_mbps > rhs.bandwidth_mbps; - }; - auto decreasing_target_info_comparator = [](const TargetInfo &lhs, - const TargetInfo &rhs) { - return lhs.bandwidth_mbps < rhs.bandwidth_mbps; - }; - - if (increasing) { - std::sort(target_info.begin(), target_info.end(), - increasing_target_info_comparator); - } else { - std::sort(target_info.begin(), target_info.end(), - decreasing_target_info_comparator); - } -} - -/** Local enqueue of buffer information */ -void BufferOrganizer::LocalEnqueueBoMove(const BoMoveList &moves, - BlobID blob_id, - BucketID bucket_id, - const std::string &internal_blob_name, - BoPriority priority) { - ThreadPool *pool = &context->bo->pool; - bool is_high_priority = priority == BoPriority::kHigh; - // NOTE(llogan): VLOG(1) -> LOG(INFO) - LOG(INFO) << "BufferOrganizer queuing Blob " << blob_id.as_int; - pool->run(std::bind(BoMove, context, rpc, moves, blob_id, bucket_id, - internal_blob_name), - is_high_priority); -} - -/** enqueue a move operation */ -void BufferOrganizer::EnqueueBoMove(const BoMoveList &moves, BlobID blob_id, - BucketID bucket_id, - const std::string &internal_name, - BoPriority priority) { - RpcCall(rpc, rpc->node_id, "BO::EnqueueBoMove", moves, blob_id, - bucket_id, internal_name, priority); -} - -/** - * copy a set of buffers into a set of new buffers. - * - * assumes all BufferIDs in destinations are local - * */ -void BufferOrganizer::BoMove(const BoMoveList &moves, - BlobID blob_id, BucketID bucket_id, - const std::string &internal_blob_name) { - // NOTE(llogan): VLOG(1) -> LOG(INFO) - LOG(INFO) << "Moving blob " - << internal_blob_name.substr(kBucketIdStringSize, std::string::npos) - << std::endl; - MetadataManager *mdm = GetMetadataManagerFromContext(context); - - bool got_lock = BeginReaderLock(&mdm->bucket_delete_lock); - if (got_lock && LocalLockBlob(context, blob_id)) { - auto warning_string = [](BufferID id) { - std::ostringstream ss; - ss << "BufferID" << id.as_int << " not found on this node\n"; - - return ss.str(); - }; - - std::vector replacement_ids; - std::vector replaced_ids; - - for (size_t move_index = 0; move_index < moves.size(); ++move_index) { - BufferID src = moves[move_index].first; - BufferHeader *src_header = GetHeaderByBufferId(context, src); - if (src_header) { - std::vector src_data(src_header->used); - Blob blob = {}; - blob.data = src_data.data(); - blob.size = src_header->used; - LocalReadBufferById(context, src, &blob, 0); - size_t offset = 0; - i64 remaining_src_size = (i64)blob.size; - replaced_ids.push_back(src); - - for (size_t i = 0; i < moves[move_index].second.size(); ++i) { - BufferID dest = moves[move_index].second[i]; - BufferHeader *dest_header = GetHeaderByBufferId(context, dest); - - if (dest_header) { - u32 dest_capacity = dest_header->capacity; - size_t portion_size = std::min((i64)dest_capacity, - remaining_src_size); - Blob blob_portion = {}; - blob_portion.data = blob.data + offset; - blob_portion.size = portion_size; - LocalWriteBufferById(context, dest, blob_portion, offset); - offset += portion_size; - remaining_src_size -= portion_size; - replacement_ids.push_back(dest); - } else { - LOG(WARNING) << warning_string(dest); - } - } - } else { - LOG(WARNING) << warning_string(src); - } - } - - if (replacement_ids.size() > 0) { - // TODO(chogan): Only need to allocate a new BufferIdList if - // replacement.size > replaced.size - std::vector buffer_ids = LocalGetBufferIdList(mdm, blob_id); - using BufferIdSet = std::unordered_set; - BufferIdSet new_buffer_ids(buffer_ids.begin(), buffer_ids.end()); - - // Remove all replaced BufferIDs from the new IDs. - for (size_t i = 0; i < replaced_ids.size(); ++i) { - new_buffer_ids.erase(replaced_ids[i]); - } - - // Add all the replacement IDs - for (size_t i = 0; i < replacement_ids.size(); ++i) { - new_buffer_ids.insert(replacement_ids[i]); - } - - std::vector ids_vec(new_buffer_ids.begin(), - new_buffer_ids.end()); - BlobID new_blob_id = {}; - new_blob_id.bits.node_id = blob_id.bits.node_id; - new_blob_id.bits.buffer_ids_offset = - LocalAllocateBufferIdList(mdm, ids_vec); - - BlobInfo new_info = {}; - BlobInfo *old_info = GetBlobInfoPtr(mdm, blob_id); - new_info.stats = old_info->stats; - // Invalidate the old Blob. It will get deleted when its TicketMutex - // reaches old_info->last - old_info->stop = true; - ReleaseBlobInfoPtr(mdm); - LocalPut(mdm, new_blob_id, new_info); - - // update blob_id in bucket's blob list - ReplaceBlobIdInBucket(context, rpc, bucket_id, blob_id, new_blob_id); - // update BlobID map - LocalPut(mdm, internal_blob_name.c_str(), new_blob_id.as_int, - kMapType_BlobId); - - if (!BlobIsInSwap(blob_id)) { - LocalReleaseBuffers(context, replaced_ids); - } - // NOTE(chogan): We don't free the Blob's BufferIdList here because that - // would make the buffer_id_list_offset available for new incoming Blobs, - // and we can't reuse the buffer_id_list_offset until the old BlobInfo is - // deleted. We take care of both in LocalLockBlob when the final - // outstanding operation on this BlobID is complete (which is tracked by - // BlobInfo::last). - } - LocalUnlockBlob(context, blob_id); - VLOG(1) << "Done moving blob " - << internal_blob_name.substr(kBucketIdStringSize, std::string::npos) - << std::endl; - } else { - if (got_lock) { - LOG(WARNING) << "Couldn't lock BlobID " << blob_id.as_int << "\n"; - } - } - - if (got_lock) { - EndReaderLock(&mdm->bucket_delete_lock); - } -} - -/** change the composition of a blob based on importance */ -void BufferOrganizer::LocalOrganizeBlob(const std::string &internal_blob_name, - BucketID bucket_id, f32 epsilon, - f32 explicit_importance_score) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - BlobID blob_id = {}; - blob_id.as_int = LocalGet(mdm, internal_blob_name.c_str(), kMapType_BlobId); - - f32 importance_score = explicit_importance_score; - if (explicit_importance_score == -1) { - importance_score = LocalGetBlobImportanceScore(context, blob_id); - } - - std::vector buffer_ids = LocalGetBufferIdList(mdm, blob_id); - std::vector buffer_info = GetBufferInfo(context, rpc, buffer_ids); - f32 access_score = ComputeBlobAccessScore(context, buffer_info); - bool increasing_access_score = importance_score > access_score; - SortBufferInfo(buffer_info, increasing_access_score); - std::vector new_buffer_info(buffer_info); - - BoMoveList src_dest; - - for (size_t i = 0; i < buffer_info.size(); ++i) { - std::vector targets = LocalGetNodeTargets(context); - std::vector target_bandwidths_mbps = GetBandwidths(context, targets); - std::vector capacities = GetRemainingTargetCapacities(context, rpc, - targets); - - std::vector target_info(targets.size()); - for (size_t j = 0; j < target_info.size(); ++j) { - target_info[j].id = targets[j]; - target_info[j].bandwidth_mbps = target_bandwidths_mbps[j]; - target_info[j].capacity = capacities[j]; - } - SortTargetInfo(target_info, increasing_access_score); - - BufferID src_buffer_id = {}; - PlacementSchema schema; - f32 new_bandwidth_mbps = 0; - for (size_t j = 0; j < target_info.size(); ++j) { - if (target_info[j].capacity > buffer_info[i].size) { - src_buffer_id = buffer_info[i].id; - if (src_buffer_id.bits.node_id == rpc->node_id) { - // Only consider local BufferIDs - schema.push_back(std::pair(buffer_info[i].size, target_info[j].id)); - new_bandwidth_mbps = target_info[j].bandwidth_mbps; - break; - } - } - } - - // TODO(chogan): Possibly merge multiple smaller buffers into one large - - std::vector dest = GetBuffers(context, schema); - if (dest.size() == 0) { - continue; - } - - // Replace old BufferInfo with new so we can calculate the updated access - // score - for (size_t j = 0; j < new_buffer_info.size(); ++j) { - if (new_buffer_info[j].id.as_int == src_buffer_id.as_int) { - new_buffer_info[j].id = dest[0]; - new_buffer_info[j].bandwidth_mbps = new_bandwidth_mbps; - BufferHeader *new_header = GetHeaderByBufferId(context, dest[0]); - // Assume we're using the full capacity - new_buffer_info[j].size = new_header->capacity; - break; - } - } - for (size_t j = 1; j < dest.size(); ++j) { - BufferInfo new_info = {}; - new_info.id = dest[j]; - new_info.bandwidth_mbps = new_bandwidth_mbps; - BufferHeader *new_header = GetHeaderByBufferId(context, dest[0]); - // Assume we're using the full capacity - new_info.size = new_header->capacity; - new_buffer_info.push_back(new_info); - } - - f32 new_access_score = ComputeBlobAccessScore(context, new_buffer_info); - - bool move_is_valid = true; - // Make sure we didn't move too far past the target - if (increasing_access_score) { - if (new_access_score > importance_score && - new_access_score - importance_score > epsilon) { - move_is_valid = false; - } - } else { - if (new_access_score < importance_score && - importance_score - new_access_score > epsilon) { - move_is_valid = false; - } - } - - if (move_is_valid) { - src_dest.push_back(std::pair(src_buffer_id, dest)); - } else { - ReleaseBuffers(context, rpc, dest); - } - - if (std::abs(importance_score - new_access_score) < epsilon) { - break; - } - } - - for (auto &src_dest_pair : src_dest) { - auto &src = src_dest_pair.first; - for (auto &dst : src_dest_pair.second) { - LOG(INFO) << "Moving " - << LocalGetBufferInfo(context, src).size / MEGABYTES(1) << " mb " - << " of " << blob_id.as_int << "" - << " from " - << LocalGetBufferInfo(context, src).bandwidth_mbps - << " into " - << LocalGetBufferInfo(context, dst).bandwidth_mbps - << std::endl; - } - } - EnqueueBoMove(rpc, src_dest, blob_id, bucket_id, internal_blob_name, - BoPriority::kLow); -} - -void BufferOrganizer::OrganizeBlob(BucketID bucket_id, - const std::string &blob_name, - f32 epsilon, f32 importance_score) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - std::string internal_name = MakeInternalBlobName(blob_name, bucket_id); - u32 target_node = HashString(internal_name.c_str()); - - if (target_node == rpc->node_id) { - LocalOrganizeBlob(context, rpc, internal_name, bucket_id, epsilon, - importance_score); - } else { - RpcCall(rpc, target_node, "BO::OrganizeBlob", internal_name, - bucket_id, epsilon); - } -} - -void BufferOrganizer::EnforceCapacityThresholds(ViolationInfo info) { - u32 target_node = info.target_id.bits.node_id; - if (target_node == rpc->node_id) { - LocalEnforceCapacityThresholds(context, rpc, info); - } else { - RpcCall(rpc, target_node, "RemoteEnforceCapacityThresholds", info); - } -} - -void BufferOrganizer::LocalEnforceCapacityThresholds(ViolationInfo info) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - - // TODO(chogan): Factor out the common code in the kMin and kMax cases - switch (info.violation) { - case ThresholdViolation::kMin: { - // TODO(chogan): Allow sorting Targets by any metric. This - // implementation only works if the Targets are listed in the - // configuration in order of decreasing bandwidth. - for (u16 target_index = mdm->node_targets.length - 1; - target_index != info.target_id.bits.index; - --target_index) { - TargetID src_target_id = { - info.target_id.bits.node_id, target_index, target_index - }; - - Target *src_target = GetTargetFromId(context, src_target_id); - src_target->effective_blobs_lock.Lock(); - std::vector blob_ids = - GetChunkedIdList(mdm, src_target->effective_blobs); - src_target->effective_blobs_lock.Unlock(); - - auto compare_importance = [context](const u64 lhs, const u64 rhs) { - BlobID lhs_blob_id = {}; - lhs_blob_id.as_int = lhs; - f32 lhs_importance_score = LocalGetBlobImportanceScore(context, - lhs_blob_id); - - BlobID rhs_blob_id = {}; - rhs_blob_id.as_int = rhs; - f32 rhs_importance_score = LocalGetBlobImportanceScore(context, - rhs_blob_id); - - return lhs_importance_score < rhs_importance_score; - }; - - std::sort(blob_ids.begin(), blob_ids.end(), compare_importance); - - size_t bytes_moved = 0; - - for (size_t idx = 0; - idx < blob_ids.size() && bytes_moved < info.violation_size; - ++idx) { - BlobID most_important_blob {}; - std::vector buffers_to_move; - most_important_blob.as_int = blob_ids[idx]; - std::vector buffer_ids = - LocalGetBufferIdList(mdm, most_important_blob); - - // Filter out BufferIDs not in the Target - std::vector buffer_ids_in_target; - for (size_t i = 0; i < buffer_ids.size(); ++i) { - BufferHeader *header = GetHeaderByBufferId(context, buffer_ids[i]); - DeviceID device_id = header->device_id; - if (device_id == src_target_id.bits.device_id) { - // TODO(chogan): Needs to changes when we support num_devices != - // num_targets - buffer_ids_in_target.push_back(buffer_ids[i]); - } - } - std::vector buffer_info = - GetBufferInfo(context, rpc, buffer_ids_in_target); - auto buffer_info_comparator = [](const BufferInfo &lhs, - const BufferInfo &rhs) { - return lhs.size > rhs.size; - }; - // Sort in descending order - std::sort(buffer_info.begin(), buffer_info.end(), - buffer_info_comparator); - for (size_t j = 0; - j < buffer_info.size() && bytes_moved < info.violation_size; - ++j) { - buffers_to_move.push_back(buffer_info[j]); - bytes_moved += buffer_info[j].size; - } - - BoMoveList moves; - for (size_t i = 0; i < buffers_to_move.size(); ++i) { - PlacementSchema schema; - using SchemaPair = std::pair; - schema.push_back(SchemaPair(buffers_to_move[i].size, - info.target_id)); - std::vector dests = GetBuffers(context, schema); - if (dests.size() != 0) { - moves.push_back(std::pair(buffers_to_move[i].id, dests)); - } - } - - if (moves.size() > 0) { - // Queue BO task to move to lower tier - BucketID bucket_id = GetBucketIdFromBlobId(context, rpc, - most_important_blob); - std::string blob_name = - LocalGetBlobNameFromId(context, most_important_blob); - std::string internal_name = MakeInternalBlobName(blob_name, - bucket_id); - EnqueueBoMove(rpc, moves, most_important_blob, bucket_id, - internal_name, BoPriority::kLow); - } - } - } - break; - } - - case ThresholdViolation::kMax: { - Target *target = GetTargetFromId(context, info.target_id); - - f32 min_importance = FLT_MAX; - BlobID least_important_blob = {}; - - target->effective_blobs_lock.Lock(); - std::vector blob_ids = GetChunkedIdList(mdm, - target->effective_blobs); - target->effective_blobs_lock.Unlock(); - - // Find least important blob in violated Target - for (size_t i = 0; i < blob_ids.size(); ++i) { - BlobID blob_id = {}; - blob_id.as_int = blob_ids[i]; - f32 importance_score = LocalGetBlobImportanceScore(context, blob_id); - if (importance_score < min_importance) { - min_importance = importance_score; - least_important_blob = blob_id; - } - } - - assert(!IsNullBlobId(least_important_blob)); - - std::vector all_buffer_ids = - LocalGetBufferIdList(mdm, least_important_blob); - std::vector buffer_ids_in_target; - // Filter out BufferIDs not in this Target - for (size_t i = 0; i < all_buffer_ids.size(); ++i) { - BufferHeader *header = GetHeaderByBufferId(context, all_buffer_ids[i]); - DeviceID device_id = header->device_id; - if (device_id == info.target_id.bits.device_id) { - // TODO(chogan): Needs to changes when we support num_devices != - // num_targets - buffer_ids_in_target.push_back(all_buffer_ids[i]); - } - } - - std::vector buffer_info = - GetBufferInfo(context, rpc, buffer_ids_in_target); - auto buffer_info_comparator = [](const BufferInfo &lhs, - const BufferInfo &rhs) { - return lhs.size > rhs.size; - }; - // Sort in descending order - std::sort(buffer_info.begin(), buffer_info.end(), buffer_info_comparator); - - size_t bytes_moved = 0; - std::vector buffers_to_move; - size_t index = 0; - // Choose largest buffer until we've moved info.violation_size - while (bytes_moved < info.violation_size) { - buffers_to_move.push_back(buffer_info[index]); - bytes_moved += buffer_info[index].size; - index++; - } - - BoMoveList moves; - // TODO(chogan): Combine multiple smaller buffers into fewer larger - // buffers - for (size_t i = 0; i < buffers_to_move.size(); ++i) { - // TODO(chogan): Allow sorting Targets by any metric. This - // implementation only works if the Targets are listed in the - // configuration in order of decreasing bandwidth. - for (u16 target_index = info.target_id.bits.index + 1; - target_index < mdm->node_targets.length; - ++target_index) { - // Select Target 1 Tier lower than violated Target - TargetID target_dest = { - info.target_id.bits.node_id, target_index, target_index - }; - - PlacementSchema schema; - schema.push_back(std::pair(bytes_moved, - target_dest)); - std::vector dests = GetBuffers(context, schema); - if (dests.size() != 0) { - moves.push_back(std::pair(buffers_to_move[i].id, dests)); - break; - } - } - } - - if (moves.size() > 0) { - // Queue BO task to move to lower tier - BucketID bucket_id = GetBucketIdFromBlobId(context, rpc, - least_important_blob); - std::string blob_name = - LocalGetBlobNameFromId(context, least_important_blob); - std::string internal_name = MakeInternalBlobName(blob_name, bucket_id); - EnqueueBoMove(rpc, moves, least_important_blob, bucket_id, - internal_name, BoPriority::kLow); - } else { - LOG(WARNING) - << "BufferOrganizer: No capacity available in lower Targets.\n"; - } - break; - } - default: { - HERMES_INVALID_CODE_PATH; - } - } -} - -void BufferOrganizer::LocalShutdownBufferOrganizer() { - // NOTE(chogan): ThreadPool destructor needs to be called manually since we - // allocated the BO instance with placement new. - context->bo->pool.~ThreadPool(); -} - -void BufferOrganizer::FlushBlob(BlobID blob_id, const std::string &filename, - u64 offset, bool async) { - if (LockBlob(context, rpc, blob_id)) { - int open_flags = 0; - mode_t open_mode = 0; - if (access(filename.c_str(), F_OK) == 0) { - open_flags = O_WRONLY; - } else { - open_flags = O_WRONLY | O_CREAT | O_TRUNC; - open_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - } - - int fd = open(filename.c_str(), open_flags, open_mode); - if (fd != -1) { - LOG(INFO) << "Flushing BlobID " << blob_id.as_int << " to file " - << filename << " at offset " << offset << "\n"; - - const int kFlushBufferSize = KILOBYTES(4); - u8 flush_buffer[kFlushBufferSize]; - Arena local_arena = {}; - InitArena(&local_arena, kFlushBufferSize, flush_buffer); - - if (flock(fd, LOCK_EX) != 0) { - FailedLibraryCall("flock"); - } - - StdIoPersistBlob(context, rpc, &local_arena, blob_id, fd, offset); - - if (flock(fd, LOCK_UN) != 0) { - FailedLibraryCall("flock"); - } - - if (close(fd) != 0) { - FailedLibraryCall("close"); - } - } else { - FailedLibraryCall("open"); - } - UnlockBlob(context, rpc, blob_id); - } - - if (async) { - DecrementFlushCount(context, rpc, filename); - } - - // TODO(chogan): - // if (DONTNEED) { - // DestroyBlobById(); - // } else { - // ReplaceBlobWithSwapBlob(); - // } -} - -bool BufferOrganizer::EnqueueFlushingTask(BlobID blob_id, - const std::string &filename, u64 offset) { - bool result = RpcCall(rpc, rpc->node_id, "BO::EnqueueFlushingTask", - blob_id, filename, offset); - - return result; -} - -bool BufferOrganizer::LocalEnqueueFlushingTask(BlobID blob_id, const std::string &filename, - u64 offset) { - bool result = false; - - // TODO(chogan): Handle Swap Blobs (should work, just needs testing) - if (!BlobIsInSwap(blob_id)) { - ThreadPool *pool = &context->bo->pool; - IncrementFlushCount(context, rpc, filename); - bool async = true; - pool->run(std::bind(FlushBlob, context, rpc, blob_id, filename, offset, - async)); - result = true; - } else { - HERMES_NOT_IMPLEMENTED_YET; - } - - return result; -} -/** - place BLOBs in hierarchy -*/ -Status BufferOrganizer::PlaceInHierarchy(SwapBlob swap_blob, - const std::string &name, - const api::Context &ctx) { - std::vector schemas; - std::vector sizes(1, swap_blob.size); - Status result = CalculatePlacement(context, rpc, sizes, schemas, ctx); - - if (result.Succeeded()) { - std::vector blob_mem(swap_blob.size); - Blob blob = {}; - blob.data = blob_mem.data(); - blob.size = blob_mem.size(); - ReadFromSwap(context, blob, swap_blob); - result = PlaceBlob(context, rpc, schemas[0], blob, name, - swap_blob.bucket_id, ctx, true); - } else { - LOG(ERROR) << result.Msg(); - } - - return result; -} - -/** adjust flush coun locally */ -void BufferOrganizer::LocalAdjustFlushCount(const std::string &vbkt_name, - int adjustment) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - VBucketID id = LocalGetVBucketId(context, vbkt_name.c_str()); - mdm->vbucket_mutex.Lock(); - VBucketInfo *info = LocalGetVBucketInfoById(mdm, id); - if (info) { - int flush_count = info->async_flush_count.fetch_add(adjustment); - VLOG(1) << "Flush count on VBucket " << vbkt_name - << (adjustment > 0 ? "incremented" : "decremented") << " to " - << flush_count + adjustment << "\n"; - } - mdm->vbucket_mutex.Unlock(); -} - -void BufferOrganizer::LocalIncrementFlushCount(const std::string &vbkt_name) { - LocalAdjustFlushCount(context, vbkt_name, 1); -} - -void BufferOrganizer::LocalDecrementFlushCount(const std::string &vbkt_name) { - LocalAdjustFlushCount(context, vbkt_name, -1); -} - -void BufferOrganizer::IncrementFlushCount(const std::string &vbkt_name) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - u32 target_node = HashString(vbkt_name.c_str()); - - if (target_node == rpc->node_id) { - LocalIncrementFlushCount(context, vbkt_name); - } else { - RpcCall(rpc, target_node, "RemoteIncrementFlushCount", - vbkt_name); - } -} - -void BufferOrganizer::DecrementFlushCount(const std::string &vbkt_name) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - u32 target_node = HashString(mdm, rpc, vbkt_name.c_str()); - - if (target_node == rpc->node_id) { - LocalDecrementFlushCount(context, vbkt_name); - } else { - RpcCall(rpc, target_node, "RemoteDecrementFlushCount", - vbkt_name); - } -} - -void BufferOrganizer::AwaitAsyncFlushingTasks(VBucketID id) { - auto sleep_time = std::chrono::milliseconds(500); - int outstanding_flushes = 0; - int log_every = 10; - int counter = 0; - - while ((outstanding_flushes = - GetNumOutstandingFlushingTasks(id)) != 0) { - if (++counter == log_every) { - LOG(INFO) << "Waiting for " << outstanding_flushes - << " outstanding flushes" << std::endl; - counter = 0; - } - std::this_thread::sleep_for(sleep_time); - } -} - -} // namespace hermes diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h deleted file mode 100644 index 63e328872..000000000 --- a/src/buffer_organizer.h +++ /dev/null @@ -1,257 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_BUFFER_ORGANIZER_H_ -#define HERMES_BUFFER_ORGANIZER_H_ - -#include "thread_pool.h" -#include "hermes_status.h" -#include "rpc_decorator.h" - -namespace hermes { - -/** move list for buffer organizer */ -using BoMoveList = std::vector>>; - -/** buffer organizer operations */ -enum class BoOperation { - kMove, - kCopy, - kDelete, - - kCount -}; - -/** buffer organizer priorities */ -enum class BoPriority { - kLow, - kHigh, - - kCount -}; - -/** - A union of structures to represent buffer organizer arguments -*/ -union BoArgs { - /** A structure to represent move arguments */ - struct { - BufferID src; /**< source buffer ID */ - TargetID dest; /**< destination target ID */ - } move_args; - /** A structure to represent copy arguments */ - struct { - BufferID src; /**< source buffer ID */ - TargetID dest; /**< destination target ID */ - } copy_args; - /** A structure to represent delete arguments */ - struct { - BufferID src; /**< source buffer ID */ - } delete_args; -}; - -/** - A structure to represent buffer organizer task -*/ -struct BoTask { - BoOperation op; /**< buffer organizer operation */ - BoArgs args; /**< buffer organizer arguments */ -}; - -/** - A structure to represent buffer information -*/ -struct BufferInfo { - BufferID id; /**< buffer ID */ - f32 bandwidth_mbps; /**< bandwidth in Megabits per second */ - size_t size; /**< buffer size */ -}; - -/** comparison operator */ -bool operator==(const BufferInfo &lhs, const BufferInfo &rhs); - -/** - A structure to represent Target information -*/ -struct TargetInfo { - TargetID id; /**< unique ID */ - f32 bandwidth_mbps; /**< bandwidth in Megabits per second */ - u64 capacity; /**< capacity */ -}; - -/** - A structure to represent buffer organizer -*/ -class BufferOrganizer { - public: - SharedMemoryContext *context_; - RpcContext *rpc_; - ThreadPool pool; /**< a pool of threads */ - - public: - /** initialize buffer organizer with \a num_threads number of threads. */ - explicit BufferOrganizer(SharedMemoryContext *context, - RpcContext *rpc, int num_threads); - - /** get buffer information locally */ - RPC BufferInfo LocalGetBufferInfo(BufferID buffer_id); - - /** get buffer information */ - BufferInfo GetBufferInfo(BufferID buffer_id); - - /** get information for multiple buffers */ - std::vector - GetBufferInfo(const std::vector &buffer_ids); - - /** normalize access score from \a raw-score using \a size_mb */ - f32 NormalizeAccessScore(f32 raw_score, f32 size_mb); - - /** compute blob access score */ - f32 ComputeBlobAccessScore(const std::vector &buffer_info); - - /** sort buffer information */ - void SortBufferInfo(std::vector &buffer_info, bool increasing); - - /** sort target information */ - void SortTargetInfo(std::vector &target_info, bool increasing); - - /** Local enqueue of buffer information */ - RPC void LocalEnqueueBoMove(const BoMoveList &moves, BlobID blob_id, - BucketID bucket_id, - const std::string &internal_blob_name, - BoPriority priority); - - /** enqueue a move operation */ - void EnqueueBoMove(const BoMoveList &moves, BlobID blob_id, - BucketID bucket_id, const std::string &internal_name, - BoPriority priority); - - /** - * copy a set of buffers into a set of new buffers. - * - * assumes all BufferIDs in destinations are local - * */ - void BoMove(const BoMoveList &moves, BlobID blob_id, BucketID bucket_id, - const std::string &internal_blob_name); - - /** change the composition of a blob based on importance locally */ - RPC void LocalOrganizeBlob(const std::string &internal_blob_name, - BucketID bucket_id, f32 epsilon, - f32 explicit_importance_score); - - /** change the composition of a blob */ - void OrganizeBlob(BucketID bucket_id, const std::string &blob_name, - f32 epsilon, f32 importance_score); - - - void EnforceCapacityThresholds(ViolationInfo info); - RPC void LocalEnforceCapacityThresholds(ViolationInfo info); - void LocalShutdownBufferOrganizer(); - void FlushBlob(BlobID blob_id, const std::string &filename, - u64 offset, bool async); - bool EnqueueFlushingTask(BlobID blob_id, - const std::string &filename, u64 offset); - RPC bool LocalEnqueueFlushingTask(BlobID blob_id, const std::string &filename, - u64 offset); - api::Status PlaceInHierarchy(SwapBlob swap_blob, const std::string &name, - const api::Context &ctx); - void LocalAdjustFlushCount(const std::string &vbkt_name, int adjustment); - RPC void LocalIncrementFlushCount(const std::string &vbkt_name); - RPC void LocalDecrementFlushCount(const std::string &vbkt_name); - void IncrementFlushCount(const std::string &vbkt_name); - void DecrementFlushCount(const std::string &vbkt_name); - void AwaitAsyncFlushingTasks(VBucketID id); - - /** Automatically Generate RPCs */ - RPC_AUTOGEN_START - RPC BufferInfo GetBufferInfo(BufferID buffer_id) { - u32 target_node = buffer_id.bits.node_id; - if (target_node == rpc_->node_id_) { - LocalAddBlobIdToVBucket( - buffer_id); - } else { - rpc_->Call(rpc, target_node, "GetBufferInfo", - buffer_id); - } - } - RPC void EnqueueBoMove(const BoMoveList &moves, BlobID blob_id, BucketID bucket_id, const std::string &internal_blob_name, BoPriority priority) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - LocalAddBlobIdToVBucket( - &moves, blob_id, bucket_id, &internal_blob_name, priority); - } else { - rpc_->Call(rpc, target_node, "EnqueueBoMove", - &moves, blob_id, bucket_id, &internal_blob_name, priority); - } - } - RPC void OrganizeBlob(const std::string &internal_blob_name, BucketID bucket_id, f32 epsilon, f32 explicit_importance_score) { - u32 target_node = HashString(internal_name.c_str()); - if (target_node == rpc_->node_id_) { - LocalAddBlobIdToVBucket( - &internal_blob_name, bucket_id, epsilon, explicit_importance_score); - } else { - rpc_->Call(rpc, target_node, "OrganizeBlob", - &internal_blob_name, bucket_id, epsilon, explicit_importance_score); - } - } - RPC void EnforceCapacityThresholds(ViolationInfo info) { - u32 target_node = info.target_id.bits.node_id; - if (target_node == rpc_->node_id_) { - LocalAddBlobIdToVBucket( - info); - } else { - rpc_->Call(rpc, target_node, "EnforceCapacityThresholds", - info); - } - } - RPC bool EnqueueFlushingTask(BlobID blob_id, const std::string &filename, u64 offset) { - u32 target_node = rpc->node_id_; - if (target_node == rpc_->node_id_) { - LocalAddBlobIdToVBucket( - blob_id, &filename, offset); - } else { - rpc_->Call(rpc, target_node, "EnqueueFlushingTask", - blob_id, &filename, offset); - } - } - RPC void IncrementFlushCount(const std::string &vbkt_name) { - u32 target_node = HashString(vbkt_name.c_str()); - if (target_node == rpc_->node_id_) { - LocalAddBlobIdToVBucket( - &vbkt_name); - } else { - rpc_->Call(rpc, target_node, "IncrementFlushCount", - &vbkt_name); - } - } - RPC void DecrementFlushCount(const std::string &vbkt_name) { - u32 target_node = HashString(vbkt_name.c_str()); - if (target_node == rpc_->node_id_) { - LocalAddBlobIdToVBucket( - &vbkt_name); - } else { - rpc_->Call(rpc, target_node, "DecrementFlushCount", - &vbkt_name); - } - } - RPC_AUTOGEN_END -}; - -static inline f32 BytesToMegabytes(size_t bytes) { - f32 result = (f32)bytes / (f32)MEGABYTES(1); - - return result; -} - -} // namespace hermes - -#endif // HERMES_BUFFER_ORGANIZER_H_ \ No newline at end of file diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc deleted file mode 100644 index bf497c4aa..000000000 --- a/src/buffer_pool.cc +++ /dev/null @@ -1,2061 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "buffer_pool.h" -#include "buffer_pool_internal.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include "mpi.h" - -#include "metadata_management.h" -#include "rpc.h" - -#include "debug_state.cc" -#include "config_parser.cc" -#include "utils.cc" -#include "traits.cc" - -#if defined(HERMES_COMMUNICATION_MPI) -#include "communication_mpi.cc" -#elif defined(HERMES_COMMUNICATION_ZMQ) -#include "communication_zmq.cc" -#else -#error "Communication implementation required " \ - "(e.g., -DHERMES_COMMUNICATION_MPI)." -#endif - -#if defined(HERMES_RPC_THALLIUM) -#include "rpc_thallium.cc" -#else -#error "RPC implementation required (e.g., -DHERMES_RPC_THALLIUM)." -#endif - -#include "metadata_management.cc" -#include "buffer_organizer.cc" - -#if defined(HERMES_MDM_STORAGE_STBDS) -#include "metadata_storage_stb_ds.cc" -#else -#error "Metadata storage implementation required" \ - "(e.g., -DHERMES_MDM_STORAGE_STBDS)." -#endif - -/** - * @file buffer_pool.cc - * - * Implementation of a BufferPool that lives in shared memory. Other processes - * interact with the BufferPool by requesting buffers through the `GetBuffers` - * call to reserve a set of `BufferID`s and then using those IDs for I/O. Remote - * processes can request remote buffers via the `GetBuffers` RPC call. - */ - -namespace hermes { - -/** comparison operator */ -bool operator==(const BufferID &lhs, const BufferID &rhs) { - return lhs.as_int == rhs.as_int; -} - -void Finalize(SharedMemoryContext *context, CommunicationContext *comm, - RpcContext *rpc, const char *shmem_name, Arena *trans_arena, - bool is_application_core, bool force_rpc_shutdown) { - WorldBarrier(comm); - if (!is_application_core && comm->first_on_node) { - StopPrefetcher(rpc); - StopGlobalSystemViewStateUpdateThread(rpc); - } - WorldBarrier(comm); - ShutdownRpcClients(rpc); - - if (is_application_core) { - ReleaseSharedMemoryContext(context); - HERMES_DEBUG_CLIENT_CLOSE(); - } - WorldBarrier(comm); - if (!is_application_core) { - if (comm->first_on_node) { - bool is_daemon = - (comm->world_size == comm->num_nodes) && !force_rpc_shutdown; - FinalizeRpcContext(rpc, is_daemon); - LocalShutdownBufferOrganizer(context); - } - SubBarrier(comm); - ReleaseSharedMemoryContext(context); - shm_unlink(shmem_name); - HERMES_DEBUG_SERVER_CLOSE(); - } - DestroyArena(trans_arena); - // TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 - // google::ShutdownGoogleLogging(); -} - -/** - Lock \a header buffer. - */ -void LockBuffer(BufferHeader *header) { - while (true) { - bool expected = false; - if (header->locked.compare_exchange_weak(expected, true)) { - break; - } - } -} - -/** - Unlock \a header buffer. - */ -void UnlockBuffer(BufferHeader *header) { - header->locked.store(false); -} - -BufferPool *GetBufferPoolFromContext(SharedMemoryContext *context) { - BufferPool *result = (BufferPool *)(context->shm_base + - context->buffer_pool_offset); - - return result; -} - -/** Get Device from \a context SharedMemoryContext and \a header BufferHeader */ -Device *GetDeviceFromHeader(SharedMemoryContext *context, - BufferHeader *header) { - BufferPool *pool = GetBufferPoolFromContext(context); - Device *devices_base = (Device *)(context->shm_base + pool->devices_offset); - Device *result = devices_base + header->device_id; - - return result; -} - -/** Get Target from \a context SharedMemoryContext and \a index index. */ -Target *GetTarget(SharedMemoryContext *context, int index) { - BufferPool *pool = GetBufferPoolFromContext(context); - Target *targets_base = (Target *)(context->shm_base + pool->targets_offset); - Target *result = targets_base + index; - - return result; -} - -/** Get Target from \a context SharedMemoryContext and \a id TargetID. */ -Target *GetTargetFromId(SharedMemoryContext *context, TargetID id) { - Target *result = GetTarget(context, id.bits.index); - - return result; -} - -std::vector GetBandwidths(SharedMemoryContext *context, - const std::vector &targets) { - std::vector result(targets.size(), 0); - - for (size_t i = 0; i < targets.size(); i++) { - Device *device = GetDeviceById(context, targets[i].bits.device_id); - result[i] = device->bandwidth_mbps; - } - - return result; -} - -Device *GetDeviceById(SharedMemoryContext *context, DeviceID device_id) { - BufferPool *pool = GetBufferPoolFromContext(context); - Device *devices_base = (Device *)(context->shm_base + pool->devices_offset); - Device *result = devices_base + device_id; - - return result; -} - -/** Get DeviceID from \a target_id TargetID. */ -DeviceID GetDeviceIdFromTargetId(TargetID target_id) { - DeviceID result = target_id.bits.device_id; - - return result; -} - -BufferHeader *GetHeadersBase(SharedMemoryContext *context) { - BufferPool *pool = GetBufferPoolFromContext(context); - BufferHeader *result = (BufferHeader *)(context->shm_base + - pool->headers_offset); - - return result; -} - -/** Get BufferHeader from \a context SharedMemoryContext and \a index index. */ -inline BufferHeader *GetHeaderByIndex(SharedMemoryContext *context, u32 index) { - [[maybe_unused]] BufferPool *pool = GetBufferPoolFromContext(context); - BufferHeader *headers = GetHeadersBase(context); - assert(index < pool->total_headers); - BufferHeader *result = headers + index; - - return result; -} - -BufferHeader *GetHeaderByBufferId(SharedMemoryContext *context, - BufferID id) { - BufferHeader *result = GetHeaderByIndex(context, id.bits.header_index); - - return result; -} - -/** Reset \a header BufferHeader. */ -void ResetHeader(BufferHeader *header) { - if (header) { - // NOTE(chogan): Keep `id` the same. They should never change. - header->next_free.as_int = 0; - // NOTE(chogan): Keep `data_offset` because splitting/merging may reuse it - header->used = 0; - header->capacity = 0; - header->device_id = 0; - header->in_use = 0; - header->locked = 0; - } -} - -/** Make \a header BufferHeader dormant by setting capacity to 0. */ -static inline void MakeHeaderDormant(BufferHeader *header) { - header->capacity = 0; -} - -bool HeaderIsDormant(BufferHeader *header) { - bool result = header->capacity == 0; - - return result; -} - -#if 0 -BufferHeader *GetFirstDormantHeader(SharedMemoryContext *context) { - BufferPool *pool = GetBufferPoolFromContext(context); - BufferHeader *headers = GetHeadersBase(context); - BufferHeader *result = 0; - - for (u32 i = 0; i < pool->num_headers; ++i) { - BufferHeader *header = &headers[i]; - if (HeaderIsDormant(header)) { - result = header; - break; - } - } - - return result; -} -#endif - -#if 0 -f32 ComputeFragmentationScore(SharedMemoryContext *context) { - BufferPool *pool = GetBufferPoolFromContext(context); - BufferHeader *headers = GetHeadersBase(context); - - u32 total_used_headers = 0; - f32 usage_score = 0; - for (u32 i = 0; i < pool->num_headers; ++i) { - BufferHeader *header = &headers[i]; - - if (header->in_use) { - total_used_headers++; - - // TODO(chogan): Is a lock really necessary? Need to check where - // `used` and `capacity` get mutated. We only read them here. Could - // just make both variables atomics. - LockBuffer(header); - f32 percentage_used = header->used / header->capacity; - usage_score += percentage_used; - UnlockBuffer(header); - } - } - - f32 percentage_of_used_headers = ((f32)total_used_headers / - (f32)pool->num_headers); - f32 max_usage_score = 1.0f * pool->num_headers; - f32 optimal_usage = percentage_of_used_headers * max_usage_score; - f32 result = optimal_usage - usage_score; - - // TODO(chogan): Reorganize BufferPool if score is > 0.5 or 0.6 - return result; -} -#endif - -/** - Get slab unit size from \a context SharedMemoryContext, \a device_id - Device ID, and \a slab_index slab index. -*/ -i32 GetSlabUnitSize(SharedMemoryContext *context, DeviceID device_id, - int slab_index) { - BufferPool *pool = GetBufferPoolFromContext(context); - i32 result = 0; - i32 *slab_unit_sizes = nullptr; - - if (device_id < pool->num_devices) { - slab_unit_sizes = (i32 *)(context->shm_base + - pool->slab_unit_sizes_offsets[device_id]); - if (slab_index < pool->num_slabs[device_id]) { - result = slab_unit_sizes[slab_index]; - } else { - // TODO(chogan): @logging - } - } else { - // TODO(chogan): @logging - } - - return result; -} - -/** - Get slab buffer size from \a context SharedMemoryContext, \a device_id - Device ID, and \a slab_index slab index. -*/ -i32 GetSlabBufferSize(SharedMemoryContext *context, DeviceID device_id, - int slab_index) { - BufferPool *pool = GetBufferPoolFromContext(context); - i32 *slab_sizes = nullptr; - i32 result = 0; - - if (device_id < pool->num_devices) { - slab_sizes = (i32 *)(context->shm_base + - pool->slab_buffer_sizes_offsets[device_id]); - if (slab_index < pool->num_slabs[device_id]) { - result = slab_sizes[slab_index]; - } else { - LOG(WARNING) << "Requested info for a non-existent slab " - << "(requested slab index: " << slab_index - << " , max index: " << pool->num_slabs[device_id] - << std::endl; - } - } else { - LOG(WARNING) << "Requested info for a non-existent Device " - << "(requested id: " << device_id << " , max id: " - << pool->num_devices << std::endl; - } - - return result; -} - -/** - Get BufferID pointer to the free list offset of \a device_id Device ID - from \a context SharedMemoryContext. -*/ -BufferID *GetFreeListPtr(SharedMemoryContext *context, DeviceID device_id) { - BufferPool *pool = GetBufferPoolFromContext(context); - BufferID *result = nullptr; - - if (device_id < pool->num_devices) { - result = - (BufferID *)(context->shm_base + pool->free_list_offsets[device_id]); - } - - return result; -} - -/** - Get slab index from \a context SharedMemoryContext and \a header BufferHeader. -*/ -int GetSlabIndexFromHeader(SharedMemoryContext *context, BufferHeader *header) { - BufferPool *pool = GetBufferPoolFromContext(context); - DeviceID device_id = header->device_id; - i32 units = header->capacity / pool->block_sizes[device_id]; - int result = 0; - - for (int i = 0; i < pool->num_slabs[device_id]; ++i) { - if (GetSlabUnitSize(context, device_id, i) == units) { - result = i; - break; - } - } - - return result; -} - -/** - Check if node ID of \a buffer_id BufferID is same as node ID of \a comm - CommunicationContext. -*/ -bool BufferIsRemote(CommunicationContext *comm, BufferID buffer_id) { - bool result = (u32)comm->node_id != buffer_id.bits.node_id; - - return result; -} - -/** - Check if node ID of \a buffer_id BufferID is same as node ID of \a rpc - RpcContext. -*/ -bool BufferIsRemote(RpcContext *rpc, BufferID buffer_id) { - bool result = rpc->node_id != buffer_id.bits.node_id; - - return result; -} - -/** Check if \a id BufferID is null. */ -bool IsNullBufferId(BufferID id) { - bool result = id.as_int == 0; - - return result; -} - -/** - Check if the device with \a context SharedMemoryContext and - \a buffer_id BufferID is byte-addressable. -*/ -bool BufferIsByteAddressable(SharedMemoryContext *context, BufferID id) { - BufferHeader *header = GetHeaderByBufferId(context, id); - Device *device = GetDeviceFromHeader(context, header); - bool result = device->is_byte_addressable; - - return result; -} - -/** - Get the first free BufferID from \a context SharedMemoryContext, - \a device_id DeviceID, and \a slab_index slab index. -*/ -BufferID PeekFirstFreeBufferId(SharedMemoryContext *context, DeviceID device_id, - int slab_index) { - BufferPool *pool = GetBufferPoolFromContext(context); - BufferID result = {}; - BufferID *free_list = GetFreeListPtr(context, device_id); - if (slab_index < pool->num_slabs[device_id]) { - result = free_list[slab_index]; - } - - return result; -} - -/** - Set the value at \a slab_index slab index of free list - from \a context SharedMemoryContext and \a device_id DeviceID - as \a new_id BufferID. -*/ -void SetFirstFreeBufferId(SharedMemoryContext *context, DeviceID device_id, - int slab_index, BufferID new_id) { - BufferPool *pool = GetBufferPoolFromContext(context); - BufferID *free_list = GetFreeListPtr(context, device_id); - if (slab_index < pool->num_slabs[device_id]) { - free_list[slab_index] = new_id; - } -} - -/** - Get the array of available buffer offsets - from \a context SharedMemoryContext and \a device_id DeviceID. -*/ -std::atomic *GetAvailableBuffersArray(SharedMemoryContext *context, - DeviceID device_id) { - BufferPool *pool = GetBufferPoolFromContext(context); - std::atomic *result = - (std::atomic *)(context->shm_base + - pool->buffers_available_offsets[device_id]); - - return result; -} - -/** - Get the number of available buffers from \a context SharedMemoryContext, - and \a device_id DeviceID at \a slab_index slab index. -*/ -static u32 GetNumBuffersAvailable(SharedMemoryContext *context, - DeviceID device_id, int slab_index) { - std::atomic *buffers_available = GetAvailableBuffersArray(context, - device_id); - u32 result = 0; - if (buffers_available) { - result = buffers_available[slab_index].load(); - } - - return result; -} - -/** - Get the number of available buffers from \a context SharedMemoryContext, - and \a device_id DeviceID. -*/ -u32 GetNumBuffersAvailable(SharedMemoryContext *context, DeviceID device_id) { - BufferPool *pool = GetBufferPoolFromContext(context); - u32 result = 0; - for (int slab = 0; slab < pool->num_slabs[device_id]; ++slab) { - result += GetNumBuffersAvailable(context, device_id, slab); - } - - return result; -} - -#if 0 -static u64 GetNumBytesRemaining(SharedMemoryContext *context, - DeviceID device_id, int slab_index) { - u32 num_free_buffers = GetNumBuffersAvailable(context, device_id, slab_index); - u32 buffer_size = GetSlabBufferSize(context, device_id, slab_index); - u64 result = num_free_buffers * buffer_size; - - return result; -} - -static u64 GetNumBytesRemaining(SharedMemoryContext *context, DeviceID id) { - BufferPool *pool = GetBufferPoolFromContext(context); - u64 result = 0; - for (int i = 0; i < pool->num_slabs[id]; ++i) { - result += GetNumBytesRemaining(context, id, i); - } - - return result; -} -#endif - -/** - Decrement the number of available buffers at \a slab_index slab index - from \a context SharedMemoryContext and \a device_id DeviceID. -*/ -static void DecrementAvailableBuffers(SharedMemoryContext *context, - DeviceID device_id, int slab_index) { - std::atomic *buffers_available = GetAvailableBuffersArray(context, - device_id); - if (buffers_available) { - buffers_available[slab_index].fetch_sub(1); - } -} - -/** - Increment the number of available buffers at \a slab_index slab index - from \a context SharedMemoryContext and \a device_id DeviceID. -*/ -static void IncrementAvailableBuffers(SharedMemoryContext *context, - DeviceID device_id, int slab_index) { - std::atomic *buffers_available = GetAvailableBuffersArray(context, - device_id); - if (buffers_available) { - buffers_available[slab_index].fetch_add(1); - } -} - -/** - Update buffering capacities of \a device_id DeviceID by \a adjustment - from \a context SharedMemoryContext. -*/ -void UpdateBufferingCapacities(SharedMemoryContext *context, i64 adjustment, - DeviceID device_id) { - BufferPool *pool = GetBufferPoolFromContext(context); - - // NOTE(chogan): Update local capacities, which will eventually be reflected - // in the global SystemViewState. - // TODO(chogan): I think Target capacities will supersede the global system - // view state once we have topologies. For now we track both node capacities - // and global capacities. - pool->capacity_adjustments[device_id].fetch_add(adjustment); - - // TODO(chogan): DeviceID is currently equal to TargetID, but that will change - // once we have topologies. This function will need to support TargetIDs - // instead of DeviceID. - Target *target = GetTarget(context, device_id); - target->remaining_space.fetch_add(adjustment); -} -/** - Release local \a buffer_id buffer from \a context SharedMemoryContext. -*/ -void LocalReleaseBuffer(SharedMemoryContext *context, BufferID buffer_id) { - BufferPool *pool = GetBufferPoolFromContext(context); - BufferHeader *header_to_free = GetHeaderByIndex(context, - buffer_id.bits.header_index); - if (header_to_free) { - pool->ticket_mutex.Lock(); - header_to_free->used = 0; - header_to_free->in_use = false; - int slab_index = GetSlabIndexFromHeader(context, header_to_free); - DeviceID device_id = header_to_free->device_id; - header_to_free->next_free = PeekFirstFreeBufferId(context, device_id, - slab_index); - SetFirstFreeBufferId(context, device_id, slab_index, buffer_id); - IncrementAvailableBuffers(context, device_id, slab_index); - - i64 capacity_adjustment = header_to_free->capacity; - UpdateBufferingCapacities(context, capacity_adjustment, device_id); - - pool->ticket_mutex.Unlock(); - } -} - -/** - Release remote \a buffer_id buffer from \a context SharedMemoryContext - and \a rpc RpcContext. -*/ -void ReleaseBuffer(SharedMemoryContext *context, RpcContext *rpc, - BufferID buffer_id) { - u32 target_node = buffer_id.bits.node_id; - if (target_node == rpc->node_id) { - LocalReleaseBuffer(context, buffer_id); - } else { - RpcCall(rpc, target_node, "RemoteReleaseBuffer", buffer_id); - } -} - -/** - Release remote \a buffer_ids buffers from \a context SharedMemoryContext - and \a rpc RpcContext. -*/ -void ReleaseBuffers(SharedMemoryContext *context, RpcContext *rpc, - const std::vector &buffer_ids) { - for (auto id : buffer_ids) { - ReleaseBuffer(context, rpc, id); - } -} - -/** - Release local \a buffer_ids buffers from \a context SharedMemoryContext. -*/ -void LocalReleaseBuffers(SharedMemoryContext *context, - const std::vector &buffer_ids) { - for (auto id : buffer_ids) { - LocalReleaseBuffer(context, id); - } -} - -/** - Get the BufferID of free buffer at \a slab_index slab index - from \a context SharedMemoryContext and \a device_id DeviceID. -*/ -BufferID GetFreeBuffer(SharedMemoryContext *context, DeviceID device_id, - int slab_index) { - BufferPool *pool = GetBufferPoolFromContext(context); - BufferID result = {}; - - pool->ticket_mutex.Lock(); - BufferID id = PeekFirstFreeBufferId(context, device_id, slab_index); - if (!IsNullBufferId(id)) { - u32 header_index = id.bits.header_index; - BufferHeader *header = GetHeaderByIndex(context, header_index); - header->in_use = true; - result = header->id; - SetFirstFreeBufferId(context, device_id, slab_index, header->next_free); - DecrementAvailableBuffers(context, device_id, slab_index); - - i64 capacity_adjustment = -(i64)header->capacity; - UpdateBufferingCapacities(context, capacity_adjustment, device_id); - } - pool->ticket_mutex.Unlock(); - - return result; -} - -std::vector GetBuffers(SharedMemoryContext *context, - const PlacementSchema &schema) { - BufferPool *pool = GetBufferPoolFromContext(context); - - bool failed = false; - std::vector result; - for (auto [size_left, target] : schema) { - DeviceID device_id = GetDeviceIdFromTargetId(target); - std::vector num_buffers(pool->num_slabs[device_id], 0); - - // NOTE(chogan): naive buffer selection algorithm: fill with largest - // buffers first - for (int i = pool->num_slabs[device_id] - 1; i >= 0; --i) { - size_t buffer_size = GetSlabBufferSize(context, device_id, i); - size_t num_buffers = buffer_size ? size_left / buffer_size : 0; - - while (num_buffers > 0) { - BufferID id = GetFreeBuffer(context, device_id, i); - if (id.as_int) { - result.push_back(id); - BufferHeader *header = GetHeaderByBufferId(context, id); - header->used = buffer_size; - size_left -= buffer_size; - num_buffers--; - } else { - // NOTE(chogan): Out of buffers in this slab. Go to next slab. - break; - } - } - } - - if (size_left > 0) { - size_t buffer_size = GetSlabBufferSize(context, device_id, 0); - BufferID id = GetFreeBuffer(context, device_id, 0); - size_t used = std::min(buffer_size, size_left); - size_left -= used; - if (id.as_int && size_left == 0) { - result.push_back(id); - BufferHeader *header = GetHeaderByBufferId(context, id); - header->used = used; - } else { - failed = true; - DLOG(INFO) << "Not enough buffers to fulfill request" << std::endl; - } - } - } - - if (failed) { - // NOTE(chogan): All or none operation. Must release the acquired buffers if - // we didn't get all we asked for - LocalReleaseBuffers(context, result); - result.clear(); - } - - return result; -} - -/** - Get buffer size from \a context SharedMemoryContext and \a id BufferID. -*/ -u32 LocalGetBufferSize(SharedMemoryContext *context, BufferID id) { - BufferHeader *header = GetHeaderByBufferId(context, id); - u32 result = header->used; - - return result; -} - -/** - Get remote buffer size from \a context SharedMemoryContext, - \a rpc RpcContext, and \a id BufferID. -*/ -u32 GetBufferSize(SharedMemoryContext *context, RpcContext *rpc, BufferID id) { - u32 result = 0; - if (BufferIsRemote(rpc, id)) { - result = RpcCall(rpc, id.bits.node_id, "RemoteGetBufferSize", id); - } else { - result = LocalGetBufferSize(context, id); - } - - return result; -} - -/** - Get remote BLOB size from \a context SharedMemoryContext, - \a rpc RpcContext, and \a buffer_ids BufferIdArray. -*/ -size_t GetBlobSize(SharedMemoryContext *context, RpcContext *rpc, - BufferIdArray *buffer_ids) { - size_t result = 0; - // TODO(chogan): @optimization Combine all ids on same node into 1 RPC - for (u32 i = 0; i < buffer_ids->length; ++i) { - u32 size = GetBufferSize(context, rpc, buffer_ids->ids[i]); - result += size; - } - - return result; -} - -/** - Get remote BLOB size from \a context SharedMemoryContext, - \a rpc RpcContext, \a arena Arena, and \a blob_id BlobID. -*/ -size_t GetBlobSizeById(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id) { - size_t result = 0; - BufferIdArray buffer_ids = - GetBufferIdsFromBlobId(arena, context, rpc, blob_id, NULL); - - if (BlobIsInSwap(blob_id)) { - SwapBlob swap_blob = IdArrayToSwapBlob(buffer_ids); - result = swap_blob.size; - } else { - result = GetBlobSize(context, rpc, &buffer_ids); - } - - return result; -} - - -/** - Get buffer offset of \a id buffer from \a context SharedMemoryContext. -*/ -ptrdiff_t GetBufferOffset(SharedMemoryContext *context, BufferID id) { - BufferHeader *header = GetHeaderByIndex(context, id.bits.header_index); - ptrdiff_t result = header->data_offset; - - return result; -} - -/** - Get RAM buffer pointer of \a id buffer from \a context SharedMemoryContext. -*/ -u8 *GetRamBufferPtr(SharedMemoryContext *context, BufferID buffer_id) { - ptrdiff_t data_offset = GetBufferOffset(context, buffer_id); - if (data_offset > context->shm_size) { - LOG(FATAL) << "Buffer pointer outside of SHM region" << std::endl; - } - u8 *result = context->shm_base + data_offset; - - return result; -} - -/** Make BufferID using \a node_id and \a header_index. */ -BufferID MakeBufferId(u32 node_id, u32 header_index) { - BufferID result = {}; - result.bits.node_id = node_id; - result.bits.header_index = header_index; - - return result; -} - -/** - Partition RAM buffers by \a block_size for \a buffer_count buffers - with \a buffer_size size in \a arena Arena. -*/ -void PartitionRamBuffers(i32 buffer_size, i32 buffer_count, - int block_size) { - for (int i = 0; i < buffer_count; ++i) { - int num_blocks_needed = buffer_size / block_size; - [[maybe_unused]] u8 *first_buffer = PushArray(arena, block_size); - - for (int block = 0; block < num_blocks_needed - 1; ++block) { - // NOTE(chogan): @optimization Since we don't have to store these - // pointers, the only effect of this loop is that the arena will end up - // with the correct "next free" address. This function isn't really - // necessary; it's mainly just testing that everything adds up correctly. - [[maybe_unused]] u8 *buffer = PushArray(arena, block_size); - // NOTE(chogan): Make sure the buffers are perfectly aligned (no holes or - // padding is introduced) - [[maybe_unused]] i32 buffer_block_offset = (block + 1) * block_size; - assert((u8 *)first_buffer == ((u8 *)buffer) - buffer_block_offset); - } - } -} - -/** - Make \a end_index - \a start_index amount of BufferHeaders. - */ -BufferID MakeBufferHeaders(int buffer_size, u32 start_index, - u32 end_index, int node_id, DeviceID device_id, - ptrdiff_t initial_offset, u8 **header_begin) { - BufferHeader dummy = {}; - BufferHeader *previous = &dummy; - - for (u32 i = start_index, j = 0; i < end_index; ++i, ++j) { - BufferHeader *header = PushClearedStruct(arena); - header->id = MakeBufferId(node_id, i); - header->capacity = buffer_size; - header->device_id = device_id; - - // NOTE(chogan): Stored as offset from base address of shared memory - header->data_offset = - (ptrdiff_t)buffer_size * (ptrdiff_t)j + initial_offset; - - previous->next_free = header->id; - previous = header; - - // NOTE(chogan): Store the address of the first header so we can later - // compute the `headers_offset` - if (i == 0 && header_begin) { - *header_begin = (u8 *)header; - } - } - - return dummy.next_free; -} - -/** - Initialize devices. - */ -Device *InitDevices(Config *config, f32 &min_bw, f32 &max_bw) { - min_bw = FLT_MAX; - max_bw = 0; - - Device *result = PushArray(arena, config->num_devices); - - for (int i = 0; i < config->num_devices; ++i) { - Device *device = result + i; - device->bandwidth_mbps = config->bandwidths[i]; - - if (device->bandwidth_mbps > max_bw) { - max_bw = device->bandwidth_mbps; - } - if (device->bandwidth_mbps < min_bw) { - min_bw = device->bandwidth_mbps; - } - - device->latency_ns = config->latencies[i]; - device->id = i; - device->is_shared = config->is_shared_device[i]; - // TODO(chogan): @configuration Get this from cmake. - device->has_fallocate = false; - size_t path_length = config->mount_points[i].size(); - - if (path_length == 0) { - device->is_byte_addressable = true; - } else { - if (path_length < kMaxPathLength) { - snprintf(device->mount_point, path_length + 1, "%s", - config->mount_points[i].c_str()); - } else { - LOG(ERROR) << "Mount point path " << config->mount_points[i] - << " exceeds max length of " << kMaxPathLength << std::endl; - } - } - } - - return result; -} - -/** Initialize targets. */ -Target *InitTargets(Config *config, Device *devices, - int node_id) { - Target *result = PushClearedArray(arena, config->num_targets); - - if (config->num_targets != config->num_devices) { - HERMES_NOT_IMPLEMENTED_YET; - } - - for (int i = 0; i < config->num_targets; ++i) { - TargetID id = {}; - id.bits.node_id = node_id; - id.bits.device_id = (DeviceID)i; - id.bits.index = i; - Target *target = result + i; - target->id = id; - target->capacity = config->capacities[i]; - target->remaining_space.store(config->capacities[i]); - target->speed.store(devices[i].bandwidth_mbps); - } - - return result; -} - -/** - Merge RAM buffer free list. - - \todo (chogan): needs more testing for the case when the free list has - been jumbled for a while. Currently, we just test a nice linear free list. -*/ -void MergeRamBufferFreeList(SharedMemoryContext *context, int slab_index) { - BufferPool *pool = GetBufferPoolFromContext(context); - - if (slab_index < 0 || slab_index >= pool->num_slabs[0] - 1) { - // TODO(chogan): @logging - return; - } - - // TODO(chogan): @configuration Assumes RAM is first Device - int this_slab_unit_size = GetSlabUnitSize(context, 0, slab_index); - int bigger_slab_unit_size = GetSlabUnitSize(context, 0, slab_index + 1); - - // TODO(chogan): Currently just handling the case where the next slab size is - // perfectly divisible by this slab's size - if (this_slab_unit_size == 0 || - bigger_slab_unit_size % this_slab_unit_size != 0) { - // TODO(chogan): @logging - return; - } - - int merge_factor = bigger_slab_unit_size / this_slab_unit_size; - int new_slab_size_in_bytes = bigger_slab_unit_size * pool->block_sizes[0]; - int old_slab_size_in_bytes = this_slab_unit_size * pool->block_sizes[0]; - - pool->ticket_mutex.Lock(); - // TODO(chogan): Assuming first Device is RAM - DeviceID device_id = 0; - BufferID id = PeekFirstFreeBufferId(context, device_id, slab_index); - - while (id.as_int != 0) { - BufferHeader *header_to_merge = GetHeaderByIndex(context, - id.bits.header_index); - ptrdiff_t initial_offset = header_to_merge->data_offset; - - // NOTE(chogan): First go through the next `merge_factor` buffers and see if - // a merge is possible. - bool have_enough_buffers = false; - bool buffers_are_contiguous = true; - bool buffer_offsets_are_ascending = true; - BufferID id_copy = id; - for (int i = 0; - i < merge_factor && id_copy.as_int != 0 && buffers_are_contiguous; - ++i) { - BufferHeader *header = GetHeaderByBufferId(context, id_copy); - if (i != 0) { - // NOTE(chogan): Contiguous buffers may be in either ascending or - // descending order - int buffer_offset = i * old_slab_size_in_bytes; - buffer_offsets_are_ascending = header->data_offset > initial_offset; - buffer_offset *= buffer_offsets_are_ascending ? 1 : -1; - if (initial_offset + buffer_offset != header->data_offset) { - buffers_are_contiguous = false; - } - } - if (i == merge_factor - 1) { - have_enough_buffers = true; - } - id_copy = header->next_free; - } - - if (have_enough_buffers && buffers_are_contiguous) { - int saved_free_list_count = 0; - // TODO(chogan): What's the max this number could be? Could save the tail - // and attach to the end of the free list rather than doing all this - // popping, saving, and pushing - const int max_saved_entries = 64; - BufferID saved_free_list_entries[max_saved_entries] = {}; - // NOTE(chogan): Pop `merge_factor` entries off the free list for - // `slab_index` - id_copy = id; - for (int i = 0; - i < merge_factor; - ++i) { - BufferHeader *header = GetHeaderByBufferId(context, id_copy); - - while (header->id.as_int != - PeekFirstFreeBufferId(context, device_id, slab_index).as_int) { - // NOTE(chogan): It's possible that the buffer we're trying to pop - // from the free list is not at the beginning of the list. In that - // case, we have to pop and save all the free buffers before the one - // we're interested in, and then restore them to the free list later. - assert(saved_free_list_count < max_saved_entries); - saved_free_list_entries[saved_free_list_count++] = - PeekFirstFreeBufferId(context, device_id, slab_index); - - BufferID first_id = PeekFirstFreeBufferId(context, device_id, - slab_index); - BufferHeader *first_free = GetHeaderByBufferId(context, first_id); - SetFirstFreeBufferId(context, device_id, slab_index, - first_free->next_free); - } - - SetFirstFreeBufferId(context, device_id, slab_index, header->next_free); - id_copy = header->next_free; - MakeHeaderDormant(header); - } - - ResetHeader(header_to_merge); - if (buffer_offsets_are_ascending) { - header_to_merge->data_offset = initial_offset; - } else { - // NOTE(chogan): In this case `initial_offset` points at the beginning - // of the last of `this_slab_unit_size` buffers. We need to back it up - // to the correct position. - ptrdiff_t back_up_count = old_slab_size_in_bytes * (merge_factor - 1); - header_to_merge->data_offset = initial_offset - back_up_count; - } - header_to_merge->capacity = new_slab_size_in_bytes; - - // NOTE(chogan): Add the new header to the next size up's free list - header_to_merge->next_free = PeekFirstFreeBufferId(context, device_id, - slab_index + 1); - SetFirstFreeBufferId(context, device_id, slab_index + 1, - header_to_merge->id); - - while (saved_free_list_count > 0) { - // NOTE(chogan): Restore headers that we popped and saved. - BufferID saved_id = saved_free_list_entries[--saved_free_list_count]; - BufferHeader *saved_header = GetHeaderByBufferId(context, saved_id); - saved_header->next_free = PeekFirstFreeBufferId(context, device_id, - slab_index); - SetFirstFreeBufferId(context, device_id, slab_index, saved_header->id); - } - - id = id_copy; - } else { - // NOTE(chogan): Didn't have enough contiguous buffers for a merge. Try - // the next free buffer. - id = header_to_merge->next_free; - } - } - pool->ticket_mutex.Unlock(); -} -/** - Split RAM buffer free list. - - \todo (chogan) Needs more testing for the case when the free list has - been jumbled for a while. Currently we just test a nice linear free list. -*/ -void SplitRamBufferFreeList(SharedMemoryContext *context, int slab_index) { - BufferPool *pool = GetBufferPoolFromContext(context); - - if (slab_index < 1 || slab_index >= pool->num_slabs[0]) { - // TODO(chogan): @logging - return; - } - - int this_slab_unit_size = GetSlabUnitSize(context, 0, slab_index); - int smaller_slab_unit_size = GetSlabUnitSize(context, 0, slab_index - 1); - - // TODO(chogan): Currently just handling the case where this slab size is - // perfectly divisible by the next size down - assert(smaller_slab_unit_size && - this_slab_unit_size % smaller_slab_unit_size == 0); - - int split_factor = this_slab_unit_size / smaller_slab_unit_size; - int new_slab_size_in_bytes = smaller_slab_unit_size * pool->block_sizes[0]; - - // TODO(chogan): @optimization We don't really want to wait for a long queue - // on the ticket mutex. If we need to split, we want to stop the world and do - // it immediately. - pool->ticket_mutex.Lock(); - // TODO(chogan): Assuming first Device is RAM - DeviceID device_id = 0; - BufferID id = PeekFirstFreeBufferId(context, device_id, slab_index); - u32 unused_header_index = 0; - BufferHeader *headers = GetHeadersBase(context); - BufferHeader *next_unused_header = &headers[unused_header_index]; - - while (id.as_int != 0) { - BufferHeader *header_to_split = GetHeaderByIndex(context, - id.bits.header_index); - ptrdiff_t old_data_offset = header_to_split->data_offset; - SetFirstFreeBufferId(context, device_id, slab_index, - header_to_split->next_free); - id = header_to_split->next_free; - - for (int i = 0; i < split_factor; ++i) { - // NOTE(chogan): Find the next dormant header. This is easy to optimize - // when splitting since we can keep the live and dormant headers separate - // and store `first_dormant_header`, but this isn't possible when merging - // (because we can't move headers that are in use). So, we have to scan - // the array. - if (i == 0) { - // NOTE(chogan): Reuse this header as the first unused one - next_unused_header = header_to_split; - } else { - while (!HeaderIsDormant(next_unused_header)) { - // NOTE(chogan): Assumes first Device is RAM - if (++unused_header_index >= pool->num_headers[0]) { - unused_header_index = 0; - } - next_unused_header = &headers[unused_header_index]; - } - } - - ResetHeader(next_unused_header); - next_unused_header->data_offset = old_data_offset; - next_unused_header->capacity = new_slab_size_in_bytes; - - next_unused_header->next_free = PeekFirstFreeBufferId(context, device_id, - slab_index - 1); - SetFirstFreeBufferId(context, device_id, slab_index - 1, - next_unused_header->id); - - old_data_offset += new_slab_size_in_bytes; - } - } - pool->ticket_mutex.Unlock(); -} - -/** - * GetBufferSlabInfo - * - * @scratch temporary memory (avoids using new/malloc) - * @config the shared-memory hermes config - * @slab_buffer_sizes the size (bytes) of each buffer in a particular device - * @buffer_counts the number of slabs in a particular device - * */ - -void GetBufferSlabInfo(ScopedTemporaryMemory &scratch, Config *config, - i32 **slab_buffer_sizes, i32 **buffer_counts, - size_t &total_ram_bytes) { - for (int device = 0; device < config->num_devices; ++device) { - slab_buffer_sizes[device] = PushArray(scratch, - config->num_slabs[device]); - buffer_counts[device] = PushArray(scratch, config->num_slabs[device]); - - for (int slab = 0; slab < config->num_slabs[device]; ++slab) { - slab_buffer_sizes[device][slab] = (config->block_sizes[device] * - config->slab_unit_sizes[device][slab]); - f32 slab_percentage = config->desired_slab_percentages[device][slab]; - f32 device_capacity = config->capacities[device]; - size_t bytes_for_slab = (size_t)((f32)device_capacity * - slab_percentage); - if (device == 0) { - bytes_for_slab *= .6; // TODO(llogan): this is a temporary hack - } - buffer_counts[device][slab] = (bytes_for_slab / - slab_buffer_sizes[device][slab]); - if (device == 0) { - total_ram_bytes += bytes_for_slab; - } - } - } -} -ptrdiff_t InitBufferPool(u8 *shmem_base, Arena *buffer_pool_arena, - Arena *scratch_arena, i32 node_id, Config *config) { - ScopedTemporaryMemory scratch(scratch_arena); - - i32 **buffer_counts = PushArray(scratch, config->num_devices); - i32 **slab_buffer_sizes = PushArray(scratch, config->num_devices); - i32 *header_counts = PushArray(scratch, config->num_devices); - size_t total_ram_bytes = 0; - - // Determine the number and size of buffers - GetBufferSlabInfo(scratch, config, slab_buffer_sizes, buffer_counts, - total_ram_bytes); - - // TODO(chogan): @configuration Assumes first Device is RAM - // TODO(chogan): Allow splitting and merging for every Device - - // NOTE(chogan): We need one header per RAM block to allow for splitting and - // merging - header_counts[0] = total_ram_bytes / config->block_sizes[0]; - for (int device = 1; device < config->num_devices; ++device) { - header_counts[device] = 0; - for (int slab = 0; slab < config->num_slabs[device]; ++slab) { - header_counts[device] += buffer_counts[device][slab]; - } - } - - // NOTE(chogan): Anything stored in the buffer_pool_arena (besides buffers) - // needs to be accounted for here. It would be nice to have a compile time - // check that makes sure anything we allocate for the buffer pool but outside - // of it gets accounted for here. - - i32 max_headers_needed = 0; - size_t free_lists_size = 0; - size_t slab_metadata_size = 0; - for (int device = 0; device < config->num_devices; ++device) { - max_headers_needed += header_counts[device]; - free_lists_size += config->num_slabs[device] * sizeof(BufferID); - // NOTE(chogan): The '* 2' is because we have an i32 for both slab unit size - // and slab buffer size - slab_metadata_size += config->num_slabs[device] * sizeof(i32) * 2; - // NOTE(chogan): buffers_available array - slab_metadata_size += config->num_slabs[device] * sizeof(u32); - } - - size_t client_info_size = sizeof(ShmemClientInfo); - size_t headers_size = max_headers_needed * sizeof(BufferHeader); - size_t devices_size = config->num_devices * sizeof(Device); - size_t buffer_pool_size = (sizeof(BufferPool) + free_lists_size + - slab_metadata_size); - - // IMPORTANT(chogan): Currently, no additional bytes are added for alignment. - // However, if we add more metadata to the BufferPool in the future, automatic - // alignment could make this number larger than we think. `PushSize` will - // print out when it adds alignment padding, so for now we can monitor that. - // In the future it would be nice to have a programatic way to account for - // alignment padding. - size_t required_bytes_for_metadata = (client_info_size + headers_size + - buffer_pool_size + devices_size); - LOG(INFO) << required_bytes_for_metadata - << " bytes required for BufferPool metadata" << std::endl; - - size_t required_bytes_for_metadata_rounded = - RoundUpToMultiple(required_bytes_for_metadata, config->block_sizes[0]); - i32 num_blocks_reserved_for_metadata = (required_bytes_for_metadata_rounded / - config->block_sizes[0]); - - if (buffer_counts[0][0] >= num_blocks_reserved_for_metadata) { - // NOTE(chogan): Remove some of the smallest RAM buffers to make room for - // metadata - buffer_counts[0][0] -= num_blocks_reserved_for_metadata; - // NOTE(chogan): We need fewer headers because we have fewer buffers now - header_counts[0] -= num_blocks_reserved_for_metadata; - } else { - if (required_bytes_for_metadata > config->capacities[0]) { - LOG(FATAL) << "Insufficient memory for BufferPool. Increase " - << "capacities_mb[0] or buffer_pool_arena_percentage\n"; - } - } - - // NOTE(chogan): Adjust the config capacity for RAM to reflect the actual - // capacity for buffering (excluding BufferPool metadata). - size_t actual_ram_buffer_capacity = 0; - for (int slab = 0; slab < config->num_slabs[0]; ++slab) { - size_t slab_bytes = - (size_t)buffer_counts[0][slab] * (size_t)slab_buffer_sizes[0][slab]; - actual_ram_buffer_capacity += slab_bytes; - } - config->capacities[0] = actual_ram_buffer_capacity; - - u32 total_headers = 0; - for (DeviceID device = 0; device < config->num_devices; ++device) { - total_headers += header_counts[device]; - } - - int *num_buffers = PushArray(scratch_arena, config->num_devices); - int total_buffers = 0; - for (int device = 0; device < config->num_devices; ++device) { - DLOG(INFO) << "Device: " << device << std::endl; - num_buffers[device] = 0; - for (int slab = 0; slab < config->num_slabs[device]; ++slab) { - DLOG(INFO) << " " << slab << "-Buffers: " - << buffer_counts[device][slab] << std::endl; - num_buffers[device] += buffer_counts[device][slab]; - } - total_buffers += num_buffers[device]; - DLOG(INFO) << " Num Headers: " << header_counts[device] << std::endl; - DLOG(INFO) << " Num Buffers: " << num_buffers[device] << std::endl; - } - DLOG(INFO) << "Total Buffers: " << total_buffers << std::endl;; - - // Build RAM buffers. - - // NOTE(chogan): Store offsets to the MDM and BPM at the beginning of shared - // memory so other processes can pick it up. - ShmemClientInfo *client_info = PushStruct(buffer_pool_arena); - - // TODO(chogan): @configuration Assumes the first Device is RAM - for (int slab = 0; slab < config->num_slabs[0]; ++slab) { - PartitionRamBuffers(buffer_pool_arena, slab_buffer_sizes[0][slab], - buffer_counts[0][slab], config->block_sizes[0]); - } - - // Init Devices and Targets - - f32 min_bw = 0; - f32 max_bw = 0; - Device *devices = InitDevices(buffer_pool_arena, config, min_bw, max_bw); - - Target *targets = InitTargets(buffer_pool_arena, config, devices, node_id); - - // Create Free Lists - - BufferID **free_lists = PushArray(scratch_arena, - config->num_devices); - for (int device = 0; device < config->num_devices; ++device) { - free_lists[device] = PushArray(scratch_arena, - config->num_slabs[device]); - } - - // Build BufferHeaders - - u32 start = 0; - u8 *header_begin = 0; - ptrdiff_t initial_offset = sizeof(ShmemClientInfo); - // TODO(chogan): @configuration Assumes first Device is RAM - for (i32 i = 0; i < config->num_slabs[0]; ++i) { - u32 end = start + buffer_counts[0][i]; - DeviceID ram_device_id = 0; - free_lists[ram_device_id][i] = - MakeBufferHeaders(buffer_pool_arena, slab_buffer_sizes[0][i], start, end, - node_id, ram_device_id, initial_offset, &header_begin); - start = end; - initial_offset += (ptrdiff_t)buffer_counts[0][i] * slab_buffer_sizes[0][i]; - } - - // NOTE(chogan): Add remaining unused RAM headers - for (u32 i = num_buffers[0]; i < (u32)header_counts[0]; ++i) { - BufferHeader *header = PushClearedStruct(buffer_pool_arena); - header->id = MakeBufferId(node_id, i); - start += 1; - } - - // NOTE(chogan): Add headers for the other Devices - for (int device = 1; device < config->num_devices; ++device) { - for (int slab = 0; slab < config->num_slabs[device]; ++slab) { - // NOTE(chogan): File buffering scheme is one file per slab per Device - u32 end = start + buffer_counts[device][slab]; - free_lists[device][slab] = - MakeBufferHeaders(buffer_pool_arena, slab_buffer_sizes[device][slab], - start, end, node_id, device, 0, &header_begin); - start = end; - } - } - - // Build BufferPool - - BufferPool *pool = PushClearedStruct(buffer_pool_arena); - pool->headers_offset = header_begin - shmem_base; - pool->devices_offset = (u8 *)devices - shmem_base; - pool->targets_offset = (u8 *)targets - shmem_base; - pool->num_devices = config->num_devices; - pool->total_headers = total_headers; - pool->min_device_bw_mbps = min_bw; - pool->max_device_bw_mbps = max_bw; - - for (int device = 0; device < config->num_devices; ++device) { - pool->block_sizes[device] = config->block_sizes[device]; - pool->num_headers[device] = header_counts[device]; - pool->num_slabs[device] = config->num_slabs[device]; - BufferID *free_list = PushArray(buffer_pool_arena, - config->num_slabs[device]); - i32 *slab_unit_sizes = PushArray(buffer_pool_arena, - config->num_slabs[device]); - i32 *slab_buffer_sizes_for_device = PushArray(buffer_pool_arena, - config->num_slabs[device]); - std::atomic *available_buffers = - PushArray>(buffer_pool_arena, config->num_slabs[device]); - - for (int slab = 0; slab < config->num_slabs[device]; ++slab) { - free_list[slab] = free_lists[device][slab]; - slab_unit_sizes[slab] = config->slab_unit_sizes[device][slab]; - slab_buffer_sizes_for_device[slab] = slab_buffer_sizes[device][slab]; - available_buffers[slab] = buffer_counts[device][slab]; - } - pool->free_list_offsets[device] = (u8 *)free_list - shmem_base; - pool->slab_unit_sizes_offsets[device] = (u8 *)slab_unit_sizes - shmem_base; - pool->slab_buffer_sizes_offsets[device] = - ((u8 *)slab_buffer_sizes_for_device - shmem_base); - pool->buffers_available_offsets[device] = - ((u8 *)available_buffers - shmem_base); - } - - ptrdiff_t buffer_pool_offset = (u8 *)pool - shmem_base; - client_info->bpm_offset = buffer_pool_offset; - - return buffer_pool_offset; -} - -/** - Write buffer pool to \a file file. -*/ -void SerializeBufferPoolToFile(SharedMemoryContext *context, FILE *file) { - int result = fwrite(context->shm_base, context->shm_size, 1, file); - - if (result < 1) { - FailedLibraryCall("fwrite"); - } -} - -// Per-rank application side initialization - -void MakeFullShmemName(char *dest, const char *base) { - size_t base_name_length = strlen(base); - snprintf(dest, base_name_length + 1, "%s", base); - char *username = getenv("USER"); - if (username) { - size_t username_length = strlen(username); - size_t total_length = base_name_length + username_length + 1; - - if (total_length < kMaxBufferPoolShmemNameLength) { - snprintf(dest + base_name_length, username_length + 1, "%s", username); - } else { - LOG(ERROR) << "Shared memory name " << base << username - << " exceeds max length of " << kMaxBufferPoolShmemNameLength - << std::endl; - } - } else { - // TODO(chogan): Use pid? - } -} - -/** Terminate if fopen() call fails. Otherwise, return file pointer. */ -FILE *FopenOrTerminate(const char *fname, const char *mode) { - FILE *result = fopen(fname, mode); - - if (!result) { - LOG(ERROR) << "Failed to open file at " << fname << ": "; - perror(nullptr); - LOG(FATAL) << "Terminating..."; - } - - return result; -} - -/** Terminate if open() call fails. Otherwise, return file pointer. */ -int OpenOrTerminate(const std::string &fname, int flags, mode_t mode = 0) { - int result = open(fname.c_str(), flags, mode); - - if (result == -1) { - LOG(ERROR) << "Failed to open file at " << fname << ": "; - perror(nullptr); - LOG(FATAL) << "Terminating..."; - } - - return result; -} - -void InitFilesForBuffering(SharedMemoryContext *context, - CommunicationContext &comm) { - BufferPool *pool = GetBufferPoolFromContext(context); - context->buffering_filenames.resize(pool->num_devices); - - // TODO(chogan): Check the limit for open files via getrlimit. We might have - // to do some smarter opening and closing to stay under the limit. Could also - // increase the soft limit to the hard limit. - for (int device_id = 0; device_id < pool->num_devices; ++device_id) { - Device *device = GetDeviceById(context, device_id); - char *mount_point = &device->mount_point[0]; - - if (strlen(mount_point) == 0) { - // NOTE(chogan): RAM Device. No need for a file. - continue; - } - - bool ends_in_slash = mount_point[strlen(mount_point) - 1] == '/'; - context->buffering_filenames[device_id].resize(pool->num_slabs[device_id]); - - for (int slab = 0; slab < pool->num_slabs[device_id]; ++slab) { - std::string node = (device->is_shared ? std::string("_node") + - std::to_string(comm.node_id) : ""); - context->buffering_filenames[device_id][slab] = - std::string(std::string(mount_point) + (ends_in_slash ? "" : "/") + - "device" + std::to_string(device_id) + "_slab" + - std::to_string(slab) + node + ".hermes"); - - int buffering_file_fd = 0; - bool reserve_space = false; - - if (comm.proc_kind == ProcessKind::kHermes) { - if (device->is_shared && comm.sub_proc_id == 0) { - // Only one rank should create the file for shared devices - reserve_space = true; - } - - if (!device->is_shared && comm.first_on_node) { - // One rank per node creates the file for node-local devices - reserve_space = true; - } - - if (reserve_space) { - int open_flags = O_RDWR | O_CREAT | O_TRUNC; - int open_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - buffering_file_fd = - OpenOrTerminate(context->buffering_filenames[device_id][slab], - open_flags, open_mode); - - u32 num_buffers = GetNumBuffersAvailable(context, device_id, slab); - i32 buffer_size = GetSlabBufferSize(context, device_id, slab); - size_t this_slabs_capacity = num_buffers * buffer_size; - - // TODO(chogan): Use posix_fallocate when it is available - // if (device->has_fallocate) { - // int fallocate_result = posix_fallocate(buffering_file_fd, 0, - // this_slabs_capacity); - // } - - int ftruncate_result = ftruncate(buffering_file_fd, - this_slabs_capacity); - if (ftruncate_result) { - LOG(ERROR) << "Failed to allocate buffering file at " - << context->buffering_filenames[device_id][slab] << ": "; - FailedLibraryCall("ftruncate"); - } - } - } - - WorldBarrier(&comm); - - if (!reserve_space) { - // File should already be created, so we just open it - int open_flags = O_RDWR; - buffering_file_fd = - OpenOrTerminate(context->buffering_filenames[device_id][slab], - open_flags); - } - context->open_files[device_id][slab] = buffering_file_fd; - } - } -} - -/** Initialize shared memory. */ -u8 *InitSharedMemory(const char *shmem_name, size_t total_size) { - u8 *result = 0; - int shmem_fd = - shm_open(shmem_name, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); - if (shmem_fd < 0) { - // shm_unlink(shmem_name); - FailedLibraryCall("shm_open"); - } - - int ftruncate_result = ftruncate(shmem_fd, total_size); - if (ftruncate_result != 0) { - FailedLibraryCall("ftruncate"); - } - - result = (u8 *)mmap(0, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, - shmem_fd, 0); - - if (result == MAP_FAILED) { - FailedLibraryCall("mmap"); - } - if (close(shmem_fd) == -1) { - FailedLibraryCall("close"); - } - - return result; -} - -SharedMemoryContext GetSharedMemoryContext(char *shmem_name) { - SharedMemoryContext result = {}; - - int shmem_fd = shm_open(shmem_name, O_RDWR, S_IRUSR | S_IWUSR); - - if (shmem_fd >= 0) { - struct stat shm_stat; - if (__fxstat(_STAT_VER, shmem_fd, &shm_stat) == 0) { - u8 *shm_base = (u8 *)mmap(0, shm_stat.st_size, PROT_READ | PROT_WRITE, - MAP_SHARED, shmem_fd, 0); - close(shmem_fd); - - if (shm_base) { - // NOTE(chogan): BPM and MDM offsets are stored at the beginning of the - // shared memory segment - ShmemClientInfo *client_info = (ShmemClientInfo *)shm_base; - result.buffer_pool_offset = client_info->bpm_offset; - result.metadata_manager_offset = client_info->mdm_offset; - result.shm_base = shm_base; - result.shm_size = shm_stat.st_size; - } else { - // TODO(chogan): @logging Error handling - perror("mmap_failed"); - } - } else { - // TODO(chogan): @logging Error handling - perror("fstat failed"); - } - } else { - // TODO(chogan): @logging Error handling - perror("shm_open failed"); - } - - return result; -} - -/** Unmap shared memory. */ -void UnmapSharedMemory(SharedMemoryContext *context) { - munmap(context->shm_base, context->shm_size); -} - -/** Close buffering files. */ -void CloseBufferingFiles(SharedMemoryContext *context) { - BufferPool *pool = GetBufferPoolFromContext(context); - - for (int device_id = 0; device_id < pool->num_devices; ++device_id) { - for (int slab = 0; slab < pool->num_slabs[device_id]; ++slab) { - if (context->open_files[device_id][slab]) { - int close_result = close(context->open_files[device_id][slab]); - if (close_result != 0) { - FailedLibraryCall("close"); - } - } - } - } - - if (context->swap_file) { - if (fclose(context->swap_file) != 0) { - FailedLibraryCall("fclose"); - } - } -} - -void ReleaseSharedMemoryContext(SharedMemoryContext *context) { - CloseBufferingFiles(context); - UnmapSharedMemory(context); -} - -// IO clients - -/** Write buffer by \a id buffer locally. */ -size_t LocalWriteBufferById(SharedMemoryContext *context, BufferID id, - const Blob &blob, size_t offset) { - BufferHeader *header = GetHeaderByIndex(context, id.bits.header_index); - Device *device = GetDeviceFromHeader(context, header); - size_t write_size = header->used; - - u8 *at = (u8 *)blob.data + offset; - if (device->is_byte_addressable) { - u8 *dest = GetRamBufferPtr(context, header->id); - memcpy(dest, at, write_size); - } else { - int slab_index = GetSlabIndexFromHeader(context, header); - const char *filename = - context->buffering_filenames[device->id][slab_index].c_str(); - // TODO(chogan): Use context->open_files - int fd = open(filename, O_WRONLY); - - if (fd != -1) { - if (flock(fd, LOCK_EX) != 0) { - FailedLibraryCall("flock"); - } - - ssize_t bytes_written = pwrite(fd, at, write_size, header->data_offset); - if (bytes_written == -1 || (size_t)bytes_written != write_size) { - FailedLibraryCall("pwrite"); - } - - if (flock(fd, LOCK_UN) != 0) { - FailedLibraryCall("flock"); - } - - if (close(fd) != 0) { - FailedLibraryCall("close"); - } - } else { - FailedLibraryCall("open"); - } - } - - return write_size; -} - -void WriteBlobToBuffers(SharedMemoryContext *context, RpcContext *rpc, - const Blob &blob, - const std::vector &buffer_ids) { - size_t bytes_left_to_write = blob.size; - size_t offset = 0; - // TODO(chogan): @optimization Handle sequential buffers as one I/O operation - // TODO(chogan): @optimization Aggregate multiple RPCs into one - for (const auto &id : buffer_ids) { - size_t bytes_written = 0; - if (BufferIsRemote(rpc, id)) { - // TODO(chogan): @optimization Set up bulk transfer if blob.size is > 4K - // TODO(chogan): @optimization Only send the portion of the blob we have - // to write. - // TODO(chogan): @optimization Avoid copy - std::vector data(blob.size); - memcpy(data.data(), blob.data, blob.size); - bytes_written = RpcCall(rpc, id.bits.node_id, - "RemoteWriteBufferById", id, data, - offset); - } else { - bytes_written = LocalWriteBufferById(context, id, blob, offset); - } - bytes_left_to_write -= bytes_written; - offset += bytes_written; - } - assert(offset == blob.size); - assert(bytes_left_to_write == 0); -} - -/** Read buffer by \a id buffer locally. */ -size_t LocalReadBufferById(SharedMemoryContext *context, BufferID id, - Blob *blob, size_t read_offset) { - BufferHeader *header = GetHeaderByIndex(context, id.bits.header_index); - Device *device = GetDeviceFromHeader(context, header); - size_t read_size = header->used; - size_t result = 0; - - if (read_size > 0) { - if (device->is_byte_addressable) { - u8 *src = GetRamBufferPtr(context, header->id); - memcpy((u8 *)blob->data + read_offset, src, read_size); - result = read_size; - } else { - int slab_index = GetSlabIndexFromHeader(context, header); - const char *filename = - context->buffering_filenames[device->id][slab_index].c_str(); - int fd = open(filename, O_RDONLY); - - if (fd != -1) { - if (flock(fd, LOCK_SH) != 0) { - FailedLibraryCall("flock"); - } - - ssize_t bytes_read = pread(fd, (u8 *)blob->data + read_offset, - read_size, header->data_offset); - if (bytes_read == -1 || (size_t)bytes_read != read_size) { - FailedLibraryCall("pread"); - } - - if (flock(fd, LOCK_UN) != 0) { - FailedLibraryCall("flock"); - } - - if (close(fd) != 0) { - FailedLibraryCall("close"); - } - - result = bytes_read; - } else { - FailedLibraryCall("open"); - } - } - } - - return result; -} - -size_t ReadBlobFromBuffers(SharedMemoryContext *context, RpcContext *rpc, - Blob *blob, BufferIdArray *buffer_ids, - u32 *buffer_sizes) { - size_t total_bytes_read = 0; - // TODO(chogan): @optimization Handle sequential buffers as one I/O operation - for (u32 i = 0; i < buffer_ids->length; ++i) { - size_t bytes_read = 0; - BufferID id = buffer_ids->ids[i]; - if (BufferIsRemote(rpc, id)) { - // TODO(chogan): @optimization Aggregate multiple RPCs to same node into - // one RPC. - if (buffer_sizes[i] > KILOBYTES(4)) { - size_t bytes_transferred = BulkRead(rpc, id.bits.node_id, - "RemoteBulkReadBufferById", - blob->data + total_bytes_read, - buffer_sizes[i], id); - if (bytes_transferred != buffer_sizes[i]) { - LOG(ERROR) << "BulkRead only transferred " << bytes_transferred - << " out of " << buffer_sizes[i] << " bytes" << std::endl; - } - bytes_read += bytes_transferred; - } else { - std::vector data = - RpcCall>(rpc, id.bits.node_id, "RemoteReadBufferById", - id); - bytes_read = data.size(); - // TODO(chogan): @optimization Avoid the copy - u8 *read_dest = (u8 *)blob->data + total_bytes_read; - memcpy(read_dest, data.data(), bytes_read); - } - } else { - bytes_read = LocalReadBufferById(context, id, blob, total_bytes_read); - } - total_bytes_read += bytes_read; - } - - if (total_bytes_read != blob->size) { - LOG(ERROR) << __func__ << "expected to read a Blob of size " << blob->size - << " but only read " << total_bytes_read << std::endl; - } - - return total_bytes_read; -} - -/** Read \a blob_id BLOB. */ -size_t ReadBlobById(SharedMemoryContext *context, RpcContext *rpc, Arena *arena, - Blob blob, BlobID blob_id) { - size_t result = 0; - - BufferIdArray buffer_ids = {}; - if (hermes::BlobIsInSwap(blob_id)) { - buffer_ids = GetBufferIdsFromBlobId(arena, context, rpc, blob_id, NULL); - SwapBlob swap_blob = IdArrayToSwapBlob(buffer_ids); - result = ReadFromSwap(context, blob, swap_blob); - } else { - u32 *buffer_sizes = 0; - buffer_ids = GetBufferIdsFromBlobId(arena, context, rpc, blob_id, - &buffer_sizes); - result = ReadBlobFromBuffers(context, rpc, &blob, &buffer_ids, - buffer_sizes); - } - - return result; -} - -/** Read a remote \a blob_id BLOB. */ -size_t ReadBlobById(SharedMemoryContext *context, RpcContext *rpc, Arena *arena, - api::Blob &dest, BlobID blob_id) { - hermes::Blob blob = {}; - blob.data = dest.data(); - blob.size = dest.size(); - size_t result = ReadBlobById(context, rpc, arena, blob, blob_id); - - return result; -} - -/** Open swap file. */ -void OpenSwapFile(SharedMemoryContext *context, u32 node_id) { - if (!context->swap_file) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - std::string swap_path = GetSwapFilename(mdm, node_id); - context->swap_file = fopen(swap_path.c_str(), "a+"); - - if (!context->swap_file) { - FailedLibraryCall("fopen"); - } - } -} - -/** Write \a blob data to a swap file. */ -SwapBlob WriteToSwap(SharedMemoryContext *context, Blob blob, u32 node_id, - BucketID bucket_id) { - SwapBlob result = {}; - - OpenSwapFile(context, node_id); - if (fseek(context->swap_file, 0, SEEK_END) != 0) { - FailedLibraryCall("fseek"); - } - - long int file_position = ftell(context->swap_file); - if (file_position == -1) { - FailedLibraryCall("ftell"); - } - result.offset = file_position; - - if (fwrite(blob.data, 1, blob.size, context->swap_file) != blob.size) { - FailedLibraryCall("fwrite"); - } - - if (fflush(context->swap_file) != 0) { - FailedLibraryCall("fflush"); - } - - result.node_id = node_id; - result.bucket_id = bucket_id; - result.size = blob.size; - - return result; -} - -/** Put \a data to a remote swap. */ -SwapBlob PutToSwap(SharedMemoryContext *context, RpcContext *rpc, - const std::string &name, BucketID bucket_id, const u8 *data, - size_t size) { - hermes::Blob blob = {}; - blob.data = (u8 *)data; - blob.size = size; - - u32 target_node = rpc->node_id; - SwapBlob swap_blob = WriteToSwap(context, blob, target_node, bucket_id); - std::vector buffer_ids = SwapBlobToVec(swap_blob); - AttachBlobToBucket(context, rpc, name.c_str(), bucket_id, buffer_ids, - kSwapTargetId, true); - - return swap_blob; -} - -/** Read \a blob data from swap file. */ -size_t ReadFromSwap(SharedMemoryContext *context, Blob blob, - SwapBlob swap_blob) { - u32 node_id = swap_blob.node_id; - OpenSwapFile(context, node_id); - if (fseek(context->swap_file, swap_blob.offset, SEEK_SET) != 0) { - FailedLibraryCall("fseek"); - } - - if (fread(blob.data, 1, swap_blob.size, context->swap_file) != - swap_blob.size) { - FailedLibraryCall("fread"); - } - - return swap_blob.size; -} - -/** Place \a blob BLOB. */ -api::Status PlaceBlob(SharedMemoryContext *context, RpcContext *rpc, - PlacementSchema &schema, Blob blob, - const std::string &name, BucketID bucket_id, - const api::Context &ctx, - bool called_from_buffer_organizer) { - api::Status result; - - if (ContainsBlob(context, rpc, bucket_id, name) - && !called_from_buffer_organizer) { - // TODO(chogan) @optimization If the existing buffers are already large - // enough to hold the new Blob, then we don't need to release them. - // Additionally, no metadata operations would be required. - DestroyBlobByName(context, rpc, bucket_id, name); - } - - HERMES_BEGIN_TIMED_BLOCK("GetBuffers"); - std::vector buffer_ids = GetBuffers(context, schema); - HERMES_END_TIMED_BLOCK(); - - if (buffer_ids.size()) { - HERMES_BEGIN_TIMED_BLOCK("WriteBlobToBuffers"); - WriteBlobToBuffers(context, rpc, blob, buffer_ids); - HERMES_END_TIMED_BLOCK(); - - std::pair max_target = - *std::max_element(schema.begin(), schema.end(), - [](const auto& lhs, const auto& rhs) { - return lhs.first < rhs.first; - }); - TargetID effective_target = max_target.second; - - // NOTE(chogan): Update all metadata associated with this Put - AttachBlobToBucket(context, rpc, name.c_str(), bucket_id, buffer_ids, - effective_target, false, called_from_buffer_organizer); - } else { - if (ctx.disable_swap) { - result = PLACE_SWAP_BLOB_TO_BUF_FAILED; - } else { - if (called_from_buffer_organizer) { - result = PLACE_SWAP_BLOB_TO_BUF_FAILED; - LOG(ERROR) << result.Msg(); - } else { - SwapBlob swap_blob = PutToSwap(context, rpc, name, bucket_id, blob.data, - blob.size); - result = BLOB_IN_SWAP_PLACE; - LOG(WARNING) << result.Msg(); - RpcCall(rpc, rpc->node_id, "BO::PlaceInHierarchy", swap_blob, - name, ctx); - } - } - } - - return result; -} - -/** Persist Bucket using stdio. */ -api::Status StdIoPersistBucket(SharedMemoryContext *context, RpcContext *rpc, - BucketID bucket_id, - const std::string &file_name, - const std::string &open_mode) { - api::Status result; - FILE *file = fopen(file_name.c_str(), open_mode.c_str()); - - if (file) { - std::vector blob_ids = GetBlobIds(context, rpc, bucket_id); - for (size_t i = 0; i < blob_ids.size(); ++i) { - ScopedTemporaryMemory scratch(arena); - size_t blob_size = GetBlobSizeById(context, rpc, arena, blob_ids[i]); - // TODO(chogan): @optimization We could use the actual Hermes buffers as - // the write buffer rather than collecting the whole blob into memory. For - // now we pay the cost of data copy in order to only do one I/O call. - api::Blob data(blob_size); - size_t num_bytes = blob_size > 0 ? sizeof(data[0]) * blob_size : 0; - if (ReadBlobById(context, rpc, arena, data, blob_ids[i]) == blob_size) { - // TODO(chogan): For now we just write the blobs in the order in which - // they were `Put`, but once we have a Trait that represents a file - // mapping, we'll need pwrite and offsets. - if (fwrite(data.data(), 1, num_bytes, file) != num_bytes) { - result = STDIO_FWRITE_FAILED; - int saved_errno = errno; - LOG(ERROR) << result.Msg() << strerror(saved_errno); - break; - } - } else { - result = READ_BLOB_FAILED; - LOG(ERROR) << result.Msg(); - break; - } - } - - if (fclose(file) != 0) { - result = STDIO_FCLOSE_FAILED; - int saved_errno = errno; - LOG(ERROR) << result.Msg() << strerror(saved_errno); - } - } else { - result = STDIO_FOPEN_FAILED; - int saved_errno = errno; - LOG(ERROR) << result.Msg() << strerror(saved_errno); - } - - return result; -} - -/** Persist BLOB using stdio. */ -api::Status StdIoPersistBlob(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id, int fd, - const i32 &offset) { - api::Status result; - - if (fd > -1) { - ScopedTemporaryMemory scratch(arena); - size_t blob_size = GetBlobSizeById(context, rpc, arena, blob_id); - // TODO(chogan): @optimization We could use the actual Hermes buffers as - // the write buffer rather than collecting the whole blob into memory. For - // now we pay the cost of data copy in order to only do one I/O call. - api::Blob data(blob_size); - size_t num_bytes = blob_size > 0 ? sizeof(data[0]) * blob_size : 0; - if (ReadBlobById(context, rpc, arena, data, blob_id) == blob_size) { - // EnsureNoNull(data); - VLOG(1) << "STDIO flush:" - << "num_bytes=" << num_bytes << ", " - << "fd=" << fd << ", " - << "offset=" << offset << ", " - << "blob_id=" << blob_id.bits.buffer_ids_offset - << std::endl; - ssize_t bytes_written = pwrite(fd, data.data(), num_bytes, offset); - if (bytes_written == -1 || (size_t)bytes_written != num_bytes) { - // TODO(chogan): - // result = POSIX_PWRITE_ERROR; - // LOG(ERROR) << result.Msg() << strerror(errno); - FailedLibraryCall("pwrite"); - } - } - } else { - result = INVALID_FILE; - LOG(ERROR) << result.Msg(); - } - - return result; -} - -} // namespace hermes diff --git a/src/buffer_pool.h b/src/buffer_pool.h deleted file mode 100644 index 12cdb3710..000000000 --- a/src/buffer_pool.h +++ /dev/null @@ -1,559 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_BUFFER_POOL_H_ -#define HERMES_BUFFER_POOL_H_ - -#include -#include -#include - -#include -#include -#include -#include - -#include "communication.h" -#include "hermes_status.h" -#include "hermes_types.h" - -#include - -/** @file buffer_pool.h - * - * The public structures and functions for interacting with the BufferPool as a - * client. The interface includes hermes-specific application core - * intialization, and the API through which the RoundRobin DPE and - * BufferOrganizer interact with the BufferPool. - */ - -namespace hermes { - -struct RpcContext; - -/** - * Information about a specific hardware Device. - * - * This could represent local RAM, remote RAM, NVMe, burst buffers, a parallel - * file system, etc. The Devices are initialized when the BufferPool is - * initialized, and they remain throughout a Hermes run. - */ -struct Device { - /** The device's theoretical bandwidth in MiB/second. */ - f32 bandwidth_mbps; - /** The device's theoretical latency in nanoseconds. */ - f32 latency_ns; - /** The Device's identifier. This is an index into the array of Devices stored - * in the BufferPool. - */ - DeviceID id; - /** True if the Device is a RAM Device (or other byte addressable, local or - * remote) - */ - bool is_byte_addressable; - /** True if the functionality of `posix_fallocate` is available on this - * Device - */ - bool has_fallocate; - /** True if the device is shared among multiple ranks (e.g., burst buffers) */ - bool is_shared; - /** The directory where buffering files can be created. Zero terminated. */ - char mount_point[kMaxPathLength]; -}; - -/** - A structure to represent target -*/ -struct Target { - TargetID id; /**< ID of target */ - /** The total capacity of the Target. */ - u64 capacity; - std::atomic remaining_space; /**< remaining space */ - std::atomic speed; /**< speed */ - ChunkedIdList effective_blobs; /**< ID list of BLOBs */ - labstor::Mutex effective_blobs_lock; /**< ticket lock for BLOBs */ -}; - -/** - * A unique identifier for any buffer in the system. - * - * This number is unique for each buffer when read as a 64 bit integer. The top - * 32 bits signify the node that "owns" the buffer, and the bottom 32 bits form - * an index into the array of BufferHeaders in the BufferPool on that node. Node - * indexing begins at 1 so that a BufferID of 0 represents the NULL BufferID. - */ -union BufferID { - /** A structure to represent 64 bits with 32-bit header index and node id */ - struct { - /** An index into the BufferHeaders array in the BufferPool on node - * `node_id`. - */ - u32 header_index; - /** The node identifier where this BufferID's BufferHeader resides - * (1-based index). - */ - u32 node_id; - } bits; - - /** A single integer that uniquely identifies a buffer. */ - u64 as_int; -}; - -/** - A structure to represent hash from buffer ID -*/ -struct BufferIdHash { - /** return unsigned 64-bit integer hash value from buffer ID. */ - size_t operator()(const BufferID &id) const { - return std::hash()(id.as_int); - } -}; - -bool operator==(const BufferID &lhs, const BufferID &rhs); - -/** - A structure to represent shared memory client information -*/ -struct ShmemClientInfo { - ptrdiff_t mdm_offset; /**< metadata manager offset */ - ptrdiff_t bpm_offset; /**< buffer pool manager offset */ -}; - -/** - * Metadata for a Hermes buffer. - * - * An array of BufferHeaders is initialized during BufferPool initialization. - * For a RAM Device, one BufferHeader is created for each block. This is to - * facilitate splitting and merging. For non-RAM Devices, we only need one - * BufferHeader per buffer. A typical workflow is to retrieve a BufferHeader - * from a BufferID using the GetHeaderByBufferId function. - */ -struct BufferHeader { - /** The unique identifier for this buffer. */ - BufferID id; - /** The next free BufferID on the free list. */ - BufferID next_free; - /** The offset (from the beginning of shared memory or a file) of the actual - * buffered data. - */ - ptrdiff_t data_offset; - /** The number of bytes this buffer is actually using. */ - u32 used; - /** The total capacity of this buffer. */ - u32 capacity; - /** An index into the array of Devices in the BufferPool that represents this - * buffer's Device. - */ - DeviceID device_id; - /** True if this buffer is being used by Hermes to buffer data, false if it is - * free. - */ - bool in_use; - /** A simple lock that is atomically set to true when the data in this buffer - * is being read or written by an I/O client or the BufferOrganizer. - */ - std::atomic locked; -}; - -/** - * Contains information about the layout of the buffers, BufferHeaders, and - * Devices in shared memory. - * - * Some terminology: - * block - A contiguous range of buffer space of the smallest unit for a given - * Device. The size for each Device is specified by - * Config::block_sizes[device_id]. RAM is typically 4K, for example. - * buffer - Made up of 1 or more blocks: 1-block buffer, 4-block buffer, etc. - * slab - The collection of all buffers of a particular size. e.g., the - * 4-block slab is made up of all the 4-block buffers. - * - * When Hermes initializes, the BufferPool is created and initialized in a - * shared memory segment, which is then closed when Hermes shuts down. A pointer - * to the BufferPool can be retrieved with the function - * GetBufferPoolFromContext. All pointer values are stored as offsets from the - * beginning of shared memory. The layout of the BufferPool is determined by the - * Config struct that is passed to InitBufferPool. Multiple BufferPools can be - * instantiated, but each must have a different buffer_pool_shmem_name, which is - * a member of Config. Each BufferPool will then exist in its own shared memory - * segment. - */ -struct BufferPool { - /** The offset from the base of shared memory where the BufferHeader array - * begins. - */ - ptrdiff_t headers_offset; - /** The offset from the base of shared memory where the Device array begins. - */ - ptrdiff_t devices_offset; - /** The offset from the targets */ - ptrdiff_t targets_offset; - /** The offset from the base of shared memory where each Device's free list is - * stored. Converting the offset to a pointer results in a pointer to an array - * of N BufferIDs where N is the number of slabs in that Device. - */ - ptrdiff_t free_list_offsets[kMaxDevices]; - /** The offset from the base of shared memory where each Device's list of slab - * unit sizes is stored. Each offset can be converted to a pointer to an array - * of N ints where N is the number of slabs in that Device. Each slab has its - * own unit size x, where x is the number of blocks that make up a buffer. - */ - ptrdiff_t slab_unit_sizes_offsets[kMaxDevices]; - /** The offset from the base of shared memory where each Device's list of slab - * buffer sizes is stored. Each offset can be converted to a pointer to an - * array of N ints where N is the number of slabs in that Device. A slab's - * buffer size (in bytes) is the slab's unit size multiplied by the Device's - * block size. - */ - ptrdiff_t slab_buffer_sizes_offsets[kMaxDevices]; - /** The offset from the base of shared memory where each Device's list of - * available buffers per slab is stored. Each offset can be converted to a - * pointer to an arry of N (num_slabs[device_id]) std::atomic. - */ - ptrdiff_t buffers_available_offsets[kMaxDevices]; - /** A ticket lock to syncrhonize access to free lists - * \todo (chogan): optimization - One mutex per free list. - */ - TicketMutex ticket_mutex; - - /** capacity adjustment for each device */ - std::atomic capacity_adjustments[kMaxDevices]; - - /** The block size for each Device. */ - i32 block_sizes[kMaxDevices]; - /** The number of slabs for each Device. */ - i32 num_slabs[kMaxDevices]; - /** The number of BufferHeaders for each Device. */ - u32 num_headers[kMaxDevices]; - /** The total number of Devices. */ - i32 num_devices; - /** total number of targets */ - i32 num_targets; - /** The total number of BufferHeaders in the header array. */ - u32 total_headers; - /** minimum device bandwidth in Megabits per second */ - f32 min_device_bw_mbps; - /** maximum device bandwidth in Megabits per second */ - f32 max_device_bw_mbps; -}; - -/** - * Information that allows each process to access the shared memory and - * BufferPool information. - * - * A SharedMemoryContext is passed as a parameter to all functions that interact - * with the BufferPool. This context allows each process to find the location of - * the BufferPool within its virtual address space. Acquiring the context via - * GetSharedMemoryContext will map the BufferPool's shared memory into the - * calling processes address space. An application core will acquire this - * context on initialization. At shutdown, application cores will call - * ReleaseSharedMemoryContext to unmap the shared memory segemnt (although, this - * happens automatically when the process exits). The Hermes core is responsible - * for creating and destroying the shared memory segment. - * - * Example: - * ```cpp - * SharedMemoryContext *context = GetSharedMemoryContext("hermes_shmem_name"); - * BufferPool *pool = GetBufferPoolFromContext(context); - * ``` - */ - -struct BufferOrganizer; - -/** - A structure to represent shared memory context -*/ -struct SharedMemoryContext { - /** The offset from the beginning of shared memory to the BufferPool. */ - ptrdiff_t buffer_pool_offset; - /** The offset from the beginning of shared memory to the Metadata Arena. */ - ptrdiff_t metadata_manager_offset; - /** This will only be valid on Hermes cores, and NULL on client cores. */ - BufferOrganizer *bo; - - // File buffering context - /** vector of buffering file names */ - std::vector> buffering_filenames; - /** 2D array of open files for each device and buffer pool slab */ - int open_files[kMaxDevices][kMaxBufferPoolSlabs]; - /** pointer to swap file */ - FILE *swap_file; -}; - -struct BufferIdArray; - -/** - * - */ -size_t GetBlobSize(SharedMemoryContext *context, RpcContext *rpc, - BufferIdArray *buffer_ids); - -/** - * - */ -size_t GetBlobSizeById(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id); - -f32 GetBlobImportanceScore(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id); -/** - * Constructs a unique (among users) shared memory name from a base name. - * - * Copies the base name into the dest buffer and appends the value of the USER - * envioronment variable. The dest buffer should be large enough to hold the - * base name and the value of USER. - * - * @param[out] dest A buffer for the full shared memory name. - * @param[in] base The base shared memory name. - */ -void MakeFullShmemName(char *dest, const char *base); - -/** - * \todo - * Creates and opens all files that will be used for buffering. Stores open FILE - * pointers in the @p context. The file buffering paradaigm uses one file per - * slab for each Device. If `posix_fallocate` is available, and `make_space` is - * `true`, each file's capacity is reserved. Otherwise, the files will be - * initialized with 0 size. - * - * @param context The SharedMemoryContext in which to store the opened FILE - * pointers. - * @param comm context for communication - */ -void InitFilesForBuffering(SharedMemoryContext *context, - CommunicationContext &comm); - -/** - * Unmaps the shared memory represented by context and closes any open file - * descriptors - * - * This isn't strictly necessary, since the segment will be unmapped when the - * process exits and the file descriptors will be closed, but is here for - * completeness. - * - * @param context The shared memory to unmap. - */ -void ReleaseSharedMemoryContext(SharedMemoryContext *context); - -/** - * - */ -void UnmapSharedMemory(SharedMemoryContext *context); - -/** - * Returns a vector of BufferIDs that satisfy the constrains of @p schema. - * - * If a request cannot be fulfilled, an empty list is returned. GetBuffers will - * never partially satisfy a request. It is all or nothing. If @p schema - * includes a remote Device, this function will make an RPC call to get - * BufferIDs from a remote node. - * - * @param context The shared memory context for the BufferPool. - * @param schema A description of the amount and Device of storage requested. - * - * @return A vector of BufferIDs that can be used for storage, and that satisfy - * @p schema, or an empty vector if the request could not be fulfilled. - */ -std::vector GetBuffers(SharedMemoryContext *context, - const PlacementSchema &schema); -/** - * Returns buffer_ids to the BufferPool free lists so that they can be used - * again. Data in the buffers is considered abandonded, and can be overwritten. - * - * @param context The shared memory context where the BufferPool lives. - * @param rpc The RPC context to enable a remote call if necessary. - * @param buffer_ids The list of buffer_ids to return to the BufferPool. - */ -void ReleaseBuffers(SharedMemoryContext *context, RpcContext *rpc, - const std::vector &buffer_ids); -/** - * Starts an RPC server that will listen for remote requests directed to the - * BufferPool. - * - * @param context The shared memory context where the BufferPool lives - * @param addr The address and port where the RPC server will listen - * This address must be a compatible with whatever the RPC implementation is. - * @param num_rpc_threads number of RPC threads - * - */ -void StartBufferPoolRpcServer(SharedMemoryContext *context, const char *addr, - i32 num_rpc_threads); - -/** - * Free all resources held by Hermes. - * - * @param context The Hermes instance's shared memory context. - * @param comm The Hermes instance's communication context. - * @param rpc The Hermes instance's RPC context. - * @param shmem_name The name of the shared memory. - * @param trans_arena The instance's transient arena. - * @param is_application_core Whether or not this rank is an app rank. - * @param force_rpc_shutdown Force RPC shutdown when it is true. - */ -void Finalize(SharedMemoryContext *context, CommunicationContext *comm, - RpcContext *rpc, const char *shmem_name, Arena *trans_arena, - bool is_application_core, bool force_rpc_shutdown); - -// I/O Clients - -/** - * Description of user data. - */ -struct Blob { - /** The beginning of the data */ - u8 *data; - /** The size of the data in bytes */ - u64 size; -}; - -/** - A structure to represent swap BLOB - - \note (chogan): When adding members to this struct, it is important to also add - an entry to the SwapBlobMembers enum below. -*/ -struct SwapBlob { - u32 node_id; /**< node ID */ - u64 offset; /**< offset of swap BLOB */ - u64 size; /**< size of swap BLOB */ - BucketID bucket_id; /**< Bucket ID */ -}; - -/** - An enum to represent swap BLOB members - \todo (chogan): metaprogramming - Generate this -*/ -enum SwapBlobMembers { - SwapBlobMembers_NodeId, - SwapBlobMembers_Offset, - SwapBlobMembers_Size, - SwapBlobMembers_BucketId, - - SwapBlobMembers_Count -}; - -/** - * Sketch of how an I/O client might write. - * - * Writes the blob to the collection of buffer_ids. The BufferIDs inform the - * call whether it is writing locally, remotely, to RAM (or a byte addressable - * Device) or to a file (block addressable Device). - * - * @param context The shared memory context needed to access BufferPool info - * @param rpc The Hermes instance's RPC context - * @param blob The data to write - * @param buffer_ids The collection of BufferIDs that should buffer the blob - */ -void WriteBlobToBuffers(SharedMemoryContext *context, RpcContext *rpc, - const Blob &blob, - const std::vector &buffer_ids); - -/** - * Sketch of how an I/O client might read. - * - * Reads the collection of buffer_ids into blob. The BufferIDs inform the - * call whether it is reading locally, remotely, from RAM (or a byte addressable - * Device) or to a file (block addressable Device). - * - * @param context The shared memory context needed to access BufferPool info. - * @param rpc The RPC context needed to make a remote call if necessary. - * @param blob A place to store the read data. - * @param buffer_ids The collection of BufferIDs that hold the buffered blob. - * @param buffer_sizes A list of sizes that correspond to each buffer in - * @p buffer_ids. Its length is the length of @p buffer_ids - * - * @return The total number of bytes read - */ -size_t ReadBlobFromBuffers(SharedMemoryContext *context, RpcContext *rpc, - Blob *blob, BufferIdArray *buffer_ids, - u32 *buffer_sizes); - -size_t ReadBlobById(SharedMemoryContext *context, RpcContext *rpc, Arena *arena, - Blob blob, BlobID blob_id); - -size_t ReadBlobById(SharedMemoryContext *context, RpcContext *rpc, Arena *arena, - api::Blob &dest, BlobID blob_id); - -size_t LocalWriteBufferById(SharedMemoryContext *context, BufferID id, - const Blob &blob, size_t offset); -size_t LocalReadBufferById(SharedMemoryContext *context, BufferID id, - Blob *blob, size_t offset); - -SwapBlob PutToSwap(SharedMemoryContext *context, RpcContext *rpc, - const std::string &name, BucketID bucket_id, const u8 *data, - size_t size); -/** - A template function to put BLOBs into swap -*/ -template -std::vector PutToSwap(SharedMemoryContext *context, RpcContext *rpc, - BucketID id, std::vector> &blobs, - std::vector &names) { - size_t num_blobs = blobs.size(); - std::vector result(num_blobs); - - for (size_t i = 0; i < num_blobs; ++i) { - SwapBlob swap_blob = - PutToSwap(context, rpc, names[i], id, (const u8 *)blobs[i].data(), - blobs[i].size() * sizeof(T)); - result.push_back(swap_blob); - } - - return result; -} - -/** - write BLOB to swap. -*/ -SwapBlob WriteToSwap(SharedMemoryContext *context, Blob blob, BlobID blob_id, - BucketID bucket_id); -size_t ReadFromSwap(SharedMemoryContext *context, Blob blob, - SwapBlob swap_blob); - -/** - * Returns a vector of bandwidths in MiB per second for a given Target list. - * - * Element @c n of the result is the bandwidth of the Device that backs the @c - * nth element of @p targets. - * - * @param context The shared memory context needed to access BufferPool info. - * @param targets The list of targets for which to retrieve bandwidth info. - * - * @return The list of bandwidths, one for each target in @p targets, in - * MiB/sec. - */ -std::vector GetBandwidths(SharedMemoryContext *context, - const std::vector &targets); - -u32 GetNumBuffersAvailable(SharedMemoryContext *context, DeviceID device_id); -u32 GetBufferSize(SharedMemoryContext *context, RpcContext *rpc, BufferID id); -bool BufferIsByteAddressable(SharedMemoryContext *context, BufferID id); -api::Status PlaceInHierarchy(SharedMemoryContext *context, RpcContext *rpc, - SwapBlob swap_blob, const std::string &blob_name, - const api::Context &ctx); -api::Status PlaceBlob(SharedMemoryContext *context, RpcContext *rpc, - PlacementSchema &schema, Blob blob, - const std::string &name, BucketID bucket_id, - const api::Context &ctx, - bool called_from_buffer_organizer = false); -api::Status StdIoPersistBucket(SharedMemoryContext *context, RpcContext *rpc, - BucketID bucket_id, - const std::string &file_name, - const std::string &open_mode); - -api::Status StdIoPersistBlob(SharedMemoryContext *context, RpcContext *rpc, - BlobID blob_id, int fd, - const i32 &offset); - -Device *GetDeviceFromHeader(SharedMemoryContext *context, BufferHeader *header); -} // namespace hermes - -#endif // HERMES_BUFFER_POOL_H_ diff --git a/src/buffer_pool_internal.h b/src/buffer_pool_internal.h deleted file mode 100644 index 1955b7841..000000000 --- a/src/buffer_pool_internal.h +++ /dev/null @@ -1,221 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_BUFFER_POOL_INTERNAL_H_ -#define HERMES_BUFFER_POOL_INTERNAL_H_ - -#include "buffer_pool.h" - -/** - * @file buffer_pool_internal.h - * - * This file contains the developer interface to the BufferPool. It describes - * the API available to direct consumers of the BufferPool which include buffer - * pool tests, the buffer pool visualizer, and the BufferPool itself. For the - * "public" API, see buffer_pool.h. - */ - -namespace hermes { - -/** - * Initializes a BufferPool inside an existing shared memory segment. - * - * Divides the shared memory segment pointed to by hermes_memory into - * 1) An array of RAM buffers. - * 2) An array of BufferHeaders. - * 3) An array of Devices. - * 4) The BufferPool struct, which contains pointers (really offsets) to the - * data above. - * - * The sizes of each of these sections is controlled by the config parameter. - * Each BufferHeader is initialized to point to a specfic offset. In the case of - * a RAM buffer, this offset is from the beginning of the shared memory. In the - * case of a file buffer, the offset is from the beginning of a file. Free lists - * for each slab in each Device are also constructed. - * - * @param hermes_memory The base pointer to a shared memory segment. - * @param buffer_pool_arena An Arena backed by the shared memory segment pointed - * to by hermes_shared_memory. - * @param scratch_arena An arena for temporary allocations that are destroyed - * when this function exits. - * @param node_id The identifier of the node this function is running on. - * @param config Configuration that specifies how the BufferPool is constructed. - * - * @return The offset of the beginning of the BufferPool from the beginning of - * shared memory. - */ -ptrdiff_t InitBufferPool(u8 *hermes_memory, i32 node_id, Config *config); - -/** - * Obtains a pointer to the BufferPool constructed in shared memory. - * - * Since the BufferPool lives in shared memory, this pointer should never be - * freed. It is only destroyed when the Hermes core closes the shared memory. - * - * @param context The shared memory context for accessing the BufferPool. - * - * @return A pointer to the BufferPool constructed in the shared memory - * represented by @p context. - */ -BufferPool *GetBufferPoolFromContext(SharedMemoryContext *context); - -/** - * Returns a pointer to the Device with index device_id in the shared memory - * context. - * - * This pointer should never be freed, since it lives in shared memory and is - * managed by the Hermes core. - * - * @param context The shared memory context where the Devices are stored. - * @param device_id An identifier for the desired Device. This is an index into - * an array of Devices. - * - * @return A pointer to the Device with ID device_id. - */ -Device *GetDeviceById(SharedMemoryContext *context, DeviceID device_id); - -/** - * Returns a pointer to the first BufferHeader in the array of BufferHeaders - * constructed in the shared memory context. - * - * This pointer should never be freed, as it is managed by the Hermes core. - * Indexing off this pointer, one can easily iterate through all BufferHeaders. - * When retrieving a specific header, use GetHeaderByBufferId. - * - * Example: - * ```cpp - * BufferHeader *headers = GetHeadersBase(context); - * for (u32 i = 0; i < pool->num_headers[device_id]; ++i) { - * BufferHeader *header = headers + i; - * // ... - * } - * ``` - * - * @param context The shared memory context where the BufferHeaders live. - * - * @return A pointer to the first BufferHeader in the array of BufferHeaders. - */ -BufferHeader *GetHeadersBase(SharedMemoryContext *context); - -/** - * Retrieves the BufferHeader that corresponds to BufferID @p id. - * - * This pointer should never be freed. The BufferHeaders are managed by the - * Hermes core. - * - * @param context The shared memory context for accessing the BufferHeaders. - * @param id The desired BufferID to retrieve. - * - * @return A pointer to the BufferHeader that corresponds to @p id. - */ -BufferHeader *GetHeaderByBufferId(SharedMemoryContext *context, BufferID id); - -/** - * Returns whether or not @p header is currently backed by physical storage. - * - * A dormant header has no storage associated with it. It exists to facilitate - * the splitting and merging mechanisms. Splitting buffers into smaller buffers - * requires more headers. When that happens, dormant headers become associated - * with backing storage, and become "live." - * - * @param header The header to check. - * - * @return true if @p header is not backed by physical storage, false otherwise. - */ -bool HeaderIsDormant(BufferHeader *header); - -/** - * TODO(chogan): - * - * @param context The shared memory context for accessing the BufferPool. - * @param slab_index The 0-based index of the slab to split. - */ -void SplitRamBufferFreeList(SharedMemoryContext *context, int slab_index); - -/** - * TODO(chogan): - * - * @param context The shared memory context for accessing the BufferPool - * @param slab_index The 0-based index of the slab to merge. - */ -void MergeRamBufferFreeList(SharedMemoryContext *context, int slab_index); - -/** - * - */ -BufferID PeekFirstFreeBufferId(SharedMemoryContext *context, DeviceID device_id, - int slab_index); - -/** - * - */ -void LocalReleaseBuffer(SharedMemoryContext *context, BufferID buffer_id); - -/** - * - */ -void LocalReleaseBuffers(SharedMemoryContext *context, - const std::vector &buffer_ids); -/** - * - */ -i32 GetSlabUnitSize(SharedMemoryContext *context, DeviceID device_id, - int slab_index); - -/** - * - */ -u32 LocalGetBufferSize(SharedMemoryContext *context, BufferID id); -/** - * - */ -i32 GetSlabBufferSize(SharedMemoryContext *context, DeviceID device_id, - int slab_index); - -/** - * - */ -void SerializeBufferPoolToFile(SharedMemoryContext *context, FILE *file); - -/** - * - */ -void ParseConfig(const char *path, Config *config); - -/** - * - */ -u8 *InitSharedMemory(const char *shmem_name, size_t total_size); - -/** - * - */ -u8 *GetRamBufferPtr(SharedMemoryContext *context, BufferID buffer_id); - -/** - * - */ -Target *GetTarget(SharedMemoryContext *context, int index); - -/** - * - */ -Target *GetTargetFromId(SharedMemoryContext *context, TargetID id); - -/** - * - */ -std::atomic *GetAvailableBuffersArray(SharedMemoryContext *context, - DeviceID device_id); -} // namespace hermes - -#endif // HERMES_BUFFER_POOL_INTERNAL_H_ diff --git a/src/buffer_pool_visualizer/CMakeLists.txt b/src/buffer_pool_visualizer/CMakeLists.txt deleted file mode 100644 index 33c117102..000000000 --- a/src/buffer_pool_visualizer/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ - -project(BufferPoolVisualizer VERSION ${HERMES_PACKAGE_VERSION}) - -add_executable(bp_viz buffer_pool_visualizer.cc) - -if(TARGET SDL2::SDL2) - # SDL2 built with cmake - target_link_libraries(bp_viz hermes SDL2::SDL2 glog::glog) -else() - # SDL2 built with autotools - target_include_directories(bp_viz PRIVATE ${SDL2_INCLUDE_DIRS}) - target_link_libraries(bp_viz hermes ${SDL2_LIBRARIES} glog::glog) -endif() - -add_custom_target(viz - COMMAND LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_SOURCE_DIR}/asan.supp - ${CMAKE_BINARY_DIR}/bin/bp_viz -) diff --git a/src/buffer_pool_visualizer/README.md b/src/buffer_pool_visualizer/README.md deleted file mode 100644 index 7cff1e019..000000000 --- a/src/buffer_pool_visualizer/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Buffer Pool Visualizer - -A visual debugging tool for the Hermes `BufferPool` and `MetadataManager`. - -To run, start a Hermes instance and then run `make viz` from the build -directory. It can also visualize a crashed Hermes run if the shared memory -segment still exists. - -To enable in the build, set `HERMES_BUILD_BUFFER_POOL_VISUALIZER=ON` in CMake. -In order to visualize the `MetadataManager`, Hermes must be built with the CMake -option `HERMES_DEBUG_HEAP=ON`. - -## Dependencies - -[SDL](https://www.libsdl.org/) is the only additional dependency. On Ubuntu, -`sudo apt install libsdl2-dev`. - -## Controls - -| Key | Functionality | -|-----|--------------------------------------------------------| -| 0-9 | If viewing the `BufferPool`, display Tier N | -| 0 | If viewing the `MetadataManager`, display the ID heap | -| 1 | If viewing the `MetadataManager`, display the map heap | -| b | View the `BufferPool` | -| c | Print a count of all buffers and slabs | -| f | Print the sizes of the buffer free lists | -| m | View the `MetadataManager` | -| r | Reload the shared memory file | -| s | Save a bitmap of the current view | -| ESC | Exit the visualizer | - -## Description of Visual Information - -### `BufferPool` mode - -![Buffer Pool Visualizer](https://github.com/HDFGroup/hermes/wiki/images/buffer_pool_visualizer_default.png) - -### `MetadataManager` mode - -![Metadata Visualizer](https://github.com/HDFGroup/hermes/wiki/images/mdm_viz.png) diff --git a/src/buffer_pool_visualizer/asan.supp b/src/buffer_pool_visualizer/asan.supp deleted file mode 100644 index 7c7a1cab3..000000000 --- a/src/buffer_pool_visualizer/asan.supp +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore leaks from external libraries -leak:libX11.so -leak:libGLX_mesa.so - diff --git a/src/buffer_pool_visualizer/buffer_pool_visualizer.cc b/src/buffer_pool_visualizer/buffer_pool_visualizer.cc deleted file mode 100644 index a66ec0dfa..000000000 --- a/src/buffer_pool_visualizer/buffer_pool_visualizer.cc +++ /dev/null @@ -1,1069 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -#include "SDL.h" - -#include "hermes_types.h" -#include "buffer_pool.h" -#include "buffer_pool_internal.h" -#include "metadata_management.h" -#include "metadata_management_internal.h" -#include "utils.h" - -#define DRAW_BUCKETS 0 - -using namespace hermes; // NOLINT(*) - -enum Color { - kColor_Red, - kColor_Yellow, - kColor_Green, - kColor_Cyan, - kColor_Magenta, - - kColor_HeapMax, - - kColor_Grey, - kColor_White, - kColor_Black, - - kColor_Count -}; - -enum IdHeapColors { - kColor_Blue1, - kColor_Blue2, - kColor_Blue3, - kColor_Blue4, - kColor_Blue5, - - kIdHeapColors_Count -}; - -enum class ActiveSegment { - BufferPool, - Metadata, -}; - -enum class ActiveHeap { - Map, - Id, -}; - -static u32 global_colors[kColor_Count]; -static u32 global_id_colors[kIdHeapColors_Count]; -static int global_bitmap_index; -static DeviceID global_active_device; -static ActiveSegment global_active_segment = ActiveSegment::Metadata; -static ActiveHeap global_active_heap; -static u32 global_color_counter; -static DebugState *global_id_debug_state; -static DebugState *global_map_debug_state; - -/** - A structure to represent range from start to end. -*/ -struct Range { - int start; /**< start value of range */ - int end; /**< end value of range */ -}; - -/** - A structure to represent a point at (x,y) location -*/ -struct Point { - int x; /**< x location value */ - int y; /**< y location value */ -}; - -/** - A structure to represent heap for metadata -*/ -struct HeapMetadata { - u8 *heap_base; /**< pointer to heap */ - ptrdiff_t heap_size; /**< size of heap */ - int total_slots; /**< total number of slots */ - int screen_width; /**< screen width */ - int num_rows; /**< number of rows */ - int y_offset; /**< y offset */ - int h; /**< height */ - f32 slots_to_bytes; /**< slots:bytes ratio */ - f32 bytes_to_slots; /**< bytes:slots ratio */ -}; - -/** - A structure to represent window -*/ -struct WindowData { - SDL_Window *window; /**< pointer to window */ - SDL_Surface *back_buffer; /**< buffer */ - SDL_Surface *screen; /**< screen */ - int width; /**< width */ - int height; /**< height */ - bool running; /**< is window running? */ -}; - -static SDL_Window *CreateWindow(int width, int height) { - SDL_Window *result = SDL_CreateWindow("BufferPool Visualizer", - 1920 - width, - 0, - width, - height, - SDL_WINDOW_RESIZABLE); - - if (result == NULL) { - SDL_Log("Could not create window: %s\n", SDL_GetError()); - exit(1); - } - - return result; -} - -static SDL_Surface *GetScreen(SDL_Window *window) { - SDL_Surface *result = SDL_GetWindowSurface(window); - - if (result == NULL) { - SDL_Log("Could not get window surface: %s\n", SDL_GetError()); - exit(1); - } - - return result; -} - -static SDL_Surface *CreateBackBuffer(int width, int height) { - Uint32 rmask; - Uint32 gmask; - Uint32 bmask; - Uint32 amask; - -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0xff000000; - gmask = 0x00ff0000; - bmask = 0x0000ff00; - amask = 0x000000ff; -#else - rmask = 0x000000ff; - gmask = 0x0000ff00; - bmask = 0x00ff0000; - amask = 0xff000000; -#endif - - SDL_Surface *result = SDL_CreateRGBSurface(0, width, height, 32, rmask, - gmask, bmask, amask); - if (result == NULL) { - SDL_Log("SDL_CreateRGBSurface() failed: %s", SDL_GetError()); - exit(1); - } - - return result; -} - -void DrawWrappingRect(SDL_Rect *rect, int width, int pad, SDL_Surface *surface, - u32 color) { - int x = rect->x; - int y = rect->y; - int w = rect->w; - int h = rect->h; - bool multi_line = false; - - while (w > 0) { - SDL_Rect fill_rect = {x + pad, y + pad, 0, h - pad}; - int rect_width = x + w; - if (rect_width > width) { - multi_line = true; - int this_line_width = width - (x + pad); - fill_rect.w = this_line_width; - w -= this_line_width; - x = 0; - y += h; - } else { - fill_rect.w = multi_line ? w - 2 * pad : w - pad; - w = -1; - } - SDL_FillRect(surface, &fill_rect, color); - } -} - -// NOTE(chogan): This won't work if we allow non-ram headers to be dormant -// because getting the next dormant header can swap headers out of their preset -// index range -static Range GetHeaderIndexRange(SharedMemoryContext *context, - DeviceID device_id) { - Range result = {}; - BufferPool *pool = GetBufferPoolFromContext(context); - - for (int i = 0; i < device_id; ++i) { - result.start += pool->num_headers[i]; - } - result.end = result.start + pool->num_headers[device_id]; - - return result; -} - -static int DrawBufferPool(SharedMemoryContext *context, - SDL_Surface *surface, int window_width, - int window_height, DeviceID device_id) { - BufferPool *pool = GetBufferPoolFromContext(context); - BufferHeader *headers = GetHeadersBase(context); - size_t block_size = pool->block_sizes[device_id]; - int block_width_pixels = 5; - f32 memory_offset_to_pixels = (f32)(block_width_pixels) / (f32)(block_size); - int pad = 2; - int h = 5; - int x = 0; - int y = 0; - int w = 0; - int final_y = 0; - - std::unordered_map block_refs; - - Range header_range = GetHeaderIndexRange(context, device_id); - - for (int i = header_range.start; i < header_range.end; ++i) { - BufferHeader *header = headers + i; - assert((u8 *)header < (u8 *)pool); - if (HeaderIsDormant(header)) { - continue; - } - - // NOTE(chogan): Mark this region as in use so we can later ensure no more - // than one header ever refers to the same memory region - int index = header->data_offset / block_size; - int num_blocks = header->capacity / block_size; - - for (int j = 0; j < num_blocks; ++j) { - std::string index_str = std::to_string(index) + ":" + std::to_string(j); - auto found = block_refs.find(index_str); - if (found != block_refs.end()) { - block_refs[index_str] += 1; - } else { - block_refs[index_str] = 1; - } - } - - int pixel_offset = (int)(header->data_offset * memory_offset_to_pixels); - - y = (pixel_offset / window_width) * h; - if (y + h + pad > window_height) { - SDL_Log("Not enough room to display all buffers\n"); - break; - } - - int color_index = -1; - for (int j = 0; j < pool->num_slabs[device_id]; ++j) { - if (num_blocks == GetSlabUnitSize(context, device_id, j)) { - color_index = j; - break; - } - } - - assert(color_index >= 0); - u32 rgb_color = global_colors[color_index]; - - if (header->in_use) { - // TODO(chogan): Just draw used in white, not whole capacity - rgb_color = global_colors[kColor_White]; - } - - x = pixel_offset % window_width; - w = num_blocks * block_width_pixels; - - SDL_Rect rect = {x, y, w, h}; - DrawWrappingRect(&rect, window_width, pad, surface, rgb_color); - - if (y + pad >= final_y) { - final_y = y + pad; - } - } - - // NOTE(chogan): Ensure that we are not drawing any portion of a buffer in - // more than one place (i.e, no headers point to overlapping buffers) - for (auto iter = block_refs.begin(); iter != block_refs.end(); ++iter) { - if (device_id == 0) { - assert(iter->second <= 1); - } else { - // TODO(chogan): Data offsets for file buffers are allowed to overlap - // becuase each slab starts at 0 - } - } - - return final_y + h; -} - -static int DrawFileBuffers(SharedMemoryContext *context, SDL_Surface *surface, - int window_width, int window_height, - DeviceID device_id) { - BufferPool *pool = GetBufferPoolFromContext(context); - BufferHeader *headers = GetHeadersBase(context); - size_t block_size = pool->block_sizes[device_id]; - int block_width_pixels = 5; - f32 memory_offset_to_pixels = (f32)(block_width_pixels) / (f32)(block_size); - int pad = 2; - int h = 5; - int x = 0; - int y = 0; - int w = 0; - int final_y = 0; - int starting_y_offset = 0; - - using BlockMap = std::unordered_map; - std::vector block_refs(pool->num_slabs[device_id]); - int block_refs_index = 0; - - Range header_range = GetHeaderIndexRange(context, device_id); - - for (int i = header_range.start; i < header_range.end; ++i) { - BufferHeader *header = headers + i; - assert((u8 *)header < (u8 *)pool); - if (HeaderIsDormant(header)) { - continue; - } - - int pixel_offset = (int)(header->data_offset * memory_offset_to_pixels); - - if (pixel_offset == 0 && y) { - starting_y_offset = final_y + h; - block_refs_index++; - } - - // NOTE(chogan): Mark this region as in use so we can later ensure no more - // than one header ever refers to the same memory region - int index = header->data_offset / block_size; - int num_blocks = header->capacity / block_size; - - for (int j = 0; j < num_blocks; ++j) { - std::string index_str = std::to_string(index) + std::to_string(j); - auto found = block_refs[block_refs_index].find(index_str); - if (found != block_refs[block_refs_index].end()) { - block_refs[block_refs_index][index_str] += 1; - } else { - block_refs[block_refs_index][index_str] = 1; - } - } - - y = starting_y_offset + (pixel_offset / window_width) * h; - if (y + h + pad > window_height) { - SDL_Log("Not enough room to display all buffers\n"); - break; - } - - int color_index = -1; - for (int j = 0; j < pool->num_slabs[device_id]; ++j) { - if (num_blocks == GetSlabUnitSize(context, device_id, j)) { - color_index = j; - break; - } - } - - assert(color_index >= 0); - u32 rgb_color = global_colors[color_index]; - - if (header->in_use) { - // TODO(chogan): Just draw used in white, not whole capacity - rgb_color = global_colors[kColor_White]; - } - - x = pixel_offset % window_width; - w = num_blocks * block_width_pixels; - - SDL_Rect rect = {x, y, w, h}; - DrawWrappingRect(&rect, window_width, pad, surface, rgb_color); - - if (y + pad >= final_y) { - final_y = y + pad; - } - } - - // NOTE(chogan): Ensure that we are not drawing any portion of a buffer in - // more than one place (i.e, no headers point to overlapping buffers) - for (size_t i = 0; i < block_refs.size(); ++i) { - for (auto iter = block_refs[i].begin(); - iter != block_refs[i].end(); - ++iter) { - assert(iter->second <= 1 && iter->second >= 0); - } - } - - return final_y + h; -} - -static void DrawEndOfRamBuffers(SharedMemoryContext *context, - SDL_Surface *surface, int window_width, - int window_height) { - BufferPool *pool = GetBufferPoolFromContext(context); - size_t block_size = pool->block_sizes[0]; - int block_width = 5; - int w = block_width * 2; - int h = 5; - int pad = 2; - f32 memory_offset_to_pixels = (f32)(block_width) / (f32)(block_size); - - int pixel_offset = (int)(pool->headers_offset * memory_offset_to_pixels); - int x = pixel_offset % window_width; - int y = (pixel_offset / window_width) * h; - - if (y + pad < window_height) { - SDL_Rect rect = {x + pad, y + pad, w - pad, h - pad}; - u32 color = global_colors[kColor_Magenta]; - SDL_FillRect(surface, &rect, color); - } -} - -static void DrawHeaders(SharedMemoryContext *context, SDL_Surface *surface, - int window_width, int window_height, int starting_y, - DeviceID device_id) { - [[maybe_unused]] BufferPool *pool = GetBufferPoolFromContext(context); - BufferHeader *headers = GetHeadersBase(context); - int pad = 1; - int x = 0; - int w = 2; - int h = 5; - int y = starting_y; - - - Range index_range = GetHeaderIndexRange(context, device_id); - - for (int i = index_range.start; i < index_range.end; ++i) { - BufferHeader *header = headers + i; - assert((u8 *)header < (u8 *)pool); - - if (x + w + (2 * pad) > window_width) { - y += h + pad; - x = 0; - } - - if (y + h + pad > window_height) { - SDL_Log("Not enough room to display everything\n"); - break; - } - - SDL_Rect rect = {x + pad, y + pad, w - pad, h - pad}; - u32 color = 0; - if (HeaderIsDormant(header)) { - color = global_colors[kColor_Grey]; - } else { - color = global_colors[kColor_Green]; - } - - SDL_FillRect(surface, &rect, color); - - x += (2 * pad) + w; - } -} - -static void ReloadSharedMemory(SharedMemoryContext *context, char *shmem_name) { - ReleaseSharedMemoryContext(context); - SharedMemoryContext new_context = GetSharedMemoryContext(shmem_name); - if (new_context.shm_base == 0) { - SDL_Log("Couldn't open BufferPool shared memory\n"); - exit(1); - } - *context = new_context; -} - -static void PrintBufferCounts(SharedMemoryContext *context, - DeviceID device_id) { - BufferPool *pool = GetBufferPoolFromContext(context); - BufferHeader *headers = GetHeadersBase(context); - std::vector buffer_counts(pool->num_slabs[device_id], 0); - - Range index_range = GetHeaderIndexRange(context, device_id); - - for (int header_index = index_range.start; - header_index < index_range.end; - ++header_index) { - BufferHeader *header = headers + header_index; - if (HeaderIsDormant(header)) { - continue; - } - - for (size_t i = 0; i < buffer_counts.size(); ++i) { - if (header->capacity == (u32)GetSlabBufferSize(context, device_id, i)) { - buffer_counts[i]++; - } - } - } - - int total_headers = 0; - for (size_t i = 0; i < buffer_counts.size(); ++i) { - int this_count = buffer_counts[i]; - SDL_Log("Slab %d: %d\n", (int)i, this_count); - total_headers += this_count; - } - SDL_Log("Total live headers: %d\n", total_headers); -} - -static void PrintFreeListSizes(SharedMemoryContext *context, - DeviceID device_id) { - BufferPool *pool = GetBufferPoolFromContext(context); - int total_free_headers = 0; - - for (int slab = 0; slab < pool->num_slabs[device_id]; ++slab) { - BufferID next_free = PeekFirstFreeBufferId(context, device_id, slab); - int this_slab_free = 0; - while (next_free.as_int != 0) { - BufferHeader *header = GetHeaderByBufferId(context, next_free); - this_slab_free += 1; - next_free = header->next_free; - } - SDL_Log("Slab %d free list size: %d\n", slab, this_slab_free); - total_free_headers += this_slab_free; - } - - SDL_Log("Total free headers: %d\n", total_free_headers); -} - -static void SaveBitmap(SDL_Surface *surface) { - char fname[32]; - snprintf(fname, sizeof(fname), "bpm_snapshot_%d.bmp", global_bitmap_index); - global_bitmap_index += 1; - SDL_SaveBMP(surface, fname); - SDL_Log("Saved bitmap %s\n", fname); -} - -static void SetActiveDevice(SharedMemoryContext *context, DeviceID device_id) { - BufferPool *pool = GetBufferPoolFromContext(context); - if (device_id < pool->num_devices) { - global_active_device = device_id; - SDL_Log("Viewing Device %u\n", device_id); - } -} - -static void HandleInput(SharedMemoryContext *context, WindowData *win_data, - char *shmem_name) { - SDL_Surface *surface = win_data->screen; - - SDL_Event event; - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_WINDOWEVENT: { - switch (event.window.event) { - case SDL_WINDOWEVENT_CLOSE: { - win_data->running = false; - break; - } - case SDL_WINDOWEVENT_RESIZED: { - win_data->width = event.window.data1; - win_data->height = event.window.data2; - SDL_FreeSurface(win_data->back_buffer); - win_data->back_buffer = CreateBackBuffer(win_data->width, - win_data->height); - win_data->screen = GetScreen(win_data->window); - break; - } - } - break; - } - case SDL_KEYUP: { - switch (event.key.keysym.scancode) { - case SDL_SCANCODE_0: { - if (global_active_segment == ActiveSegment::BufferPool) { - SetActiveDevice(context, 0); - } else { - global_active_heap = ActiveHeap::Id; - } - break; - } - case SDL_SCANCODE_1: { - if (global_active_segment == ActiveSegment::BufferPool) { - SetActiveDevice(context, 1); - } else { - global_active_heap = ActiveHeap::Map; - } - break; - } - case SDL_SCANCODE_2: { - SetActiveDevice(context, 2); - break; - } - case SDL_SCANCODE_3: { - SetActiveDevice(context, 3); - break; - } - case SDL_SCANCODE_4: { - SetActiveDevice(context, 4); - break; - } - case SDL_SCANCODE_5: { - SetActiveDevice(context, 5); - break; - } - case SDL_SCANCODE_6: { - SetActiveDevice(context, 6); - break; - } - case SDL_SCANCODE_7: { - SetActiveDevice(context, 7); - break; - } - case SDL_SCANCODE_B: { - global_active_segment = ActiveSegment::BufferPool; - SDL_Log("Viewing BufferPool segment\n"); - break; - } - case SDL_SCANCODE_C: { - PrintBufferCounts(context, global_active_device); - break; - } - case SDL_SCANCODE_F: { - PrintFreeListSizes(context, global_active_device); - break; - } - case SDL_SCANCODE_M: { - if (global_id_debug_state == 0 || global_map_debug_state == 0) { - SDL_Log("Must enable HERMES_DEBUG_HEAP to inspect metadata\n"); - } else { - global_active_segment = ActiveSegment::Metadata; - SDL_Log("Viewing Metadata segment\n"); - } - break; - } - case SDL_SCANCODE_R: { - ReloadSharedMemory(context, shmem_name); - SDL_Log("Reloaded shared memory\n"); - break; - } - case SDL_SCANCODE_S: { - SaveBitmap(surface); - break; - } - case SDL_SCANCODE_ESCAPE: { - win_data->running = false; - break; - } - default: - break; - } - break; - } - } - } -} - -static void InitColors(SDL_PixelFormat *format) { - global_colors[kColor_Red] = SDL_MapRGB(format, 255, 0, 0); - global_colors[kColor_Yellow] = SDL_MapRGB(format, 255, 255, 0); - global_colors[kColor_Green] = SDL_MapRGB(format, 0, 255, 0); - global_colors[kColor_Cyan] = SDL_MapRGB(format, 24, 154, 211); - global_colors[kColor_Grey] = SDL_MapRGB(format, 128, 128, 128); - global_colors[kColor_White] = SDL_MapRGB(format, 255, 255, 255); - global_colors[kColor_Magenta] = SDL_MapRGB(format, 255, 0, 255); - global_colors[kColor_Black] = SDL_MapRGB(format, 0, 0, 0); - - global_id_colors[kColor_Blue1] = SDL_MapRGB(format, 0x03, 0x04, 0x5e); - global_id_colors[kColor_Blue2] = SDL_MapRGB(format, 0, 0x77, 0xb6); - global_id_colors[kColor_Blue3] = SDL_MapRGB(format, 0, 0xb4, 0xd8); - global_id_colors[kColor_Blue4] = SDL_MapRGB(format, 0x90, 0xe0, 0xef); - global_id_colors[kColor_Blue5] = SDL_MapRGB(format, 0xca, 0xf0, 0xf8); -} - -static void DisplayBufferPoolSegment(SharedMemoryContext *context, - WindowData *win_data) { - SDL_Surface *back_buffer = win_data->back_buffer; - int width = win_data->width; - int height = win_data->height; - int ending_y = 0; - if (global_active_device == 0) { - ending_y = DrawBufferPool(context, back_buffer, width, height, - global_active_device); - DrawEndOfRamBuffers(context, back_buffer, width, height); - } else { - ending_y = DrawFileBuffers(context, back_buffer, width, height, - global_active_device); - } - - ending_y += 2; - SDL_Rect dividing_line = {0, ending_y, width, 1}; - SDL_FillRect(back_buffer, &dividing_line, - global_colors[kColor_Magenta]); - DrawHeaders(context, back_buffer, width, height, - ending_y + 5, global_active_device); -} - - -Point AddrToPoint(HeapMetadata *hmd, uintptr_t addr) { - Point result = {}; - f32 t = (f32)(addr - (uintptr_t)hmd->heap_base) / (f32)hmd->heap_size; - u32 slot_number = (u32)(t * hmd->total_slots); - result.x = slot_number % hmd->screen_width; - result.y = (slot_number / hmd->screen_width) * 5 + hmd->y_offset; - - return result; -} - -static inline int SlotsToPixelWidth(HeapMetadata *hmd, f32 size) { - int result = (int)(size * hmd->bytes_to_slots); - - return result; -} - -static SDL_Rect OffsetToRect(HeapMetadata *hmd, Heap *heap, u32 offset, - u32 size, bool free_block) { - if (!heap->grows_up) { - assert(hmd->heap_size >= offset); - // Make offset relative to start of heap - offset = hmd->heap_size - offset; - - u32 extent_offset_from_start = hmd->heap_size - heap->extent; - if (offset <= extent_offset_from_start && free_block) { - offset = extent_offset_from_start; - size = hmd->slots_to_bytes * 3; - } - } else { - assert(offset <= heap->extent); - if ((offset + size) > heap->extent && free_block) { - size = heap->extent - offset; - } - } - - u32 slot_number = (u32)(hmd->bytes_to_slots * (f32)offset); - int x = slot_number % hmd->screen_width; - int y = (slot_number / hmd->screen_width * hmd->h + hmd->y_offset); - int w = SlotsToPixelWidth(hmd, size); - int h = hmd->h; - - SDL_Rect result = {x, y, w, h}; - - return result; -} - -static void DrawAllocatedHeapBlocks(DebugState *state, HeapMetadata *hmd, - Heap *heap, SDL_Surface *surface) { - global_color_counter = 0; - state->mutex.Lock();; - for (u32 i = 0; i < state->allocation_count; ++i) { - DebugHeapAllocation *allocation = &state->allocations[i]; - SDL_Rect rect = OffsetToRect(hmd, heap, allocation->offset, - allocation->size, false); - - global_color_counter++; - u32 color_max = kIdHeapColors_Count; - // int color_max = kColor_HeapMax; - if (global_color_counter == color_max) { - global_color_counter = 0; - } - // u32 color = global_colors[global_color_counter]; - u32 color = global_id_colors[global_color_counter]; - DrawWrappingRect(&rect, hmd->screen_width, 0, surface, color); - } - state->mutex.Unlock();; -} - -static void DrawHeapExtent(HeapMetadata *hmd, Heap *heap, int w, - SDL_Surface *surface) { - u32 offset = heap->extent; - if (!heap->grows_up) { - assert(hmd->heap_size >= offset); - // Make offset relative to start of heap - offset = hmd->heap_size - offset; - } - - u32 slot_number = (u32)(hmd->bytes_to_slots * (f32)offset); - int x = slot_number % hmd->screen_width; - int y = (slot_number / hmd->screen_width * hmd->h + hmd->y_offset); - SDL_Rect rect = {x, y, w, hmd->h}; - DrawWrappingRect(&rect, hmd->screen_width, 0, surface, - global_colors[kColor_Magenta]); -} - -static void DrawFreeHeapBlocks(HeapMetadata *hmd, Heap *heap, - SDL_Surface *surface) { - heap->mutex.Lock(); - u32 offset = heap->free_list_offset; - FreeBlock *head = GetHeapFreeList(heap); - while (head) { - if (!heap->grows_up) { - offset = offset - sizeof(FreeBlock) + head->size; - } - SDL_Rect rect = OffsetToRect(hmd, heap, offset, head->size, true); - DrawWrappingRect(&rect, hmd->screen_width, 0, surface, - global_colors[kColor_White]); - offset = head->next_offset; - head = NextFreeBlock(heap, head); - } - heap->mutex.Unlock(); -} - -#if DRAW_BUCKETS -static int DrawBucketsAndVBuckets(MetadataManager *mdm, SDL_Surface *surface, - int width, int height, int w, int h, int pad) { - int x = 0; - int y = 0; - - // BucketInfo - for (size_t i = 0; i < mdm->max_buckets; ++i) { - mdm->bucket_mutex.Lock(); - BucketInfo *info = LocalGetBucketInfoByIndex(mdm, i); - bool active = info->active; - mdm->bucket_mutex.Unlock(); - - if (x > width) { - x = 0; - y += h + pad; - } - - if (y + h + pad > height) { - SDL_Log("Not enough room to display all Buckets\n"); - break; - } - - u32 rgb_color = active ? global_colors[kColor_White] : - global_colors[kColor_Red]; - - SDL_Rect rect = {x, y, w, h}; - DrawWrappingRect(&rect, width, pad, surface, rgb_color); - x += w; - } - - // VBucketInfo - for (size_t i = 0; i < mdm->max_vbuckets; ++i) { - mdm->vbucket_mutex.Lock(); - VBucketInfo *info = GetVBucketInfoByIndex(mdm, i); - bool active = info->active; - mdm->vbucket_mutex.Unlock(); - - if (x > width) { - x = 0; - y += h + pad; - } - - if (y + h + pad > height) { - SDL_Log("Not enough room to display all Buckets\n"); - break; - } - - u32 rgb_color = active ? global_colors[kColor_White] : - global_colors[kColor_Yellow]; - SDL_Rect rect = {x, y, w, h}; - DrawWrappingRect(&rect, width, pad, surface, rgb_color); - x += w; - } - - int ending_y = y + h + pad; - SDL_Rect dividing_line = {0, ending_y, width, 1}; - SDL_FillRect(surface, &dividing_line, global_colors[kColor_Magenta]); - - ending_y += h + pad; - - return ending_y; -} -#endif // DRAW_BUCKETS - -static bool PopulateByteCounts(DebugState *state, Heap *heap, - std::vector &byte_counts, u32 heap_size) { - for (size_t i = 0; i < state->allocation_count; ++i) { - DebugHeapAllocation *dha = &state->allocations[i]; - u32 offset = dha->offset; - - if (!heap->grows_up) { - assert(heap_size > dha->offset); - offset = heap_size - dha->offset; - } - - for (size_t j = offset; j < offset + dha->size; ++j) { - byte_counts[j]++; - // Ensure no 2 blocks refer to the same byte - if (byte_counts[j] > 1) { - SDL_Log("Byte %lu is referred to in %u blocks\n", j, byte_counts[j]); - return false; - } - } - } - - return true; -} - -static bool CheckFreeBlocks(Heap *heap, const std::vector &byte_counts, - u32 heap_size) { - heap->mutex.Lock(); - u32 extent_offset_from_start = heap->extent; - if (!heap->grows_up) { - extent_offset_from_start = heap_size - heap->extent; - } - - bool result = true; - u32 offset = heap->free_list_offset; - FreeBlock *head = GetHeapFreeList(heap); - bool stop = false; - while (head && !stop) { - if (!heap->grows_up) { - offset = offset - sizeof(FreeBlock) + head->size; - offset = heap_size - offset; - } - - size_t start = 0; - size_t stop = 0; - - if (heap->grows_up) { - start = offset; - stop = std::min(offset + head->size, extent_offset_from_start); - } else { - start = std::max(offset, extent_offset_from_start); - stop = offset + head->size; - } - - for (size_t i = start; i < stop; ++i) { - if (byte_counts[i] != 0) { - SDL_Log("Byte %lu is referred to by a free block with offset %u\n", i, - offset); - stop = true; - result = false; - break; - } - } - - offset = head->next_offset; - head = NextFreeBlock(heap, head); - } - heap->mutex.Unlock(); - - return result; -} - -static bool CheckOverlap(HeapMetadata *hmd, Heap *map_heap, - Heap *id_heap) { - std::vector heap_byte_counts(hmd->heap_size, 0); - - global_id_debug_state->mutex.Lock(); - global_map_debug_state->mutex.Lock(); - - bool result = true; - if (!PopulateByteCounts(global_id_debug_state, id_heap, heap_byte_counts, - hmd->heap_size)) { - result = false; - } - if (!PopulateByteCounts(global_map_debug_state, map_heap, heap_byte_counts, - hmd->heap_size)) { - result = false; - } - - // Make sure free blocks don't overlap with any allocated blocks - if (!CheckFreeBlocks(map_heap, heap_byte_counts, hmd->heap_size)) { - result = false; - } - if (!CheckFreeBlocks(id_heap, heap_byte_counts, hmd->heap_size)) { - result = false; - } - - global_id_debug_state->mutex.Unlock(); - global_map_debug_state->mutex.Unlock(); - - return result; -} - -static void DisplayMetadataSegment(SharedMemoryContext *context, - WindowData *win_data, - DebugState *map_debug_state, - DebugState *id_debug_state) { - SDL_Surface *surface = win_data->back_buffer; - int width = win_data->width; - int height = win_data->height; - - MetadataManager *mdm = GetMetadataManagerFromContext(context); - int pad = 2; - int w = 3; - int h = 3; - -#if DRAW_BUCKETS - int ending_y = DrawBucketsAndVBuckets(mdm, surface, width, height, w, h); -# else - int ending_y = pad; -#endif - - int num_pixel_rows = height - 1 - ending_y; - num_pixel_rows = RoundDownToMultiple(num_pixel_rows, h); - - Heap *id_heap = GetIdHeap(mdm); - Heap *map_heap = GetMapHeap(mdm); - - HeapMetadata hmd = {}; - hmd.num_rows = (num_pixel_rows / h) - 1; - hmd.total_slots = width * hmd.num_rows; - hmd.heap_base = (u8 *)(map_heap + 1); - hmd.heap_size = (u8 *)(id_heap) - (u8 *)(map_heap + 1); - hmd.screen_width = width; - hmd.y_offset = ending_y; - hmd.h = h; - hmd.slots_to_bytes = (f32)hmd.heap_size / (f32)hmd.total_slots; - hmd.bytes_to_slots = 1.0f / hmd.slots_to_bytes; - assert(hmd.heap_size > hmd.total_slots); - - // Map Heap - DrawAllocatedHeapBlocks(map_debug_state, &hmd, map_heap, surface); - DrawFreeHeapBlocks(&hmd, map_heap, surface); - // ID Heap - DrawFreeHeapBlocks(&hmd, id_heap, surface); - DrawAllocatedHeapBlocks(id_debug_state, &hmd, id_heap, surface); - - DrawHeapExtent(&hmd, map_heap, w, surface); - DrawHeapExtent(&hmd, id_heap, w, surface); - - if (!CheckOverlap(&hmd, map_heap, id_heap)) { - win_data->running = false; - } -} - -int main() { - SDL_Init(SDL_INIT_VIDEO); - - WindowData win_data = {}; - win_data.width = 1200; - win_data.height = 600; - win_data.window = CreateWindow(win_data.width, win_data.height); - win_data.back_buffer = CreateBackBuffer(win_data.width, win_data.height); - win_data.screen = GetScreen(win_data.window); - win_data.running = true; - - InitColors(win_data.back_buffer->format); - - char full_shmem_name[kMaxBufferPoolShmemNameLength]; - char base_shmem_name[] = "/hermes_buffer_pool_"; - MakeFullShmemName(full_shmem_name, base_shmem_name); - SharedMemoryContext context = GetSharedMemoryContext(full_shmem_name); - if (context.shm_base == 0) { - SDL_Log("Couldn't open BufferPool shared memory\n"); - exit(1); - } - - while (win_data.running) { - HandleInput(&context, &win_data, full_shmem_name); - - SDL_FillRect(win_data.back_buffer, NULL, global_colors[kColor_Black]); - - switch (global_active_segment) { - case ActiveSegment::BufferPool: { - DisplayBufferPoolSegment(&context, &win_data); - break; - } - case ActiveSegment::Metadata: { - DisplayMetadataSegment(&context, &win_data, global_map_debug_state, - global_id_debug_state); - break; - } - } - - SDL_BlitSurface(win_data.back_buffer, NULL, win_data.screen, NULL); - SDL_UpdateWindowSurface(win_data.window); - - SDL_Delay(60); - } - - ReleaseSharedMemoryContext(&context); - - SDL_FreeSurface(win_data.back_buffer); - SDL_DestroyWindow(win_data.window); - SDL_Quit(); - - return 0; -} diff --git a/src/communication.h b/src/communication.h index dbbd969d9..f33cf0809 100644 --- a/src/communication.h +++ b/src/communication.h @@ -25,22 +25,11 @@ namespace hermes { -/** - * The type of communicator - * */ - -enum class CommunicationType { - kMpi -}; - /** A structure to represent MPI communication context */ -struct CommunicationContext { - virtual void WorldBarrier() = 0; /** E.g., MPI_Barrier(MPI_COMM_WORLD)*/ - virtual void SubBarrier() = 0; /** E.g., MPI_Barrier(something else)*/ - virtual void Finalize() = 0; /** E.g., MPI_Finalize() */ - +class CommunicationContext { + public: /** A unique identifier for each rank, relative to all ranks. */ i32 world_proc_id; /** a unique identifier for each rank, releative to each ProcessKind. */ @@ -63,23 +52,23 @@ struct CommunicationContext { * is not relative to all ranks, but to each ProcessKind. This is useful for * operations that only need to happen once per node. */ bool first_on_node; -}; - -size_t InitCommunication(CommunicationContext *comm, - size_t trans_arena_size_per_node, - bool is_daemon = false, bool is_adapter = false); -/** world communicator */ -inline void WorldBarrier(CommunicationContext *comm) { - comm->world_barrier(comm->state); -} -/** sub-communicator */ -inline void SubBarrier(CommunicationContext *comm) { - comm->sub_barrier(comm->state); -} - -void *GetAppCommunicator(CommunicationContext *comm); + public: + virtual void WorldBarrier() = 0; /** E.g., MPI_Barrier(MPI_COMM_WORLD)*/ + virtual void SubBarrier() = 0; /** E.g., MPI_Barrier(something else)*/ + virtual void Finalize() = 0; /** E.g., MPI_Finalize() */ +}; } // namespace hermes +#if defined(HERMES_COMMUNICATION_MPI) +#include "communication_mpi.h" +#define COMM_TYPE MpiCommunicator +#elif defined(HERMES_COMMUNICATION_ZMQ) +#include "communication_zmq.cc" +#else +#error "Communication implementation required " \ + "(e.g., -DHERMES_COMMUNICATION_MPI)." +#endif + #endif // HERMES_COMMUNICATION_H_ diff --git a/src/communication_factory.h b/src/communication_factory.h deleted file mode 100644 index d5ea87ae4..000000000 --- a/src/communication_factory.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// Created by lukemartinlogan on 11/30/22. -// - -#ifndef HERMES_SRC_RPC_FACTORY_H_ -#define HERMES_SRC_RPC_FACTORY_H_ - -#include "communication.h" -#include "communication_mpi.cc" -#include - -namespace hermes { -class CommunicationFactory { - public: - /** - * Return an RPC. Uses factory pattern. - * - * @param type, RpcType, type of mapper to be used by the STDIO adapter. - * @return Instance of RPC given a type. - */ - static std::unique_ptr Get( - const CommunicationType &type) { - switch (type) { - case CommunicationType::kMpi: { - return std::make_unique(); - } - default: - return nullptr; - } - } -}; -} // namespace hermes - -#endif // HERMES_SRC_RPC_FACTORY_H_ diff --git a/src/communication_mpi.cc b/src/communication_mpi.h similarity index 97% rename from src/communication_mpi.cc rename to src/communication_mpi.h index 3fb2e64a6..2a9b96872 100644 --- a/src/communication_mpi.cc +++ b/src/communication_mpi.h @@ -10,7 +10,12 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#ifndef HERMES_SRC_COMMUNICATION_MPI_H +#define HERMES_SRC_COMMUNICATION_MPI_H + #include "communication.h" +#include "mpi.h" +#include /** * @file communication_mpi.cc @@ -253,8 +258,10 @@ class MpiCommunicator : public CommunicationContext { } } - return trans_arena_size_for_rank; + // return trans_arena_size_for_rank; } }; } // namespace hermes + +#endif // HERMES_SRC_COMMUNICATION_MPI_H diff --git a/src/config.h b/src/config.h new file mode 100644 index 000000000..6525542dc --- /dev/null +++ b/src/config.h @@ -0,0 +1,255 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_CONFIG_PARSER_H_ +#define HERMES_CONFIG_PARSER_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "hermes_types.h" + +namespace hermes { + +/** + * Configuration used to intialize client + * */ + +struct ClientConfig { + public: + bool stop_daemon_; + + public: + ClientConfig(); + void LoadText(const std::string &text); + void LoadFromFile(const char *path); + void LoadDefault(); +}; + +/** + * System and user configuration that is used to initialize Hermes. + */ +class ServerConfig { + public: + /** The total capacity of each buffering Device */ + size_t capacities_[kMaxDevices]; + /** The block sizes for each device */ + lipcl::vector block_sizes_; + + /** The block sizes of each Device */ + int block_sizes_[kMaxDevices]; + /** The unit of each slab, a multiple of the Device's block size */ + int slab_unit_sizes[kMaxDevices][kMaxBufferPoolSlabs]; + /** The percentage of space each slab should occupy per Device. The values + * for each Device should add up to 1.0. + */ + f32 desired_slab_percentages[kMaxDevices][kMaxBufferPoolSlabs]; + /** The bandwidth of each Device */ + f32 bandwidths[kMaxDevices]; + /** The latency of each Device */ + f32 latencies[kMaxDevices]; + /** The number of Devices */ + int num_devices; + /** The number of Targets */ + int num_targets; + + /** The maximum number of buckets per node */ + u32 max_buckets_per_node; + /** The maximum number of vbuckets per node */ + u32 max_vbuckets_per_node; + /** The length of a view state epoch */ + u32 system_view_state_update_interval_ms; + + /** The mount point or desired directory for each Device. RAM Device should + * be the empty string. + */ + std::string mount_points[kMaxDevices]; + /** The mount point of the swap target. */ + std::string swap_mount; + /** The number of times the BufferOrganizer will attempt to place a swap + * blob into the hierarchy before giving up. */ + int num_buffer_organizer_retries; + + /** If non-zero, the device is shared among all nodes (e.g., burst buffs) */ + int is_shared_device[kMaxDevices]; + + /** The name of a file that contains host names, 1 per line */ + std::string rpc_server_host_file; + /** The hostname of the RPC server, minus any numbers that Hermes may + * auto-generate when the rpc_hostNumber_range is specified. */ + std::string rpc_server_base_name; + /** The list of numbers from all server names. E.g., '{1, 3}' if your servers + * are named ares-comp-1 and ares-comp-3 */ + std::vector host_numbers; + /** The RPC server name suffix. This is appended to the base name plus host + number. */ + std::string rpc_server_suffix; + /** The parsed hostnames from the hermes conf */ + std::vector host_names; + /** The RPC protocol to be used. */ + std::string rpc_protocol; + /** The RPC domain name for verbs transport. */ + std::string rpc_domain; + /** The RPC port number. */ + int rpc_port; + /** The RPC port number for the buffer organizer. */ + int buffer_organizer_port; + /** The number of handler threads per RPC server. */ + int rpc_num_threads; + /** The number of buffer organizer threads. */ + int bo_num_threads; + /** The default blob placement policy. */ + api::PlacementPolicy default_placement_policy; + /** Whether blob splitting is enabled for Round-Robin blob placement. */ + bool default_rr_split; + /** The min and max capacity threshold in MiB for each device at which the + * BufferOrganizer will trigger. */ + Thresholds bo_capacity_thresholds[kMaxDevices]; + /** A base name for the BufferPool shared memory segement. Hermes appends the + * value of the USER environment variable to this string. + */ + char buffer_pool_shmem_name[kMaxBufferPoolShmemNameLength]; + + /** + * Paths prefixed with the following directories are not tracked in Hermes + * Exclusion list used by darshan at + * darshan/darshan-runtime/lib/darshan-core.c + */ + std::vector path_exclusions; + + /** + * Paths prefixed with the following directories are tracked by Hermes even if + * they share a root with a path listed in path_exclusions + */ + std::vector path_inclusions; + + public: + ServerConfig(); + void LoadText(const std::string &text); + void LoadFromFile(const char *path); + void LoadDefault(); +}; + +/** print \a expected value and fail when an error occurs */ +void PrintExpectedAndFail(const std::string &expected, u32 line_number = 0) { + std::ostringstream msg; + msg << "Configuration parser expected '" << expected << "'"; + if (line_number > 0) { + msg << " on line " << line_number; + } + msg << "\n"; + + LOG(FATAL) << msg.str(); +} + +/** parse \a var array from configuration file in YAML */ +template +void ParseArray(YAML::Node list_node, const std::string var, + T *list, int max_list_len) { + int i = 0; + if (max_list_len < (int)list_node.size()) { + LOG(FATAL) << var << " (array) had " + << list_node.size() << " arguments " + << "but up to " << max_list_len << " expected\n"; + } + for (auto val_node : list_node) { + list[i++] = val_node.as(); + } +} + +/** parse \a list_node vector from configuration file in YAML */ +template +void ParseVector(YAML::Node list_node, std::vector &list) { + for (auto val_node : list_node) { + list.emplace_back(val_node.as()); + } +} + +/** parse \a matrix_node matrix using \a col_len column length */ +template +void ParseMatrix(YAML::Node matrix_node, const std::string var, T *matrix, + int max_row_len, int max_col_len, int *col_len) { + int i = 0; + if (max_row_len < (int)matrix_node.size()) { + LOG(FATAL) << var << " (matrix) had " + << matrix_node.size() << " arguments " + << "but up to " << max_row_len << " expected\n"; + } + for (auto row : matrix_node) { + ParseArray(row, var, &matrix[i*max_col_len], col_len[i]); + ++i; + } +} + +/** parse \a matrix_node matrix from configuration file in YAML */ +template +void ParseMatrix(YAML::Node matrix_node, std::string var, T *matrix, + int max_row_len, int max_col_len) { + int i = 0; + if (max_row_len < (int)matrix_node.size()) { + LOG(FATAL) << var << " (matrix) had " + << matrix_node.size() << " arguments " + << "but up to " << max_row_len << " expected\n"; + } + for (auto row : matrix_node) { + ParseArray(row, var, &matrix[i*max_col_len], max_col_len); + ++i; + } +} + +/** parse range list from configuration file in YAML */ +void ParseRangeList(YAML::Node list_node, std::string var, + std::vector &list) { + int min, max, width = 0; + for (auto val_node : list_node) { + std::string val = val_node.as(); + if (val.find('-') == std::string::npos) { + min = val_node.as(); + max = min; + } else { + std::stringstream ss(val); + std::string word; + std::vector words; + while (std::getline(ss, word, '-')) { + words.push_back(word); + } + if (words.size() != 2) { + LOG(FATAL) << var << + " has invalid range definition " << val << std::endl; + return; + } + min = std::stoi(words[0]); + max = std::stoi(words[1]); + width = words[0].size(); + } + + if (width > 0) { + for (int i = min; i <= max; ++i) { + std::stringstream ss; + ss << std::setw(width) << std::setfill('0') << i; + list.emplace_back(ss.str()); + } + } else { + for (int i = min; i <= max; ++i) { + list.emplace_back(std::to_string(i)); + } + } + } +} + +} // namespace hermes +#endif // HERMES_CONFIG_PARSER_H_ diff --git a/src/config_client.cc b/src/config_client.cc new file mode 100644 index 000000000..8c1bc96e6 --- /dev/null +++ b/src/config_client.cc @@ -0,0 +1,14 @@ +// +// Created by lukemartinlogan on 12/2/22. +// + +#include "config.h" +#include "config_client_default.h" + +namespace hermes { + +ClientConfig::ClientConfig() { + +} + +} // namespace hermes \ No newline at end of file diff --git a/src/config_client_default.h b/src/config_client_default.h new file mode 100644 index 000000000..5787a7e89 --- /dev/null +++ b/src/config_client_default.h @@ -0,0 +1,6 @@ +#ifndef HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ +#define HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ +const char* kClientDefaultConfigStr = +"stop_daemon: true" +"file_page_size_kb: 1024"; +#endif // HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ \ No newline at end of file diff --git a/src/config_parser.cc b/src/config_parser.cc deleted file mode 100644 index 70e9ad942..000000000 --- a/src/config_parser.cc +++ /dev/null @@ -1,556 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "utils.h" -#include "config_parser.h" -#include - -// Steps to add a new configuration variable: -// 1. Add an "if" statement similar to ParseConfigYAML function for the variable -// 2. Add an Assert to config_parser_test.cc to test the functionality. -// 3. Set a default value in InitDefaultConfig -// 4. Add the variable with documentation to test/data/hermes.yaml - -namespace hermes { - -// TODO(llogan): Use to check for invalid params -/* -static const char *kConfigVariableStrings[] = { - "unknown", - "num_devices", - "num_targets", - "capacities_bytes", - "capacities_kb", - "capacities_mb", - "capacities_gb", - "block_sizes_bytes", - "block_sizes_kb", - "block_sizes_mb", - "block_sizes_gb", - "num_slabs", - "slab_unit_sizes", - "desired_slab_percentages", - "bandwidths_mbps", - "latencies_us", - "buffer_pool_arena_percentage", - "metadata_arena_percentage", - "transient_arena_percentage", - "mount_points", - "swap_mount", - "num_buffer_organizer_retries", - "max_buckets_per_node", - "max_vbuckets_per_node", - "system_view_state_update_interval_ms", - "rpc_server_host_file", - "rpc_server_base_name", - "rpc_server_suffix", - "buffer_pool_shmem_name", - "rpc_protocol", - "rpc_domain", - "rpc_port", - "buffer_organizer_port", - "rpc_host_number_range", - "rpc_num_threads", - "default_placement_policy", - "is_shared_device", - "buffer_organizer_num_threads", - "default_rr_split", - "bo_capacity_thresholds", -};*/ - -/** print \a expected value and fail when an error occurs */ -void PrintExpectedAndFail(const std::string &expected, u32 line_number = 0) { - std::ostringstream msg; - msg << "Configuration parser expected '" << expected << "'"; - if (line_number > 0) { - msg << " on line " << line_number; - } - msg << "\n"; - - LOG(FATAL) << msg.str(); -} - -/** log an error message when the number of devices is 0 in \a config */ -void RequireNumDevices(Config *config) { - if (config->num_devices == 0) { - LOG(FATAL) << "The configuration variable 'num_devices' must be defined " - << "first" << std::endl; - } -} - -/** log an error message when the number of slabs is 0 in \a config */ -void RequireNumSlabs(Config *config) { - if (config->num_slabs == 0) { - LOG(FATAL) << "The configuration variable 'num_slabs' must be defined first" - << std::endl; - } -} - -/** log an error message when capacities are specified multiple times */ -void RequireCapacitiesUnset(bool &already_specified) { - if (already_specified) { - LOG(FATAL) << "Capacities are specified multiple times in the configuration" - << " file. Only use one of 'capacities_bytes', 'capacities_kb'," - << "'capacities_mb', or 'capacities_gb'\n"; - } else { - already_specified = true; - } -} - -/** log an error message when block sizes are specified multiple times */ -void RequireBlockSizesUnset(bool &already_specified) { - if (already_specified) { - LOG(FATAL) << "Block sizes are specified multiple times in the " - << "configuration file. Only use one of 'block_sizes_bytes'," - << "'block_sizes_kb', 'block_sizes_mb', or 'block_sizes_gb'\n"; - } else { - already_specified = true; - } -} - -/** parse capacities from configuration file in YAML */ -void ParseCapacities(Config *config, YAML::Node capacities, - int unit_conversion, bool &already_specified) { - int i = 0; - RequireNumDevices(config); - RequireCapacitiesUnset(already_specified); - for (auto val_node : capacities) { - config->capacities[i++] = val_node.as() * unit_conversion; - } -} - -/** parse block sizes from configuration file in YAML */ -void ParseBlockSizes(Config *config, YAML::Node block_sizes, - int unit_conversion, bool &already_specified) { - int i = 0; - RequireNumDevices(config); - RequireBlockSizesUnset(already_specified); - for (auto val_node : block_sizes) { - size_t block_size = val_node.as() * unit_conversion; - if (block_size > INT_MAX) { - LOG(FATAL) << "Max supported block size is " << INT_MAX << " bytes. " - << "Config file requested " << block_size << " bytes\n"; - } - config->block_sizes[i++] = block_size; - } -} - -/** parse \a var array from configuration file in YAML */ -template -void ParseArray(YAML::Node list_node, const std::string var, - T *list, int max_list_len) { - int i = 0; - if (max_list_len < (int)list_node.size()) { - LOG(FATAL) << var << " (array) had " - << list_node.size() << " arguments " - << "but up to " << max_list_len << " expected\n"; - } - for (auto val_node : list_node) { - list[i++] = val_node.as(); - } -} - -/** parse \a list_node vector from configuration file in YAML */ -template -void ParseVector(YAML::Node list_node, std::vector &list) { - for (auto val_node : list_node) { - list.emplace_back(val_node.as()); - } -} - -/** parse \a matrix_node matrix using \a col_len column length */ -template -void ParseMatrix(YAML::Node matrix_node, const std::string var, T *matrix, - int max_row_len, int max_col_len, int *col_len) { - int i = 0; - if (max_row_len < (int)matrix_node.size()) { - LOG(FATAL) << var << " (matrix) had " - << matrix_node.size() << " arguments " - << "but up to " << max_row_len << " expected\n"; - } - for (auto row : matrix_node) { - ParseArray(row, var, &matrix[i*max_col_len], col_len[i]); - ++i; - } -} - -/** parse \a matrix_node matrix from configuration file in YAML */ -template -void ParseMatrix(YAML::Node matrix_node, std::string var, T *matrix, - int max_row_len, int max_col_len) { - int i = 0; - if (max_row_len < (int)matrix_node.size()) { - LOG(FATAL) << var << " (matrix) had " - << matrix_node.size() << " arguments " - << "but up to " << max_row_len << " expected\n"; - } - for (auto row : matrix_node) { - ParseArray(row, var, &matrix[i*max_col_len], max_col_len); - ++i; - } -} - -/** parse range list from configuration file in YAML */ -void ParseRangeList(YAML::Node list_node, std::string var, - std::vector &list) { - int min, max, width = 0; - for (auto val_node : list_node) { - std::string val = val_node.as(); - if (val.find('-') == std::string::npos) { - min = val_node.as(); - max = min; - } else { - std::stringstream ss(val); - std::string word; - std::vector words; - while (std::getline(ss, word, '-')) { - words.push_back(word); - } - if (words.size() != 2) { - LOG(FATAL) << var << - " has invalid range definition " << val << std::endl; - return; - } - min = std::stoi(words[0]); - max = std::stoi(words[1]); - width = words[0].size(); - } - - if (width > 0) { - for (int i = min; i <= max; ++i) { - std::stringstream ss; - ss << std::setw(width) << std::setfill('0') << i; - list.emplace_back(ss.str()); - } - } else { - for (int i = min; i <= max; ++i) { - list.emplace_back(std::to_string(i)); - } - } - } -} - -/** parse host names from configuration file in YAML */ -void ParseHostNames(YAML::Node yaml_conf, hermes::Config *config) { - if (yaml_conf["rpc_server_host_file"]) { - config->rpc_server_host_file = - yaml_conf["rpc_server_host_file"].as(); - } - if (yaml_conf["rpc_server_base_name"]) { - config->rpc_server_base_name = - yaml_conf["rpc_server_base_name"].as(); - } - if (yaml_conf["rpc_server_suffix"]) { - config->rpc_server_suffix = - yaml_conf["rpc_server_suffix"].as(); - } - if (yaml_conf["rpc_host_number_range"]) { - ParseRangeList(yaml_conf["rpc_host_number_range"], - "rpc_host_number_range", - config->host_numbers); - } - - if (config->rpc_server_host_file.empty()) { - config->host_names.clear(); - if (config->host_numbers.size() == 0) { - config->host_numbers.emplace_back(""); - } - for (auto &host_number : config->host_numbers) { - config->host_names.emplace_back( - config->rpc_server_base_name + - host_number + - config->rpc_server_suffix); - } - } -} - -/** check constraints in \a config configuration */ -void CheckConstraints(Config *config) { - // rpc_domain must be present if rpc_protocol is "verbs" - if (config->rpc_protocol.find("verbs") != std::string::npos && - config->rpc_domain.empty()) { - PrintExpectedAndFail("a non-empty value for rpc_domain"); - } - - double tolerance = 0.0000001; - - // arena_percentages must add up to 1.0 - double arena_percentage_sum = 0; - for (int i = 0; i < kArenaType_Count; ++i) { - arena_percentage_sum += config->arena_percentages[i]; - } - if (fabs(1.0 - arena_percentage_sum) > tolerance) { - std::ostringstream msg; - msg << "the values in arena_percentages to add up to 1.0 but got "; - msg << arena_percentage_sum << "\n"; - PrintExpectedAndFail(msg.str()); - } - - // Each slab's desired_slab_percentages should add up to 1.0 - for (int device = 0; device < config->num_devices; ++device) { - double total_slab_percentage = 0; - for (int slab = 0; slab < config->num_slabs[device]; ++slab) { - total_slab_percentage += config->desired_slab_percentages[device][slab]; - } - if (fabs(1.0 - total_slab_percentage) > tolerance) { - std::ostringstream msg; - msg << "the values in desired_slab_percentages["; - msg << device; - msg << "] to add up to 1.0 but got "; - msg << total_slab_percentage << "\n"; - PrintExpectedAndFail(msg.str()); - } - } -} - -void ParseConfigYAML(YAML::Node &yaml_conf, Config *config) { - bool capcities_specified = false, block_sizes_specified = false; - std::vector host_numbers; - std::vector host_basename; - std::string host_suffix; - - if (yaml_conf["num_devices"]) { - config->num_devices = yaml_conf["num_devices"].as(); - config->num_targets = config->num_devices; - } - if (yaml_conf["num_targets"]) { - config->num_targets = yaml_conf["num_targets"].as(); - } - - if (yaml_conf["capacities_bytes"]) { - ParseCapacities(config, yaml_conf["capacities_bytes"], 1, - capcities_specified); - } - if (yaml_conf["capacities_kb"]) { - ParseCapacities(config, yaml_conf["capacities_kb"], KILOBYTES(1), - capcities_specified); - } - if (yaml_conf["capacities_mb"]) { - ParseCapacities(config, yaml_conf["capacities_mb"], MEGABYTES(1), - capcities_specified); - } - if (yaml_conf["capacities_gb"]) { - ParseCapacities(config, yaml_conf["capacities_gb"], GIGABYTES(1), - capcities_specified); - } - - if (yaml_conf["block_sizes_bytes"]) { - ParseBlockSizes(config, yaml_conf["block_sizes_bytes"], - 1, block_sizes_specified); - } - if (yaml_conf["block_sizes_kb"]) { - ParseBlockSizes(config, yaml_conf["block_sizes_kb"], KILOBYTES(1), - block_sizes_specified); - } - if (yaml_conf["block_sizes_mb"]) { - ParseBlockSizes(config, yaml_conf["block_sizes_mb"], MEGABYTES(1), - block_sizes_specified); - } - if (yaml_conf["block_sizes_gb"]) { - ParseBlockSizes(config, yaml_conf["block_sizes_gb"], GIGABYTES(1), - block_sizes_specified); - } - - if (yaml_conf["num_slabs"]) { - RequireNumDevices(config); - ParseArray(yaml_conf["num_slabs"], "num_slabs", - config->num_slabs, - config->num_devices); - } - if (yaml_conf["slab_unit_sizes"]) { - RequireNumDevices(config); - RequireNumSlabs(config); - ParseMatrix(yaml_conf["slab_unit_sizes"], - "slab_unit_sizes", - reinterpret_cast(config->slab_unit_sizes), - kMaxDevices, kMaxBufferPoolSlabs, config->num_slabs); - } - if (yaml_conf["desired_slab_percentages"]) { - RequireNumDevices(config); - RequireNumSlabs(config); - ParseMatrix(yaml_conf["desired_slab_percentages"], - "desired_slab_percentages", - reinterpret_cast(config->desired_slab_percentages), - kMaxDevices, kMaxBufferPoolSlabs, config->num_slabs); - } - if (yaml_conf["bandwidth_mbps"]) { - RequireNumDevices(config); - ParseArray(yaml_conf["bandwidth_mbps"], - "bandwidth_mbps", - config->bandwidths, config->num_devices); - } - if (yaml_conf["latencies"]) { - RequireNumDevices(config); - ParseArray(yaml_conf["latencies"], - "latencies", - config->latencies, config->num_devices); - } - if (yaml_conf["buffer_pool_arena_percentage"]) { - config->arena_percentages[hermes::kArenaType_BufferPool] = - yaml_conf["buffer_pool_arena_percentage"].as(); - } - if (yaml_conf["metadata_arena_percentage"]) { - config->arena_percentages[hermes::kArenaType_MetaData] = - yaml_conf["metadata_arena_percentage"].as(); - } - if (yaml_conf["transient_arena_percentage"]) { - config->arena_percentages[hermes::kArenaType_Transient] = - yaml_conf["transient_arena_percentage"].as(); - } - if (yaml_conf["mount_points"]) { - RequireNumDevices(config); - ParseArray(yaml_conf["mount_points"], - "mount_points", - config->mount_points, config->num_devices); - } - if (yaml_conf["swap_mount"]) { - config->swap_mount = yaml_conf["swap_mount"].as(); - } - if (yaml_conf["num_buffer_organizer_retries"]) { - config->num_buffer_organizer_retries = - yaml_conf["num_buffer_organizer_retries"].as(); - } - if (yaml_conf["max_buckets_per_node"]) { - config->max_buckets_per_node = - yaml_conf["max_buckets_per_node"].as(); - } - if (yaml_conf["max_vbuckets_per_node"]) { - config->max_vbuckets_per_node = - yaml_conf["max_vbuckets_per_node"].as(); - } - if (yaml_conf["system_view_state_update_interval_ms"]) { - config->system_view_state_update_interval_ms = - yaml_conf["system_view_state_update_interval_ms"].as(); - } - if (yaml_conf["buffer_pool_shmem_name"]) { - std::string name = yaml_conf["buffer_pool_shmem_name"].as(); - std::snprintf(config->buffer_pool_shmem_name, - kMaxBufferPoolShmemNameLength, - "%s", name.c_str()); - } - if (yaml_conf["rpc_protocol"]) { - config->rpc_protocol = yaml_conf["rpc_protocol"].as(); - } - if (yaml_conf["rpc_domain"]) { - config->rpc_domain = yaml_conf["rpc_domain"].as(); - } - if (yaml_conf["rpc_port"]) { - config->rpc_port = yaml_conf["rpc_port"].as(); - } - if (yaml_conf["buffer_organizer_port"]) { - config->buffer_organizer_port = - yaml_conf["buffer_organizer_port"].as(); - } - if (yaml_conf["rpc_num_threads"]) { - config->rpc_num_threads = - yaml_conf["rpc_num_threads"].as(); - } - if (yaml_conf["default_placement_policy"]) { - std::string policy = - yaml_conf["default_placement_policy"].as(); - - if (policy == "MinimizeIoTime") { - config->default_placement_policy = - api::PlacementPolicy::kMinimizeIoTime; - } else if (policy == "Random") { - config->default_placement_policy = api::PlacementPolicy::kRandom; - } else if (policy == "RoundRobin") { - config->default_placement_policy = api::PlacementPolicy::kRoundRobin; - } else { - LOG(FATAL) << "Unknown default_placement_policy: '" << policy << "'" - << std::endl; - } - } - if (yaml_conf["is_shared_device"]) { - RequireNumDevices(config); - ParseArray(yaml_conf["is_shared_device"], - "is_shared_device", - config->is_shared_device, config->num_devices); - } - if (yaml_conf["buffer_organizer_num_threads"]) { - config->bo_num_threads = - yaml_conf["buffer_organizer_num_threads"].as(); - } - if (yaml_conf["default_rr_split"]) { - config->default_rr_split = yaml_conf["default_rr_split"].as(); - } - if (yaml_conf["bo_num_threads"]) { - config->bo_num_threads = yaml_conf["bo_num_threads"].as(); - } - if (yaml_conf["bo_capacity_thresholds"]) { - RequireNumDevices(config); - f32 thresholds[kMaxDevices][2] = {0}; - ParseMatrix(yaml_conf["bo_capacity_thresholds"], - "bo_capacity_thresholds", - reinterpret_cast(thresholds), - kMaxDevices, 2); - for (int i = 0; i < config->num_devices; ++i) { - config->bo_capacity_thresholds[i].min = thresholds[i][0]; - config->bo_capacity_thresholds[i].max = thresholds[i][1]; - } - } - if (yaml_conf["path_exclusions"]) { - ParseVector( - yaml_conf["path_exclusions"], config->path_exclusions); - } - if (yaml_conf["path_inclusions"]) { - ParseVector( - yaml_conf["path_inclusions"], config->path_inclusions); - } - ParseHostNames(yaml_conf, config); - CheckConstraints(config); -} - -/** - parse YAML configuration file - */ -void ParseConfig(const char *path, Config *config) { - ScopedTemporaryMemory scratch(arena); - InitDefaultConfig(config); - LOG(INFO) << "ParseConfig-LoadFile" << std::endl; - YAML::Node yaml_conf = YAML::LoadFile(path); - LOG(INFO) << "ParseConfig-LoadComplete" << std::endl; - ParseConfigYAML(yaml_conf, config); -} - -/** - parse configuration string - */ -void ParseConfigString( - const std::string &config_string, Config *config) { - ScopedTemporaryMemory scratch(arena); - InitDefaultConfig(config); - YAML::Node yaml_conf = YAML::Load(config_string); - ParseConfigYAML(yaml_conf, config); -} - -void InitConfig(hermes::Config *config, const char *config_file) { - const size_t kConfigMemorySize = KILOBYTES(16); - hermes::u8 config_memory[kConfigMemorySize]; - if (config_file) { - hermes::Arena config_arena = {}; - hermes::InitArena(&config_arena, kConfigMemorySize, config_memory); - hermes::ParseConfig(&config_arena, config_file, config); - } else { - InitDefaultConfig(config); - } -} - -} // namespace hermes diff --git a/src/config_parser.h b/src/config_parser.h deleted file mode 100644 index 981fe41a8..000000000 --- a/src/config_parser.h +++ /dev/null @@ -1,30 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_CONFIG_PARSER_H_ -#define HERMES_CONFIG_PARSER_H_ - -#include - -#include "hermes_types.h" - -namespace hermes { - -void ParseConfig(const char *path, Config *config); -void ParseConfigString(const std::string &config_string, - Config *config); -void InitConfig(hermes::Config *config, const char *config_file); -/** create configuration file */ -hermes::Config *CreateConfig(const char *config_file); - -} // namespace hermes -#endif // HERMES_CONFIG_PARSER_H_ diff --git a/src/config_server.cc b/src/config_server.cc new file mode 100644 index 000000000..0990711e8 --- /dev/null +++ b/src/config_server.cc @@ -0,0 +1,367 @@ +// +// Created by lukemartinlogan on 12/2/22. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" +#include "config.h" +#include + +#include "config.h" +#include "config_server_default.h" + +namespace hermes { + +/** log an error message when the number of devices is 0 in \a config */ +void ServerConfig::RequireNumDevices() { + if (num_devices == 0) { + LOG(FATAL) << "The configuration variable 'num_devices' must be defined " + << "first" << std::endl; + } +} + +/** log an error message when the number of slabs is 0 in \a config */ +void ServerConfig::RequireNumSlabs() { + if (num_slabs == 0) { + LOG(FATAL) << "The configuration variable 'num_slabs' must be defined first" + << std::endl; + } +} + +/** log an error message when capacities are specified multiple times */ +void ServerConfig::RequireCapacitiesUnset(bool &already_specified) { + if (already_specified) { + LOG(FATAL) << "Capacities are specified multiple times in the configuration" + << " file. Only use one of 'capacities_bytes', 'capacities_kb'," + << "'capacities_mb', or 'capacities_gb'\n"; + } else { + already_specified = true; + } +} + +/** log an error message when block sizes are specified multiple times */ +void ServerConfig::RequireBlockSizesUnset(bool &already_specified) { + if (already_specified) { + LOG(FATAL) << "Block sizes are specified multiple times in the " + << "configuration file. Only use one of 'block_sizes_bytes'," + << "'block_sizes_kb', 'block_sizes_mb', or 'block_sizes_gb'\n"; + } else { + already_specified = true; + } +} + +/** parse capacities from configuration file in YAML */ +void ServerConfig::ParseCapacities(YAML::Node capacities, int unit_conversion, + bool &already_specified) { + int i = 0; + RequireNumDevices(config); + RequireCapacitiesUnset(already_specified); + for (auto val_node : capacities) { + capacities[i++] = val_node.as() * unit_conversion; + } +} + +/** parse block sizes from configuration file in YAML */ +void ServerConfig::ParseBlockSizes(YAML::Node block_sizes, int unit_conversion, + bool &already_specified) { + int i = 0; + RequireNumDevices(config); + RequireBlockSizesUnset(already_specified); + for (auto val_node : block_sizes) { + size_t block_size = val_node.as() * unit_conversion; + if (block_size > INT_MAX) { + LOG(FATAL) << "Max supported block size is " << INT_MAX << " bytes. " + << "Config file requested " << block_size << " bytes\n"; + } + block_sizes[i++] = block_size; + } +} + +/** parse host names from configuration file in YAML */ +void ServerConfig::ParseHostNames(YAML::Node yaml_conf) { + if (yaml_conf["rpc_server_host_file"]) { + rpc_server_host_file = + yaml_conf["rpc_server_host_file"].as(); + } + if (yaml_conf["rpc_server_base_name"]) { + rpc_server_base_name = + yaml_conf["rpc_server_base_name"].as(); + } + if (yaml_conf["rpc_server_suffix"]) { + rpc_server_suffix = + yaml_conf["rpc_server_suffix"].as(); + } + if (yaml_conf["rpc_host_number_range"]) { + ParseRangeList(yaml_conf["rpc_host_number_range"], "rpc_host_number_range", + host_numbers); + } + + if (rpc_server_host_file.empty()) { + host_names.clear(); + if (host_numbers.size() == 0) { + host_numbers.emplace_back(""); + } + for (auto &host_number : host_numbers) { + host_names.emplace_back(rpc_server_base_name + + host_number + rpc_server_suffix); + } + } +} + +/** check constraints in \a config configuration */ +void ServerConfig::CheckConstraints() { + // rpc_domain must be present if rpc_protocol is "verbs" + if (rpc_protocol.find("verbs") != std::string::npos && + rpc_domain.empty()) { + PrintExpectedAndFail("a non-empty value for rpc_domain"); + } + + double tolerance = 0.0000001; + + // arena_percentages must add up to 1.0 + /*double arena_percentage_sum = 0; + for (int i = 0; i < kArenaType_Count; ++i) { + arena_percentage_sum += arena_percentages[i]; + } + if (fabs(1.0 - arena_percentage_sum) > tolerance) { + std::ostringstream msg; + msg << "the values in arena_percentages to add up to 1.0 but got "; + msg << arena_percentage_sum << "\n"; + PrintExpectedAndFail(msg.str()); + }*/ + + // Each slab's desired_slab_percentages should add up to 1.0 + for (int device = 0; device < num_devices; ++device) { + double total_slab_percentage = 0; + for (int slab = 0; slab < num_slabs[device]; ++slab) { + total_slab_percentage += desired_slab_percentages[device][slab]; + } + if (fabs(1.0 - total_slab_percentage) > tolerance) { + std::ostringstream msg; + msg << "the values in desired_slab_percentages["; + msg << device; + msg << "] to add up to 1.0 but got "; + msg << total_slab_percentage << "\n"; + PrintExpectedAndFail(msg.str()); + } + } +} + +/** parse the YAML node */ +void ServerConfig::ParseYAML(YAML::Node &yaml_conf) { + bool capcities_specified = false, block_sizes_specified = false; + std::vector host_numbers; + std::vector host_basename; + std::string host_suffix; + + if (yaml_conf["num_devices"]) { + num_devices = yaml_conf["num_devices"].as(); + num_targets = num_devices; + } + if (yaml_conf["num_targets"]) { + num_targets = yaml_conf["num_targets"].as(); + } + + if (yaml_conf["capacities_bytes"]) { + ParseCapacities(yaml_conf["capacities_bytes"], 1, + capcities_specified); + } + if (yaml_conf["capacities_kb"]) { + ParseCapacities(yaml_conf["capacities_kb"], KILOBYTES(1), + capcities_specified); + } + if (yaml_conf["capacities_mb"]) { + ParseCapacities(yaml_conf["capacities_mb"], MEGABYTES(1), + capcities_specified); + } + if (yaml_conf["capacities_gb"]) { + ParseCapacities(yaml_conf["capacities_gb"], GIGABYTES(1), + capcities_specified); + } + + if (yaml_conf["block_sizes_bytes"]) { + ParseBlockSizes(yaml_conf["block_sizes_bytes"], 1, + block_sizes_specified); + } + if (yaml_conf["block_sizes_kb"]) { + ParseBlockSizes(yaml_conf["block_sizes_kb"], KILOBYTES(1), + block_sizes_specified); + } + if (yaml_conf["block_sizes_mb"]) { + ParseBlockSizes(yaml_conf["block_sizes_mb"], MEGABYTES(1), + block_sizes_specified); + } + if (yaml_conf["block_sizes_gb"]) { + ParseBlockSizes(yaml_conf["block_sizes_gb"], GIGABYTES(1), + block_sizes_specified); + } + + if (yaml_conf["num_slabs"]) { + RequireNumDevices(); + ParseArray(yaml_conf["num_slabs"], "num_slabs", num_slabs, + num_devices); + } + if (yaml_conf["slab_unit_sizes"]) { + RequireNumDevices(); + RequireNumSlabs(); + ParseMatrix(yaml_conf["slab_unit_sizes"], "slab_unit_sizes", + reinterpret_cast(slab_unit_sizes), + kMaxDevices, kMaxBufferPoolSlabs, num_slabs); + } + if (yaml_conf["desired_slab_percentages"]) { + RequireNumDevices(); + RequireNumSlabs(); + ParseMatrix(yaml_conf["desired_slab_percentages"], + "desired_slab_percentages", + reinterpret_cast(desired_slab_percentages), + kMaxDevices, kMaxBufferPoolSlabs, num_slabs); + } + if (yaml_conf["bandwidth_mbps"]) { + RequireNumDevices(); + ParseArray(yaml_conf["bandwidth_mbps"], "bandwidth_mbps", + bandwidths, num_devices); + } + if (yaml_conf["latencies"]) { + RequireNumDevices(); + ParseArray(yaml_conf["latencies"], "latencies", latencies, + num_devices); + } + /*if (yaml_conf["buffer_pool_arena_percentage"]) { + arena_percentages[hermes::kArenaType_BufferPool] = + yaml_conf["buffer_pool_arena_percentage"].as(); + } + if (yaml_conf["metadata_arena_percentage"]) { + arena_percentages[hermes::kArenaType_MetaData] = + yaml_conf["metadata_arena_percentage"].as(); + } + if (yaml_conf["transient_arena_percentage"]) { + arena_percentages[hermes::kArenaType_Transient] = + yaml_conf["transient_arena_percentage"].as(); + }*/ + if (yaml_conf["mount_points"]) { + RequireNumDevices(); + ParseArray(yaml_conf["mount_points"], "mount_points", + mount_points, num_devices); + } + if (yaml_conf["swap_mount"]) { + swap_mount = yaml_conf["swap_mount"].as(); + } + if (yaml_conf["num_buffer_organizer_retries"]) { + num_buffer_organizer_retries = + yaml_conf["num_buffer_organizer_retries"].as(); + } + if (yaml_conf["max_buckets_per_node"]) { + max_buckets_per_node = yaml_conf["max_buckets_per_node"].as(); + } + if (yaml_conf["max_vbuckets_per_node"]) { + max_vbuckets_per_node = + yaml_conf["max_vbuckets_per_node"].as(); + } + if (yaml_conf["system_view_state_update_interval_ms"]) { + system_view_state_update_interval_ms = + yaml_conf["system_view_state_update_interval_ms"].as(); + } + if (yaml_conf["buffer_pool_shmem_name"]) { + std::string name = yaml_conf["buffer_pool_shmem_name"].as(); + std::snprintf(buffer_pool_shmem_name, kMaxBufferPoolShmemNameLength, + "%s", name.c_str()); + } + if (yaml_conf["rpc_protocol"]) { + rpc_protocol = yaml_conf["rpc_protocol"].as(); + } + if (yaml_conf["rpc_domain"]) { + rpc_domain = yaml_conf["rpc_domain"].as(); + } + if (yaml_conf["rpc_port"]) { + rpc_port = yaml_conf["rpc_port"].as(); + } + if (yaml_conf["buffer_organizer_port"]) { + buffer_organizer_port = + yaml_conf["buffer_organizer_port"].as(); + } + if (yaml_conf["rpc_num_threads"]) { + rpc_num_threads = yaml_conf["rpc_num_threads"].as(); + } + if (yaml_conf["default_placement_policy"]) { + std::string policy = + yaml_conf["default_placement_policy"].as(); + + if (policy == "MinimizeIoTime") { + default_placement_policy = api::PlacementPolicy::kMinimizeIoTime; + } else if (policy == "Random") { + default_placement_policy = api::PlacementPolicy::kRandom; + } else if (policy == "RoundRobin") { + default_placement_policy = api::PlacementPolicy::kRoundRobin; + } else { + LOG(FATAL) << "Unknown default_placement_policy: '" << policy << "'" + << std::endl; + } + } + if (yaml_conf["is_shared_device"]) { + RequireNumDevices(); + ParseArray(yaml_conf["is_shared_device"], "is_shared_device", + is_shared_device, num_devices); + } + if (yaml_conf["buffer_organizer_num_threads"]) { + bo_num_threads = + yaml_conf["buffer_organizer_num_threads"].as(); + } + if (yaml_conf["default_rr_split"]) { + default_rr_split = yaml_conf["default_rr_split"].as(); + } + if (yaml_conf["bo_num_threads"]) { + bo_num_threads = yaml_conf["bo_num_threads"].as(); + } + if (yaml_conf["bo_capacity_thresholds"]) { + RequireNumDevices(); + f32 thresholds[kMaxDevices][2] = {0}; + ParseMatrix(yaml_conf["bo_capacity_thresholds"], + "bo_capacity_thresholds", + reinterpret_cast(thresholds), kMaxDevices, 2); + for (int i = 0; i < num_devices; ++i) { + bo_capacity_thresholds[i].min = thresholds[i][0]; + bo_capacity_thresholds[i].max = thresholds[i][1]; + } + } + if (yaml_conf["path_exclusions"]) { + ParseVector(yaml_conf["path_exclusions"], + path_exclusions); + } + if (yaml_conf["path_inclusions"]) { + ParseVector(yaml_conf["path_inclusions"], + path_inclusions); + } + ParseHostNames(yaml_conf); + CheckConstraints(); +} + +/** load configuration from a string */ +void ServerConfig::LoadText(const std::string &config_string) { + YAML::Node yaml_conf = YAML::Load(config_string); + ParseYAML(yaml_conf); +} + +/** load configuration from file */ +void ServerConfig::LoadFromFile(const char *path) { + if (path == nullptr) { + return; + } + LOG(INFO) << "ParseConfig-LoadFile" << std::endl; + YAML::Node yaml_conf = YAML::LoadFile(path); + LOG(INFO) << "ParseConfig-LoadComplete" << std::endl; + ParseYAML(yaml_conf); +} + +/** The default server config */ +ServerConfig::ServerConfig() { + +} + +} // namespace hermes diff --git a/src/config_server_default.h b/src/config_server_default.h new file mode 100644 index 000000000..0902288ce --- /dev/null +++ b/src/config_server_default.h @@ -0,0 +1,140 @@ +#ifndef HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ +#define HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ +const char* kServerDefaultConfigStr = +"# Example Hermes configuration file" +"" +"### Define properties of the storage devices" +"devices:" +" # The name of the device." +" # It can be whatever the user wants, there are no special names" +" ram:" +" # The mount point of each device. RAM should be the empty string. For block" +" # devices, this is the directory where Hermes will create buffering files. For" +" # object storage or cloud targets, this will be a url." +" mount_point: \"\"" +"" +" # The maximum buffering capacity in MiB of each device. Here we say that all 4" +" # devices get 50 MiB of buffering capacity." +" capacity_mb: 50" +"" +" # The size of the smallest available buffer in KiB. In general this should be" +" # the page size of your system for byte addressable storage, and the block size" +" # of the storage device for block addressable storage." +" block_size_kb: 4" +"" +" # The number of blocks (the size of which is chosen in block_sizes_kb) that each" +" # device should contain for each slab (controlled by num_slabs). This allows for" +" # precise control of the distibution of buffer sizes." +" slab_units: [1, 4, 16, 32]" +"" +" # The maximum theoretical bandwidth (as advertised by the manufacturer) in" +" # MiB/sec. of each device." +" bandwidth_mbps: 6000" +"" +" # The latency in microseconds of each device (as advertised by the manufacturer)." +" latencies_us: 15" +"" +" # For each device, indicate \'1\' if it is shared among nodes (e.g., burst" +" # buffers), or \'0\' if it is per node (e.g., local NVMe)." +" is_shared_device: 0" +"" +" nvme:" +" mount_point: \"./\"" +" capacity_mb: 50" +" block_size_kb: 4" +" slab_units: [1, 4, 16, 32]" +" is_shared_device: 0" +"" +" ssd:" +" mount_point: \"./\"" +" capacity_mb: 50" +" block_size_kb: 4" +" slab_units: [ 1, 4, 16, 32 ]" +" is_shared_device: 0" +"" +" pfs:" +" mount_point: \"./\"" +" capacity_mb: inf" +" block_size_kb: 64 # Assume 64KB strip size" +" slab_units: [1, 4, 16, 32]" +"" +"### Define the network communication protocol" +"rpc:" +" # A path to a file containing a list of server names, 1 per line. If your" +" # servers are named according to a pattern (e.g., server-1, server-2, etc.)," +" # prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this" +" # option is not empty, it will override anything in `rpc_server_base_name`." +" host_file: \"\"" +"" +" # Host names are constructed as \"base_name +" +" # host_number + rpc_server_suffix.\" Each entry in the rpc_host_number_range_list" +" # can be either a single number, or a range, which is 2 numbers separated by a" +" # hyphen (-). For example the list {01, 03-05, 07, 08-10} will be expanded to" +" # {01, 03, 04, 05, 07, 08, 09, 10}." +" server_base_name: \"localhost\"" +" server_host_number_range: []" +" server_suffix: \"\"" +"" +" # The RPC protocol. This must come from the documentation of the specific RPC" +" # library in use." +" protocol: \"ofi+sockets\"" +"" +" # RPC domain name for verbs transport. Blank for tcp." +" domain: \"\"" +"" +" # Desired RPC port number." +" port: 8080" +"" +" # Desired RPC port number for buffer organizer." +" buffer_organizer_port: 8081" +"" +" # The number of handler threads for each RPC server." +" num_threads: 1" +"" +"### Define properties of the BORG" +"buffer_organizer:" +" # The number of threads used in the background organization of internal Hermes buffers." +" num_threads: 4" +"" +" # For each device, the minimum and maximum percent capacity threshold at which" +" # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause" +" # the BufferOrganizer to move data to lower devices, making more room in faster" +" # devices (ideal for write-heavy workloads). Conversely, increasing the minimum" +" # threshold will cause data to be moved from slower devices into faster devices" +" # (ideal for read-heavy workloads). For example, a maximum capacity threshold of" +" # 0.8 would have the effect of always keeping 20% of the device\'s space free for" +" # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure" +" # that the device is always at least 30% occupied." +" capacity_thresholds: [" +" [ 0.0, 1.0 ]," +" [ 0.0, 1.0 ]," +" [ 0.0, 1.0 ]," +" [ 0.0, 1.0 ]" +" ]" +"" +"### Define the default data placement policy" +"dpe:" +" # Choose Random, RoundRobin, or MinimizeIoTime" +" default_placement_policy: \"MinimizeIoTime\"" +"" +" # If true (1) the RoundRobin placement policy algorithm will split each Blob" +" # into a random number of smaller Blobs." +" default_rr_split: 0" +"" +"# The shared memory prefix for the hermes shared memory segment. A user name" +"# will be automatically appended." +"shmem_name: \"/hermes_shm_\"" +"# The interval in milliseconds at which to update the global system view." +"system_view_state_update_interval_ms: 1000" +"" +"#Paths which are ignored when buffering data" +"path_exclusions: [" +" \"/bin/\", \"/boot/\", \"/dev/\", \"/etc/\"," +" \"/lib/\", \"/opt/\", \"/proc/\", \"/sbin/\"," +" \"/sys/\", \"/usr/\", \"/var/\", \"/run/\"," +" \"pipe\", \"socket:\", \"anon_inode:\"" +"]" +"#Paths which are never ignored when buffering data" +"path_inclusions: [\"/var/opt/cray/dws/mounts/\"]" +""; +#endif // HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ \ No newline at end of file diff --git a/src/data_placement_engine.cc b/src/data_placement_engine.cc deleted file mode 100644 index 7082fd035..000000000 --- a/src/data_placement_engine.cc +++ /dev/null @@ -1,173 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "data_placement_engine_factory.h" - -#include -#include -#include - -#include -#include -#include - -#include "hermes.h" -#include "hermes_types.h" -#include "metadata_management.h" -#include "metadata_management_internal.h" -#include "metadata_storage.h" - -namespace hermes { - -using hermes::api::Status; - -std::vector DPE::GetValidSplitChoices(size_t blob_size) { - int split_option = 10; - // Split the blob if size is greater than 64KB - if (blob_size > KILOBYTES(64) && blob_size <= KILOBYTES(256)) { - split_option = 2; - } else if (blob_size > KILOBYTES(256) && blob_size <= MEGABYTES(1)) { - split_option = 5; - } else if (blob_size > MEGABYTES(1) && blob_size <= MEGABYTES(4)) { - split_option = 8; - } - - constexpr int split_range[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; - std::vector result(split_range, split_range + split_option - 1); - - return result; -} - -bool DPE::SplitBlob(size_t blob_size) { - bool result = false; - std::random_device dev; - std::mt19937 rng(dev()); - - if (blob_size > KILOBYTES(64)) { - std::uniform_int_distribution distribution(0, 1); - if (distribution(rng) == 1) { - result = true; - } - } - - return result; -} - -void DPE::GetSplitSizes(size_t blob_size, std::vector &output) { - std::random_device dev; - std::mt19937 rng(dev()); - - std::vector split_choice = GetValidSplitChoices(blob_size); - - // Random pickup a number from split_choice to split the blob - std::uniform_int_distribution - position(0, split_choice.size()-1); - int split_num = split_choice[position(rng)]; - - size_t blob_each_portion {blob_size/split_num}; - for (int j {0}; j < split_num - 1; ++j) { - output.push_back(blob_each_portion); - } - output.push_back(blob_size - blob_each_portion*(split_num-1)); -} - -/** aggregate BLOB schema */ -PlacementSchema AggregateBlobSchema(PlacementSchema &schema) { - std::unordered_map place_size; - PlacementSchema result; - - for (auto [size, target] : schema) { - place_size.insert({target.as_int, 0}); - place_size[target.as_int] += size; - } - for (auto [target, size] : place_size) { - TargetID id = {}; - id.as_int = target; - result.push_back(std::make_pair(size, id)); - } - - return result; -} - -/** topology */ -enum Topology { - Topology_Local, - Topology_Neighborhood, - Topology_Global, - - Topology_Count -}; - -/** calculate data placement */ -Status CalculatePlacement(SharedMemoryContext *context, RpcContext *rpc, - const std::vector &blob_sizes, - std::vector &output, - const api::Context &api_context) { - std::vector output_tmp; - Status result; - - // NOTE(chogan): Start with local targets and gradually expand the target - // list until the placement succeeds. - for (int i = 0; i < Topology_Count; ++i) { - std::vector targets; - - switch (i) { - case Topology_Local: { - // TODO(chogan): @optimization We can avoid the copy here when getting - // local targets by just getting a pointer and length. - targets = LocalGetNodeTargets(context); - break; - } - case Topology_Neighborhood: { - targets = GetNeighborhoodTargets(context, rpc); - break; - } - case Topology_Global: { - // TODO(chogan): GetGlobalTargets(context, rpc); - break; - } - } - - if (targets.size() == 0) { - result = DPE_PLACEMENTSCHEMA_EMPTY; - continue; - } - - std::vector node_state = - GetRemainingTargetCapacities(context, rpc, targets); - auto dpe = DPEFactory().Get(api_context.policy); - dpe->bandwidths = GetBandwidths(context, targets); - result = dpe->Placement(blob_sizes, node_state, - targets, api_context, output_tmp); - - if (!result.Failed()) { - break; - } - } - - // Aggregate placement schemas from the same target - if (result.Succeeded()) { - for (auto it = output_tmp.begin(); it != output_tmp.end(); ++it) { - PlacementSchema schema = AggregateBlobSchema((*it)); - if (schema.size() == 0) { - result = DPE_PLACEMENTSCHEMA_EMPTY; - LOG(ERROR) << result.Msg(); - return result; - } - output.push_back(schema); - } - } - - return result; -} - -} // namespace hermes diff --git a/src/data_placement_engine.h b/src/data_placement_engine.h deleted file mode 100644 index 047798e35..000000000 --- a/src/data_placement_engine.h +++ /dev/null @@ -1,69 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_DATA_PLACEMENT_ENGINE_H_ -#define HERMES_DATA_PLACEMENT_ENGINE_H_ - -#include - -#include "hermes.h" -#include "hermes_status.h" -#include "hermes_types.h" - -namespace hermes { - -#define VERIFY_DPE_POLICY(ctx) \ - if (ctx.policy != policy_) { \ - return Status(); \ - } - -using api::Status; -using hermes::api::PlacementPolicy; - -/** - A class to represent data placement engine -*/ -class DPE { - protected: - PlacementPolicy policy_; /**< data placement policy */ - - public: - std::vector bandwidths; /**< a vector of bandwidths */ - /** constructor function */ - explicit DPE(PlacementPolicy policy) : policy_(policy) {} - virtual ~DPE() = default; - /** - set placement schema given BLOB sizes, node states, targets, and context. - */ - virtual Status Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, - const api::Context &ctx, - std::vector &output) = 0; - - protected: - /** get valid choices for splitting BLOB. */ - std::vector GetValidSplitChoices(size_t blob_size); - bool SplitBlob(size_t blob_size); - /** get split sizes for \a blob_size. */ - void GetSplitSizes(size_t blob_size, std::vector &output); -}; - -PlacementSchema AggregateBlobSchema(PlacementSchema &schema); - -Status CalculatePlacement(SharedMemoryContext *context, RpcContext *rpc, - const std::vector &blob_size, - std::vector &output, - const api::Context &api_context); - -} // namespace hermes -#endif // HERMES_DATA_PLACEMENT_ENGINE_H_ diff --git a/src/data_placement_engine_factory.h b/src/data_placement_engine_factory.h deleted file mode 100644 index 21d9b2ca6..000000000 --- a/src/data_placement_engine_factory.h +++ /dev/null @@ -1,60 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_DPE_DATA_PLACEMENT_ENGINE_FACTORY_H_ -#define HERMES_SRC_DPE_DATA_PLACEMENT_ENGINE_FACTORY_H_ - -#include "dpe/minimize_io_time.h" -#include "dpe/random.h" -#include "dpe/round_robin.h" - -namespace hermes { - -using hermes::api::PlacementPolicy; - -/** - A class to represent Data Placement Engine Factory -*/ -class DPEFactory { - public: - /** - * return a pointer to data placement engine given a policy type. - * This uses factory pattern. - * - * @param[in] type a placement policy type to be used by the - * data placement engine factory. - * @return pointer to DataPlacementEngine given \a type PlacementPolicy. - */ - std::unique_ptr Get(const PlacementPolicy &type) { - switch (type) { - case PlacementPolicy::kRandom: { - return std::make_unique(); - } - case PlacementPolicy::kRoundRobin: { - return std::make_unique(); - } - case PlacementPolicy::kMinimizeIoTime: { - return std::make_unique(); - } - case PlacementPolicy::kNone: - default: { - // TODO(luke): @errorhandling not implemented - LOG(FATAL) << "PlacementPolicy not implemented" << std::endl; - return NULL; - } - } - } -}; - -} // namespace hermes - -#endif // HERMES_SRC_DPE_DATA_PLACEMENT_ENGINE_FACTORY_H_ diff --git a/src/dpe/linprog.h b/src/dpe/linprog.h deleted file mode 100644 index bb53bc968..000000000 --- a/src/dpe/linprog.h +++ /dev/null @@ -1,163 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_DPE_LINPROG_H_ -#define HERMES_SRC_DPE_LINPROG_H_ - -#include -#include - -#include -#include - -namespace hermes { - -/** - A structure to represent 2D array index -*/ -struct Array2DIdx { - int nrow_; /**< number of rows */ - int ncol_; /**< number of columns */ - - /** Initialize structure with \a nrow and \a ncol. */ - Array2DIdx(int nrow, int ncol) : nrow_(nrow), ncol_(ncol) {} - - /** Get the index of row \a i and column \a j. */ - int Get(int i, int j) { return i * nrow_ + j; } - - /** Get the beginning index of row \a i. */ - int Begin(int i) { return Get(i, 0); } - - /** Get the last index of row \a i. */ - int End(int i) { return Get(i, ncol_); } -}; - -/** - * GLPK documentation: http://most.ccib.rutgers.edu/glpk.pdf - * */ - -const size_t kDefaultCoeffs = 1000 + 1; - -/** - A structure to represent linear program -*/ -class LinearProgram { - private: - int num_vars_; /**< number of variables */ - int num_constraints_; /**< number of constraints */ - glp_prob *lp_; /**< pointer to GLPK problem solver */ - std::vector ia_; /**< The "i" in A[i][j] */ - std::vector ja_; /**< The "j" in A[i][j] */ - std::vector ar_; /**< values for A[i][j] */ - size_t cur_constraint_; /**< current constraint */ - size_t result_; /**< result of solver */ - - public: - /** Initialize linear program solver with \a name. */ - explicit LinearProgram(const char *name) { - lp_ = glp_create_prob(); - glp_set_prob_name(lp_, name); - cur_constraint_ = 0; - } - - /** Clean up resources used by the GLPK solver. */ - ~LinearProgram() { - glp_delete_prob(lp_); - glp_free_env(); - } - - /** Define the problem size using \a num_vars and \a num_constraints. */ - void DefineDimension(int num_vars, int num_constraints) { - // NOTE(llogan): GLPK requires arrays start from "1" instead of "0" - glp_add_rows(lp_, num_constraints); - glp_add_cols(lp_, num_vars); - ia_.reserve(kDefaultCoeffs); - ia_.emplace_back(0); - ja_.reserve(kDefaultCoeffs); - ja_.emplace_back(0); - ar_.reserve(kDefaultCoeffs); - ar_.emplace_back(0.0); - num_vars_ = num_vars; - num_constraints_ = num_constraints; - } - - /** Add a constraint to the GLPK solver. */ - void AddConstraint(const std::string &base_name, int op_type, double lb, - double ub) { - cur_constraint_ += 1; - std::string name = base_name + std::to_string(cur_constraint_); - glp_set_row_name(lp_, cur_constraint_, name.c_str()); - glp_set_row_bnds(lp_, cur_constraint_, op_type, lb, ub); - } - - /** Set coefficient value as \a val for the \a var variable. */ - void SetConstraintCoeff(int var, double val) { - var += 1; - ia_.emplace_back(cur_constraint_); - ja_.emplace_back(var); - ar_.emplace_back(val); - } - - /** Set the upper and lower bound for \a var variable. */ - void SetVariableBounds(const std::string &base_name, int var, int op_type, - double lb, double ub) { - var += 1; - std::string name = base_name + std::to_string(var); - glp_set_col_name(lp_, var, name.c_str()); - glp_set_col_bnds(lp_, var, op_type, lb, ub); - } - - /** Set the objective function to optimize. */ - void SetObjective(int objective) { glp_set_obj_dir(lp_, objective); } - - /** Set the coefficients of objective function. */ - void SetObjectiveCoeff(int var, double val) { - var += 1; - glp_set_obj_coef(lp_, var, val); - } - - /** Solve the problem. */ - void Solve() { - glp_load_matrix(lp_, ia_.size() - 1, ia_.data(), ja_.data(), ar_.data()); - glp_smcp parm; - glp_init_smcp(&parm); - parm.msg_lev = GLP_MSG_OFF; - glp_simplex(lp_, &parm); - result_ = glp_get_status(lp_); - } - - /** Check if optimal solution exists. */ - bool IsOptimal() { return result_ == GLP_OPT; } - - /** Get solution.*/ - double GetSolution() { return glp_get_obj_val(lp_); } - - /** Get the values for optimal solution.*/ - double GetVariable(int var) { - var += 1; - return glp_get_col_prim(lp_, var); - } - - /** Collect the values as a vector.*/ - std::vector ToVector() { - std::vector v; - v.reserve(num_vars_); - for (int var = 0; var < num_vars_; ++var) { - v.emplace_back(GetVariable(var)); - } - return v; - } -}; - -} // namespace hermes - -#endif // HERMES_SRC_DPE_LINPROG_H_ diff --git a/src/dpe/minimize_io_time.cc b/src/dpe/minimize_io_time.cc deleted file mode 100644 index f88fc0fde..000000000 --- a/src/dpe/minimize_io_time.cc +++ /dev/null @@ -1,179 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "minimize_io_time.h" -#include "linprog.h" -#include -#include -#include - -namespace hermes { - -Status MinimizeIoTime::Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, - const api::Context &ctx, - std::vector &output) { - Status result; - const size_t num_targets = targets.size(); - const size_t num_blobs = blob_sizes.size(); - VERIFY_DPE_POLICY(ctx) - - const double minimum_remaining_capacity = - ctx.minimize_io_time_options.minimum_remaining_capacity; - const double capacity_change_threshold = - ctx.minimize_io_time_options.capacity_change_threshold; - GetPlacementRatios(node_state, ctx); - - size_t constraints_per_target = 2; - VLOG(1) << "MinimizeIoTimePlacement()::minimum_remaining_capacity=" << - minimum_remaining_capacity; - VLOG(1) << "MinimizeIoTimePlacement()::constraints_per_target=" << - constraints_per_target; - const size_t total_constraints = - num_blobs + (num_targets * constraints_per_target); - Array2DIdx var(num_blobs, num_targets); - hermes::LinearProgram lp("min_io"); - lp.DefineDimension(num_blobs * num_targets, total_constraints); - - // Constraint #1: Sum of fraction of each blob is 1. - for (size_t i = 0; i < num_blobs; ++i) { - // Ensure the entire row sums up to 1 - lp.AddConstraint("blob_row_", GLP_FX, 1.0, 1.0); - - // TODO(KIMMY): consider remote nodes? - for (size_t j = 0; j < num_targets; ++j) { - lp.SetConstraintCoeff(var.Get(i, j), 1); - if (placement_ratios_[j] > 0) { - lp.SetVariableBounds("blob_dst_", var.Get(i, j), GLP_DB, 0, - placement_ratios_[j]); - } else { - lp.SetVariableBounds("blob_dst_", var.Get(i, j), GLP_FX, 0, 0); - } - } - } - - // Constraint #2: Capacity constraints - for (size_t j = 0; j < num_targets; ++j) { - double rem_cap_thresh = - static_cast(node_state[j]) * (1 - minimum_remaining_capacity); - double est_rem_cap = capacity_change_threshold * node_state[j]; - double max_capacity = std::max({rem_cap_thresh, est_rem_cap}); - if (max_capacity > 0) { - lp.AddConstraint("rem_cap_", GLP_DB, 0.0, max_capacity); - } else { - lp.AddConstraint("rem_gap_", GLP_FX, 0.0, 0.0); - } - for (size_t i = 0; i < num_blobs; ++i) { - lp.SetConstraintCoeff(var.Get(i, j), - static_cast(blob_sizes[i])); - } - } - - // Objective to minimize IO time - lp.SetObjective(GLP_MIN); - for (size_t i = 0; i < num_blobs; ++i) { - for (size_t j = 0; j < num_targets; ++j) { - lp.SetObjectiveCoeff(var.Get(i, j), - static_cast(blob_sizes[i])/bandwidths[j]); - } - } - - // Solve the problem - lp.Solve(); - if (!lp.IsOptimal()) { - result = DPE_ORTOOLS_NO_SOLUTION; - LOG(ERROR) << result.Msg(); - return result; - } - std::vector vars = lp.ToVector(); - - // Create the placement schema - for (size_t i = 0; i < num_blobs; ++i) { - PlacementSchema schema; - int row_start = var.Begin(i); - int row_end = var.End(i); - - // Convert solution from blob fractions to bytes - std::transform(vars.begin() + row_start, - vars.begin() + row_end, - vars.begin() + row_start, - std::bind(std::multiplies(), - std::placeholders::_1, blob_sizes[i])); - std::vector vars_bytes(vars.begin(), vars.end()); - - // Account for rounding errors - size_t est_io_size_u = std::accumulate(vars_bytes.begin(), - vars_bytes.end(), - 0ul); - ssize_t est_io_size = static_cast(est_io_size_u); - ssize_t true_io_size = static_cast(blob_sizes[i]); - ssize_t io_diff = true_io_size - est_io_size; - PlaceBytes(0, io_diff, vars_bytes, node_state); - - // Push all non-zero schemas to target - for (size_t j = 0; j < num_targets; ++j) { - size_t io_to_target = vars_bytes[j]; - if (io_to_target != 0) { - schema.push_back(std::make_pair(io_to_target, targets[j])); - } - } - output.push_back(schema); - } - return result; -} - -void MinimizeIoTime::PlaceBytes(size_t j, ssize_t bytes, - std::vector &vars_bytes, - const std::vector &node_state) { - if (vars_bytes[j] == 0) { - PlaceBytes(j+1, bytes, vars_bytes, node_state); - return; - } - ssize_t node_cap = static_cast(node_state[j]); - ssize_t req_bytes = static_cast(vars_bytes[j]); - req_bytes += bytes; - ssize_t io_diff = req_bytes - node_cap; - if (io_diff <= 0) { - vars_bytes[j] = static_cast(req_bytes); - return; - } - if (j == node_state.size() - 1) { - LOG(FATAL) << "No capacity left to buffer blob" << std::endl; - return; - } - req_bytes -= io_diff; - vars_bytes[j] = static_cast(req_bytes); - PlaceBytes(j+1, io_diff, vars_bytes, node_state); -} - -void MinimizeIoTime::GetPlacementRatios(const std::vector &node_state, - const api::Context &ctx) { - placement_ratios_.reserve(node_state.size()); - if (ctx.minimize_io_time_options.use_placement_ratio) { - size_t total_bytes = std::accumulate( - node_state.begin(), node_state.end(), (size_t)0); - double total = static_cast(total_bytes); - for (size_t j = 0; j < node_state.size() - 1; ++j) { - double target_cap = static_cast(node_state[j]); - double placement_ratio = target_cap / total; - placement_ratios_.emplace_back(placement_ratio); - } - placement_ratios_.emplace_back(1.0); - } else { - for (size_t j = 0; j < node_state.size(); ++j) { - placement_ratios_.emplace_back(1.0); - } - } -} - -} // namespace hermes diff --git a/src/dpe/minimize_io_time.h b/src/dpe/minimize_io_time.h deleted file mode 100644 index fcec7403c..000000000 --- a/src/dpe/minimize_io_time.h +++ /dev/null @@ -1,48 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_DPE_MINIMIZE_IO_TIME_H_ -#define HERMES_SRC_DPE_MINIMIZE_IO_TIME_H_ - -#include "data_placement_engine.h" - -namespace hermes { -/** - A class to represent data placement engine that minimizes I/O time. -*/ -class MinimizeIoTime : public DPE { - private: - std::vector placement_ratios_; /**< a vector of placement ratios */ - - public: - MinimizeIoTime() : DPE(PlacementPolicy::kMinimizeIoTime) {} - ~MinimizeIoTime() = default; - Status Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, - const api::Context &ctx, - std::vector &output); - - private: - /** get the absolute difference value from \a x size and \a y size */ - size_t AbsDiff(size_t x, size_t y, bool &y_gt_x); - /** place bytes */ - void PlaceBytes(size_t j, ssize_t bytes, std::vector &vars_bytes, - const std::vector &node_state); - /** get placement ratios from node states in \a ctx context */ - void GetPlacementRatios(const std::vector &node_state, - const api::Context &ctx); -}; - -} // namespace hermes - -#endif // HERMES_SRC_DPE_MINIMIZE_IO_TIME_H_ diff --git a/src/dpe/random.cc b/src/dpe/random.cc deleted file mode 100644 index 528f416a3..000000000 --- a/src/dpe/random.cc +++ /dev/null @@ -1,95 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "random.h" - -#include -#include -#include - -namespace hermes { - -Status Random::AddSchema(std::multimap &ordered_cap, - size_t blob_size, PlacementSchema &schema) { - std::random_device rd; - std::mt19937 gen(rd()); - Status result; - - auto itlow = ordered_cap.lower_bound(blob_size); - if (itlow == ordered_cap.end()) { - result = DPE_RANDOM_FOUND_NO_TGT; - LOG(ERROR) << result.Msg(); - } else { - // distance from lower bound to the end - std::uniform_int_distribution<> - dst_dist(1, std::distance(itlow, ordered_cap.end())); - size_t dst_relative = dst_dist(gen); - std::advance(itlow, dst_relative-1); - ordered_cap.insert(std::pair((*itlow).first-blob_size, - (*itlow).second)); - - schema.push_back(std::make_pair(blob_size, (*itlow).second)); - ordered_cap.erase(itlow); - } - - return result; -} - -void Random::GetOrderedCapacities(const std::vector &node_state, - const std::vector &targets, - std::multimap &ordered_cap) { - for (size_t i = 0; i < node_state.size(); ++i) { - ordered_cap.insert(std::pair(node_state[i], targets[i])); - } -} - -Status Random::Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, - const api::Context &ctx, - std::vector &output) { - Status result; - std::multimap ordered_cap; - VERIFY_DPE_POLICY(ctx) - - GetOrderedCapacities(node_state, targets, ordered_cap); - - for (size_t i {0}; i < blob_sizes.size(); ++i) { - PlacementSchema schema; - - // Split the blob - if (SplitBlob(blob_sizes[i])) { - // Construct the vector for the splitted blob - std::vector new_blob_size; - GetSplitSizes(blob_sizes[i], new_blob_size); - - for (size_t k {0}; k < new_blob_size.size(); ++k) { - result = AddSchema(ordered_cap, new_blob_size[k], schema); - - if (!result.Succeeded()) { - break; - } - } - } else { - // Blob size is less than 64KB or do not split - result = AddSchema(ordered_cap, blob_sizes[i], schema); - if (!result.Succeeded()) { - return result; - } - } - output.push_back(schema); - } - - return result; -} - -} // namespace hermes diff --git a/src/dpe/random.h b/src/dpe/random.h deleted file mode 100644 index 383b656d3..000000000 --- a/src/dpe/random.h +++ /dev/null @@ -1,46 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_DPE_RANDOM_H_ -#define HERMES_SRC_DPE_RANDOM_H_ - -#include "data_placement_engine.h" - -namespace hermes { -/** - A class to represent data placement engine that places data randomly. -*/ -class Random : public DPE { - public: - Random() : DPE(PlacementPolicy::kRandom) {} - ~Random() = default; - Status Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, - const api::Context &ctx, - std::vector &output); - - private: - /** - get the capacities of each \a node_state and \a targets and store them - into \a ordered_cap.*/ - void GetOrderedCapacities(const std::vector &node_state, - const std::vector &targets, - std::multimap &ordered_cap); - /** add placement schema */ - Status AddSchema(std::multimap &ordered_cap, size_t blob_size, - PlacementSchema &schema); -}; - -} // namespace hermes - -#endif // HERMES_SRC_DPE_RANDOM_H_ diff --git a/src/dpe/round_robin.cc b/src/dpe/round_robin.cc deleted file mode 100644 index 7f55a4436..000000000 --- a/src/dpe/round_robin.cc +++ /dev/null @@ -1,142 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "round_robin.h" -#include - -#include "metadata_management.h" -#include "metadata_management_internal.h" -#include "metadata_storage.h" - -namespace hermes { - -using hermes::api::Status; - -// Initialize RoundRobin devices -std::vector RoundRobin::devices_; - -void RoundRobin::InitDevices(hermes::Config *config, - std::shared_ptr result) { - devices_.reserve(config->num_devices); - for (DeviceID id = 0; id < config->num_devices; ++id) { - if (GetNumBuffersAvailable(&result->context_, id)) { - devices_.push_back(id); - } - } -} - -void RoundRobin::InitDevices(int count, int start_val) { - devices_ = std::vector(count); - std::iota(devices_.begin(), - devices_.end(), start_val); -} - -size_t RoundRobin::GetNumDevices() const { - return devices_.size(); -} - -DeviceID RoundRobin::GetDeviceByIndex(int i) const { - return devices_[i]; -} - -int RoundRobin::GetCurrentDeviceIndex() const { - return current_device_index_; -} - -void RoundRobin::SetCurrentDeviceIndex(int new_device_index) { - current_device_index_ = new_device_index; -} - -Status RoundRobin::AddSchema(size_t index, std::vector &node_state, - const std::vector &blob_sizes, - const std::vector &targets, - PlacementSchema &output) { - Status result; - TargetID dst = {}; - size_t num_targets = targets.size(); - int current_device_index {GetCurrentDeviceIndex()}; - size_t num_devices = GetNumDevices(); - - // NOTE(chogan): Starting with current_device, loop through all devices until - // we either 1) find a matching Target or 2) end up back at the starting - // device. - for (size_t i = 0; i < num_devices; ++i) { - int next_index = (current_device_index + i) % num_devices; - DeviceID dev_id = GetDeviceByIndex(next_index); - - for (size_t j = 0; j < num_targets; ++j) { - if (node_state[j] >= blob_sizes[index]) { - if (targets[j].bits.device_id == dev_id) { - dst = targets[j]; - output.push_back(std::make_pair(blob_sizes[index], dst)); - node_state[j] -= blob_sizes[index]; - SetCurrentDeviceIndex((next_index + 1) % num_devices); - break; - } - } - } - - if (!IsNullTargetId(dst)) { - break; - } - } - - if (IsNullTargetId(dst)) { - result = DPE_RR_FIND_TGT_FAILED; - LOG(ERROR) << result.Msg(); - } - - return result; -} - -Status RoundRobin::Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, - const api::Context &ctx, - std::vector &output) { - Status result; - std::vector ns_local(node_state.begin(), node_state.end()); - bool split = ctx.rr_split; - VERIFY_DPE_POLICY(ctx) - - if (ctx.policy != hermes::api::PlacementPolicy::kRoundRobin) { - return result; - } - for (size_t i {0}; i < blob_sizes.size(); ++i) { - PlacementSchema schema; - - if (split) { - // Construct the vector for the splitted blob - std::vector new_blob_size; - GetSplitSizes(blob_sizes[i], new_blob_size); - - for (size_t k {0}; k < new_blob_size.size(); ++k) { - result = AddSchema(k, ns_local, new_blob_size, targets, - schema); - if (!result.Succeeded()) { - break; - } - } - } else { - result = AddSchema(i, ns_local, blob_sizes, targets, schema); - if (!result.Succeeded()) { - return result; - } - } - output.push_back(schema); - } - - return result; -} - - -} // namespace hermes diff --git a/src/dpe/round_robin.h b/src/dpe/round_robin.h deleted file mode 100644 index 4814ea509..000000000 --- a/src/dpe/round_robin.h +++ /dev/null @@ -1,73 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_DPE_ROUND_ROBIN_H_ -#define HERMES_SRC_DPE_ROUND_ROBIN_H_ - -#include - -#include "data_placement_engine.h" - -namespace hermes { - -using api::Status; - -/** Represents the state of a Round-Robin data placement strategy */ -class RoundRobin : public DPE { - private: - static inline int current_device_index_{}; /**< The current device index */ - static std::vector devices_; /**< A list of device targets */ - std::mutex device_index_mutex_; /**< Protect index updates */ - - public: - RoundRobin() : DPE(PlacementPolicy::kRoundRobin) { - device_index_mutex_.lock(); - } - ~RoundRobin() { device_index_mutex_.unlock(); } - - Status Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, - const api::Context &ctx, - std::vector &output); - - /** Retrieves the number of devices */ - size_t GetNumDevices() const; - - /** Retrieves the current device index */ - int GetCurrentDeviceIndex() const; - - /** Retrieves the device ID at a given index */ - DeviceID GetDeviceByIndex(int i) const; - - /** Re-/Sets the current device index */ - void SetCurrentDeviceIndex(int new_device_index); - - /** Initialize the static variable for devices*/ - static void InitDevices(hermes::Config *config, - std::shared_ptr result); - /** Initialize \a count devices with \a start_val value */ - static void InitDevices(int count, int start_val = 0); - - private: - /** - add placement schema to \a output - */ - Status AddSchema(size_t index, std::vector &node_state, - const std::vector &blob_sizes, - const std::vector &targets, - PlacementSchema &output); -}; - -} // namespace hermes - -#endif // HERMES_SRC_DPE_ROUND_ROBIN_H_ diff --git a/adapter/test/hermes_daemon.cc b/src/hermes_daemon.cc similarity index 80% rename from adapter/test/hermes_daemon.cc rename to src/hermes_daemon.cc index 965f095bd..2eb4d6ff3 100644 --- a/adapter/test/hermes_daemon.cc +++ b/src/hermes_daemon.cc @@ -16,8 +16,6 @@ #include #include -#include "hermes.h" - /** * kHermesConf env variable is used to define path to kHermesConf in adapters. * This is used for initialization of Hermes. @@ -26,17 +24,9 @@ const char* kHermesConf = "HERMES_CONF"; int main(int argc, char* argv[]) { MPI_Init(&argc, &argv); - char* hermes_config = nullptr; - if (argc > 1) { - std::string option(argv[1]); - if (option == "-v") { - LOG(INFO) << "Hermes version: " << hermes::api::GetVersion() << "\n"; - return 0; - } else { - hermes_config = argv[1]; - } - } else { - hermes_config = getenv(kHermesConf); + std::string hermes_config = ""; + if (argc == 2) { + hermes_config = argv[1]; } auto hermes = hermes::InitHermesDaemon(hermes_config); diff --git a/src/hermes_types.h b/src/hermes_types.h index 4c13f8297..14ba1227e 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -28,9 +28,17 @@ * Types used in Hermes. */ +#ifndef KILOBYTES #define KILOBYTES(n) (((size_t)n) * 1024) /**< KB */ +#endif + +#ifndef MEGABYTES #define MEGABYTES(n) (((size_t)n) * 1024 * 1024) /**< MB */ +#endif + +#ifndef GIGABYTES #define GIGABYTES(n) (((size_t)n) * 1024UL * 1024UL * 1024UL) /**< GB */ +#endif /** * \namespace hermes @@ -50,15 +58,6 @@ typedef double f64; /**< 64-bit float */ typedef u16 DeviceID; /**< device id in unsigned 16-bit integer */ -/** - A structure to represent chunked ID list - */ -struct ChunkedIdList { - u32 head_offset; /**< offset of head in the list */ - u32 length; /**< length of list */ - u32 capacity; /**< capacity of list */ -}; - union BucketID { /** The Bucket ID as bitfield */ struct { @@ -72,7 +71,7 @@ union BucketID { /** The BucketID as a unsigned 64-bit integer */ u64 as_int; - bool IsNull() { return as_int == 0; } + bool IsNull() const { return as_int == 0; } }; // NOTE(chogan): We reserve sizeof(BucketID) * 2 bytes in order to embed the @@ -97,7 +96,7 @@ union VBucketID { /** The VBucketID as a unsigned 64-bit integer */ u64 as_int; - bool IsNull() { return as_int == 0; } + bool IsNull() const { return as_int == 0; } }; union BlobID { @@ -114,9 +113,9 @@ union BlobID { /** The BlobID as an unsigned 64-bit integer */ u64 as_int; - bool IsNull() { return as_int == 0; } - bool InSwap() { return bits.node_id < 0; } - i32 GetNodeId() { return bits.node_id; } + bool IsNull() const { return as_int == 0; } + bool InSwap() const { return bits.node_id < 0; } + i32 GetNodeId() const { return bits.node_id; } }; /** @@ -293,14 +292,9 @@ union TargetID { /** The TargetID as a unsigned 64-bit integer */ u64 as_int; - bool IsNull() { return as_int == 0; } + bool IsNull() const { return as_int == 0; } }; -/** - A constant for swap target IDs - */ -const TargetID kSwapTargetId = {{0, 0, 0}}; - /** * A PlacementSchema is a vector of (size, target) pairs where size is the * number of bytes to buffer and target is the TargetID where to buffer those @@ -319,13 +313,6 @@ enum class ProcessKind { kCount /**< Sentinel value */ }; -/** Arena types */ -enum ArenaType { - kArenaType_BufferPool, /**< Buffer pool: This must always be first! */ - kArenaType_MetaData, /**< Metadata */ - kArenaType_Transient, /**< Scratch space */ - kArenaType_Count /**< Sentinel value */ -}; /** * A structure to represent thesholds with mimimum and maximum values @@ -335,106 +322,6 @@ struct Thresholds { float max; /**< maximum threshold value */ }; -/** - * System and user configuration that is used to initialize Hermes. - */ -struct Config { - /** The total capacity of each buffering Device */ - size_t capacities[kMaxDevices]; - /** The block sizes of each Device */ - int block_sizes[kMaxDevices]; - /** The number of slabs that each Device has */ - int num_slabs[kMaxDevices]; - /** The unit of each slab, a multiple of the Device's block size */ - int slab_unit_sizes[kMaxDevices][kMaxBufferPoolSlabs]; - /** The percentage of space each slab should occupy per Device. The values - * for each Device should add up to 1.0. - */ - f32 desired_slab_percentages[kMaxDevices][kMaxBufferPoolSlabs]; - /** The bandwidth of each Device */ - f32 bandwidths[kMaxDevices]; - /** The latency of each Device */ - f32 latencies[kMaxDevices]; - /** The percentages of the total available Hermes memory allotted for each - * `ArenaType` - */ - f32 arena_percentages[kArenaType_Count]; - /** The number of Devices */ - int num_devices; - /** The number of Targets */ - int num_targets; - - /** The maximum number of buckets per node */ - u32 max_buckets_per_node; - /** The maximum number of vbuckets per node */ - u32 max_vbuckets_per_node; - /** The length of a view state epoch */ - u32 system_view_state_update_interval_ms; - - /** The mount point or desired directory for each Device. RAM Device should - * be the empty string. - */ - std::string mount_points[kMaxDevices]; - /** The mount point of the swap target. */ - std::string swap_mount; - /** The number of times the BufferOrganizer will attempt to place a swap - * blob into the hierarchy before giving up. */ - int num_buffer_organizer_retries; - - /** If non-zero, the device is shared among all nodes (e.g., burst buffs) */ - int is_shared_device[kMaxDevices]; - - /** The name of a file that contains host names, 1 per line */ - std::string rpc_server_host_file; - /** The hostname of the RPC server, minus any numbers that Hermes may - * auto-generate when the rpc_hostNumber_range is specified. */ - std::string rpc_server_base_name; - /** The list of numbers from all server names. E.g., '{1, 3}' if your servers - * are named ares-comp-1 and ares-comp-3 */ - std::vector host_numbers; - /** The RPC server name suffix. This is appended to the base name plus host - number. */ - std::string rpc_server_suffix; - /** The parsed hostnames from the hermes conf */ - std::vector host_names; - /** The RPC protocol to be used. */ - std::string rpc_protocol; - /** The RPC domain name for verbs transport. */ - std::string rpc_domain; - /** The RPC port number. */ - int rpc_port; - /** The RPC port number for the buffer organizer. */ - int buffer_organizer_port; - /** The number of handler threads per RPC server. */ - int rpc_num_threads; - /** The number of buffer organizer threads. */ - int bo_num_threads; - /** The default blob placement policy. */ - api::PlacementPolicy default_placement_policy; - /** Whether blob splitting is enabled for Round-Robin blob placement. */ - bool default_rr_split; - /** The min and max capacity threshold in MiB for each device at which the - * BufferOrganizer will trigger. */ - Thresholds bo_capacity_thresholds[kMaxDevices]; - /** A base name for the BufferPool shared memory segement. Hermes appends the - * value of the USER environment variable to this string. - */ - char buffer_pool_shmem_name[kMaxBufferPoolShmemNameLength]; - - /** - * Paths prefixed with the following directories are not tracked in Hermes - * Exclusion list used by darshan at - * darshan/darshan-runtime/lib/darshan-core.c - */ - std::vector path_exclusions; - - /** - * Paths prefixed with the following directories are tracked by Hermes even if - * they share a root with a path listed in path_exclusions - */ - std::vector path_inclusions; -}; - /** Trait ID type */ typedef u64 TraitID; diff --git a/src/metadata_management.cc b/src/metadata_management.cc deleted file mode 100644 index ceb2b6780..000000000 --- a/src/metadata_management.cc +++ /dev/null @@ -1,1502 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "metadata_management.h" - -#include - -#include -#include - -#include "buffer_pool.h" -#include "buffer_pool_internal.h" -#include "buffer_organizer.h" -#include "rpc.h" -#include "metadata_storage.h" - -namespace hermes { - -/** "not equal" comparision operator */ -bool operator!=(const TargetID &lhs, const TargetID &rhs) { - return lhs.as_int != rhs.as_int; -} - -/** is \a name too long for \a max? */ -static bool IsNameTooLong(const std::string &name, size_t max) { - bool result = false; - if (name.size() + 1 >= max) { - LOG(WARNING) << "Name '" << name << "' exceeds the maximum name size of " - << max << " bytes." << std::endl; - result = true; - } - - return result; -} - -/** is BLOB's \a name too long for kMaxBlobNameSize? */ -bool MetadataManager::IsBlobNameTooLong(const std::string &name) { - bool result = IsNameTooLong(name, kMaxBlobNameSize); - - return result; -} - -/** is Bucket's \a name too long for kMaxBucketNameSize? */ -bool MetadataManager::IsBucketNameTooLong(const std::string &name) { - bool result = IsNameTooLong(name, kMaxBucketNameSize); - - return result; -} - -/** is vBucket's \a name too long for kMaxVBucketNameSize? */ -bool MetadataManager::IsVBucketNameTooLong(const std::string &name) { - bool result = IsNameTooLong(name, kMaxVBucketNameSize); - return result; -} - -/** get hash string for metadata storage */ -u32 MetadataManager::HashString(const char *str) { - u32 result = HashStringForStorage(str); - - return result; -} - -/** get bucket id */ -BucketID MetadataManager::GetBucketId(const char *name) { - u32 target_node = HashString(name); - if (target_node == rpc_->node_id_) { - LocalGetBucketId(name); - } else { - // TODO(llogan): Add RemoteGetBucketId - return rpc_->Call(target_node, - "RemoteGetBucketId", - std::string(name)); - } -} - -/** get local bucket id */ -BucketID MetadataManager::LocalGetBucketId(const char *name) { - return bucket_id_map_[name]; -} - -/** get virtual bucket id */ -VBucketID MetadataManager::GetVBucketId(const char *name) { - u32 target_node = HashString(name); - if (target_node == rpc_->node_id_) { - return LocalGetVBucketId(name); - } else { - // TODO(llogan): Add RemoteGetVBucketId - return rpc_->Call(target_node, - "RemoteGetVBucketId", - std::string(name)); - } -} - -/** get local virtual bucket id */ -VBucketID MetadataManager::LocalGetVBucketId(const char *name) { - return vbucket_id_map_[name]; -} - -/** make an internal BLOB name */ -std::string MetadataManager::MakeInternalBlobName(const std::string &name, - BucketID id) { - std::stringstream ss; - - // NOTE(chogan): Store the bytes of \p id at the beginning of the name. We - // can't just stick the raw bytes in there because the Blob name will - // eventually be treated as a C string, which means a null byte will be - // treated as a null terminator. Instead, we store the string representation - // of each byte in hex, which means we need two bytes to represent one byte. - for (int i = sizeof(BucketID) - 1; i >= 0 ; --i) { - // TODO(chogan): @portability Need to perform this loop in reverse on a - // big-endian platform - u8 *byte = ((u8 *)&id.as_int) + i; - ss << std::hex << std::setw(2) << std::setfill('0') << (int)(*byte); - } - ss << name; - - std::string result = ss.str(); - - return result; -} - -/** get BLOB id */ -BlobID MetadataManager::GetBlobId(const std::string &name, - BucketID bucket_id, - bool track_stats) { - std::string internal_name = MakeInternalBlobName(name, bucket_id); - BlobID result; - u32 target_node = HashString(name.c_str()); - if (target_node == rpc_->node_id_) { - result = LocalGetBlobId(name); - } else { - // TODO(llogan): Add RemoteGetBlobId - result = rpc_->Call(target_node, - "RemoteGetBlobId", - std::string(name)); - } - if (!result.IsNull() && track_stats) { - IncrementBlobStats(result); - } - return result; -} - -/** get local BLOB id */ -BlobID MetadataManager::LocalGetBlobId(const std::string &name) { - return blob_id_map_[name]; -} - -/** put bucket id */ -void MetadataManager::PutBucketId(const std::string &name, BucketID id) { - PutId(rpc, name, id.as_int, kMapType_Bucket); -} - -/** put bucket id locally */ -void MetadataManager::LocalPutBucketId(const std::string &name, BucketID id) { - LocalPut(name.c_str(), id.as_int, kMapType_Bucket); -} - -/** put virtual bucket id */ -void MetadataManager::PutVBucketId(const std::string &name, VBucketID id) { - PutId(rpc, name, id.as_int, kMapType_VBucket); -} - -/** put virtual bucket id locally */ -void MetadataManager::LocalPutVBucketId(const std::string &name, VBucketID id) { - LocalPut(name.c_str(), id.as_int, kMapType_VBucket); -} - -/** put BLOB id */ -void MetadataManager::PutBlobId(const std::string &name, - BlobID id, BucketID bucket_id) { - std::string internal_name = MakeInternalBlobName(name, bucket_id); - PutId(rpc, internal_name, id.as_int, kMapType_BlobId); -} - -/** delete id */ -void MetadataManager::DeleteId(const std::string &name, - MapType map_type) { - u32 target_node = HashString(rpc, name.c_str()); - - if (target_node == rpc_->node_id_) { - LocalDelete(name.c_str(), map_type); - } else { - RpcCall(rpc, target_node, "RemoteDelete", name, map_type); - } -} - -/** delete bucket id */ -void MetadataManager::DeleteBucketId(const std::string &name) { - DeleteId(rpc, name, kMapType_Bucket); -} - -/** delete virtual bucket id */ -void MetadataManager::DeleteVBucketId(const std::string &name) { - DeleteId(rpc, name, kMapType_VBucket); -} - -/** delete BLOB information locally */ -void MetadataManager::LocalDeleteBlobInfo(BlobID blob_id) { - LocalDelete(blob_id); -} - -/** delete BLOB id locally */ -void MetadataManager::LocalDeleteBlobId(const std::string &name, - BucketID bucket_id) { - std::string internal_name = MakeInternalBlobName(name, bucket_id); - LocalDelete(internal_name.c_str(), kMapType_BlobId); -} - -/** delete BLOB id */ -void MetadataManager::DeleteBlobId(const std::string &name, - BucketID bucket_id) { - std::string internal_name = MakeInternalBlobName(name, bucket_id); - DeleteId(rpc, internal_name, kMapType_BlobId); -} - -/** get bucket information by \a index index locally */ -BucketInfo* MetadataManager::LocalGetBucketInfoByIndex(u32 index) { - BucketInfo *info_array = (BucketInfo *)((u8 *)mdm + bucket_info_offset); - BucketInfo *result = info_array + index; - - return result; -} - -/** get BLOB name from \a blob_id locally */ -std::string MetadataManager::LocalGetBlobNameFromId(BlobID blob_id) { - mdm = GetMetadataManagerFromContext(context); - std::string blob_name = ReverseGetFromStorage(blob_id.as_int, - kMapType_BlobId); - - std::string result; - if (blob_name.size() > kBucketIdStringSize) { - result = blob_name.substr(kBucketIdStringSize, std::string::npos); - } - - return result; -} - -/** get BLOB name from \a blob_id */ -std::string MetadataManager::GetBlobNameFromId(BlobID blob_id) { - u32 target_node = blob_id.GetNodeId(); - std::string result; - if (target_node == rpc_->node_id_) { - result = LocalGetBlobNameFromId(context, blob_id); - } else { - result = RpcCall(rpc, target_node, "RemoteGetBlobNameFromId", - blob_id); - } - - return result; -} - -/** \note (chogan): Lookup table for HexStringToU64() */ -static const u64 hextable[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, - 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0 -}; - -u64 MetadataManager::HexStringToU64(const std::string &s) { - u64 result = 0; - for (size_t i = 0; i < kBucketIdStringSize; ++i) { - result = (result << 4) | hextable[(int)s[i]]; - } - - return result; -} - -/** get bucket ID from \a blob_id locally */ -BucketID MetadataManager::LocalGetBucketIdFromBlobId(BlobID id) { - mdm = GetMetadataManagerFromContext(context); - std::string internal_name = ReverseGetFromStorage(id.as_int, - kMapType_BlobId); - BucketID result = {}; - if (internal_name.size() > kBucketIdStringSize) { - result.as_int = HexStringToU64(internal_name); - } - - return result; -} - -/** get bucket ID from \a blob_id */ -BucketID MetadataManager::GetBucketIdFromBlobId(BlobID id) { - BucketID result = {}; - u32 target_node = GetBlobNodeId(id); - if (target_node == rpc_->node_id_) { - result = LocalGetBucketIdFromBlobId(context, id); - } else { - result = RpcCall(rpc, target_node, "RemoteGetBucketIdFromBlobId", - id); - } - - return result; -} - -/** get bucket information from \a bucket_id */ -BucketInfo* MetadataManager::LocalGetBucketInfoById(BucketID id) { - BucketInfo *result = LocalGetBucketInfoByIndex(id.bits.index); - - return result; -} - -/** get BLOB IDs from \a bucket_id */ -std::vector MetadataManager::GetBlobIds(BucketID bucket_id) { - std::vector result; - u32 target_node = bucket_id.bits.node_id; - if (target_node == rpc_->node_id_) { - result = LocalGetBlobIds(context, bucket_id); - } else { - result = RpcCall>(rpc, target_node, "RemoteGetBlobIds", - bucket_id); - } - - return result; -} - -/** get virtual bucket information by \a index */ -VBucketInfo* MetadataManager::GetVBucketInfoByIndex(u32 index) { - VBucketInfo *info_array = - (VBucketInfo *)((u8 *)mdm + vbucket_info_offset); - VBucketInfo *result = info_array + index; - - return result; -} - -/** - * Returns an available BucketID and marks it as in use in the MDM. - * - * Assumes bucket_mutex is already held by the caller. - */ -BucketID MetadataManager::LocalGetNextFreeBucketId(const std::string &name) { - mdm = GetMetadataManagerFromContext(context); - BucketID result = {}; - - if (num_buckets < max_buckets) { - result = first_free_bucket; - - if (!IsNullBucketId(result)) { - BucketInfo *info = LocalGetBucketInfoByIndex(result.bits.index); - info->blobs = {}; - info->ref_count.store(1); - info->active = true; - first_free_bucket = info->next_free; - num_buckets++; - } - } else { - LOG(ERROR) << "Exceeded max allowed buckets. " - << "Increase max_buckets_per_node in the Hermes configuration." - << std::endl; - } - - if (!IsNullBucketId(result)) { - // NOTE(chogan): Add metadata entry - LocalPutBucketId(name, result); - } - - return result; -} - -/** get or create a bucket ID locally */ -BucketID MetadataManager::LocalGetOrCreateBucketId(const std::string &name) { - mdm = GetMetadataManagerFromContext(context); - bucket_mutex.Lock();; - BucketID result = LocalGetBucketId(context, name.c_str()); - - if (result.as_int != 0) { - LOG(INFO) << "Opening Bucket '" << name << "'" << std::endl; - LocalIncrementRefcount(context, result); - } else { - LOG(INFO) << "Creating Bucket '" << name << "'" << std::endl; - result = LocalGetNextFreeBucketId(context, name); - } - bucket_mutex.Unlock(); - - return result; -} - -/** get or create a bucket ID */ -BucketID MetadataManager::GetOrCreateBucketId(const std::string &name) { - mdm = GetMetadataManagerFromContext(context); - u32 target_node = HashString(rpc, name.c_str()); - BucketID result = {}; - if (target_node == rpc_->node_id_) { - result = LocalGetOrCreateBucketId(context, name); - } else { - result = RpcCall(rpc, target_node, "RemoteGetOrCreateBucketId", - name); - } - - return result; -} - -/** - * Returns an available VBucketID and marks it as in use in the MDM. - * - * Assumes MetadataManager::vbucket_mutex is already held by the caller. - */ -VBucketID MetadataManager::LocalGetNextFreeVBucketId(const std::string &name) { - mdm = GetMetadataManagerFromContext(context); - VBucketID result = {}; - - // TODO(chogan): Could replace this with lock-free version if/when it matters - - if (num_vbuckets < max_vbuckets) { - result = first_free_vbucket; - if (!IsNullVBucketId(result)) { - VBucketInfo *info = GetVBucketInfoByIndex(result.bits.index); - info->blobs = {}; - memset(info->traits, 0, sizeof(TraitID) * kMaxTraitsPerVBucket); - info->ref_count.store(1); - info->active = true; - first_free_vbucket = info->next_free; - num_vbuckets++; - } - } else { - LOG(ERROR) << "Exceeded max allowed vbuckets. " - << "Increase max_vbuckets_per_node in the Hermes configuration." - << std::endl; - } - if (!IsNullVBucketId(result)) { - LocalPutVBucketId(name, result); - } - - return result; -} - -/** get or create a virtual bucket ID locally */ -VBucketID MetadataManager::LocalGetOrCreateVBucketId(const std::string &name) { - mdm = GetMetadataManagerFromContext(context); - - vbucket_mutex.Lock(); - VBucketID result = LocalGetVBucketId(context, name.c_str()); - - if (result.as_int != 0) { - LOG(INFO) << "Opening VBucket '" << name << "'" << std::endl; - LocalIncrementRefcount(context, result); - } else { - LOG(INFO) << "Creating VBucket '" << name << "'" << std::endl; - result = LocalGetNextFreeVBucketId(context, name); - } - vbucket_mutex.Unlock(); - - return result; -} - -/** get or create a virtual bucket ID */ -VBucketID MetadataManager::GetOrCreateVBucketId(const std::string &name) { - VBucketID result = {}; - mdm = GetMetadataManagerFromContext(context); - u32 target_node = HashString(rpc, name.c_str()); - if (target_node == rpc_->node_id_) { - result = LocalGetOrCreateVBucketId(context, name); - } else { - result = RpcCall(rpc, target_node, "RemoteGetOrCreateVBucketId", - name); - } - - return result; -} - -/** copy IDs */ -void MetadataManager::CopyIds(u64 *dest, u64 *src, u32 count) { - static_assert(sizeof(BlobID) == sizeof(BufferID)); - for (u32 i = 0; i < count; ++i) { - dest[i] = src[i]; - } -} - -void MetadataManager::ReplaceBlobIdInBucket(BucketID bucket_id, - BlobID old_blob_id, - BlobID new_blob_id) { - u32 target_node = bucket_id.bits.node_id; - if (target_node == rpc_->node_id_) { - LocalReplaceBlobIdInBucket(context, bucket_id, old_blob_id, new_blob_id); - } else { - RpcCall(rpc, target_node, "RemoteReplaceBlobIdInBucket", bucket_id, - old_blob_id, new_blob_id); - } -} - -/** add BLOB ID to bucket */ -void MetadataManager::AddBlobIdToBucket(BlobID blob_id, - BucketID bucket_id) { - u32 target_node = bucket_id.bits.node_id; - - if (target_node == rpc_->node_id_) { - LocalAddBlobIdToBucket(bucket_id, blob_id); - } else { - RpcCall(rpc, target_node, "RemoteAddBlobIdToBucket", bucket_id, - blob_id); - } -} - -/** add BLOB ID to virtual bucket */ -void MetadataManager::AddBlobIdToVBucket(BlobID blob_id, - VBucketID vbucket_id) { - u32 target_node = vbucket_id.bits.node_id; - - if (target_node == rpc_->node_id_) { - LocalAddBlobIdToVBucket(vbucket_id, blob_id); - } else { - RpcCall(rpc, target_node, "RemoteAddBlobIdToVBucket", vbucket_id, - blob_id); - } -} - -/** allocate buffer ID list */ -u32 MetadataManager::AllocateBufferIdList( - u32 target_node, const std::vector &buffer_ids) { - mdm = GetMetadataManagerFromContext(context); - u32 result = 0; - - if (target_node == rpc_->node_id_) { - result = LocalAllocateBufferIdList(buffer_ids); - } else { - result = RpcCall(rpc, target_node, "RemoteAllocateBufferIdList", - buffer_ids); - } - - return result; -} - -/** get buffer ID list */ -void MetadataManager::GetBufferIdList(BlobID blob_id, - BufferIdArray *buffer_ids) { - mdm = GetMetadataManagerFromContext(context); - u32 target_node = blob_id.GetNodeId(); - - if (target_node == rpc_->node_id_) { - LocalGetBufferIdList(blob_id, buffer_ids); - } else { - std::vector result = - RpcCall>(rpc, target_node, "RemoteGetBufferIdList", - blob_id); - buffer_ids->ids = PushArray(result.size()); - buffer_ids->length = (u32)result.size(); - CopyIds((u64 *)buffer_ids->ids, (u64 *)result.data(), result.size()); - } -} - -/** get buffer ID list as vector */ -std::vector MetadataManager::GetBufferIdList(BlobID blob_id) { - mdm = GetMetadataManagerFromContext(context); - u32 target_node = blob_id.GetNodeId(); - - std::vector result; - - if (target_node == rpc_->node_id_) { - result = LocalGetBufferIdList(blob_id); - } else { - result = RpcCall>(rpc, target_node, - "RemoteGetBufferIdList", blob_id); - } - - return result; -} - -/** get buffer IDs from BLOB id */ -BufferIdArray MetadataManager::GetBufferIdsFromBlobId(BlobID blob_id, - u32 **sizes) { - BufferIdArray result = {}; - GetBufferIdList(context, rpc, blob_id, &result); - - if (sizes) { - u32 *buffer_sizes = PushArray(result.length); - for (u32 i = 0; i < result.length; ++i) { - buffer_sizes[i] = GetBufferSize(context, rpc, result.ids[i]); - } - *sizes = buffer_sizes; - } - - return result; -} - -/** create BLOB metadata locally */ -void MetadataManager::LocalCreateBlobMetadata(const std::string &blob_name, - BlobID blob_id, - TargetID effective_target) { - LocalPut(blob_name.c_str(), blob_id.as_int, kMapType_BlobId); - BlobInfo blob_info = {}; - blob_info.stats.frequency = 1; - blob_info.stats.recency = clock++; - blob_info.effective_target = effective_target; - - if (effective_target != kSwapTargetId) { - assert(blob_id.bits.node_id == (int)effective_target.bits.node_id); - Target *target = GetTargetFromId(context, effective_target); - target->effective_blobs_lock.Lock(); - AppendToChunkedIdList(&target->effective_blobs, blob_id.as_int); - target->effective_blobs_lock.Unlock(); - } - - LocalPut(blob_id, blob_info); -} - -/** create BLOB metadata */ -void MetadataManager::CreateBlobMetadata(const std::string &blob_name, - BlobID blob_id, - TargetID effective_target) { - mdm = GetMetadataManagerFromContext(context); - u32 target_node = blob_id.GetNodeId(); - if (target_node == rpc_->node_id_) { - LocalCreateBlobMetadata(context, blob_name, blob_id, effective_target); - } else { - RpcCall(rpc, target_node, "RemoteCreateBlobMetadata", blob_name, - blob_id, effective_target); - } -} - -/** attach BLOB to bucket */ -void MetadataManager::AttachBlobToBucket( - const char *blob_name, BucketID bucket_id, - const std::vector &buffer_ids, - TargetID effective_target, bool is_swap_blob, - bool called_from_buffer_organizer) { - mdm = GetMetadataManagerFromContext(context); - - std::string internal_name = MakeInternalBlobName(blob_name, bucket_id); - int target_node = HashString(rpc, internal_name.c_str()); - - BlobID blob_id = {}; - if (called_from_buffer_organizer) { - blob_id = GetBlobId(context, rpc, blob_name, bucket_id); - - if (!IsNullBlobId(blob_id)) { - // Remove old BlobID from the bucket's list of Blobs - RemoveBlobFromBucketInfo(context, rpc, bucket_id, blob_id); - - // Release the IDs that represented the SwapBlob info - FreeBufferIdList(context, rpc, blob_id); - } else { - LOG(WARNING) << "Expected to find BlobID " << blob_id.as_int - << " in Map but didn't." << std::endl; - } - } - - // NOTE(chogan): A negative node_id indicates a swap blob - blob_id.bits.node_id = is_swap_blob ? -target_node : target_node; - blob_id.bits.buffer_ids_offset = AllocateBufferIdList(context, rpc, - target_node, - buffer_ids); - CreateBlobMetadata(context, rpc, internal_name, blob_id, effective_target); - AddBlobIdToBucket(rpc, blob_id, bucket_id); -} - -/** free buffer ID list */ -void MetadataManager::FreeBufferIdList(BlobID blob_id) { - u32 target_node = blob_id.GetNodeId(); - if (target_node == rpc_->node_id_) { - LocalFreeBufferIdList(context, blob_id); - } else { - RpcCall(rpc, target_node, "RemoteFreeBufferIdList", blob_id); - } -} - -/** delete BLOB metadata locally */ -void MetadataManager::LocalDeleteBlobMetadata(const char *blob_name, - BlobID blob_id, BucketID bucket_id) { - LocalDeleteBlobId(blob_name, bucket_id); - LocalDeleteBlobInfo(blob_id); -} - -/** wait for outstanding BLOB operations */ -void MetadataManager::WaitForOutstandingBlobOps(BlobID blob_id) { - BlobInfo *blob_info = GetBlobInfoPtr(blob_id); - if (blob_info) { - blob_info->lock.Lock(); - blob_info->lock.Unlock(); - } else { - ReleaseBlobInfoPtr(mdm); - } -} - -/** destroy BLOB by name locally */ -void MetadataManager::LocalDestroyBlobByName(const char *blob_name, - BlobID blob_id, - BucketID bucket_id) { - mdm = GetMetadataManagerFromContext(context); - - // NOTE(chogan): Holding the blob_info_map_mutex - WaitForOutstandingBlobOps(blob_id); - - if (!BlobIsInSwap(blob_id)) { - std::vector buffer_ids = GetBufferIdList(context, rpc, blob_id); - ReleaseBuffers(context, rpc, buffer_ids); - } else { - // TODO(chogan): Invalidate swap region once we have a SwapManager - } - - FreeBufferIdList(context, rpc, blob_id); - - LocalDeleteBlobMetadata(blob_name, blob_id, bucket_id); - - ReleaseBlobInfoPtr(mdm); -} - -/** destroy BLOB by ID locally */ -void MetadataManager::LocalDestroyBlobById(BlobID blob_id, - BucketID bucket_id) { - std::string blob_name = LocalGetBlobNameFromId(context, blob_id); - if (blob_name.size() > 0) { - LocalDestroyBlobByName(context, rpc, blob_name.c_str(), blob_id, bucket_id); - } else { - DLOG(INFO) << "Expected to find blob_id " << blob_id.as_int - << " in Map but didn't" << std::endl; - } -} - -void MetadataManager::RemoveBlobFromBucketInfo(BucketID bucket_id, - BlobID blob_id) { - u32 target_node = bucket_id.bits.node_id; - if (target_node == rpc_->node_id_) { - LocalRemoveBlobFromBucketInfo(context, bucket_id, blob_id); - } else { - RpcCall(rpc, target_node, "RemoteRemoveBlobFromBucketInfo", bucket_id, - blob_id); - } -} - -/** destroy BLOB by name */ -void MetadataManager::DestroyBlobByName(BucketID bucket_id, - const std::string &blob_name) { - BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id); - if (!IsNullBlobId(blob_id)) { - u32 blob_id_target_node = blob_id.GetNodeId(); - - if (blob_id_target_node == rpc_->node_id_) { - LocalDestroyBlobByName(context, rpc, blob_name.c_str(), blob_id, - bucket_id); - } else { - RpcCall(rpc, blob_id_target_node, "RemoteDestroyBlobByName", - blob_name, blob_id, bucket_id); - } - RemoveBlobFromBucketInfo(context, rpc, bucket_id, blob_id); - } -} - -/** rename BLOB */ -void MetadataManager::RenameBlob(const std::string &old_name, - const std::string &new_name, - BucketID bucket_id) { - mdm = GetMetadataManagerFromContext(context); - BlobID blob_id = GetBlobId(context, rpc, old_name, bucket_id); - if (!IsNullBlobId(blob_id)) { - DeleteBlobId(rpc, old_name, bucket_id); - PutBlobId(rpc, new_name, blob_id, bucket_id); - } else { - LOG(ERROR) << "Invalid BlobID for Blob '" << old_name << "'" << std::endl; - } -} - -/** does \a bucket_id bucket contain \a blob_name BLOB? */ -bool MetadataManager::ContainsBlob(BucketID bucket_id, - const std::string &blob_name) { - BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id); - bool result = false; - - if (!IsNullBlobId(blob_id)) { - u32 target_node = bucket_id.bits.node_id; - if (target_node == rpc_->node_id_) { - result = LocalContainsBlob(context, bucket_id, blob_id); - } else { - result = RpcCall(rpc, target_node, "RemoteContainsBlob", bucket_id, - blob_id); - } - } - - return result; -} - -/** destroy BLOB by ID */ -void MetadataManager::DestroyBlobById(BlobID id, BucketID bucket_id) { - u32 target_node = GetBlobNodeId(id); - if (target_node == rpc_->node_id_) { - LocalDestroyBlobById(context, rpc, id, bucket_id); - } else { - RpcCall(rpc, target_node, "RemoteDestroyBlobById", id, bucket_id); - } -} - -/** destroy bucket */ -bool MetadataManager::DestroyBucket(const char *name, BucketID bucket_id) { - u32 target_node = bucket_id.bits.node_id; - bool destroyed = false; - if (target_node == rpc_->node_id_) { - destroyed = LocalDestroyBucket(context, rpc, name, bucket_id); - } else { - destroyed = RpcCall(rpc, target_node, "RemoteDestroyBucket", - std::string(name), bucket_id); - } - - return destroyed; -} - -/** destroy virtual bucket */ -bool MetadataManager::DestroyVBucket(const char *name, VBucketID vbucket_id) { - u32 target_node = vbucket_id.bits.node_id; - bool destroyed = false; - if (target_node == rpc_->node_id_) { - destroyed = LocalDestroyVBucket(context, name, vbucket_id); - } else { - destroyed = RpcCall(rpc, target_node, "RemoteDestroyVBucket", - std::string(name), vbucket_id); - } - - return destroyed; -} - -/** rename bucket locally */ -void MetadataManager::LocalRenameBucket(BucketID id, - const std::string &old_name, - const std::string &new_name) { - mdm = GetMetadataManagerFromContext(context); - DeleteBucketId(rpc, old_name); - PutBucketId(rpc, new_name, id); -} - -/** rename bucket */ -void MetadataManager::RenameBucket(BucketID id, - const std::string &old_name, - const std::string &new_name) { - u32 target_node = id.bits.node_id; - if (target_node == rpc_->node_id_) { - LocalRenameBucket(context, rpc, id, old_name, new_name); - } else { - RpcCall(rpc, target_node, "RemoteRenameBucket", id, old_name, - new_name); - } -} - -/** increment reference count locally */ -void MetadataManager::LocalIncrementRefcount(BucketID id) { - mdm = GetMetadataManagerFromContext(context); - BucketInfo *info = LocalGetBucketInfoById(id); - info->ref_count.fetch_add(1); -} - -/** decrement reference count locally */ -void MetadataManager::LocalDecrementRefcount(BucketID id) { - mdm = GetMetadataManagerFromContext(context); - BucketInfo *info = LocalGetBucketInfoById(id); - info->ref_count.fetch_sub(1); - assert(info->ref_count.load() >= 0); -} - -/** decrement reference count */ -void MetadataManager::DecrementRefcount(BucketID id) { - u32 target_node = id.bits.node_id; - if (target_node == rpc_->node_id_) { - LocalDecrementRefcount(context, id); - } else { - RpcCall(rpc, target_node, "RemoteDecrementRefcount", id); - } -} - -/** get remaning target capacity locally */ -u64 MetadataManager::LocalGetRemainingTargetCapacity(TargetID id) { - Target *target = GetTargetFromId(context, id); - u64 result = target->remaining_space.load(); - - return result; -} - -/** get global device capacities locally */ -std::vector MetadataManager::LocalGetGlobalDeviceCapacities() { - GlobalSystemViewState *global_svs = GetGlobalSystemViewState(context); - - std::vector result(global_svs->num_devices); - for (size_t i = 0; i < result.size(); ++i) { - result[i] = global_svs->bytes_available[i].load(); - } - - return result; -} - -/** get global device capacities */ -std::vector MetadataManager::GetGlobalDeviceCapacities() { - mdm = GetMetadataManagerFromContext(context); - u32 target_node = global_system_view_state_node_id; - - std::vector result; - - if (target_node == rpc_->node_id_) { - result = LocalGetGlobalDeviceCapacities(context); - } else { - result = RpcCall>(rpc, target_node, - "RemoteGetGlobalDeviceCapacities"); - } - - return result; -} - -/** get global system view state from \a context */ -GlobalSystemViewState* MetadataManager::GetGlobalSystemViewState() { - mdm = GetMetadataManagerFromContext(context); - GlobalSystemViewState *result = - (GlobalSystemViewState *)((u8 *)mdm + global_system_view_state_offset); - assert((u8 *)result != (u8 *)mdm); - - return result; -} - -/** update global system view state locally */ -std::vector -MetadataManager::LocalUpdateGlobalSystemViewState( - u32 node_id, std::vector adjustments) { - std::vector result; - for (size_t device_idx = 0; device_idx < adjustments.size(); ++device_idx) { - GlobalSystemViewState *state = GetGlobalSystemViewState(context); - u32 target_idx = ((node_id - 1) * adjustments.size()) + device_idx; - if (adjustments[device_idx]) { - state->bytes_available[target_idx].fetch_add(adjustments[device_idx]); - DLOG(INFO) << "DeviceID " << device_idx << " on node " << node_id - << " adjusted by " << adjustments[device_idx] << " bytes\n"; - } - - // Collect devices for which to trigger the BufferOrganizer if the - // capacities are beyond the min/max thresholds - float percentage_available = 0.0f; - if (state->bytes_available[target_idx] > 0) { - percentage_available = ((f32)state->bytes_available[target_idx].load() / - (f32)state->capacities[device_idx]); - } - - ViolationInfo info = {}; - float percentage_violation = 0.0f; - f32 percentage_used = 1.0f - percentage_available; - float min_threshold = state->bo_capacity_thresholds[device_idx].min; - float max_threshold = state->bo_capacity_thresholds[device_idx].max; - - if (percentage_used > max_threshold) { - percentage_violation = percentage_used - max_threshold; - info.violation = ThresholdViolation::kMax; - } - if (percentage_used < min_threshold) { - percentage_violation = min_threshold - percentage_used; - info.violation = ThresholdViolation::kMin; - } - - if (percentage_violation > 0.0f) { - TargetID target_id = {}; - target_id.bits.node_id = node_id; - target_id.bits.device_id = (DeviceID)device_idx; - // TODO(chogan): This needs to change when we support num_devices != - // num_targets - target_id.bits.index = device_idx; - - info.target_id = target_id; - info.violation_size = - (size_t)(percentage_violation * state->capacities[device_idx]); - result.push_back(info); - } - } - - return result; -} - -/** update global system view state */ -void MetadataManager::UpdateGlobalSystemViewState() { - mdm = GetMetadataManagerFromContext(context); - BufferPool *pool = GetBufferPoolFromContext(context); - - bool update_needed = false; - std::vector adjustments(pool->num_devices); - for (size_t i = 0; i < adjustments.size(); ++i) { - adjustments[i] = pool->capacity_adjustments[i].exchange(0); - if (adjustments[i] != 0) { - update_needed = true; - } - } - - std::vector devices_to_organize; - if (update_needed) { - u32 target_node = global_system_view_state_node_id; - if (target_node == rpc_->node_id_) { - devices_to_organize = - LocalUpdateGlobalSystemViewState(context, rpc_->node_id_, adjustments); - } else { - devices_to_organize = - RpcCall>(rpc, target_node, - "RemoteUpdateGlobalSystemViewState", - adjustments); - } - } - - for (size_t i = 0; i < devices_to_organize.size(); ++i) { - EnforceCapacityThresholds(context, rpc, devices_to_organize[i]); - } -} - -/** find target ID from device ID */ -TargetID MetadataManager::FindTargetIdFromDeviceId( - const std::vector &targets, DeviceID device_id) { - TargetID result = {}; - // TODO(chogan): @optimization Inefficient O(n) - for (size_t target_index = 0; - target_index < targets.size(); - ++target_index) { - if (targets[target_index].bits.device_id == device_id) { - result = targets[target_index]; - break; - } - } - - return result; -} - -/** create system view state */ -SystemViewState* -MetadataManager::CreateSystemViewState(Config *config) { - SystemViewState *result = PushClearedStruct(arena); - result->num_devices = config->num_devices; - for (int i = 0; i < result->num_devices; ++i) { - result->capacities[i] = config->capacities[i]; - result->bytes_available[i] = config->capacities[i]; - - // Min and max thresholds - result->bo_capacity_thresholds[i] = config->bo_capacity_thresholds[i]; - } - - return result; -} - -/** create global system view state */ -GlobalSystemViewState* -MetadataManager::CreateGlobalSystemViewState(Config *config) { - GlobalSystemViewState *result = - PushClearedStruct(arena); - result->num_devices = config->num_devices; - - for (int i = 0; i < result->num_devices; ++i) { - result->capacities[i] = config->capacities[i]; - // Min and max thresholds - result->bo_capacity_thresholds[i] = config->bo_capacity_thresholds[i]; - } - size_t num_targets = config->num_devices * rpc_->num_nodes; - result->num_targets = num_targets; - result->bytes_available = - PushClearedArray>(num_targets); - - for (u32 node_idx = 0; node_idx < rpc_->num_nodes; ++node_idx) { - for (int device_idx = 0; device_idx < result->num_devices; ++device_idx) { - u64 index = (node_idx * result->num_devices) + device_idx; - result->bytes_available[index].store(result->capacities[device_idx]); - } - } - - return result; -} - -/** get swap file name */ -std::string MetadataManager::GetSwapFilename(u32 node_id) { - char *prefix = (char *)((u8 *)mdm + swap_filename_prefix_offset); - char *suffix = (char *)((u8 *)mdm + swap_filename_suffix_offset); - std::string result = (prefix + std::to_string(node_id) + suffix); - - return result; -} - -/** swap BLOB to vector */ -std::vector -MetadataManager::SwapBlobToVec(SwapBlob swap_blob) { - // TODO(chogan): @metaprogramming Improve this, since it currently only works - // if each member in SwapBlob (plus padding) is eight bytes. - static_assert((sizeof(SwapBlob) / 8) == SwapBlobMembers_Count); - - std::vector result(SwapBlobMembers_Count); - result[SwapBlobMembers_NodeId].as_int = swap_blob.node_id; - result[SwapBlobMembers_Offset].as_int = swap_blob.offset; - result[SwapBlobMembers_Size].as_int = swap_blob.size; - result[SwapBlobMembers_BucketId].as_int = swap_blob.bucket_id.as_int; - - return result; -} - -/** vector to swap BLOB */ -SwapBlob MetadataManager::VecToSwapBlob(std::vector &vec) { - SwapBlob result = {}; - - if (vec.size() == SwapBlobMembers_Count) { - result.node_id = (u32)vec[SwapBlobMembers_NodeId].as_int; - result.offset = vec[SwapBlobMembers_Offset].as_int; - result.size = vec[SwapBlobMembers_Size].as_int; - result.bucket_id.as_int = vec[SwapBlobMembers_BucketId].as_int; - } else { - // TODO(chogan): @errorhandling - HERMES_NOT_IMPLEMENTED_YET; - } - - return result; -} - -/** ID array to swap BLOB */ -SwapBlob MetadataManager::IdArrayToSwapBlob(BufferIdArray ids) { - SwapBlob result = {}; - - if (ids.length == SwapBlobMembers_Count) { - result.node_id = (u32)ids.ids[SwapBlobMembers_NodeId].as_int; - result.offset = ids.ids[SwapBlobMembers_Offset].as_int; - result.size = ids.ids[SwapBlobMembers_Size].as_int; - result.bucket_id.as_int = ids.ids[SwapBlobMembers_BucketId].as_int; - } else { - // TODO(chogan): @errorhandling - HERMES_NOT_IMPLEMENTED_YET; - } - - return result; -} - -/** initialize metadata manager */ -MetadataManager::MetadataManager(RpcContext *rpc, Config *config) : - config_(config), rpc_(rpc) { - // NOTE(chogan): All MetadataManager offsets are relative to the address of - // the MDM itself. - u32 node_id = rpc_->node_id__; - - map_seed = 0x4E58E5DF; - SeedHashForStorage(map_seed); - - system_view_state_update_interval_ms = - config->system_view_state_update_interval_ms; - - // Initialize SystemViewState - - SystemViewState *sv_state = CreateSystemViewState(config); - system_view_state_offset = GetOffsetFromMdm(sv_state); - - // Initialize Global SystemViewState - - if (node_id == 1) { - // NOTE(chogan): Only Node 1 has the Global SystemViewState - GlobalSystemViewState *global_state = - CreateGlobalSystemViewState(rpc, config); - global_system_view_state_offset = GetOffsetFromMdm(global_state); - } - global_system_view_state_node_id = 1; - - // Initialize BucketInfo array - - BucketInfo *buckets = PushArray(arena, - config->max_buckets_per_node); - bucket_info_offset = GetOffsetFromMdm(buckets); - first_free_bucket.bits.node_id = (u32)node_id; - first_free_bucket.bits.index = 0; - num_buckets = 0; - max_buckets = config->max_buckets_per_node; - - for (u32 i = 0; i < config->max_buckets_per_node; ++i) { - BucketInfo *info = buckets + i; - info->active = false; - - if (i == config->max_buckets_per_node - 1) { - info->next_free.as_int = 0; - } else { - info->next_free.bits.node_id = (u32)node_id; - info->next_free.bits.index = i + 1; - } - } - - // Initialize VBucketInfo array - - VBucketInfo *vbuckets = PushArray(arena, - config->max_vbuckets_per_node); - vbucket_info_offset = GetOffsetFromMdm(vbuckets); - first_free_vbucket.bits.node_id = (u32)node_id; - first_free_vbucket.bits.index = 0; - num_vbuckets = 0; - max_vbuckets = config->max_vbuckets_per_node; - - for (u32 i = 0; i < config->max_vbuckets_per_node; ++i) { - VBucketInfo *info = vbuckets + i; - info->active = false; - info->async_flush_count.store(0); - - if (i == config->max_vbuckets_per_node - 1) { - info->next_free.as_int = 0; - } else { - info->next_free.bits.node_id = (u32)node_id; - info->next_free.bits.index = i + 1; - } - } -} - -/** get virtual bucket information by index locally */ -VBucketInfo* MetadataManager::LocalGetVBucketInfoByIndex(u32 index) { - VBucketInfo *info_array = - (VBucketInfo *)((u8 *)mdm + vbucket_info_offset); - VBucketInfo *result = info_array + index; - return result; -} - -/** get virtual bucket information by id locally */ -VBucketInfo* MetadataManager::LocalGetVBucketInfoById(VBucketID id) { - VBucketInfo *result = LocalGetVBucketInfoByIndex(id.bits.index); - return result; -} - -/** increment reference counter locally */ -void MetadataManager::LocalIncrementRefcount(VBucketID id) { - mdm = GetMetadataManagerFromContext(context); - VBucketInfo *info = LocalGetVBucketInfoById(id); - info->ref_count.fetch_add(1); -} - -/** decrement reference counter locally */ -void MetadataManager::LocalDecrementRefcount(VBucketID id) { - mdm = GetMetadataManagerFromContext(context); - VBucketInfo *info = LocalGetVBucketInfoById(id); - info->ref_count.fetch_sub(1); - assert(info->ref_count.load() >= 0); -} - -/** decrement reference counter */ -void MetadataManager::DecrementRefcount(VBucketID id) { - u32 target_node = id.bits.node_id; - if (target_node == rpc_->node_id_) { - LocalDecrementRefcount(context, id); - } else { - RpcCall(rpc, target_node, "RemoteDecrementRefcountVBucket", id); - } -} - -/** get relative node ID */ -u32 MetadataManager::GetRelativeNodeId(int offset) { - int result = rpc_->node_id_ + offset; - assert(result >= 0); - assert(result <= (int)(rpc_->num_nodes + 1)); - - if (result > (int)rpc_->num_nodes) { - result = 1; - } else if (result == 0) { - result = rpc_->num_nodes; - } - - return (u32)result; -} - -/** get next node */ -u32 MetadataManager::GetNextNode() { - u32 result = GetRelativeNodeId(1); - - return result; -} - -/** get previous node */ -u32 MetadataManager::GetPreviousNode() { - u32 result = GetRelativeNodeId(-1); - - return result; -} - -/** get node targets */ -std::vector MetadataManager::GetNodeTargets(u32 target_node) { - std::vector result; - - if (target_node == rpc_->node_id_) { - result = LocalGetNodeTargets(context); - } else { - result = RpcCall>(rpc, target_node, - "RemoteGetNodeTargets"); - } - - return result; -} - -/** get neighborhood node targets */ -std::vector MetadataManager::GetNeighborhoodTargets() { - // TODO(chogan): Inform the concept of "neighborhood" with a network topology - // NOTE(chogan): For now, each node has 2 neighbors, NodeID-1 and NodeID+1 - // (wrapping around for nodes 1 and N). - std::vector result; - - switch (rpc_->num_nodes) { - case 1: { - // No neighbors - break; - } - case 2: { - // One neighbor - u32 next_node = GetNextNode(rpc); - result = GetNodeTargets(context, rpc, next_node); - break; - } - default: { - // Two neighbors - u32 next_node = GetNextNode(rpc); - std::vector next_targets = GetNodeTargets(context, rpc, - next_node); - u32 prev_node = GetPreviousNode(rpc); - std::vector prev_targets = GetNodeTargets(context, rpc, - prev_node); - - result.reserve(next_targets.size() + prev_targets.size()); - result.insert(result.end(), next_targets.begin(), next_targets.end()); - result.insert(result.end(), prev_targets.begin(), prev_targets.end()); - } - } - - return result; -} - -/** get remaining target capacity */ -u64 MetadataManager::GetRemainingTargetCapacity(TargetID target_id) { - u64 result = 0; - u32 target_node = target_id.bits.node_id; - - if (target_node == rpc_->node_id_) { - result = LocalGetRemainingTargetCapacity(context, target_id); - } else { - result = RpcCall(rpc, target_node, "RemoteGetRemainingTargetCapacity", - target_id); - } - - return result; -} - -/** get remaining target capacities */ -std::vector MetadataManager::GetRemainingTargetCapacities( - const std::vector &targets) { - std::vector result(targets.size()); - - for (size_t i = 0; i < targets.size(); ++i) { - result[i] = GetRemainingTargetCapacity(context, rpc, targets[i]); - } - - return result; -} - -void MetadataManager::AttachBlobToVBucket(const char *blob_name, - const char *bucket_name, - VBucketID vbucket_id) { - mdm = GetMetadataManagerFromContext(context); - BucketID bucket_id = GetBucketId(context, rpc, bucket_name); - BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id); - AddBlobIdToVBucket(rpc, blob_id, vbucket_id); -} - -/** get bucket name by ID locally */ -std::string -MetadataManager::LocalGetBucketNameById(BucketID blob_id) { - mdm = GetMetadataManagerFromContext(context); - std::string bucket_name = - ReverseGetFromStorage(blob_id.as_int, kMapType_Bucket); - return bucket_name; -} - -std::vector -MetadataManager::GetBlobsFromVBucketInfo(VBucketID vbucket_id) { - u32 target_node = vbucket_id.bits.node_id; - if (target_node == rpc_->node_id_) { - return LocalGetBlobsFromVBucketInfo(context, vbucket_id); - } else { - return RpcCall>( - rpc, target_node, "RemoteGetBlobsFromVBucketInfo", vbucket_id); - } -} - -void MetadataManager::RemoveBlobFromVBucketInfo(VBucketID vbucket_id, - const char *blob_name, - const char *bucket_name) { - BucketID bucket_id = GetBucketId(context, rpc, bucket_name); - BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id); - u32 target_node = vbucket_id.bits.node_id; - if (target_node == rpc_->node_id_) { - LocalRemoveBlobFromVBucketInfo(context, vbucket_id, blob_id); - } else { - RpcCall(rpc, target_node, "RemoteRemoveBlobFromVBucketInfo", - vbucket_id, blob_id); - } -} - -std::string MetadataManager::GetBucketNameById(BucketID id) { - auto target_node = id.bits.node_id; - if (target_node == rpc_->node_id_) { - return LocalGetBucketNameById(context, id); - } else { - return RpcCall(rpc, target_node, "RemoteGetBucketNameById", - id); - } -} - -/** - * Returns the score calculated from @p stats. - * - * A high score indicates a "cold" Blob, or one that has not been accessed very - * recently or frequently. - * - */ -f32 MetadataManager::ScoringFunction(Stats *stats) { - f32 recency_weight = 0.5; - f32 frequency_weight = 0.5; - // NOTE(chogan): A high relative_recency corresponds to a "cold" Blob. - f32 relative_recency = clock - stats->recency; - f32 result = (relative_recency * recency_weight - - stats->frequency * frequency_weight); - - return result; -} - -/** get number of outstanding flushing tasks locally */ -int MetadataManager::LocalGetNumOutstandingFlushingTasks(VBucketID id) { - mdm = GetMetadataManagerFromContext(context); - vbucket_mutex.Lock(); - VBucketInfo *info = LocalGetVBucketInfoById(id); - int result = 0; - if (info) { - result = info->async_flush_count; - } - vbucket_mutex.Unlock(); - - return result; -} - -/** get number of outstanding flushing tasks */ -int MetadataManager::GetNumOutstandingFlushingTasks(VBucketID id) { - u32 target_node = id.bits.node_id; - int result = 0; - - if (target_node == rpc_->node_id_) { - result = LocalGetNumOutstandingFlushingTasks(context, id); - } else { - result = RpcCall(rpc, target_node, - "RemoteGetNumOutstandingFlushingTasks", id); - } - - return result; -} - -bool MetadataManager::LocalLockBlob(BlobID blob_id) { - mdm = GetMetadataManagerFromContext(context); - BlobInfo *blob_info = GetBlobInfoPtr(blob_id); - if (blob_info) { - blob_info->lock.Lock(); - } else { - ReleaseBlobInfoPtr(mdm); - return false; - } - if (blob_info->stop) { - blob_info->lock.Unlock(); - LocalDelete(blob_id); - LocalFreeBufferIdList(context, blob_id); - ReleaseBlobInfoPtr(mdm); - return false; - } - ReleaseBlobInfoPtr(mdm); - return true; -} - -bool MetadataManager::LocalUnlockBlob(BlobID blob_id) { - BlobInfo *blob_info = GetBlobInfoPtr(blob_id); - bool result = false; - if (blob_info) { - blob_info->lock.Unlock(); - result = true; - } - ReleaseBlobInfoPtr(mdm); - return result; -} - -/** lock BLOB */ -bool MetadataManager::LockBlob(BlobID blob_id) { - u32 target_node = blob_id.GetNodeId(); - bool result; - if (target_node == rpc_->node_id_) { - result = LocalLockBlob(blob_id); - } else { - result = rpc_->Call(target_node, "RemoteLockBlob", blob_id); - } - return result; -} - -/** unlock BLOB */ -bool MetadataManager::UnlockBlob(BlobID blob_id) { - u32 target_node = blob_id.GetNodeId(); - bool result; - if (target_node == rpc_->node_id_) { - result = LocalUnlockBlob(context, blob_id); - } else { - result = RpcCall(rpc, target_node, "RemoteUnlockBlob", blob_id); - } - - return result; -} - -} // namespace hermes diff --git a/src/metadata_management.h b/src/metadata_management.h deleted file mode 100644 index 5507b15ee..000000000 --- a/src/metadata_management.h +++ /dev/null @@ -1,622 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_METADATA_MANAGEMENT_H_ -#define HERMES_METADATA_MANAGEMENT_H_ - -#include - -#include -#include - -#include "buffer_pool.h" -#include "rpc_thallium.h" -#include -#include - -namespace hermes { - -static const u32 kGlobalMutexNodeId = 1; /**< global mutex node ID */ - -struct RpcContext; - -/** - * Representation of a non-NULL-terminated string in shared memory. - * - * Both the ShmemString iteself and the memory for the string it represents must - * reside in the same shared memory segement, and the ShmemString must be stored - * at a lower address than the string memory because the offset is from the - * ShmemString instance itself. Here is a diagram: - * - * |-----------8 bytes offset ------------| - * [ ShmemString | offset: 8 | size: 16 ] [ "string in memory" ] - * - * @see MakeShmemString() - * @see GetShmemString() - * - */ -struct ShmemString { - /** offset is from the address of this ShmemString instance iteself */ - u32 offset; - /** The size of the string (not NULL terminated) */ - u32 size; - - ShmemString(const ShmemString &) = delete; - ShmemString(const ShmemString &&) = delete; - ShmemString &operator=(const ShmemString &) = delete; - ShmemString &operator=(const ShmemString &&) = delete; -}; - -/** min/max threshold violation */ -enum class ThresholdViolation { kMin, kMax }; - -/** - A structure to represent violation information -*/ -struct ViolationInfo { - TargetID target_id; /**< target node ID */ - ThresholdViolation violation; /**< threshold violation */ - size_t violation_size; /**< size of violation */ -}; - -/** - A structure to represent statistics - */ -struct Stats { - u32 recency; /**< recency */ - u32 frequency; /**< frequency */ -}; - -const int kIdListChunkSize = 10; /**< chunk size of ID list */ -/** - A structure to represent ID list -*/ -struct IdList { - u32 head_offset; /**< the offset of head in the list */ - u32 length; /**< length of list */ -}; - -/** - A structure to represent the array of buffer IDs - */ -struct BufferIdArray { - BufferID *ids; /**< pointer to IDs */ - u32 length; /**< length of array */ -}; - -/** - A structure to represent Blob information - */ -struct BlobInfo { - Stats stats; /**< BLOB statistics */ - labstor::Mutex lock; /**< lock */ - TargetID effective_target; /**< target ID */ - u32 last; /**< last */ - bool stop; /**< stop */ - - BlobInfo() : last(0), stop(false) { - stats.recency = 0; - stats.frequency = 0; - effective_target.as_int = 0; - } - - /** Copy \a other BlobInfo sturcture. */ - BlobInfo &operator=(const BlobInfo &other) { - stats = other.stats; - effective_target = other.effective_target; - last = other.last; - stop = other.stop; - - return *this; - } -}; - -/** - A structure to represent bucket information -*/ -struct BucketInfo { - BucketID next_free; /**< id of next free bucket */ - ChunkedIdList blobs; /**< list of BLOB IDs */ - std::atomic ref_count; /**< reference count */ - bool active; /**< is bucket active? */ -}; - -/** maxinum number of traits per bucket */ -static constexpr int kMaxTraitsPerVBucket = 8; - -/** - A structure to represent virtual bucket information - */ -struct VBucketInfo { - VBucketID next_free; /**< id of next free virtual bucket */ - ChunkedIdList blobs; /**< list of BLOB IDs */ - std::atomic ref_count; /**< reference count */ - std::atomic async_flush_count; /**< asynchrnous flush count */ - /** Not currently used since Traits are process local. */ - TraitID traits[kMaxTraitsPerVBucket]; - bool active; /**< is virtual bucket active? */ -}; - -/** - A sntructure to view the current state of system - */ -struct SystemViewState { - /** Total capacities of each device. */ - u64 capacities[kMaxDevices]; - /** The remaining bytes available for buffering in each device. */ - std::atomic bytes_available[kMaxDevices]; - /** The min and max threshold (percentage) for each device at which the - * BufferOrganizer will trigger. */ - Thresholds bo_capacity_thresholds[kMaxDevices]; - /** The total number of buffering devices. */ - int num_devices; -}; - -// TODO(chogan): -/** - * A snapshot view of the entire system's Targets' available capacities. - * - * This information is only stored on 1 node, designated by - * MetadataManager::global_system_view_state_node_id, and is only updated by 1 - * rank (the Hermes process on that node). Hence, it does not need to be stored - * in shared memory and we are able to use normal std containers. However, since - * multiple RPC handler threads can potentially update the `bytes_available` - * field concurrently, we must not do any operations on the vector itself. We - * can only do operations on the atomics within. The vector is created in - * StartGlobalSystemViewStateUpdateThread, and thereafter we can only call - * functions on the individual atomics (e.g., bytes_available[i].fetch_add), - * which is thread safe. - */ -struct GlobalSystemViewState { - /** The total number of buffering Targets in the system */ - u64 num_targets; - /** The number of devices per node */ - int num_devices; - u64 capacities[kMaxDevices]; /**< capacities of devices */ - /** The remaining capacity of each Target in the system */ - std::atomic *bytes_available; - /** The min and max capacity thresholds (percentage) for each Target in the - * system */ - Thresholds bo_capacity_thresholds[kMaxDevices]; -}; - -/** - A structure to represent metadata manager -*/ - -namespace lipc = labstor::ipc; -namespace lipcl = labstor::ipc::lockless; - -class MetadataManager { - public: - Config *config_; - SharedMemoryContext *context_; - ThalliumRpc *rpc_; - SystemViewState local_state_; - GlobalSystemViewState global_state_; - - // All offsets are relative to the beginning of the MDM - ptrdiff_t bucket_info_offset; /**< bucket information */ - BucketID first_free_bucket; /**< ID of first free bucket */ - - ptrdiff_t vbucket_info_offset; /**< virtual bucket information */ - VBucketID first_free_vbucket; /**< ID of first free virtual bucket */ - - ptrdiff_t rpc_state_offset; /**< RPC state */ - ptrdiff_t host_names_offset; /**< host names */ - ptrdiff_t host_numbers_offset; /**< host numbers */ - ptrdiff_t system_view_state_offset; /**< system view state */ - ptrdiff_t global_system_view_state_offset; /**< global system view state */ - - ptrdiff_t id_heap_offset; /**< ID heap */ - ptrdiff_t map_heap_offset; /**< map heap */ - - ptrdiff_t swap_filename_prefix_offset; /**< swap file name prefix */ - ptrdiff_t swap_filename_suffix_offset; /**< swap file name suffix */ - - // TODO(chogan): @optimization Should the mutexes here be reader/writer - // locks? - - lipc::unordered_map - blob_id_map_; /**< BLOB ID map */ - lipc::unordered_map - bucket_id_map_; /**< Bucket ID map */ - lipc::unordered_map - vbucket_id_map_; /**< VBucket ID map */ - - lipc::unordered_map - blob_info_map_; /**< BLOB information map */ - lipc::unordered_map - bucket_map_; /**< bucket map */ - lipc::unordered_map - vbucket_map_; /**< virtual bucket map */ - - /** Lock for accessing `IdList`s and `ChunkedIdList`s */ - labstor::Mutex id_mutex; - - size_t map_seed; /**< map seed */ - - IdList node_targets; /**< ID list of node targets */ - IdList neighborhood_targets; /**< ID list of neighborhood targets */ - - u32 system_view_state_update_interval_ms; /**< sys. view update interval */ - u32 global_system_view_state_node_id; /**< node ID fo global sys. view */ - u32 num_buckets; /**< number of buckets */ - u32 max_buckets; /**< maximum number of buckets */ - u32 num_vbuckets; /**< number of virtual buckets */ - u32 max_vbuckets; /**< maximum number of virtual buckets */ - std::atomic clock; /**< clock */ - - public: - - /** - * initialize metadata manager - * */ - MetadataManager(SharedMemoryContext *context, RpcContext *rpc, Config *config); - - /** get virtual bucket information by index locally */ - VBucketInfo* LocalGetVBucketInfoByIndex(u32 index); - - /** get virtual bucket information by id locally */ - VBucketInfo* LocalGetVBucketInfoById(VBucketID id); - - /** increment reference counter locally */ - void LocalIncrementRefcount(VBucketID id); - - /** decrement reference counter locally */ - void LocalDecrementRefcount(VBucketID id); - - /** decrement reference counter */ - void DecrementRefcount(VBucketID id); - - /** get relative node ID */ - u32 GetRelativeNodeId(int offset); - - /** get next node */ - u32 GetNextNode(); - - /** get previous node */ - u32 GetPreviousNode(); - - /** get node targets */ - std::vector GetNodeTargets(u32 target_node); - - /** get neighborhood node targets */ - std::vector GetNeighborhoodTargets(); - - /** get remaining target capacity */ - u64 GetRemainingTargetCapacity(TargetID target_id); - - /** get remaining target capacities */ - std::vector - GetRemainingTargetCapacities(const std::vector &targets); - - void AttachBlobToVBucket(const char *blob_name, const char *bucket_name, - VBucketID vbucket_id); - - /** get bucket name by ID locally */ - std::string LocalGetBucketNameById(BucketID blob_id); - - std::vector GetBlobsFromVBucketInfo(VBucketID vbucket_id); - - void RemoveBlobFromVBucketInfo(VBucketID vbucket_id, const char *blob_name, - const char *bucket_name); - - std::string GetBucketNameById(BucketID id); - - f32 ScoringFunction(Stats *stats); - - int LocalGetNumOutstandingFlushingTasks(VBucketID id); - - int GetNumOutstandingFlushingTasks(VBucketID id); - - bool LocalLockBlob(BlobID blob_id); - - bool LocalUnlockBlob(BlobID blob_id); - - /** lock BLOB */ - bool LockBlob(BlobID blob_id); - - /** unlock BLOB */ - bool UnlockBlob(BlobID blob_id); - - private: - - /** is BLOB's \a name too long for kMaxBlobNameSize? */ - bool IsBlobNameTooLong(const std::string &name); - - /** is Bucket's \a name too long for kMaxBucketNameSize? */ - bool IsBucketNameTooLong(const std::string &name); - - /** is vBucket's \a name too long for kMaxVBucketNameSize? */ - bool IsVBucketNameTooLong(const std::string &name); - - /** get hash string for metadata storage */ - u32 HashString(const char *str); - - /** get bucket id */ - BucketID GetBucketId(const char *name); - - /** get local bucket id */ - BucketID LocalGetBucketId(const char *name); - - /** get virtual bucket id */ - VBucketID GetVBucketId(const char *name); - - /** get local virtual bucket id */ - VBucketID LocalGetVBucketId(const char *name); - - /** make an internal BLOB name */ - std::string MakeInternalBlobName(const std::string &name, BucketID id); - - /** get BLOB id */ - BlobID GetBlobId(const std::string &name, BucketID bucket_id, - bool track_stats); - - /** get local BLOB id */ - BlobID LocalGetBlobId(const std::string &name); - - /** put BLOB id */ - void PutId(const std::string &name, u64 id, MapType map_type); - - /** put bucket id */ - void PutBucketId(const std::string &name, BucketID id); - - /** put bucket id locally */ - void LocalPutBucketId(const std::string &name,BucketID id); - - /** put virtual bucket id */ - void PutVBucketId(const std::string &name, VBucketID id); - - /** put virtual bucket id locally */ - void LocalPutVBucketId(const std::string &name, VBucketID id); - - /** put BLOB id */ - void PutBlobId(const std::string &name, BlobID id, BucketID bucket_id); - - /** delete id */ - void DeleteId(const std::string &name,MapType map_type); - - /** delete bucket id */ - void DeleteBucketId(const std::string &name); - - /** delete virtual bucket id */ - void DeleteVBucketId(const std::string &name); - - /** delete BLOB information locally */ - void LocalDeleteBlobInfo(BlobID blob_id); - - /** delete BLOB id locally */ - void LocalDeleteBlobId(const std::string &name, - BucketID bucket_id); - - /** delete BLOB id */ - void DeleteBlobId(const std::string &name, BucketID bucket_id); - - /** get bucket information by \a index index locally */ - BucketInfo *LocalGetBucketInfoByIndex(u32 index); - - /** get BLOB name from \a blob_id locally */ - std::string LocalGetBlobNameFromId(BlobID blob_id); - - /** get BLOB name from \a blob_id */ - std::string GetBlobNameFromId(BlobID blob_id); - - u64 HexStringToU64(const std::string &s); - - /** get bucket ID from \a blob_id locally */ - BucketID LocalGetBucketIdFromBlobId(BlobID id); - - /** get bucket ID from \a blob_id */ - BucketID GetBucketIdFromBlobId(BlobID id); - - /** get bucket information from \a bucket_id */ - BucketInfo *LocalGetBucketInfoById(BucketID id); - - /** get BLOB IDs from \a bucket_id */ - std::vector GetBlobIds(BucketID bucket_id); - - /** get virtual bucket information by \a index */ - VBucketInfo *GetVBucketInfoByIndex(u32 index); - - /** - * Returns an available BucketID and marks it as in use in the MDM. - * - * Assumes bucket_mutex is already held by the caller. - */ - BucketID LocalGetNextFreeBucketId(const std::string &name); - - /** get or create a bucket ID locally */ - BucketID LocalGetOrCreateBucketId(const std::string &name); - - /** get or create a bucket ID */ - BucketID GetOrCreateBucketId(const std::string &name); - - /** - * Returns an available VBucketID and marks it as in use in the MDM. - * - * Assumes MetadataManager::vbucket_mutex is already held by the caller. - */ - VBucketID LocalGetNextFreeVBucketId(const std::string &name); - - /** get or create a virtual bucket ID locally */ - VBucketID LocalGetOrCreateVBucketId(const std::string &name); - - /** get or create a virtual bucket ID */ - VBucketID GetOrCreateVBucketId(const std::string &name); - - /** copy IDs */ - void CopyIds(u64 *dest, u64 *src, u32 count); - - void ReplaceBlobIdInBucket(BucketID bucket_id, - BlobID old_blob_id, - BlobID new_blob_id); - - /** add BLOB ID to bucket */ - void AddBlobIdToBucket(BlobID blob_id, - BucketID bucket_id); - - /** add BLOB ID to virtual bucket */ - void AddBlobIdToVBucket(BlobID blob_id, - VBucketID vbucket_id); - - /** allocate buffer ID list */ - u32 AllocateBufferIdList(u32 target_node, - const std::vector &buffer_ids); - - /** get buffer ID list */ - void GetBufferIdList( - BlobID blob_id, - BufferIdArray *buffer_ids); - - /** get buffer ID list as vector */ - std::vector GetBufferIdList(BlobID blob_id); - - /** get buffer IDs from BLOB id */ - BufferIdArray GetBufferIdsFromBlobId(BlobID blob_id, - u32 **sizes); - - /** create BLOB metadata locally */ - void LocalCreateBlobMetadata(const std::string &blob_name, BlobID blob_id, - TargetID effective_target); - - /** create BLOB metadata */ - void CreateBlobMetadata( - const std::string &blob_name, BlobID blob_id, - TargetID effective_target); - - /** attach BLOB to bucket */ - void AttachBlobToBucket( - const char *blob_name, BucketID bucket_id, - const std::vector &buffer_ids, - TargetID effective_target, bool is_swap_blob, - bool called_from_buffer_organizer); - - /** free buffer ID list */ - void FreeBufferIdList( - BlobID blob_id); - - /** delete BLOB metadata locally */ - void LocalDeleteBlobMetadata(const char *blob_name, - BlobID blob_id, BucketID bucket_id); - - /** wait for outstanding BLOB operations */ - void WaitForOutstandingBlobOps(BlobID blob_id); - - /** destroy BLOB by name locally */ - void LocalDestroyBlobByName(const char *blob_name, - BlobID blob_id, - BucketID bucket_id); - - /** destroy BLOB by ID locally */ - void LocalDestroyBlobById(BlobID blob_id, BucketID bucket_id); - - void RemoveBlobFromBucketInfo(BucketID bucket_id, BlobID blob_id); - - /** destroy BLOB by name */ - void DestroyBlobByName(BucketID bucket_id, const std::string &blob_name); - - /** rename BLOB */ - void RenameBlob(const std::string &old_name, - const std::string &new_name, - BucketID bucket_id); - - /** does \a bucket_id bucket contain \a blob_name BLOB? */ - bool ContainsBlob(BucketID bucket_id, const std::string &blob_name); - - /** destroy BLOB by ID */ - void DestroyBlobById(BlobID id, - BucketID bucket_id); - - /** destroy bucket */ - bool DestroyBucket( - const char *name, BucketID bucket_id); - - /** destroy virtual bucket */ - bool DestroyVBucket( - const char *name, VBucketID vbucket_id); - - /** rename bucket locally */ - void LocalRenameBucket( - BucketID id, const std::string &old_name, - const std::string &new_name); - - /** rename bucket */ - void RenameBucket(BucketID id, - const std::string &old_name, - const std::string &new_name); - - /** increment reference count locally */ - void LocalIncrementRefcount(BucketID id); - - /** decrement reference count locally */ - void LocalDecrementRefcount(BucketID id); - - /** decrement reference count */ - void DecrementRefcount(BucketID id); - - /** get remaning target capacity locally */ - u64 LocalGetRemainingTargetCapacity(TargetID id); - - /** get local system view state */ - SystemViewState *GetLocalSystemViewState(); - - /** get global device capacities locally */ - std::vector LocalGetGlobalDeviceCapacities(); - - /** get global device capacities */ - std::vector GetGlobalDeviceCapacities(); - - /** update global system view state locally */ - std::vector - LocalUpdateGlobalSystemViewState(u32 node_id, - std::vector adjustments); - - /** update global system view state */ - void UpdateGlobalSystemViewState(); - - /** find target ID from device ID */ - TargetID FindTargetIdFromDeviceId(const std::vector &targets, - DeviceID device_id); - - /** create system view state */ - SystemViewState* CreateSystemViewState(Config *config); - - /** create global system view state */ - GlobalSystemViewState* CreateGlobalSystemViewState(Config *config); - - /** get swap file name */ - std::string GetSwapFilename(u32 node_id); - - /** swap BLOB to vector */ - std::vector SwapBlobToVec(SwapBlob swap_blob); - - /** vector to swap BLOB */ - SwapBlob VecToSwapBlob(std::vector &vec); - - /** ID array to swap BLOB */ - SwapBlob IdArrayToSwapBlob(BufferIdArray ids); - -#define RPC_METADATA_MANAGER_RPC -#undef RPC_METADATA_MANAGER_RPC -}; - -/** log error when metadata arena capacity is full */ -static void MetadataArenaErrorHandler() { - LOG(FATAL) << "Metadata arena capacity exceeded. Consider increasing the " - << "value of metadata_arena_percentage in the Hermes configuration" - << std::endl; -} - -} // namespace hermes - -#endif // HERMES_METADATA_MANAGEMENT_H_ diff --git a/src/prefetcher.cc b/src/prefetcher.cc deleted file mode 100644 index 9f8d0bce1..000000000 --- a/src/prefetcher.cc +++ /dev/null @@ -1,226 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "prefetcher_factory.h" -#include "metadata_management.h" -#include "singleton.h" -#include "metadata_management_internal.h" - -using hermes::api::Hermes; - -namespace hermes { - -bool Prefetcher::LogIoStat(Hermes *hermes, IoLogEntry &entry) { - RpcContext *rpc = &hermes->rpc_; - u32 target_node = HashToNode(hermes, entry); - bool result = false; - if (target_node == rpc->node_id) { - auto prefetcher = Singleton::GetInstance(); - prefetcher->Log(entry); - result = true; - } else { - result = RpcCall(rpc, target_node, - "LogIoStat", entry); - } - return result; -} - -/** - * HashToNode - * - * Determines which node an IoLogEntry should be keyed to. - * We hash IoLogEntries to nodes using only the BucketID. - * This way, IoLogEntries regarding a particular blob are - * always placed on the same node. - * - * This approach assumes that prefetching decisions are based - * solely on the bucket's access pattern, not patterns across-buckets. - * */ - -size_t Prefetcher::HashToNode(Hermes *hermes, IoLogEntry &entry) { - CommunicationContext *comm = &hermes->comm_; - size_t hash = std::hash{}(entry.bkt_id_.as_int); - return (hash % comm->num_nodes) + 1; -} - -void Prefetcher::Log(IoLogEntry &entry) { - LOG(INFO) << "Logging I/O stat" << std::endl; - lock_.lock(); - if (log_.size() == max_length_) { - log_.pop_front(); - } - timespec_get(&entry.timestamp_, TIME_UTC); - log_.emplace_back(entry); - lock_.unlock(); -} - -float Prefetcher::EstimateBlobMovementTime(BlobID blob_id) { - Arena arena = InitArenaAndAllocate(MEGABYTES(1)); - u32 *buffer_sizes = 0; - BufferIdArray id_array = GetBufferIdsFromBlobId(&arena, - &hermes_->context_, - &hermes_->rpc_, - blob_id, - &buffer_sizes); - std::vector buffer_ids(id_array.ids, - id_array.ids + id_array.length); - DestroyArena(&arena); - std::vector buffer_info = GetBufferInfo( - &hermes_->context_, &hermes_->rpc_, buffer_ids); - - float xfer_time = 0; - for (auto &info : buffer_info) { - xfer_time += static_cast(info.size) / MEGABYTES(info.bandwidth_mbps); - /*LOG(INFO) << "size: " << info.size / MEGABYTES(1) - << " bw: " << info.bandwidth_mbps - << " current total: " << xfer_time << std::endl;*/ - } - xfer_time *= 2; // x2 because movement reads, and then writes data - return xfer_time; -} - -bool HasOnlyDemotions(PrefetchDecision &decision, float &decay) { - decay = std::numeric_limits::infinity(); - if (decision.stats_.size() == 0) return false; - for (auto &prefetch_stat : decision.stats_) { - if (prefetch_stat.decay_ < 0) { - return false; - } - decay = std::min(decay, prefetch_stat.decay_); - } - return true; -}; - -void Prefetcher::CalculateBlobScore(struct timespec &ts, - PrefetchDecision &decision) { - float est_xfer_time = decision.est_xfer_time_; - decision.new_score_ = -1; - decision.queue_later_ = false; - - float decay; - if (HasOnlyDemotions(decision, decay)) { - decision.new_score_ = GetBlobImportanceScore(&hermes_->context_, - &hermes_->rpc_, - decision.blob_id_); - decision.new_score_ *= decay; - if (decision.new_score_ < 0) { - decision.new_score_ = 0; - } - decision.decay_ = true; - return; - } - - for (auto &prefetch_stat : decision.stats_) { - if (prefetch_stat.decay_ >= 0) continue; - // Wait until the I/O for this Get seems to have completed - /*float time_left_on_io = prefetch_stat.TimeLeftOnIo( - est_xfer_time, &ts); - LOG(INFO) << "Blob id: " << decision.blob_id_.as_int - << " Time left before starting prefetch: " - << time_left_on_io << std::endl; - if (time_left_on_io > 0) { - decision.queue_later_ = true; - continue; - }*/ - float next_access_sec = prefetch_stat.TimeToNextIo(&ts); - LOG(INFO) << "Next access sec: " << next_access_sec << std::endl; - LOG(INFO) << "Est xfer time : " << est_xfer_time << std::endl; - // if (next_access_sec < est_xfer_time) continue; - float max_access_wait = std::max(max_wait_xfer_*est_xfer_time, - max_wait_sec_); - LOG(INFO) << "Max access wait: " << max_access_wait << std::endl; - float est_wait = (next_access_sec - est_xfer_time); - if (est_wait > max_access_wait) { - decision.queue_later_ = true; - continue; - } - float score = (max_access_wait - est_wait) / max_access_wait; - if (score > decision.new_score_) { - decision.new_score_ = score; - } - } -} - -void Prefetcher::Process() { - // Group log by I/O hint - lock_.lock(); - std::unordered_map> hint_logs; - for (auto &entry : log_) { - hint_logs[entry.pctx_.hint_].emplace_back(entry); - } - log_.erase(log_.begin(), log_.end()); - lock_.unlock(); - if (hint_logs.size() == 0 && queue_later_.size() == 0) { - return; - } - - // Based on the current log, determine what blobs to prefetch - PrefetchSchema schema; - for (auto &[hint, hint_log] : hint_logs) { - auto algorithm = PrefetcherFactory::Get(hint); - algorithm->Process(hint_log, schema); - } - - // Take into consideration old prefetching decisions - for (auto &[blob_id, decision] : queue_later_) { - schema.emplace(decision); - } - queue_later_.erase(queue_later_.begin(), queue_later_.end()); - - // Get the current time - struct timespec ts; - timespec_get(&ts, TIME_UTC); - - // Calculate new blob scores - for (auto &[blob_id, decision] : schema) { - if (decision.est_xfer_time_ == -1) { - decision.est_xfer_time_ = EstimateBlobMovementTime(blob_id); - } - CalculateBlobScore(ts, decision); - if (decision.new_score_ < 0) { - if (decision.queue_later_) { - queue_later_.emplace(blob_id, decision); - } - } - } - - // Process decay blobs first (make room) - for (auto &[blob_id, decision] : schema) { - if (!decision.decay_) { continue; } - LOG(INFO) << "Decaying Blob: " << blob_id.as_int - << " to score: " << decision.new_score_ << std::endl; - OrganizeBlob(&hermes_->context_, &hermes_->rpc_, - decision.bkt_id_, decision.blob_name_, - epsilon_, decision.new_score_); - } - - // TODO(llogan): a hack to help BORG shuffle data - struct timespec ts2; - while(PrefetchStat::DiffTimespec(&ts2, &ts) < 1) { - timespec_get(&ts2, TIME_UTC); - ABT_thread_yield(); - } - - // Calculate new blob scores - for (auto &[blob_id, decision] : schema) { - if (decision.decay_) { continue; } - if (decision.new_score_ < 0) { continue; } - LOG(INFO) << "Prefetching bkt_id: " << decision.bkt_id_.as_int - << " blob_id: " << decision.blob_name_ - << " score: " << decision.new_score_ << std::endl; - OrganizeBlob(&hermes_->context_, &hermes_->rpc_, - decision.bkt_id_, decision.blob_name_, - epsilon_, 1.0); - } -} - -} // namespace hermes diff --git a/src/prefetcher.h b/src/prefetcher.h deleted file mode 100644 index 315e6fa1c..000000000 --- a/src/prefetcher.h +++ /dev/null @@ -1,268 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_PREFETCHER_H_ -#define HERMES_SRC_PREFETCHER_H_ - -#include "hermes.h" -#include "hermes_types.h" -#include "rpc_thallium.h" -#include -#include -#include -#include -#include - -namespace hermes { - -using hermes::api::PrefetchContext; -using hermes::api::PrefetchHint; - -static bool operator==(const BlobID& first, const BlobID& second) { - return first.as_int == second.as_int; -} - -enum class IoType { - kNone, kPut, kGet -}; - -struct GlobalThreadID { - int rank_; - int tid_; - GlobalThreadID() : rank_(0), tid_(0) {} - explicit GlobalThreadID(int rank) : rank_(rank) { - ABT_unit_id tid_argo; - ABT_thread_self_id(&tid_argo); - tid_ = tid_argo; - } - - bool operator==(const GlobalThreadID &other) const { - return (rank_ == other.rank_ && tid_ == other.tid_); - } -}; - -struct UniqueBucket { - VBucketID vbkt_id_; - BucketID bkt_id_; - - UniqueBucket() = default; - UniqueBucket(VBucketID vbkt_id, BucketID bkt_id) : - vbkt_id_(vbkt_id), bkt_id_(bkt_id) {} - - bool operator==(const UniqueBucket &other) const { - return (vbkt_id_.as_int == other.vbkt_id_.as_int && - bkt_id_.as_int == other.bkt_id_.as_int); - } -}; - -struct IoLogEntry { - VBucketID vbkt_id_; - BucketID bkt_id_; - BlobID blob_id_; - IoType type_; - off_t off_; - size_t size_; - PrefetchContext pctx_; - GlobalThreadID tid_; - bool historical_; - struct timespec timestamp_; -}; - -struct PrefetchStat { - float est_next_time_; - struct timespec start_; - float decay_; - - PrefetchStat() : est_next_time_(0), decay_(-1) {} - - explicit PrefetchStat(float est_next_time, struct timespec &start) : - est_next_time_(est_next_time), start_(start), decay_(-1) {} - - explicit PrefetchStat(float decay) : decay_(decay) {} - - float TimeLeftOnIo(float est_xfer_time, const struct timespec *cur) { - float diff = DiffTimespec(cur, &start_); - /*LOG(INFO) << "Time since I/O submitted: " << diff << std::endl; - LOG(INFO) << "Est I/O time: " << est_xfer_time << std::endl;*/ - return est_xfer_time - diff; - } - - float TimeToNextIo(const struct timespec *cur) { - float diff = DiffTimespec(cur, &start_); - return est_next_time_ - diff; - } - - static float DiffTimespec(const struct timespec *left, - const struct timespec *right) { - return (left->tv_sec - right->tv_sec) - + (left->tv_nsec - right->tv_nsec) / 1000000000.0; - } -}; - -struct PrefetchDecision { - BucketID bkt_id_; - BlobID blob_id_; - std::string blob_name_; - std::list stats_; - bool queue_later_; - float est_xfer_time_; - float new_score_; - bool decay_; - - PrefetchDecision() : queue_later_(false), - est_xfer_time_(-1), - new_score_(-1), - decay_(false) {} - void AddStat(float est_access_time, struct timespec &start) { - stats_.emplace_back(est_access_time, start); - } - void AddStat(float decay) { - stats_.emplace_back(decay); - } -}; - -class PrefetchSchema { - private: - std::unordered_map schema_; - - public: - void emplace(PrefetchDecision &decision) { - auto prior_decision_iter = schema_.find(decision.blob_id_); - if (prior_decision_iter == schema_.end()) { - schema_.emplace(decision.blob_id_, decision); - return; - } - auto &[blob_id, prior_decision] = (*prior_decision_iter); - prior_decision.est_xfer_time_ = decision.est_xfer_time_; - prior_decision.stats_.splice( - prior_decision.stats_.end(), - decision.stats_); - } - - std::unordered_map::iterator begin() { - return schema_.begin(); - } - - std::unordered_map::iterator end() { - return schema_.end(); - } -}; - -class PrefetchAlgorithm { - public: - virtual void Process(std::list &log, - PrefetchSchema &schema) = 0; -}; - -class Prefetcher { - private: - uint32_t max_length_; - thallium::mutex lock_; - std::list log_; - std::unordered_map queue_later_; - - public: - float max_wait_xfer_; - float max_wait_sec_; - float epsilon_; - - public: - std::shared_ptr hermes_; - - Prefetcher() : max_length_(4096), max_wait_xfer_(10), max_wait_sec_(60), - epsilon_(.05) {} - void SetHermes(std::shared_ptr &hermes) { hermes_ = hermes; } - void SetLogLength(uint32_t max_length) { max_length_ = max_length; } - void Log(IoLogEntry &entry); - static bool LogIoStat(api::Hermes *hermes, IoLogEntry &entry); - void Process(); - - private: - static size_t HashToNode(api::Hermes *hermes, IoLogEntry &entry); - float EstimateBlobMovementTime(BlobID blob_id); - void CalculateBlobScore(struct timespec &ts, - PrefetchDecision &decision); -}; - -/** RPC SERIALIZERS */ - -// IoType -template -void save(A &ar, IoType &hint) { - ar << static_cast(hint); -} -template -void load(A &ar, IoType &hint) { - int hint_i; - ar >> hint_i; - hint = static_cast(hint_i); -} - -// struct timespec -template -void save(A &ar, struct timespec &ts) { - ar << ts.tv_sec; - ar << ts.tv_nsec; -} -template -void load(A &ar, struct timespec &ts) { - ar >> ts.tv_sec; - ar >> ts.tv_nsec; -} - -// GlobalThreadID -template -void serialize(A &ar, GlobalThreadID &tid) { - ar & tid.rank_; - ar & tid.tid_; -} - -// IoLogEntry -template -void serialize(A &ar, IoLogEntry &entry) { - ar & entry.vbkt_id_; - ar & entry.bkt_id_; - ar & entry.blob_id_; - ar & entry.type_; - ar & entry.off_; - ar & entry.size_; - ar & entry.pctx_; - ar & entry.tid_; - // ar & entry.timestamp_; - ar & entry.historical_; -} - -} // namespace hermes - -namespace std { -template <> -struct hash { - std::size_t operator()(const hermes::GlobalThreadID &key) const { - size_t h1 = std::hash{}(key.rank_); - size_t h2 = std::hash{}(key.tid_); - size_t hash = h1^h2; - return hash; - } -}; - -template <> -struct hash { - std::size_t operator()(const hermes::UniqueBucket &key) const { - size_t h1 = std::hash{}(key.vbkt_id_); - size_t h2 = std::hash{}(key.bkt_id_); - size_t hash = h1^h2; - return hash; - } -}; -} // namespace std - -#endif // HERMES_SRC_PREFETCHER_H_ diff --git a/src/prefetcher_factory.h b/src/prefetcher_factory.h deleted file mode 100644 index ecb138f2b..000000000 --- a/src/prefetcher_factory.h +++ /dev/null @@ -1,48 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_PREFETCHER_FACTORY_H_ -#define HERMES_SRC_PREFETCHER_FACTORY_H_ - -#include "prefetcher.h" -#include - -#include "prefetchers/sequential.h" -#include "prefetchers/apriori.h" -#include "singleton.h" - -namespace hermes { - -class PrefetcherFactory { - public: - /** - * Return the instance of mapper given a type. Uses factory pattern. - * - * @param type, MapperType, type of mapper to be used by the STDIO adapter. - * @return Instance of mapper given a type. - */ - static PrefetchAlgorithm* Get(const PrefetchHint &type) { - switch (type) { - case PrefetchHint::kFileSequential: { - return Singleton::GetInstance(); - } - case PrefetchHint::kApriori: { - return Singleton::GetInstance(); - } - default: return nullptr; - } - } -}; - -} // namespace hermes - -#endif // HERMES_SRC_PREFETCHER_FACTORY_H_ diff --git a/src/prefetchers/apriori.cc b/src/prefetchers/apriori.cc deleted file mode 100644 index 88f58be94..000000000 --- a/src/prefetchers/apriori.cc +++ /dev/null @@ -1,13 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "apriori.h" diff --git a/src/prefetchers/apriori.h b/src/prefetchers/apriori.h deleted file mode 100644 index 666c5d0e9..000000000 --- a/src/prefetchers/apriori.h +++ /dev/null @@ -1,28 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_PREFETCHERS_APRIORI_H_ -#define HERMES_SRC_PREFETCHERS_APRIORI_H_ - -#include "prefetcher.h" - -namespace hermes { - -class AprioriPrefetcher : public PrefetchAlgorithm { - public: - void Process(std::list &log, - PrefetchSchema &schema) {} -}; - -} // namespace hermes - -#endif // HERMES_SRC_PREFETCHERS_APRIORI_H_ diff --git a/src/prefetchers/sequential.cc b/src/prefetchers/sequential.cc deleted file mode 100644 index d2131960d..000000000 --- a/src/prefetchers/sequential.cc +++ /dev/null @@ -1,145 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "sequential.h" -#include "singleton.h" -#include "api/bucket.h" -#include - -using hermes::adapter::BlobPlacement; - -namespace hermes { - -void SequentialPrefetcher::Process(std::list &log, - PrefetchSchema &schema) { - auto prefetcher = Singleton::GetInstance(); - - // Increase each unique_bucket access count - for (auto &entry : log) { - UniqueBucket id(entry.vbkt_id_, entry.bkt_id_); - auto &state = state_[id]; - if (state.count_ == 0) { - state.first_access_ = entry.timestamp_; - } - ++state.count_; - } - - // Append time estimates and read-aheads to the schema - for (auto &entry : log) { - UniqueBucket id(entry.vbkt_id_, entry.bkt_id_); - auto &state = state_[id]; - float cur_runtime = PrefetchStat::DiffTimespec(&entry.timestamp_, - &state.first_access_); - float avg_time = cur_runtime / state.count_; - if (avg_time == 0) { - avg_time = prefetcher->max_wait_sec_ / 2.0; - } - LOG(INFO) << "Avg time: " << avg_time << std::endl; - - // Read-ahead the next few blobs - BlobID cur_id = entry.blob_id_; - for (int i = 0; i < entry.pctx_.read_ahead_; ++i) { - PrefetchDecision decision; - decision.bkt_id_ = entry.bkt_id_; - if (IsNullVBucketId(entry.vbkt_id_)) { - GetNextFromBucket(entry, decision, cur_id); - } else { - GetNextFromVbucket(entry, decision, cur_id); - } - if (IsNullBlobId(decision.blob_id_)) { - break; - } - decision.AddStat((i+1)*avg_time, entry.timestamp_); - schema.emplace(decision); - cur_id = decision.blob_id_; - } - - // Demote the previous blobs - cur_id = entry.blob_id_; - for (int i = 0; i < entry.pctx_.read_ahead_; ++i) { - PrefetchDecision decision; - if (IsNullVBucketId(entry.vbkt_id_)) { - GetPriorFromBucket(entry, decision, cur_id); - } else { - GetPriorFromVbucket(entry, decision, cur_id); - } - if (IsNullBlobId(decision.blob_id_)) { - break; - } - decision.AddStat(entry.pctx_.decay_); - schema.emplace(decision); - cur_id = decision.blob_id_; - } - } -} - -void SequentialPrefetcher::GetNextFromBucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobID &cur_id) { - // Get current blob name - auto prefetcher = Singleton::GetInstance(); - auto hermes = prefetcher->hermes_; - std::string blob_name = GetBlobNameFromId(&hermes->context_, - &hermes->rpc_, - cur_id); - - // Get next blob name - BlobPlacement p; - p.DecodeBlobName(blob_name); - p.page_ += 1; - decision.blob_name_ = p.CreateBlobName(); - - // Get the next blob ID from the bucket - decision.blob_id_ = GetBlobId(&hermes->context_, &hermes->rpc_, - decision.blob_name_, entry.bkt_id_, - false); -} - -void SequentialPrefetcher::GetNextFromVbucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobID &cur_id) { - // TODO(llogan): Not implemented for now. -} - -void SequentialPrefetcher::GetPriorFromBucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobID &cur_id) { - // Get current blob name - auto prefetcher = Singleton::GetInstance(); - auto hermes = prefetcher->hermes_; - std::string blob_name = GetBlobNameFromId(&hermes->context_, - &hermes->rpc_, - cur_id); - - // Get prior blob name - BlobPlacement p; - p.DecodeBlobName(blob_name); - if (p.page_ == 0) { - cur_id.as_int = 0; - return; - } - p.page_ -= 1; - decision.blob_name_ = p.CreateBlobName(); - - // Get the prior blob ID from the bucket - decision.blob_id_ = GetBlobId(&hermes->context_, &hermes->rpc_, - decision.blob_name_, entry.bkt_id_, - false); -} - -void SequentialPrefetcher::GetPriorFromVbucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobID &cur_id) { - // TODO(llogan): Not implemented for now. -} - -} // namespace hermes diff --git a/src/prefetchers/sequential.h b/src/prefetchers/sequential.h deleted file mode 100644 index b27328db8..000000000 --- a/src/prefetchers/sequential.h +++ /dev/null @@ -1,52 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ -#define HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ - -#include "prefetcher.h" - -namespace hermes { - -struct SequentialState { - struct timespec first_access_; - u32 count_; - - SequentialState() : count_(0) {} -}; - -class SequentialPrefetcher : public PrefetchAlgorithm { - private: - std::unordered_map state_; - - public: - void Process(std::list &log, - PrefetchSchema &schema); - - private: - void GetNextFromBucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobID &cur_id); - void GetNextFromVbucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobID &cur_id); - void GetPriorFromBucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobID &cur_id); - void GetPriorFromVbucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobID &cur_id); -}; - -} // namespace hermes - -#endif // HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ diff --git a/src/rpc.h b/src/rpc.h index 8aa42227c..7918ef03c 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -17,7 +17,7 @@ #include #include "hermes_types.h" -#include "metadata_management.h" +#include "communication.h" #include #include @@ -38,8 +38,7 @@ namespace lipcl = labstor::ipc::lockless; class RpcContext { public: - CommunicationContext *comm_; - SharedMemoryContext *context_; + COMM_TYPE *comm_; Config *config_; /** The hermes configuration used to initialize this RPC */ /** Array of host names stored in shared memory. This array size is * RpcContext::num_nodes. */ @@ -58,10 +57,9 @@ class RpcContext { // char *host_file_name; public: - explicit RpcContext(CommunicationContext *comm, - SharedMemoryContext *context, + explicit RpcContext(COMM_TYPE *comm, u32 num_nodes, u32 node_id, Config *config) : - comm_(comm), context_(context), num_nodes_(num_nodes), + comm_(comm), num_nodes_(num_nodes), node_id_(node_id), config_(config) { port_ = config->rpc_port; if (!config->rpc_server_host_file.empty()) { @@ -98,6 +96,7 @@ class RpcContext { // I'd like to only have it in one place. #if defined(HERMES_RPC_THALLIUM) #include "rpc_thallium.h" +#define RPC_TYPE ThalliumRpc #else #error "RPC implementation required (e.g., -DHERMES_RPC_THALLIUM)." #endif diff --git a/src/rpc_factory.h b/src/rpc_factory.h deleted file mode 100644 index 2b7a710a6..000000000 --- a/src/rpc_factory.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// Created by lukemartinlogan on 11/30/22. -// - -#ifndef HERMES_SRC_RPC_FACTORY_H_ -#define HERMES_SRC_RPC_FACTORY_H_ - -#include "rpc.h" -#include "rpc_thallium.h" - -namespace hermes { -class RpcFactory { - public: - /** - * Return an RPC. Uses factory pattern. - * - * @param type, RpcType, type of mapper to be used by the STDIO adapter. - * @return Instance of RPC given a type. - */ - static std::unique_ptr Get( - const RpcType &type, - CommunicationContext *comm, - SharedMemoryContext *context, - u32 num_nodes, u32 node_id, Config *config) { - switch (type) { - case RpcType::kThallium: { - return std::make_unique( - comm, context, num_nodes, node_id, config); - } - default: - return nullptr; - } - } -}; -} // namespace hermes - -#endif // HERMES_SRC_RPC_FACTORY_H_ diff --git a/src/rpc_generator/generate.py b/src/rpc_generator/generate.py deleted file mode 100644 index 8770209b1..000000000 --- a/src/rpc_generator/generate.py +++ /dev/null @@ -1,30 +0,0 @@ - -""" -Automatically generate the RPCs for a series of Local functions - -USAGE: - cd /path/to/rpc_generator - python3 generate.py [whether or not to modify path or make tmpfiles] -""" - -import sys -from rpc_generator.rpc_generator import RpcGenerator - -if len(sys.argv) < 2: - gen = RpcGenerator(False) -else: - gen = RpcGenerator(sys.argv[1]) - -gen.set_file("../buffer_organizer.h", "BufferOrganizer", "borg") -gen.add("LocalGetBufferInfo", "buffer_id.bits.node_id") -gen.add("LocalEnqueueBoMove", "rpc_->node_id_") -gen.add("LocalOrganizeBlob", "HashString(internal_name.c_str())") -gen.add("LocalEnforceCapacityThresholds", "info.target_id.bits.node_id") -gen.add("LocalEnqueueFlushingTask", "rpc->node_id_") -gen.add("LocalIncrementFlushCount", "HashString(vbkt_name.c_str())") -gen.add("LocalDecrementFlushCount", "HashString(vbkt_name.c_str())") - -# gen.set_file("metadata_management.h", "METADTA_MANAGER_RPC", "mdm") -# gen.add("LocalGetVBucketInfoById", "HashString(name)") - -gen.generate() \ No newline at end of file diff --git a/src/rpc_generator/rpc_generator/rpc_generator.py b/src/rpc_generator/rpc_generator/rpc_generator.py deleted file mode 100644 index d1c3f40d1..000000000 --- a/src/rpc_generator/rpc_generator/rpc_generator.py +++ /dev/null @@ -1,244 +0,0 @@ -import sys, os, re - -rpc_func_text = """ -{RET} {GLOBAL_NAME}({PARAMS}) {{ - u32 target_node = {TARGET_NODE}; - if (target_node == rpc_->node_id_) {{ - LocalAddBlobIdToVBucket( - {PASS_PARAMS}); - }} else {{ - rpc_->Call(rpc, target_node, "{GLOBAL_NAME}", - {PASS_PARAMS}); - }} -}} -""" - -# Will add this to rpc_thallium.cc -rpc_lambda_text = """ -auto {LAMBDA_NAME} = [{CONTEXT}](const request &req, {PARAMS}) {{ - auto result = {CONTEXT}->{LOCAL_NAME}({PASS_PARAMS}); - req.respond(result); -}}; -rpc_server->define("{GLOBAL_NAME}", rpc_get_buffers); -""" - -class Api: - def __init__(self, api_str): - self.api_str = api_str - self.name = None # The name of the API - self.global_name = None # Name of API without "Local" - self.lambda_name = None # Name of lambda caller of API (rpc_{name}) - self.ret = None # Return value of the API - self.var_defs = None # The variables in the API - self.decompose_prototype(api_str) - - def _is_text(self, tok): - first_is_text = re.match("[_a-zA-Z]", tok[0]) is not None - if not first_is_text: - return False - return re.match("[_a-zA-Z0-9]+", tok) is not None - - def _clean(self, toks): - return [tok for tok in toks if tok is not None and len(tok) > 0] - - def get_arg_tuple(self, arg): - arg_toks = self._clean(re.split("[ ]|(\*+)", arg)) - if len(arg_toks) == 1: - if arg_toks[0] == '...': - type = "" - name = "..." - return (type, name) - type = " ".join(arg_toks[:-1]) - name = arg_toks[-1] - return (type, name) - - def decompose_prototype(self, api_str): - toks = self._clean(re.split("[()]|;", api_str)) - proto, args = toks[0], toks[1] - - try: - proto = self._clean(re.split("[ ]|(\*+)", proto)) - self.name = proto[-1] - self.global_name = self.name.replace("Local", "") - self.lambda_name = f"Rpc{self.global_name}" - self.ret = " ".join(proto[:-1]) - except: - print(f"Failed to decompose proto name: {proto}") - exit() - - try: - self.var_defs = [] - args = args.split(',') - for arg in args: - self.var_defs.append(self.get_arg_tuple(arg)) - except: - print(f"Failed to decompose proto args: {args}") - exit(1) - - def get_args(self): - if len(self.var_defs) == 0: - return "" - try: - args = [" ".join(arg_tuple) for arg_tuple in self.var_defs] - except: - print(f"Failed to get arg list: {self.var_defs}") - exit(1) - return ", ".join(args) - - def pass_args(self): - if self.var_defs is None: - return "" - args = [arg[-1] for arg in self.var_defs if arg[0] != ''] - return ", ".join(args) - -class RpcGenerator: - def __init__(self, modify): - if modify != "True": - self.modify = False - else: - self.modify = True - self.path = None - self.macro = None - self.context = None - self.rpcs = {} - - def set_file(self, path, class_name, context): - self.path = path - self.class_name = class_name - self.context = context - - def add(self, local_rpc_name, target_node): - if self.path not in self.rpcs: - self.rpcs[self.path] = {} - if self.class_name not in self.rpcs[self.path]: - self.rpcs[self.path][self.class_name] = [] - self.rpcs[self.path][self.class_name].append( - (local_rpc_name, target_node, self.context)) - - def generate(self): - rpc_lambdas = [] - for path, class_rpcs in self.rpcs.items(): - self.generate_class_file(path, class_rpcs, rpc_lambdas) - self.generate_rpc_file(rpc_lambdas) - - def generate_class_file(self, path, class_rpcs, rpc_lambdas): - with open(path) as fp: - class_lines = fp.read().splitlines() - rpc_map = self.get_rpcs_from_class(class_lines) - for class_name, rpcs in class_rpcs.items(): - gen_start = rpc_map[class_name]['gen_start'] - gen_end = rpc_map[class_name]['gen_end'] - space = self.get_macro_space(class_lines[gen_start]) - global_rpc_funcs = [] - for rpc in rpcs: - local_rpc_name = rpc[0] - target_node = rpc[1] - context = rpc[2] - local_rpc_api = rpc_map[class_name]['apis'][local_rpc_name] - self.create_global_rpc_func(local_rpc_api, target_node, - space, global_rpc_funcs) - self.create_rpc_lambda(local_rpc_api, context, - space, rpc_lambdas) - - class_lines = class_lines[:gen_start+1] + class_lines[gen_end:] - class_lines = class_lines[:gen_start + 1] + \ - global_rpc_funcs + \ - class_lines[gen_start + 1:] - - if self.modify: - with open(path, 'w') as fp: - fp.write("\n".join(class_lines)) - else: - tmp_path = os.path.basename(path) - with open(f"tmp_{tmp_path}", 'w') as fp: - fp.write("\n".join(class_lines)) - - def generate_rpc_file(self, rpc_lambdas): - path = "../rpc_thallium.cc" - with open(path) as fp: - rpc_lines = fp.read().splitlines() - gen_start = self.find_macro("RPC_AUTOGEN_START", rpc_lines) - gen_end = self.find_macro("RPC_AUTOGEN_END", rpc_lines) - rpc_lines = rpc_lines[:gen_start+1] + rpc_lines[gen_end:] - rpc_lines = rpc_lines[:gen_start+1] + \ - rpc_lambdas + \ - rpc_lines[gen_start+1:] - if self.modify: - with open(path, 'w') as fp: - fp.write("\n".join(rpc_lines)) - else: - tmp_path = os.path.basename(path) - with open(tmp_path, 'w') as fp: - fp.write("\n".join(rpc_lines)) - - def get_rpcs_from_class(self, class_lines): - cur_class = None - rpc_map = {} - for i, line in enumerate(class_lines): - if "class" == line.strip()[0:5]: - cur_class = self.get_class_name(line) - rpc_map[cur_class] = {'apis': {}, - 'gen_start': None, - 'gen_end': None} - elif "RPC_AUTOGEN_START" in line: - rpc_map[cur_class]['gen_start'] = i - elif "RPC_AUTOGEN_END" in line: - rpc_map[cur_class]['gen_end'] = i - elif "RPC" == line.strip()[0:3]: - text_proto = self.get_rpc_prototype(class_lines[i:]) - api = Api(text_proto) - local_rpc_name = api.name - rpc_map[cur_class]['apis'][local_rpc_name] = api - return rpc_map - - def get_class_name(self, line): - toks = re.split("[\:\*+ ]", line) - toks = [tok.strip() for tok in toks if tok is not None and len(tok)] - class_name = toks[1] - return class_name - - def get_rpc_prototype(self, lines): - proto_toks = [] - for line in lines: - proto_toks.append(line.strip()) - if ';' in line: - break - proto = " ".join(proto_toks) - return proto - - def find_macro(self, macro, lines): - for i, line in enumerate(lines): - if macro in line: - return i - - def get_macro_space(self, line): - space_len = len(line) - len(line.lstrip()) - return " " * space_len - - def add_space(self, space, text): - lines = text.splitlines() - for j, line in enumerate(lines): - lines[j] = f"{space}{line}" - return "\n".join(lines) - - def create_global_rpc_func(self, rpc, target_node, space, lines): - lines.append(rpc_func_text.format( - RET=rpc.ret, - GLOBAL_NAME=rpc.global_name, - PARAMS=rpc.get_args(), - PASS_PARAMS=rpc.pass_args(), - TARGET_NODE=target_node - ).strip()) - lines[-1] = self.add_space(space, lines[-1]) - - def create_rpc_lambda(self, rpc, context, space, lines): - lines.append(rpc_lambda_text.format( - GLOBAL_NAME=rpc.global_name, - LAMBDA_NAME=rpc.lambda_name, - CONTEXT=context, - PARAMS=rpc.get_args(), - PASS_PARAMS=rpc.pass_args(), - LOCAL_NAME=rpc.name - ).strip()) - lines[-1] = self.add_space(space, lines[-1]) - diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index e991b03c7..8ec65489a 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -21,18 +21,6 @@ namespace tl = thallium; namespace hermes { -/** copy string to character array */ -void CopyStringToCharArray(const std::string &src, char *dest, size_t max) { - size_t src_size = src.size(); - if (src_size >= max) { - LOG(WARNING) << "Can only fit " << max << " characters from the string " - << src << std::endl; - } - size_t copy_size = std::min(max - 1, src_size); - memcpy(dest, src.c_str(), copy_size); - dest[copy_size] = '\0'; -} - /** Get protocol */ std::string ThalliumRpc::GetProtocol() { std::string prefix = std::string(server_name_prefix); @@ -77,10 +65,10 @@ void ThalliumRpc::RunDaemon(const char *shmem_name) { auto prefinalize_callback = [this, &comm = comm_]() { comm->SubBarrier(); - StopPrefetcher(); - StopGlobalSystemViewStateUpdateThread(); - SubBarrier(comm); - ShutdownRpcClients(); + this->StopPrefetcher(); + this->StopGlobalSystemViewStateUpdateThread(); + comm->SubBarrier(); + ShutdownClients(); }; engine->push_prefinalize_callback(prefinalize_callback); @@ -91,42 +79,31 @@ void ThalliumRpc::RunDaemon(const char *shmem_name) { LocalShutdownBufferOrganizer(); delete engine; delete bo_engine; - ReleaseSharedMemoryContext(context); - shm_unlink(shmem_name); - HERMES_DEBUG_SERVER_CLOSE(); - DestroyArena(trans_arena); // TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 // google::ShutdownGoogleLogging(); } /** finalize client */ void ThalliumRpc::FinalizeClient(bool stop_daemon) { - SubBarrier(comm); - - if (stop_daemon && comm->first_on_node) { - ClientThalliumState *state = GetClientThalliumState(rpc); - - std::string bo_server_name = GetServerName(rpc, rpc->node_id, true); + comm_->SubBarrier(); + if (stop_daemon && comm_->first_on_node) { + std::string bo_server_name = GetServerName(node_id_, true); tl::endpoint bo_server = engine->lookup(bo_server_name); engine->shutdown_remote_engine(bo_server); - std::string server_name = GetServerName(rpc, rpc->node_id); + std::string server_name = GetServerName(node_id_, true); tl::endpoint server = engine->lookup(server_name); engine->shutdown_remote_engine(server); } - - SubBarrier(comm); - ShutdownRpcClients(rpc); - ReleaseSharedMemoryContext(context); - HERMES_DEBUG_CLIENT_CLOSE(); - DestroyArena(trans_arena); + comm_->SubBarrier(); + ShutdownClients(); // TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 // google::ShutdownGoogleLogging(); } /** get server name */ -std::string ThalliumRpc::GetServerName(u32 node_id, bool is_buffer_organizer) { +std::string ThalliumRpc::GetServerName(u32 node_id) { std::string host_name = GetHostNameFromNodeId(node_id); // TODO(chogan): @optimization Could cache the last N hostname->IP mappings to // avoid excessive syscalls. Should profile first. @@ -151,7 +128,9 @@ std::string ThalliumRpc::GetServerName(u32 node_id, bool is_buffer_organizer) { } char ip_address[INET_ADDRSTRLEN]; - const char *inet_result = inet_ntop(AF_INET, addr_list[0], ip_address, + const char *inet_result = inet_ntop(AF_INET, + addr_list[0], + ip_address, INET_ADDRSTRLEN); if (!inet_result) { FailedLibraryCall("inet_ntop"); @@ -169,721 +148,11 @@ std::string ThalliumRpc::GetServerName(u32 node_id, bool is_buffer_organizer) { return result; } -/** read bulk */ -size_t ThalliumRpc::BulkRead(u32 node_id, const char *func_name, - u8 *data, size_t max_size, BufferID id) { - std::string server_name = GetServerName(node_id, false); - std::string protocol = GetProtocol(); - - tl::engine engine(protocol, THALLIUM_CLIENT_MODE, true); - tl::remote_procedure remote_proc = engine.define(func_name); - tl::endpoint server = engine.lookup(server_name); - - std::vector> segments(1); - segments[0].first = data; - segments[0].second = max_size; - - tl::bulk bulk = engine.expose(segments, tl::bulk_mode::write_only); - size_t result = remote_proc.on(server)(bulk, id); - - return result; -} - -/** start buffer organizer */ -void ThalliumRpc::StartBufferOrganizer(const char *addr, int num_threads, - int port) { - context->bo = PushStruct(arena); - new(context->bo) BufferOrganizer(num_threads); - - ThalliumState *state = GetThalliumState(rpc); - - int num_bo_rpc_threads = 1; - bo_engine = new tl::engine(addr, THALLIUM_SERVER_MODE, true, - num_bo_rpc_threads); - tl::engine *rpc_server = bo_engine; - - std::string rpc_server_name = rpc_server->self(); - LOG(INFO) << "Buffer organizer serving at " << rpc_server_name << " with " - << num_bo_rpc_threads << " RPC threads and " << num_threads - << " BO worker threads" << std::endl; - - std::string server_name_postfix = ":" + std::to_string(port); - CopyStringToCharArray(server_name_postfix, bo_server_name_postfix, - kMaxServerNamePostfix); - - auto rpc_place_in_hierarchy = [context, rpc](const tl::request &req, - SwapBlob swap_blob, - const std::string name, - api::Context ctx) { - (void)req; - for (int i = 0; i < ctx.buffer_organizer_retries; ++i) { - LOG(INFO) << "Buffer Organizer placing blob '" << name - << "' in hierarchy. Attempt " << i + 1 << " of " - << ctx.buffer_organizer_retries << std::endl; - api::Status result = PlaceInHierarchy(context, rpc, swap_blob, name, ctx); - if (result.Succeeded()) { - break; - } else { - ThalliumState *state = GetThalliumState(rpc); - - if (state && bo_engine) { - // TODO(chogan): We probably don't want to sleep here, but for now - // this enables testing. - double sleep_ms = 2000; - tl::thread::self().sleep(*bo_engine, sleep_ms); - } - } - } - }; - - auto rpc_move_to_target = [context, rpc](const tl::request &req, - SwapBlob swap_blob, - TargetID target_id, int retries) { - (void)req; - (void)swap_blob; - (void)target_id; - for (int i = 0; i < retries; ++i) { - // TODO(chogan): MoveToTarget(context, rpc, target_id, swap_blob); - HERMES_NOT_IMPLEMENTED_YET; - } - }; - - auto rpc_enqueue_flushing_task = - [context, rpc](const tl::request &req, BlobID blob_id, - const std::string &filename, u64 offset) { - bool result = LocalEnqueueFlushingTask(context, rpc, blob_id, filename, - offset); - - req.respond(result); - }; - - auto rpc_enqueue_bo_move = [context, rpc](const tl::request &req, - const BoMoveList &moves, - BlobID blob_id, - BucketID bucket_id, - const std::string &internal_name, - BoPriority priority) { - LocalEnqueueBoMove(context, rpc, moves, blob_id, bucket_id, internal_name, - priority); - - req.respond(true); - }; - - auto rpc_organize_blob = [context, rpc](const tl::request &req, - const std::string &internal_blob_name, - BucketID bucket_id, f32 epsilon, - f32 importance_score) { - LocalOrganizeBlob(context, rpc, internal_blob_name, bucket_id, epsilon, - importance_score); - - req.respond(true); - }; - - rpc_server->define("PlaceInHierarchy", - rpc_place_in_hierarchy).disable_response(); - rpc_server->define("MoveToTarget", - rpc_move_to_target).disable_response(); - rpc_server->define("EnqueueFlushingTask", rpc_enqueue_flushing_task); - rpc_server->define("EnqueueBoMove", rpc_enqueue_bo_move); - rpc_server->define("OrganizeBlob", rpc_organize_blob); -} - -/** start prefetcher */ -void ThalliumRpc::StartPrefetcher(double sleep_ms) { - tl::engine *rpc_server = engine; - using tl::request; - - // Create the LogIoStat RPC - auto rpc_log_io_stat = [](const request &req, IoLogEntry &entry) { - auto prefetcher = Singleton::GetInstance(); - prefetcher->Log(entry); - req.respond(true); - }; - rpc_server->define("LogIoStat", rpc_log_io_stat); - - // Prefetcher thread args - struct PrefetcherThreadArgs { - SharedMemoryContext *context; - RpcContext *rpc; - double sleep_ms; - bool init_; - }; - - // Create the prefetcher thread lambda - auto prefetch = [](void *args) { - PrefetcherThreadArgs targs = *((PrefetcherThreadArgs*)args); - ThalliumState *state = GetThalliumState(targs.rpc); - LOG(INFO) << "Prefetching thread started" << std::endl; - auto prefetcher = Singleton::GetInstance(); - while (!kill_requested.load()) { - prefetcher->Process(); - tl::thread::self().sleep(*engine, targs.sleep_ms); - } - LOG(INFO) << "Finished prefetcher" << std::endl; - }; - - // Create prefetcher thread - PrefetcherThreadArgs *args = PushStruct(arena); - args->context = context; - args->rpc = rpc; - args->sleep_ms = sleep_ms; - args->init_ = false; - - ABT_xstream_create(ABT_SCHED_NULL, &execution_stream); - ABT_thread_create_on_xstream(execution_stream, - prefetch, args, - ABT_THREAD_ATTR_NULL, NULL); -} - -/** stop prefetcher */ -void ThalliumRpc::StopPrefetcher() { - kill_requested.store(true); - ABT_xstream_join(execution_stream); - ABT_xstream_free(&execution_stream); -} - -/** start global system view state update thread */ -void ThalliumRpc::StartGlobalSystemViewStateUpdateThread(double sleep_ms) { - struct ThreadArgs { - SharedMemoryContext *context; - RpcContext *rpc; - double sleep_ms; - }; - - auto update_global_system_view_state = [](void *args) { - ThreadArgs *targs = (ThreadArgs *)args; - ThalliumState *state = GetThalliumState(targs->rpc); - LOG(INFO) << "Update global system view state start" << std::endl; - while (!kill_requested.load()) { - UpdateGlobalSystemViewState(targs->context, targs->rpc); - tl::thread::self().sleep(*engine, targs->sleep_ms); - } - LOG(INFO) << "Finished global system view update thread" << std::endl; - }; - - ThreadArgs *args = PushStruct(arena); - args->context = context; - args->rpc = rpc; - args->sleep_ms = sleep_ms; - - ThalliumState *state = GetThalliumState(rpc); - ABT_thread_create_on_xstream(execution_stream, - update_global_system_view_state, args, - ABT_THREAD_ATTR_NULL, NULL); -} - -/** stop global system view state update thread */ -void ThalliumRpc::StopGlobalSystemViewStateUpdateThread() { - ThalliumState *state = GetThalliumState(rpc); - kill_requested.store(true); - ABT_xstream_join(execution_stream); - ABT_xstream_free(&execution_stream); -} - /** start Thallium RPC server */ void ThalliumRpc::StartServer(const char *addr, i32 num_rpc_threads) { - ThalliumState *state = GetThalliumState(rpc); - engine = new tl::engine(addr, THALLIUM_SERVER_MODE, true, - num_rpc_threads); - - tl::engine *rpc_server = engine; - - std::string rpc_server_name = rpc_server->self(); - LOG(INFO) << "Serving at " << rpc_server_name << " with " - << num_rpc_threads << " RPC threads" << std::endl; - - size_t end_of_protocol = rpc_server_name.find_first_of(":"); - std::string server_name_prefix = - rpc_server_name.substr(0, end_of_protocol) + "://"; - CopyStringToCharArray(server_name_prefix, server_name_prefix, - kMaxServerNamePrefix); - - std::string server_name_postfix = ":" + std::to_string(rpc->port); - CopyStringToCharArray(server_name_postfix, server_name_postfix, - kMaxServerNamePostfix); - - using std::function; - using std::string; - using std::vector; - using tl::request; - RPC_AUTOGEN_START - auto RpcGetBufferInfo = [borg](const request &req, BufferID buffer_id) { - auto result = borg->LocalGetBufferInfo(buffer_id); - req.respond(result); - }; - rpc_server->define("GetBufferInfo", rpc_get_buffers); - auto RpcEnqueueBoMove = [borg](const request &req, const BoMoveList &moves, BlobID blob_id, BucketID bucket_id, const std::string &internal_blob_name, BoPriority priority) { - auto result = borg->LocalEnqueueBoMove(&moves, blob_id, bucket_id, &internal_blob_name, priority); - req.respond(result); - }; - rpc_server->define("EnqueueBoMove", rpc_get_buffers); - auto RpcOrganizeBlob = [borg](const request &req, const std::string &internal_blob_name, BucketID bucket_id, f32 epsilon, f32 explicit_importance_score) { - auto result = borg->LocalOrganizeBlob(&internal_blob_name, bucket_id, epsilon, explicit_importance_score); - req.respond(result); - }; - rpc_server->define("OrganizeBlob", rpc_get_buffers); - auto RpcEnforceCapacityThresholds = [borg](const request &req, ViolationInfo info) { - auto result = borg->LocalEnforceCapacityThresholds(info); - req.respond(result); - }; - rpc_server->define("EnforceCapacityThresholds", rpc_get_buffers); - auto RpcEnqueueFlushingTask = [borg](const request &req, BlobID blob_id, const std::string &filename, u64 offset) { - auto result = borg->LocalEnqueueFlushingTask(blob_id, &filename, offset); - req.respond(result); - }; - rpc_server->define("EnqueueFlushingTask", rpc_get_buffers); - auto RpcIncrementFlushCount = [borg](const request &req, const std::string &vbkt_name) { - auto result = borg->LocalIncrementFlushCount(&vbkt_name); - req.respond(result); - }; - rpc_server->define("IncrementFlushCount", rpc_get_buffers); - auto RpcDecrementFlushCount = [borg](const request &req, const std::string &vbkt_name) { - auto result = borg->LocalDecrementFlushCount(&vbkt_name); - req.respond(result); - }; - rpc_server->define("DecrementFlushCount", rpc_get_buffers); RPC_AUTOGEN_END - - - // BufferPool requests - - auto rpc_get_buffers = - [context](const request &req, const PlacementSchema &schema) { - std::vector result = GetBuffers(context, schema); - req.respond(result); - }; - - auto rpc_release_buffer = [context](const request &req, BufferID id) { - LocalReleaseBuffer(context, id); - req.respond(true); - }; - - auto rpc_split_buffers = [context](const request &req, int slab_index) { - (void)req; - SplitRamBufferFreeList(context, slab_index); - }; - - auto rpc_merge_buffers = [context](const request &req, int slab_index) { - (void)req; - MergeRamBufferFreeList(context, slab_index); - }; - - auto rpc_get_buffer_size = [context](const request &req, BufferID id) { - u32 result = LocalGetBufferSize(context, id); - - req.respond(result); - }; - - auto rpc_write_buffer_by_id = - [context](const request &req, BufferID id, std::vector data, - size_t offset) { - Blob blob = {}; - blob.size = data.size(); - blob.data = data.data(); - size_t result = LocalWriteBufferById(context, id, blob, offset); - - req.respond(result); - }; - - auto rpc_read_buffer_by_id = [context](const request &req, BufferID id) { - BufferHeader *header = GetHeaderByBufferId(context, id); - std::vector result(header->used); - Blob blob = {}; - blob.size = result.size(); - blob.data = result.data(); - [[maybe_unused]] size_t bytes_read = LocalReadBufferById(context, id, - &blob, 0); - assert(bytes_read == result.size()); - - req.respond(result); - }; - - auto rpc_bulk_read_buffer_by_id = - [context, rpc_server, arena](const request &req, tl::bulk &bulk, - BufferID id) { - tl::endpoint endpoint = req.get_endpoint(); - BufferHeader *header = GetHeaderByBufferId(context, id); - ScopedTemporaryMemory temp_memory(arena); - - u8 *buffer_data = 0; - size_t size = header->used; - - if (BufferIsByteAddressable(context, id)) { - buffer_data = GetRamBufferPtr(context, id); - } else { - // TODO(chogan): Probably need a way to lock the trans_arena. Currently - // an assertion will fire if multiple threads try to use it at once. - if (size > GetRemainingCapacity(temp_memory)) { - // TODO(chogan): Need to transfer in a loop if we don't have enough - // temporary memory available - HERMES_NOT_IMPLEMENTED_YET; - } - buffer_data = PushSize(temp_memory, size); - Blob blob = {}; - blob.data = buffer_data; - blob.size = size; - size_t read_offset = 0; - LocalReadBufferById(context, id, &blob, read_offset); - } - - std::vector> segments(1); - segments[0].first = buffer_data; - segments[0].second = size; - tl::bulk local_bulk = rpc_server->expose(segments, - tl::bulk_mode::read_only); - - size_t bytes_read = local_bulk >> bulk.on(endpoint); - // TODO(chogan): @errorhandling - assert(bytes_read == size); - - req.respond(bytes_read); - }; - - // Metadata requests - - auto rpc_map_get = - [context](const request &req, string name, const MapType &map_type) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - u64 result = LocalGet(mdm, name.c_str(), map_type); - - req.respond(result); - }; - - auto rpc_map_put = - [context](const request &req, const string &name, u64 val, - const MapType &map_type) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalPut(mdm, name.c_str(), val, map_type); - req.respond(true); - }; - - auto rpc_map_delete = - [context](const request &req, string name, const MapType &map_type) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalDelete(mdm, name.c_str(), map_type); - req.respond(true); - }; - - auto rpc_add_blob_bucket = - [context](const request &req, BucketID bucket_id, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalAddBlobIdToBucket(mdm, bucket_id, blob_id); - req.respond(true); - }; - - auto rpc_add_blob_vbucket = - [context](const request &req, VBucketID vbucket_id, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalAddBlobIdToVBucket(mdm, vbucket_id, blob_id); - req.respond(true); - }; - - auto rpc_get_buffer_id_list = - [context](const request &req, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - std::vector result = LocalGetBufferIdList(mdm, blob_id); - - req.respond(result); - }; - - auto rpc_free_buffer_id_list = [context](const request &req, BlobID blob_id) { - LocalFreeBufferIdList(context, blob_id); - req.respond(true); - }; - - auto rpc_destroy_bucket = - [context, rpc](const request &req, const string &name, BucketID id) { - bool result = LocalDestroyBucket(context, rpc, name.c_str(), id); - - req.respond(result); - }; - - auto rpc_destroy_vbucket = - [context](const request &req, const string &name, VBucketID id) { - bool result = LocalDestroyVBucket(context, name.c_str(), id); - req.respond(result); - }; - - auto rpc_get_or_create_bucket_id = - [context](const request &req, const std::string &name) { - BucketID result = LocalGetOrCreateBucketId(context, name); - - req.respond(result); - }; - - auto rpc_get_or_create_vbucket_id = - [context](const request &req, std::string &name) { - VBucketID result = LocalGetOrCreateVBucketId(context, name); - - req.respond(result); - }; - - auto rpc_allocate_buffer_id_list = - [context](const request &req, const vector &buffer_ids) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - u32 result = LocalAllocateBufferIdList(mdm, buffer_ids); - - req.respond(result); - }; - - auto rpc_rename_bucket = - [context, rpc](const request &req, BucketID id, const string &old_name, - const string &new_name) { - LocalRenameBucket(context, rpc, id, old_name, new_name); - req.respond(true); - }; - - auto rpc_destroy_blob_by_name = - [context, rpc](const request &req, const string &name, BlobID id, - BucketID bucket_id) { - LocalDestroyBlobByName(context, rpc, name.c_str(), id, bucket_id); - req.respond(true); - }; - - auto rpc_destroy_blob_by_id = - [context, rpc](const request &req, BlobID id, BucketID bucket_id) { - LocalDestroyBlobById(context, rpc, id, bucket_id); - req.respond(true); - }; - - auto rpc_contains_blob = - [context](const request &req, BucketID bucket_id, BlobID blob_id) { - bool result = LocalContainsBlob(context, bucket_id, blob_id); - req.respond(result); - }; - - auto rpc_remove_blob_from_bucket_info = - [context](const request &req, BucketID bucket_id, BlobID blob_id) { - LocalRemoveBlobFromBucketInfo(context, bucket_id, blob_id); - req.respond(true); - }; - - auto rpc_decrement_refcount_bucket = - [context](const request &req, BucketID id) { - LocalDecrementRefcount(context, id); - req.respond(true); - }; - - auto rpc_decrement_refcount_vbucket = - [context](const request &req, VBucketID id) { - LocalDecrementRefcount(context, id); - req.respond(true); - }; - - auto rpc_get_global_device_capacities = [context](const request &req) { - std::vector result = LocalGetGlobalDeviceCapacities(context); - - req.respond(result); - }; - - auto rpc_get_remaining_capacity = [context](const request &req, TargetID id) { - u64 result = LocalGetRemainingTargetCapacity(context, id); - - req.respond(result); - }; - - auto rpc_update_global_system_view_state = - [context, rpc](const request &req, std::vector adjustments) { - std::vector result = - LocalUpdateGlobalSystemViewState(context, rpc->node_id, adjustments); - - req.respond(result); - }; - - auto rpc_get_blob_ids = [context](const request &req, BucketID bucket_id) { - std::vector result = LocalGetBlobIds(context, bucket_id); - - req.respond(result); - }; - - auto rpc_get_node_targets = [context](const request &req) { - std::vector result = LocalGetNodeTargets(context); - - req.respond(result); - }; - - auto rpc_get_bucket_id_from_blob_id = - [context](const request &req, BlobID id) { - BucketID result = LocalGetBucketIdFromBlobId(context, id); - - req.respond(result); - }; - - auto rpc_get_blob_name_from_id = [context](const request &req, BlobID id) { - std::string result = LocalGetBlobNameFromId(context, id); - - req.respond(result); - }; - - auto rpc_finalize = [rpc](const request &req) { - (void)req; - ThalliumState *state = GetThalliumState(rpc); - engine->finalize(); - }; - - auto rpc_remove_blob_from_vbucket_info = [context](const request &req, - VBucketID vbucket_id, - BlobID blob_id) { - LocalRemoveBlobFromVBucketInfo(context, vbucket_id, blob_id); - - req.respond(true); - }; - - auto rpc_get_blobs_from_vbucket_info = [context](const request &req, - VBucketID vbucket_id) { - auto ret = LocalGetBlobsFromVBucketInfo(context, vbucket_id); - - req.respond(ret); - }; - - auto rpc_get_bucket_name_by_id = [context](const request &req, BucketID id) { - auto ret = LocalGetBucketNameById(context, id); - - req.respond(ret); - }; - - auto rpc_increment_blob_stats = - [context](const request &req, BlobID blob_id) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalIncrementBlobStats(mdm, blob_id); - - req.respond(true); - }; - - auto rpc_get_blob_importance_score = - [context](const request &req, BlobID blob_id) { - f32 result = LocalGetBlobImportanceScore(context, blob_id); - - req.respond(result); - }; - - auto rpc_increment_flush_count = [context](const request &req, - const std::string &name) { - LocalIncrementFlushCount(context, name); - - req.respond(true); - }; - - auto rpc_decrement_flush_count = [context](const request &req, - const std::string &name) { - LocalDecrementFlushCount(context, name); - - req.respond(true); - }; - - auto rpc_get_num_outstanding_flushing_tasks = - [context](const request &req, VBucketID id) { - int result = LocalGetNumOutstandingFlushingTasks(context, id); - - req.respond(result); - }; - - auto rpc_lock_blob = [context](const request &req, BlobID id) { - bool result = LocalLockBlob(context, id); - - req.respond(result); - }; - - auto rpc_unlock_blob = [context](const request &req, BlobID id) { - bool result = LocalUnlockBlob(context, id); - - req.respond(result); - }; - - auto rpc_create_blob_metadata = - [context](const request &req, const std::string &blob_name, - BlobID blob_id, TargetID effective_target) { - MetadataManager *mdm = GetMetadataManagerFromContext(context); - LocalCreateBlobMetadata(context, mdm, blob_name, blob_id, - effective_target); - - req.respond(true); - }; - - auto rpc_replace_blob_id_in_bucket = [context](const request &req, - BucketID bucket_id, - BlobID old_blob_id, - BlobID new_blob_id) { - LocalReplaceBlobIdInBucket(context, bucket_id, old_blob_id, new_blob_id); - req.respond(true); - }; - - auto rpc_enforce_capacity_thresholds = [context, rpc](const request &req, - ViolationInfo info) { - LocalEnforceCapacityThresholds(info); - // TODO(chogan): Can this be async? - req.respond(true); - }; - - // TODO(chogan): Currently these three are only used for testing. - rpc_server->define("GetBuffers", rpc_get_buffers); - rpc_server->define("SplitBuffers", rpc_split_buffers).disable_response(); - rpc_server->define("MergeBuffers", rpc_merge_buffers).disable_response(); - // - - rpc_server->define("RemoteReleaseBuffer", rpc_release_buffer); - rpc_server->define("RemoteGetBufferSize", rpc_get_buffer_size); - - rpc_server->define("RemoteReadBufferById", rpc_read_buffer_by_id); - rpc_server->define("RemoteWriteBufferById", rpc_write_buffer_by_id); - rpc_server->define("RemoteBulkReadBufferById", rpc_bulk_read_buffer_by_id); - - rpc_server->define("RemoteGet", rpc_map_get); - rpc_server->define("RemotePut", rpc_map_put); - rpc_server->define("RemoteDelete", rpc_map_delete); - rpc_server->define("RemoteAddBlobIdToBucket", rpc_add_blob_bucket); - rpc_server->define("RemoteAddBlobIdToVBucket", rpc_add_blob_vbucket); - rpc_server->define("RemoteDestroyBucket", rpc_destroy_bucket); - rpc_server->define("RemoteDestroyVBucket", rpc_destroy_vbucket); - rpc_server->define("RemoteRenameBucket", rpc_rename_bucket); - rpc_server->define("RemoteDestroyBlobByName", rpc_destroy_blob_by_name); - rpc_server->define("RemoteDestroyBlobById", rpc_destroy_blob_by_id); - rpc_server->define("RemoteContainsBlob", rpc_contains_blob); - rpc_server->define("RemoteRemoveBlobFromBucketInfo", - rpc_remove_blob_from_bucket_info); - rpc_server->define("RemoteAllocateBufferIdList", rpc_allocate_buffer_id_list); - rpc_server->define("RemoteGetBufferIdList", rpc_get_buffer_id_list); - rpc_server->define("RemoteFreeBufferIdList", rpc_free_buffer_id_list); - rpc_server->define("RemoteGetOrCreateBucketId", rpc_get_or_create_bucket_id); - rpc_server->define("RemoteGetOrCreateVBucketId", - rpc_get_or_create_vbucket_id); - rpc_server->define("RemoteDecrementRefcount", rpc_decrement_refcount_bucket); - rpc_server->define("RemoteDecrementRefcountVBucket", - rpc_decrement_refcount_vbucket); - rpc_server->define("RemoteGetRemainingTargetCapacity", - rpc_get_remaining_capacity); - rpc_server->define("RemoteUpdateGlobalSystemViewState", - rpc_update_global_system_view_state); - rpc_server->define("RemoteGetGlobalDeviceCapacities", - rpc_get_global_device_capacities); - rpc_server->define("RemoteGetBlobIds", rpc_get_blob_ids); - rpc_server->define("RemoteGetNodeTargets", rpc_get_node_targets); - rpc_server->define("RemoteGetBucketIdFromBlobId", - rpc_get_bucket_id_from_blob_id); - rpc_server->define("RemoteGetBlobNameFromId", rpc_get_blob_name_from_id); - rpc_server->define("RemoteFinalize", rpc_finalize).disable_response(); - rpc_server->define("RemoteRemoveBlobFromVBucketInfo", - rpc_remove_blob_from_vbucket_info); - rpc_server->define("RemoteGetBlobsFromVBucketInfo", - rpc_get_blobs_from_vbucket_info); - rpc_server->define("RemoteGetBucketNameById", - rpc_get_bucket_name_by_id); - rpc_server->define("RemoteIncrementBlobStats", rpc_increment_blob_stats); - rpc_server->define("RemoteGetBlobImportanceScore", - rpc_get_blob_importance_score); - rpc_server->define("RemoteIncrementFlushCount", rpc_increment_flush_count); - rpc_server->define("RemoteDecrementFlushCount", rpc_decrement_flush_count); - rpc_server->define("RemoteGetNumOutstandingFlushingTasks", - rpc_get_num_outstanding_flushing_tasks); - rpc_server->define("RemoteLockBlob", rpc_lock_blob); - rpc_server->define("RemoteUnlockBlob", rpc_unlock_blob); - rpc_server->define("RemoteCreateBlobMetadata", rpc_create_blob_metadata); - rpc_server->define("RemoteReplaceBlobIdInBucket", - rpc_replace_blob_id_in_bucket); - rpc_server->define("RemoteEnforceCapacityThresholds", - rpc_enforce_capacity_thresholds); } } // namespace hermes \ No newline at end of file diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index a5cb2c543..699ab7548 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -23,6 +23,7 @@ #include #include +#include "rpc.h" #include "buffer_organizer.h" namespace tl = thallium; @@ -72,54 +73,15 @@ class ThalliumRpc : public RpcContext { tl::engine *client_engine_; /**< pointer to engine */ /** initialize RPC context */ - explicit ThalliumRpc(CommunicationContext *comm, - SharedMemoryContext *context, + explicit ThalliumRpc(COMM_TYPE *comm, u32 num_nodes, u32 node_id, Config *config) : - RpcContext(comm, context, num_nodes, node_id, config) { + RpcContext(comm, num_nodes, node_id, config) { } /** Get protocol */ std::string GetProtocol(); - /** initialize RPC clients */ - void InitClients(); - /** shut down RPC clients */ - void ShutdownClients(); - - /** finalize RPC context */ - void Finalize(bool is_daemon); - - /** run daemon */ - void RunDaemon(const char *shmem_name); - - /** finalize client */ - void FinalizeClient(bool stop_daemon); - - /** get server name */ - std::string GetServerName(u32 node_id, bool is_buffer_organizer); - - /** read bulk */ - size_t BulkRead(u32 node_id, const char *func_name, - u8 *data, size_t max_size, BufferID id); - - /** start Thallium RPC server */ - void StartServer(const char *addr, i32 num_rpc_threads); - - /** start buffer organizer */ - void StartBufferOrganizer(const char *addr, int num_threads, int port); - - /** start prefetcher */ - void StartPrefetcher(double sleep_ms); - - /** stop prefetcher */ - void StopPrefetcher(); - - /** start global system view state update thread */ - void StartGlobalSystemViewStateUpdateThread(double sleep_ms); - - /** stop global system view state update thread */ - void StopGlobalSystemViewStateUpdateThread(); /** RPC call */ template @@ -149,19 +111,6 @@ class ThalliumRpc : public RpcContext { } }; -/** - * Lets Thallium know how to serialize a BufferID. - * - * This function is called implicitly by Thallium. - * - * @param ar An archive provided by Thallium. - * @param buffer_id The BufferID to serialize. - */ -template -void serialize(A &ar, BufferID &buffer_id) { - ar &buffer_id.as_int; -} - /** * Lets Thallium know how to serialize a BucketID. * @@ -214,19 +163,10 @@ void serialize(A &ar, TargetID &target_id) { ar &target_id.as_int; } -/** serialize \a swap_blob */ -template -void serialize(A &ar, SwapBlob &swap_blob) { - ar &swap_blob.node_id; - ar &swap_blob.offset; - ar &swap_blob.size; - ar &swap_blob.bucket_id; -} - /** serialize \a info */ template void serialize(A &ar, BufferInfo &info) { - ar &info.id; + ar &info.target_; ar &info.bandwidth_mbps; ar &info.size; } @@ -237,35 +177,6 @@ void serialize(A &ar, BufferInfo &info) { // default so we must write serialization code for all enums when we're not // using cereal. -/** - * Lets Thallium know how to serialize a MapType. - * - * This function is called implicitly by Thallium. - * - * @param ar An archive provided by Thallium. - * @param map_type The MapType to serialize. - */ -template -void save(A &ar, MapType &map_type) { - int val = (int)map_type; - ar.write(&val, 1); -} - -/** - * Lets Thallium know how to serialize a MapType. - * - * This function is called implicitly by Thallium. - * - * @param ar An archive provided by Thallium. - * @param map_type The MapType to serialize. - */ -template -void load(A &ar, MapType &map_type) { - int val = 0; - ar.read(&val, 1); - map_type = (MapType)val; -} - /** save \a priority */ template void save(A &ar, BoPriority &priority) { @@ -282,19 +193,19 @@ void load(A &ar, BoPriority &priority) { } /** save \a violation */ -template +/* template void save(A &ar, ThresholdViolation &violation) { int val = (int)violation; ar.write(&val, 1); -} +} */ /** load \a violation */ -template +/* template void load(A &ar, ThresholdViolation &violation) { int val = 0; ar.read(&val, 1); violation = (ThresholdViolation)val; -} +} */ #endif // #ifndef THALLIUM_USE_CEREAL /** save buffer organizer \a op */ @@ -312,27 +223,19 @@ void load(A &ar, BoOperation &op) { op = (BoOperation)val; } -/** serialize buffer organizer arguments */ -template -void serialize(A &ar, BoArgs &bo_args) { - ar &bo_args.move_args.src; - ar &bo_args.move_args.dest; -} - /** serialize buffer organizer task */ template void serialize(A &ar, BoTask &bo_task) { ar &bo_task.op; - ar &bo_task.args; } /** serialize violation information */ -template +/*template void serialize(A &ar, ViolationInfo &info) { ar &info.target_id; ar &info.violation; ar &info.violation_size; -} +}*/ namespace api { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 61654d4b4..af6bacfcf 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -83,7 +83,7 @@ target_link_libraries(config_parser_test hermes $<$:thallium> glog::glog) add_test(NAME TestConfigParser - COMMAND config_parser_test ${CMAKE_CURRENT_SOURCE_DIR}/data/hermes.yaml) + COMMAND config_parser_test ${CMAKE_CURRENT_SOURCE_DIR}/data/hermes_server.yaml) target_compile_definitions(config_parser_test PRIVATE $<$:HERMES_RPC_THALLIUM>) diff --git a/test/bucket_test.cc b/test/bucket_test.cc deleted file mode 100644 index 484ad82ee..000000000 --- a/test/bucket_test.cc +++ /dev/null @@ -1,280 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include -#include "zlib.h" - -#include "hermes.h" -#include "bucket.h" -#include "vbucket.h" -#include "test_utils.h" - -namespace hapi = hermes::api; -using HermesPtr = std::shared_ptr; - -HermesPtr hermes_app; - -int compress_blob(HermesPtr hermes, hapi::TraitInput &input, - hapi::Trait *trait); -struct MyTrait : public hapi::Trait { - int compress_level; - MyTrait() : hapi::Trait(10001, std::vector(), - hapi::TraitType::META) { - onLinkFn = std::bind(&compress_blob, std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3); - } - - // optional function pointer if only known at runtime -}; - -void add_buffer_to_vector(hapi::Blob &vector, const char *buffer, - uLongf length) { - for (uLongf character_index = 0; character_index < length; - character_index++) { - char current_character = buffer[character_index]; - vector.push_back(current_character); - } -} - -// The Trait implementer must define callbacks that match the VBucket::TraitFunc -// type. -int compress_blob(HermesPtr hermes, hapi::TraitInput &input, - hapi::Trait *trait) { - (void)hermes; - MyTrait *my_trait = (MyTrait *)trait; - - hapi::Bucket bkt(input.bucket_name, hermes_app); - hapi::Blob blob = {}; - size_t blob_size = bkt.Get(input.blob_name, blob); - blob.resize(blob_size); - bkt.Get(input.blob_name, blob); - // If Hermes is already linked with a compression library, you can call the - // function directly here. If not, the symbol will have to be dynamically - // loaded and probably stored as a pointer in the Trait. - uLongf source_length = blob.size(); - uLongf destination_length = compressBound(source_length); - char *destination_data = new char[destination_length]; - - LOG(INFO) << "Compressing blob\n"; - - if (destination_data == nullptr) - return Z_MEM_ERROR; - - int return_value = compress2((Bytef *) destination_data, - &destination_length, (Bytef *) blob.data(), - source_length, my_trait->compress_level); - hapi::Blob destination {0}; - // TODO(KIMMY): where to store compressed data - add_buffer_to_vector(destination, destination_data, destination_length); - delete [] destination_data; - - return return_value; -} - - -void TestBucketPersist(HermesPtr hermes) { - constexpr int bytes_per_blob = KILOBYTES(3); - constexpr int num_blobs = 3; - constexpr int total_bytes = num_blobs * bytes_per_blob; - - hapi::Status status; - hapi::Blob blobx(bytes_per_blob, 'x'); - hapi::Blob bloby(bytes_per_blob, 'y'); - hapi::Blob blobz(bytes_per_blob, 'z'); - hapi::Bucket bkt("persistent_bucket", hermes); - status = bkt.Put("blobx", blobx); - Assert(status.Succeeded()); - status = bkt.Put("bloby", bloby); - Assert(status.Succeeded()); - status = bkt.Put("blobz", blobz); - Assert(status.Succeeded()); - - std::string saved_file("blobsxyz.txt"); - bkt.Persist(saved_file); - bkt.Destroy(); - Assert(!bkt.IsValid()); - - FILE *bkt_file = fopen(saved_file.c_str(), "r"); - Assert(bkt_file); - - hermes::u8 read_buffer[total_bytes] = {}; - Assert(fread(read_buffer, 1, total_bytes, bkt_file) == total_bytes); - - for (int offset = 0; offset < num_blobs; ++offset) { - for (int i = offset * bytes_per_blob; - i < bytes_per_blob * (offset + 1); - ++i) { - char expected = '\0'; - switch (offset) { - case 0: { - expected = 'x'; - break; - } - case 1: { - expected = 'y'; - break; - } - case 2: { - expected = 'z'; - break; - } - default: { - HERMES_INVALID_CODE_PATH; - } - } - Assert(read_buffer[i] == expected); - } - } - - Assert(std::remove(saved_file.c_str()) == 0); -} - -void TestPutOverwrite(HermesPtr hermes) { - hapi::Bucket bucket("overwrite", hermes); - - std::string blob_name("1"); - size_t blob_size = KILOBYTES(6); - hapi::Blob blob(blob_size, 'x'); - hapi::Status status = bucket.Put(blob_name, blob); - Assert(status.Succeeded()); - - hermes::testing::GetAndVerifyBlob(bucket, blob_name, blob); - - // NOTE(chogan): Overwrite the data - size_t new_size = KILOBYTES(9); - hapi::Blob new_blob(new_size, 'z'); - status = bucket.Put(blob_name, new_blob); - Assert(status.Succeeded()); - - hermes::testing::GetAndVerifyBlob(bucket, blob_name, new_blob); - - bucket.Destroy(); -} - -void TestCompressionTrait(HermesPtr hermes) { - hapi::Status status; - - const std::string bucket_name = "compression"; - hapi::Bucket my_bucket(bucket_name, hermes); - hapi::Blob p1(1024*1024*1, 255); - hapi::Blob p2(p1); - - const std::string blob1_name = "Blob1"; - const std::string blob2_name = "Blob2"; - Assert(my_bucket.Put(blob1_name, p1).Succeeded()); - Assert(my_bucket.Put(blob2_name, p2).Succeeded()); - - Assert(my_bucket.ContainsBlob(blob1_name)); - Assert(my_bucket.ContainsBlob(blob2_name)); - - const std::string vbucket_name = "VB1"; - hapi::VBucket my_vb(vbucket_name, hermes); - my_vb.Link(blob1_name, bucket_name); - my_vb.Link(blob2_name, bucket_name); - - Assert(my_vb.ContainsBlob(blob1_name, bucket_name) == 1); - Assert(my_vb.ContainsBlob(blob2_name, bucket_name) == 1); - - MyTrait trait; - trait.compress_level = 6; - // Compression Trait compresses all blobs on Attach - Assert(my_vb.Attach(&trait).Succeeded()); - - Assert(my_vb.Unlink(blob1_name, bucket_name).Succeeded()); - Assert(my_vb.Detach(&trait).Succeeded()); - - Assert(my_vb.Destroy().Succeeded()); - Assert(my_bucket.Destroy().Succeeded()); -} - -void TestMultiGet(HermesPtr hermes) { - const size_t num_blobs = 4; - const int blob_size = KILOBYTES(4); - - std::vector blob_names(num_blobs); - for (size_t i = 0; i < num_blobs; ++i) { - blob_names[i]= "Blob" + std::to_string(i); - } - - std::vector blobs(num_blobs); - for (size_t i = 0; i < num_blobs; ++i) { - blobs[i] = hapi::Blob(blob_size, (char)i); - } - - hapi::Context ctx; - const std::string bucket_name = "b1"; - hapi::Bucket bucket(bucket_name, hermes, ctx); - - for (size_t i = 0; i < num_blobs; ++i) { - Assert(bucket.Put(blob_names[i], blobs[i], ctx).Succeeded()); - } - - std::vector retrieved_blobs(num_blobs); - std::vector sizes = bucket.Get(blob_names, retrieved_blobs, ctx); - - for (size_t i = 0; i < num_blobs; ++i) { - retrieved_blobs[i].resize(sizes[i]); - } - - sizes = bucket.Get(blob_names, retrieved_blobs, ctx); - for (size_t i = 0; i < num_blobs; ++i) { - Assert(blobs[i] == retrieved_blobs[i]); - Assert(sizes[i] == retrieved_blobs[i].size()); - } - - // Test Get into user buffer - hermes::u8 user_buffer[blob_size] = {}; - size_t b1_size = bucket.Get(blob_names[0], nullptr, 0, ctx); - Assert(b1_size == blob_size); - b1_size = bucket.Get(blob_names[0], user_buffer, b1_size, ctx); - - for (size_t i = 0; i < b1_size; ++i) { - Assert(user_buffer[i] == blobs[0][i]); - } - - bucket.Destroy(ctx); -} - -int main(int argc, char **argv) { - int mpi_threads_provided; - MPI_Init_thread(NULL, NULL, MPI_THREAD_MULTIPLE, &mpi_threads_provided); - if (mpi_threads_provided < MPI_THREAD_MULTIPLE) { - fprintf(stderr, "Didn't receive appropriate MPI threading specification\n"); - return 1; - } - - char *config_file = 0; - if (argc == 2) { - config_file = argv[1]; - } - - hermes_app = hapi::InitHermes(config_file); - - if (hermes_app->IsApplicationCore()) { - TestCompressionTrait(hermes_app); - TestBucketPersist(hermes_app); - TestPutOverwrite(hermes_app); - TestMultiGet(hermes_app); - } else { - // Hermes core. No user code here. - } - - hermes_app->Finalize(); - - MPI_Finalize(); - - return 0; -} diff --git a/test/buffer_organizer_test.cc b/test/buffer_organizer_test.cc deleted file mode 100644 index 21c4b891e..000000000 --- a/test/buffer_organizer_test.cc +++ /dev/null @@ -1,388 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -#include - -#include "hermes.h" -#include "vbucket.h" -#include "metadata_management_internal.h" -#include "buffer_pool_internal.h" -#include "test_utils.h" - - -namespace hapi = hermes::api; -using HermesPtr = std::shared_ptr; -using hermes::u8; -using hermes::f32; -using hermes::u64; -using hermes::SharedMemoryContext; -using hermes::RpcContext; -using hermes::BoTask; -using hermes::BufferID; -using hermes::TargetID; -using hermes::BucketID; -using hermes::BlobID; -using hermes::BufferInfo; -using hapi::VBucket; -using hapi::Bucket; - -static void TestIsBoFunction() { - using hermes::IsBoFunction; - Assert(IsBoFunction("BO::TriggerBufferOrganizer")); - Assert(IsBoFunction("BO::A")); - Assert(IsBoFunction("BO::")); - Assert(!IsBoFunction("")); - Assert(!IsBoFunction("A")); - Assert(!IsBoFunction("BO:")); - Assert(!IsBoFunction("BO:A")); - Assert(!IsBoFunction("TriggerBufferOrganizer")); -} - -static void TestBackgroundFlush() { - HermesPtr hermes = hermes::InitHermesDaemon(); - const int io_size = KILOBYTES(4); - const int iters = 4; - const int total_bytes = io_size * iters; - std::string final_destination = "./test_background_flush.out"; - std::string bkt_name = "background_flush"; - hapi::Bucket bkt(bkt_name, hermes); - hapi::VBucket vbkt(bkt_name, hermes); - - hapi::PersistTrait persist_trait(final_destination, {}, false); - vbkt.Attach(&persist_trait); - - std::vector data(iters); - std::iota(data.begin(), data.end(), 'a'); - - for (int i = 0; i < iters; ++i) { - hapi::Blob blob(io_size, data[i]); - std::string blob_name = std::to_string(i); - bkt.Put(blob_name, blob); - - persist_trait.offset_map.emplace(blob_name, i * io_size); - vbkt.Link(blob_name, bkt_name); - } - - vbkt.Destroy(); - bkt.Destroy(); - - hermes->Finalize(true); - - // NOTE(chogan): Verify that file is on disk with correct data - FILE *fh = fopen(final_destination.c_str(), "r"); - Assert(fh); - - std::vector result(total_bytes, 0); - size_t bytes_read = fread(result.data(), 1, total_bytes, fh); - Assert(bytes_read == total_bytes); - - for (int i = 0; i < iters; ++i) { - for (int j = 0; j < io_size; ++j) { - int index = i * io_size + j; - Assert(result[index] == data[i]); - } - } - - Assert(fclose(fh) == 0); - Assert(std::remove(final_destination.c_str()) == 0); -} - -static void PutThenMove(HermesPtr hermes, bool move_up) { - SharedMemoryContext *context = &hermes->context_; - RpcContext *rpc = &hermes->rpc_; - - std::string bkt_name = - "BoMove" + (move_up ? std::string("Up") : std::string("Down")); - hapi::Bucket bkt(bkt_name, hermes); - - size_t blob_size = KILOBYTES(20); - std::string blob_name = "1"; - hapi::Blob blob(blob_size, (move_up ? 'z' : 'a')); - hapi::Status status = bkt.Put(blob_name, blob); - Assert(status.Succeeded()); - - BucketID bucket_id = {}; - bucket_id.as_int = bkt.GetId(); - BlobID old_blob_id = GetBlobId(context, rpc, blob_name, bucket_id, false); - Assert(!IsNullBlobId(old_blob_id)); - std::vector old_buffer_ids = GetBufferIdList(context, rpc, - old_blob_id); - Assert(old_buffer_ids.size() > 0); - std::vector old_buffer_info = GetBufferInfo(context, rpc, - old_buffer_ids); - Assert(old_buffer_info.size() == old_buffer_ids.size()); - - f32 old_access_score = ComputeBlobAccessScore(context, old_buffer_info); - Assert(old_access_score == (move_up ? 0 : 1)); - - BufferID src = old_buffer_ids[0]; - hermes::BufferHeader *header = GetHeaderByBufferId(context, src); - Assert(header); - - std::vector targets = LocalGetNodeTargets(context); - hermes::PlacementSchema schema; - int target_index = move_up ? 0 : (targets.size() - 1); - schema.push_back(std::pair(header->used, targets[target_index])); - - std::vector destinations = hermes::GetBuffers(context, schema); - Assert(destinations.size()); - - hermes::BoMoveList moves; - moves.push_back(std::pair(src, destinations)); - std::string internal_blob_name = MakeInternalBlobName(blob_name, bucket_id); - hermes::BoMove(context, rpc, moves, old_blob_id, bucket_id, - internal_blob_name); - - BlobID new_blob_id = GetBlobId(context, rpc, blob_name, bucket_id, false); - Assert(!IsNullBlobId(new_blob_id)); - std::vector new_buffer_ids = GetBufferIdList(context, rpc, - new_blob_id); - Assert(new_buffer_ids.size() > 0); - Assert(new_buffer_ids != old_buffer_ids); - std::vector new_buffer_info = GetBufferInfo(context, rpc, - new_buffer_ids); - Assert(new_buffer_info.size() == new_buffer_ids.size()); - Assert(new_buffer_info != old_buffer_info); - - f32 new_access_score = ComputeBlobAccessScore(context, new_buffer_info); - if (move_up) { - Assert(old_access_score < new_access_score); - } else { - Assert(new_access_score < old_access_score); - } - - hapi::Blob retrieved_blob; - size_t retrieved_blob_size = bkt.Get(blob_name, retrieved_blob); - Assert(retrieved_blob_size == blob_size); - retrieved_blob.resize(retrieved_blob_size); - bkt.Get(blob_name, retrieved_blob); - Assert(blob == retrieved_blob); - - bkt.Destroy(); -} - -static void TestBoMove() { - hermes::Config config = {}; - hermes::InitDefaultConfig(&config); - config.default_placement_policy = hapi::PlacementPolicy::kRoundRobin; - HermesPtr hermes = hermes::InitHermesDaemon(&config); - - hermes::RoundRobin rr_state; - size_t num_devices = rr_state.GetNumDevices(); - - // Force Blob to RAM, then call BoMove to move a Buffer to the lowest tier and - // ensure that the access score has changed appropriately. - rr_state.SetCurrentDeviceIndex(0); - PutThenMove(hermes, false); - - // Force Blob to lowest Tier, then call BoMove to move a Buffer to the RAM - // tier and ensure that the access score has changed appropriately. - rr_state.SetCurrentDeviceIndex(num_devices - 1); - PutThenMove(hermes, true); - - hermes->Finalize(true); -} - -void TestOrganizeBlob() { - hermes::Config config = {}; - hermes::InitDefaultConfig(&config); - config.default_placement_policy = hapi::PlacementPolicy::kRoundRobin; - HermesPtr hermes = hermes::InitHermesDaemon(&config); - SharedMemoryContext *context = &hermes->context_; - RpcContext *rpc = &hermes->rpc_; - - // Put a Blob in RAM - hermes::RoundRobin rr_state; - rr_state.SetCurrentDeviceIndex(0); - size_t blob_size = KILOBYTES(20); - hapi::Bucket bkt("Organize", hermes); - std::string blob_name = "1"; - hapi::Blob blob(blob_size, 'x'); - hapi::Status status = bkt.Put(blob_name, blob); - Assert(status.Succeeded()); - - // Call OrganizeBlob with 0 importance, meaning the BORG should move all - // buffers to the lowest tier, resulting in an access score of 0 - f32 epsilon = 0.000001; - f32 custom_importance = 0; - bkt.OrganizeBlob(blob_name, epsilon, custom_importance); - - // Wait for organization to complete - std::this_thread::sleep_for(std::chrono::seconds(2)); - - // Get access score and make sure it's 0 - BucketID bucket_id = {}; - bucket_id.as_int = bkt.GetId(); - BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id, false); - Assert(!IsNullBlobId(blob_id)); - hermes::MetadataManager *mdm = GetMetadataManagerFromContext(context); - std::vector buffer_ids = LocalGetBufferIdList(mdm, blob_id); - std::vector buffer_info = GetBufferInfo(context, rpc, buffer_ids); - f32 access_score = ComputeBlobAccessScore(context, buffer_info); - Assert(access_score == 0); - - // Get the Blob and compare it with the original - hapi::Blob retrieved_blob; - size_t retrieved_blob_size = bkt.Get(blob_name, retrieved_blob); - Assert(retrieved_blob_size == blob_size); - retrieved_blob.resize(retrieved_blob_size); - bkt.Get(blob_name, retrieved_blob); - Assert(blob == retrieved_blob); - - bkt.Destroy(); - - hermes->Finalize(true); -} - -static void TestWriteOnlyBucket() { - HermesPtr hermes = hermes::InitHermesDaemon(getenv("HERMES_CONF")); - std::string bkt_name = "WriteOnly"; - VBucket vbkt(bkt_name, hermes); - Bucket bkt(bkt_name, hermes); - - hapi::WriteOnlyTrait trait; - vbkt.Attach(&trait); - - const size_t kBlobSize = KILOBYTES(4); - hapi::Blob blob(kBlobSize); - std::iota(blob.begin(), blob.end(), 0); - - const int kIters = 128; - for (int i = 0; i < kIters; ++i) { - std::string blob_name = "b" + std::to_string(i); - bkt.Put(blob_name, blob); - vbkt.Link(blob_name, bkt_name); - } - - vbkt.Destroy(); - bkt.Destroy(); - hermes->Finalize(true); -} - -void TestMinThresholdViolation() { - hermes::Config config = {}; - InitDefaultConfig(&config); - - size_t cap = MEGABYTES(1); - config.capacities[0] = cap; - config.capacities[1] = cap; - config.capacities[2] = cap; - config.capacities[3] = cap; - - for (int i = 0; i < config.num_devices; ++i) { - config.num_slabs[i] = 1; - config.desired_slab_percentages[i][0] = 1.0; - } - - f32 min = 0.25f; - f32 max = 0.75f; - config.bo_capacity_thresholds[0] = {0, max}; - config.bo_capacity_thresholds[1] = {min, max}; - config.bo_capacity_thresholds[2] = {0, max}; - - HermesPtr hermes = hermes::InitHermesDaemon(&config); - - - hermes::RoundRobin rr_state; - rr_state.SetCurrentDeviceIndex(2); - hapi::Context ctx; - ctx.policy = hapi::PlacementPolicy::kRoundRobin; - Bucket bkt(__func__, hermes, ctx); - // Blob is big enough to exceed minimum capacity of Target 1 - const size_t kBlobSize = (min * cap) + KILOBYTES(4); - hapi::Blob blob(kBlobSize, 'q'); - Assert(bkt.Put("1", blob).Succeeded()); - - // Let the BORG run. It should move enough data from Target 2 to Target 1 to - // fill > the minimum capacity threshold - std::this_thread::sleep_for(std::chrono::seconds(2)); - - // Check remaining capacities - std::vector targets = {{1, 1, 1}, {1, 2, 2}}; - std::vector capacities = - GetRemainingTargetCapacities(&hermes->context_, &hermes->rpc_, targets); - Assert(capacities[0] == cap - kBlobSize + KILOBYTES(4)); - Assert(capacities[1] == cap - KILOBYTES(4)); - - bkt.Destroy(); - hermes->Finalize(true); -} - -void TestMaxThresholdViolation() { - hermes::Config config = {}; - InitDefaultConfig(&config); - - size_t cap = MEGABYTES(1); - config.capacities[0] = cap; - config.capacities[1] = cap; - config.capacities[2] = cap; - config.capacities[3] = cap; - - for (int i = 0; i < config.num_devices; ++i) { - config.num_slabs[i] = 1; - config.desired_slab_percentages[i][0] = 1.0; - } - - f32 min = 0.0f; - f32 max = 0.75f; - config.bo_capacity_thresholds[0] = {min, max}; - config.bo_capacity_thresholds[1] = {min, max}; - config.bo_capacity_thresholds[2] = {min, max}; - - HermesPtr hermes = hermes::InitHermesDaemon(&config); - - hermes::RoundRobin rr_state; - rr_state.SetCurrentDeviceIndex(1); - hapi::Context ctx; - ctx.policy = hapi::PlacementPolicy::kRoundRobin; - Bucket bkt(__func__, hermes, ctx); - // Exceed maximum capacity of Target 1 by 4KiB - const size_t kBlobSize = (max * MEGABYTES(1)) + KILOBYTES(4); - hapi::Blob blob(kBlobSize, 'q'); - Assert(bkt.Put("1", blob).Succeeded()); - - // Let the BORG run. It should move 4KiB from Target 1 to 2 - std::this_thread::sleep_for(std::chrono::seconds(2)); - - // Check remaining capacities - std::vector targets = {{1, 1, 1}, {1, 2, 2}}; - std::vector capacities = - GetRemainingTargetCapacities(&hermes->context_, &hermes->rpc_, targets); - Assert(capacities[0] == cap - kBlobSize + KILOBYTES(4)); - Assert(capacities[1] == cap - KILOBYTES(4)); - - bkt.Destroy(); - hermes->Finalize(true); -} - -int main(int argc, char *argv[]) { - int mpi_threads_provided; - MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &mpi_threads_provided); - if (mpi_threads_provided < MPI_THREAD_MULTIPLE) { - fprintf(stderr, "Didn't receive appropriate MPI threading specification\n"); - return 1; - } - - HERMES_ADD_TEST(TestIsBoFunction); - HERMES_ADD_TEST(TestBackgroundFlush); - HERMES_ADD_TEST(TestBoMove); - HERMES_ADD_TEST(TestOrganizeBlob); - HERMES_ADD_TEST(TestWriteOnlyBucket); - HERMES_ADD_TEST(TestMinThresholdViolation); - HERMES_ADD_TEST(TestMaxThresholdViolation); - - MPI_Finalize(); - - return 0; -} diff --git a/test/buffer_pool_client_test.cc b/test/buffer_pool_client_test.cc deleted file mode 100644 index 70beff772..000000000 --- a/test/buffer_pool_client_test.cc +++ /dev/null @@ -1,371 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "hermes.h" -#include "buffer_pool.h" -#include "buffer_pool_internal.h" -#include "utils.h" -#include "test_utils.h" -/** - * @file buffer_pool_client_test.cc - * - * This shows how an application core might interact with the BufferPool. A - * client must open the existing BufferPool shared memory (created by the hermes - * core intialization), intialize communication, set up files for buffering, and - * can then call the BufferPool either directly (same node) or via RPC (remote - * node). - */ - -using namespace hermes; // NOLINT(*) -using hermes::testing::Timer; -namespace hapi = hermes::api; -const size_t kFourKiB = KILOBYTES(4); - -struct TimingResult { - double get_buffers_time; - double release_buffers_time; -}; - -TimingResult TestGetBuffersRpc(RpcContext *rpc, int iters) { - TimingResult result = {}; - TargetID ram_target = testing::DefaultRamTargetId(); - PlacementSchema schema{std::make_pair(kFourKiB, ram_target)}; - - Timer get_timer; - Timer release_timer; - for (int i = 0; i < iters; ++i) { - get_timer.resumeTime(); - std::vector ret = - hermes::RpcCall>(rpc, rpc->node_id, "GetBuffers", - schema); - get_timer.pauseTime(); - - if (ret.size() == 0) { - break; - } - - release_timer.resumeTime(); - for (size_t i = 0; i < ret.size(); ++i) { - RpcCall(rpc, rpc->node_id, "RemoteReleaseBuffer", ret[i]); - } - release_timer.pauseTime(); - } - - result.get_buffers_time = get_timer.getElapsedTime(); - result.release_buffers_time = release_timer.getElapsedTime(); - - return result; -} - -TimingResult TestGetBuffers(SharedMemoryContext *context, int iters) { - TimingResult result = {}; - TargetID ram_target = testing::DefaultRamTargetId(); - PlacementSchema schema{std::make_pair(kFourKiB, ram_target)}; - - Timer get_timer; - Timer release_timer; - for (int i = 0; i < iters; ++i) { - get_timer.resumeTime(); - std::vector ret = GetBuffers(context, schema); - get_timer.pauseTime(); - - if (ret.size() == 0) { - break; - } - - release_timer.resumeTime(); - LocalReleaseBuffers(context, ret); - release_timer.pauseTime(); - } - - result.get_buffers_time = get_timer.getElapsedTime(); - result.release_buffers_time = release_timer.getElapsedTime(); - - return result; -} - -double TestSplitBuffers(SharedMemoryContext *context, RpcContext *rpc, - int slab_index, bool use_rpc) { - Timer timer; - if (use_rpc) { - timer.resumeTime(); - RpcCall(rpc, rpc->node_id, "SplitBuffers", slab_index); - timer.pauseTime(); - } else { - timer.resumeTime(); - SplitRamBufferFreeList(context, slab_index); - timer.pauseTime(); - } - double result = timer.getElapsedTime(); - // TODO(chogan): Verify results - return result; -} - -double TestMergeBuffers(SharedMemoryContext *context, RpcContext *rpc, - int slab_index, bool use_rpc) { - Timer timer; - - if (use_rpc) { - timer.resumeTime(); - RpcCall(rpc, rpc->node_id, "MergeBuffers", slab_index); - timer.pauseTime(); - } else { - timer.resumeTime(); - MergeRamBufferFreeList(context, slab_index); - timer.pauseTime(); - } - double result = timer.getElapsedTime(); - // TODO(chogan): Verify results - return result; -} - -struct FileMapper { - Blob blob; - - explicit FileMapper(const char *path) { - FILE *f = fopen(path, "r"); - blob = {}; - if (f) { - fseek(f, 0, SEEK_END); - blob.size = ftell(f); - blob.data = (u8 *)mmap(0, blob.size, PROT_READ, MAP_PRIVATE, fileno(f), - 0); - fclose(f); - } else { - perror(0); - } - } - - ~FileMapper() { - munmap(blob.data, blob.size); - } -}; - -void TestFileBuffering(std::shared_ptr hermes, int rank, - const char *test_file) { - SharedMemoryContext *context = &hermes->context_; - RpcContext *rpc = &hermes->rpc_; - TargetID file_target = testing::DefaultFileTargetId(); - ScopedTemporaryMemory scratch(&hermes->trans_arena_); - - FileMapper mapper(test_file); - Blob blob = mapper.blob; - - if (blob.data) { - PlacementSchema schema{std::make_pair(blob.size, file_target)}; - std::vector buffer_ids(0); - - while (buffer_ids.size() == 0) { - buffer_ids = GetBuffers(context, schema); - } - - size_t num_buffers = buffer_ids.size(); - u32 *buffer_sizes = PushArray(scratch, num_buffers); - for (u32 i = 0; i < num_buffers; ++i) { - buffer_sizes[i] = GetBufferSize(context, rpc, buffer_ids[i]); - } - - WriteBlobToBuffers(context, rpc, blob, buffer_ids); - - std::vector data(blob.size); - Blob result = {}; - result.size = blob.size; - result.data = data.data(); - - BufferIdArray buffer_id_arr = {}; - buffer_id_arr.ids = buffer_ids.data(); - buffer_id_arr.length = buffer_ids.size(); - ReadBlobFromBuffers(context, rpc, &result, &buffer_id_arr, buffer_sizes); - - std::stringstream out_filename_stream; - out_filename_stream << "TestfileBuffering_rank" << std::to_string(rank) - << ".bmp"; - std::string out_filename = out_filename_stream.str(); - FILE *out_file = fopen(out_filename.c_str(), "w"); - size_t items_written = fwrite(result.data, result.size, 1, out_file); - Assert(items_written == 1); - fclose(out_file); - - LocalReleaseBuffers(context, buffer_ids); - - FileMapper result_mapper(out_filename.c_str()); - Blob result_blob = result_mapper.blob; - Assert(blob.size == result_blob.size); - Assert(memcmp(blob.data, result_blob.data, blob.size) == 0); - } else { - perror(0); - } -} - -void PrintUsage(char *program) { - fprintf(stderr, "Usage %s [-r]\n", program); - fprintf(stderr, " -b\n"); - fprintf(stderr, " Run GetBuffers test.\n"); - fprintf(stderr, " -c \n"); - fprintf(stderr, " Path to a Hermes configuration file.\n"); - fprintf(stderr, " -f \n"); - fprintf(stderr, " Run FileBuffering test on file at .\n"); - fprintf(stderr, " -h\n"); - fprintf(stderr, " Print help message and exit.\n"); - fprintf(stderr, " -i \n"); - fprintf(stderr, " Use iterations in GetBuffers test.\n"); - fprintf(stderr, " -k\n"); - fprintf(stderr, " Kill RPC server on program exit.\n"); - fprintf(stderr, " -m \n"); - fprintf(stderr, " Run MergeBuffers test on slab .\n"); - fprintf(stderr, " -r\n"); - fprintf(stderr, " Run GetBuffers test using RPC.\n"); - fprintf(stderr, " -s \n"); - fprintf(stderr, " Run SplitBuffers test on slab .\n"); -} - -int main(int argc, char **argv) { - int option = -1; - bool test_get_release = false; - char *config_file = 0; - bool use_rpc = false; - bool test_split = false; - bool test_merge = false; - bool test_file_buffering = false; - char *test_file = 0; - bool kill_server = false; - int slab_index = 0; - int iters = 100000; - - while ((option = getopt(argc, argv, "bc:f:hi:km:rs:")) != -1) { - switch (option) { - case 'b': { - test_get_release = true; - break; - } - case 'c': { - config_file = optarg; - break; - } - case 'f': { - test_file_buffering = true; - test_get_release = false; - test_file = optarg; - break; - } - case 'h': { - PrintUsage(argv[0]); - return 1; - } - case 'i': { - iters = atoi(optarg); - break; - } - case 'k': { - kill_server = true; - break; - } - case 'm': { - test_merge = true; - slab_index = atoi(optarg) - 1; - test_get_release = false; - break; - } - case 'r': { - use_rpc = true; - break; - } - case 's': { - test_split = true; - slab_index = atoi(optarg) - 1; - test_get_release = false; - break; - } - default: - PrintUsage(argv[0]); - return 1; - } - } - - int mpi_threads_provided; - MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &mpi_threads_provided); - if (mpi_threads_provided < MPI_THREAD_MULTIPLE) { - fprintf(stderr, "Didn't receive appropriate MPI threading specification\n"); - return 1; - } - - std::shared_ptr hermes = - hermes::InitHermesClient(config_file); - int app_rank = hermes->GetProcessRank(); - int app_size = hermes->GetNumProcesses(); - SharedMemoryContext *context = &hermes->context_; - RpcContext *rpc = &hermes->rpc_; - - if (test_get_release) { - TimingResult timing = {}; - - if (use_rpc) { - timing = TestGetBuffersRpc(rpc, iters); - } else { - timing = TestGetBuffers(context, iters); - } - - int total_iters = iters * app_size; - double total_get_seconds = 0; - double total_release_seconds = 0; - MPI_Reduce(&timing.get_buffers_time, &total_get_seconds, 1, MPI_DOUBLE, - MPI_SUM, 0, MPI_COMM_WORLD); - MPI_Reduce(&timing.release_buffers_time, &total_release_seconds, 1, - MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); - - if (app_rank == 0) { - double avg_get_seconds = total_get_seconds / app_size; - double avg_release_seconds = total_release_seconds / app_size; - double gets_per_second = total_iters / avg_get_seconds; - double releases_per_second = total_iters / avg_release_seconds; - printf("%f %f ", gets_per_second, releases_per_second); - } - } - - if (test_split) { - assert(app_size == 1); - double seconds_for_split = TestSplitBuffers(context, rpc, slab_index, - use_rpc); - printf("%f\n", seconds_for_split); - } - if (test_merge) { - assert(app_size == 1); - double seconds_for_merge = TestMergeBuffers(context, rpc, slab_index, - use_rpc); - printf("%f\n", seconds_for_merge); - } - if (test_file_buffering) { - Assert(test_file); - TestFileBuffering(hermes, app_rank, test_file); - } - - if (app_rank == 0 && kill_server) { - hermes::RpcCall(rpc, rpc->node_id, "RemoteFinalize"); - } - - hermes->Finalize(); - - MPI_Finalize(); - - return 0; -} diff --git a/test/buffer_pool_test.cc b/test/buffer_pool_test.cc deleted file mode 100644 index 4dbf454da..000000000 --- a/test/buffer_pool_test.cc +++ /dev/null @@ -1,336 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "hermes.h" -#include "bucket.h" -#include "buffer_pool_internal.h" -#include "metadata_management_internal.h" -#include "utils.h" -#include "test_utils.h" - -/** - * @file buffer_pool_test.cc - * - * Tests the functionality of the BufferPool - */ - -namespace hapi = hermes::api; -using HermesPtr = std::shared_ptr; - -static void GetSwapConfig(hermes::Config *config) { - InitDefaultConfig(config); - // NOTE(chogan): Make capacities small so that a Put of 1MB will go to swap - // space. After metadata, this configuration gives us 1 4KB RAM buffer. - config->capacities[0] = KILOBYTES(26); - config->capacities[1] = 8; - config->capacities[2] = 8; - config->capacities[3] = 8; - config->desired_slab_percentages[0][0] = 1; - config->desired_slab_percentages[0][1] = 0; - config->desired_slab_percentages[0][2] = 0; - config->desired_slab_percentages[0][3] = 0; - config->arena_percentages[hermes::kArenaType_BufferPool] = 0.5; - config->arena_percentages[hermes::kArenaType_MetaData] = 0.5; -} - -static void TestGetBuffers() { - using namespace hermes; // NOLINT(*) - - HermesPtr hermes = InitHermesDaemon(); - - SharedMemoryContext *context = &hermes->context_; - BufferPool *pool = GetBufferPoolFromContext(context); - TargetID ram_target = testing::DefaultRamTargetId(); - i32 block_size = pool->block_sizes[ram_target.bits.device_id]; - - { - // A request smaller than the block size should return 1 buffer - PlacementSchema schema{std::make_pair(block_size / 2, ram_target)}; - std::vector ret = GetBuffers(context, schema); - Assert(ret.size() == 1); - LocalReleaseBuffers(context, ret); - } - - { - // A request larger than the available space should return no buffers - PlacementSchema schema{std::make_pair(GIGABYTES(3), ram_target)}; - std::vector ret = GetBuffers(context, schema); - Assert(ret.size() == 0); - } - - { - // Get all buffers on the device - UpdateGlobalSystemViewState(context, &hermes->rpc_); - std::vector global_state = GetGlobalDeviceCapacities(context, - &hermes->rpc_); - PlacementSchema schema{ - std::make_pair(global_state[ram_target.bits.device_id], ram_target)}; - std::vector ret = GetBuffers(context, schema); - Assert(ret.size()); - // The next request should fail - PlacementSchema failed_schema{std::make_pair(1, ram_target)}; - std::vector failed_request = GetBuffers(context, failed_schema); - Assert(failed_request.size() == 0); - LocalReleaseBuffers(context, ret); - } - - hermes->Finalize(true); -} - -static void TestGetBandwidths() { - using namespace hermes; // NOLINT(*) - - HermesPtr hermes = InitHermesDaemon(); - - std::vector targets = LocalGetNodeTargets(&hermes->context_); - std::vector bandwidths = GetBandwidths(&hermes->context_, targets); - Config config; - InitDefaultConfig(&config); - for (size_t i = 0; i < bandwidths.size(); ++i) { - Assert(bandwidths[i] == config.bandwidths[i]); - Assert(bandwidths.size() == (size_t)config.num_devices); - } - - hermes->Finalize(true); -} - -static hapi::Status ForceBlobToSwap(hapi::Hermes *hermes, hermes::u64 id, - hapi::Blob &blob, const char *blob_name, - hapi::Context &ctx) { - using namespace hermes; // NOLINT(*) - PlacementSchema schema; - schema.push_back({blob.size(), testing::DefaultRamTargetId()}); - Blob internal_blob = {}; - internal_blob.data = blob.data(); - internal_blob.size = blob.size(); - hermes::BucketID bucket_id = {}; - bucket_id.as_int = id; - hapi::Status result = PlaceBlob(&hermes->context_, &hermes->rpc_, schema, - internal_blob, blob_name, bucket_id, ctx); - - return result; -} - -/** - * Fills out @p config to represent one `Device` (RAM) with 2, 4 KB buffers. - */ -static void MakeTwoBufferRAMConfig(hermes::Config *config) { - InitDefaultConfig(config); - config->num_devices = 1; - config->num_targets = 1; - config->capacities[0] = KILOBYTES(32); - config->desired_slab_percentages[0][0] = 1; - config->desired_slab_percentages[0][1] = 0; - config->desired_slab_percentages[0][2] = 0; - config->desired_slab_percentages[0][3] = 0; - config->arena_percentages[hermes::kArenaType_BufferPool] = 0.5; - config->arena_percentages[hermes::kArenaType_MetaData] = 0.5; -} - -static void TestBlobOverwrite() { - using namespace hermes; // NOLINT(*) - hermes::Config config = {}; - MakeTwoBufferRAMConfig(&config); - HermesPtr hermes = InitHermesDaemon(&config); - SharedMemoryContext *context = &hermes->context_; - DeviceID ram_id = 0; - int slab_index = 0; - std::atomic *buffers_available = - GetAvailableBuffersArray(context, ram_id); - Assert(buffers_available[slab_index] == 2); - - hapi::Context ctx; - ctx.policy = hapi::PlacementPolicy::kRandom; - hapi::Bucket bucket("overwrite", hermes, ctx); - - std::string blob_name("1"); - size_t blob_size = KILOBYTES(2); - hapi::Blob blob(blob_size, '1'); - hapi::Status status = bucket.Put(blob_name, blob); - Assert(status.Succeeded()); - - Assert(buffers_available[slab_index] == 1); - - // NOTE(chogan): Overwrite the data - hapi::Blob new_blob(blob_size, '2'); - Assert(bucket.Put(blob_name, new_blob).Succeeded()); - - Assert(buffers_available[slab_index] == 1); - - bucket.Destroy(); - - hermes->Finalize(true); -} - -static void TestSwap() { - hermes::Config config = {}; - GetSwapConfig(&config); - HermesPtr hermes = hermes::InitHermesDaemon(&config); - - hapi::Context ctx; - ctx.policy = hapi::PlacementPolicy::kRandom; - hapi::Bucket bucket(std::string("swap_bucket"), hermes, ctx); - size_t data_size = MEGABYTES(1); - hapi::Blob data(data_size, 'x'); - std::string blob_name("swap_blob"); - hapi::Status status = ForceBlobToSwap(hermes.get(), bucket.GetId(), data, - blob_name.c_str(), ctx); - Assert(status == hermes::BLOB_IN_SWAP_PLACE); - // NOTE(chogan): The Blob is in the swap space, but the API behaves as normal. - Assert(bucket.ContainsBlob(blob_name)); - - hapi::Blob get_result; - size_t blob_size = bucket.Get(blob_name, get_result); - get_result.resize(blob_size); - blob_size = bucket.Get(blob_name, get_result); - - Assert(get_result == data); - - bucket.Destroy(); - - hermes->Finalize(true); -} - -static void TestBufferOrganizer() { - hermes::Config config = {}; - GetSwapConfig(&config); - HermesPtr hermes = hermes::InitHermesDaemon(&config); - - hapi::Context ctx; - ctx.policy = hapi::PlacementPolicy::kRandom; - hapi::Bucket bucket(std::string("bo_bucket"), hermes, ctx); - - // NOTE(chogan): Fill our single buffer with a blob. - hapi::Blob data1(KILOBYTES(4), 'x'); - std::string blob1_name("bo_blob1"); - hapi::Status status = bucket.Put(blob1_name, data1); - Assert(status.Succeeded()); - Assert(bucket.ContainsBlob(blob1_name)); - - // NOTE(chogan): Force a second Blob to the swap space. - hapi::Blob data2(KILOBYTES(4), 'y'); - std::string blob2_name("bo_blob2"); - status = ForceBlobToSwap(hermes.get(), bucket.GetId(), data2, - blob2_name.c_str(), ctx); - Assert(status == hermes::BLOB_IN_SWAP_PLACE); - Assert(bucket.BlobIsInSwap(blob2_name)); - - // NOTE(chogan): Delete the first blob, which will make room for the second, - // and the buffer organizer should move it from swap space to the hierarchy. - bucket.DeleteBlob(blob1_name); - - // NOTE(chogan): Give the BufferOrganizer time to finish. - std::this_thread::sleep_for(std::chrono::seconds(3)); - - Assert(bucket.ContainsBlob(blob2_name)); - Assert(!bucket.BlobIsInSwap(blob2_name)); - - hapi::Blob get_result; - size_t blob_size = bucket.Get(blob2_name, get_result); - get_result.resize(blob_size); - blob_size = bucket.Get(blob2_name, get_result); - - Assert(get_result == data2); - - bucket.Destroy(); - - hermes->Finalize(true); -} - -static void TestBufferingFiles(hermes::Config *config, - size_t *expected_capacities) { - const int kNumBlockDevices = 3; - - int num_slabs[] = { - config->num_slabs[1], - config->num_slabs[2], - config->num_slabs[3] - }; - - HermesPtr hermes = hermes::InitHermesDaemon(config); - hermes->Finalize(true); - - for (int i = 0; i < kNumBlockDevices; ++i) { - size_t device_total_capacity = 0; - std::string node = - config->is_shared_device[i + 1] ? std::string("_node1") : ""; - for (int j = 0; j < num_slabs[i]; ++j) { - std::string buffering_filename = ("device" + std::to_string(i + 1) + - "_slab" + std::to_string(j) + node + - ".hermes"); - - struct stat st = {}; - Assert(stat(buffering_filename.c_str(), &st) == 0); - device_total_capacity += st.st_size; - } - Assert(device_total_capacity == expected_capacities[i]); - } -} - -static void TestBufferingFileCorrectness() { - using namespace hermes; // NOLINT(*) - { - Config config = {}; - InitDefaultConfig(&config); - size_t expected_capacities[] = { - config.capacities[1], - config.capacities[2], - config.capacities[3], - }; - TestBufferingFiles(&config, expected_capacities); - } - - { - Config config = {}; - InitDefaultConfig(&config); - config.capacities[1] = KILOBYTES(4) * 5; - config.capacities[2] = KILOBYTES(4) * 5; - config.capacities[3] = KILOBYTES(4) * 5; - size_t expected_capacities[] = { - KILOBYTES(4), - KILOBYTES(4), - KILOBYTES(4) - }; - TestBufferingFiles(&config, expected_capacities); - } -} - -int main(int argc, char **argv) { - int mpi_threads_provided; - MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &mpi_threads_provided); - if (mpi_threads_provided < MPI_THREAD_MULTIPLE) { - fprintf(stderr, "Didn't receive appropriate MPI threading specification\n"); - return 1; - } - - TestGetBuffers(); - TestGetBandwidths(); - TestBlobOverwrite(); - TestSwap(); - TestBufferOrganizer(); - TestBufferingFileCorrectness(); - - MPI_Finalize(); - - return 0; -} diff --git a/test/catch_config.h b/test/catch_config.h deleted file mode 100644 index b277383e9..000000000 --- a/test/catch_config.h +++ /dev/null @@ -1,43 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_CATCH_CONFIG_H -#define HERMES_CATCH_CONFIG_H - -#define CATCH_CONFIG_RUNNER -#include -#include - -namespace cl = Catch::Clara; - -cl::Parser define_options(); - -int init(); -int finalize(); - -int main(int argc, char* argv[]) { - MPI_Init(&argc, &argv); - Catch::Session session; - auto cli = session.cli() | define_options(); - int returnCode = init(); - if (returnCode != 0) return returnCode; - session.cli(cli); - returnCode = session.applyCommandLine(argc, argv); - if (returnCode != 0) return returnCode; - int test_return_code = session.run(); - returnCode = finalize(); - if (returnCode != 0) return returnCode; - MPI_Finalize(); - return test_return_code; -} - -#endif diff --git a/test/clear_cache.sh b/test/clear_cache.sh deleted file mode 100644 index 6bfd1dc55..000000000 --- a/test/clear_cache.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -sync -echo 3 > /proc/sys/vm/drop_caches \ No newline at end of file diff --git a/test/config_parser_test.cc b/test/config_parser_test.cc deleted file mode 100644 index b7fc84635..000000000 --- a/test/config_parser_test.cc +++ /dev/null @@ -1,271 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include "hermes_types.h" -#include "buffer_pool_internal.h" -#include "test_utils.h" -#include "config_parser.h" - -using hermes::u8; -using hermes::Config; - -namespace hermes { -namespace testing { - -Config ParseConfigStringTest(const std::string &config_string) { - Config config = {}; - ParseConfigString(config_string, &config); - return config; -} - -void RunHostNumbersTest(const std::string &config_string, - const std::vector &expected) { - Config config = ParseConfigStringTest(config_string); - Assert(config.host_names == expected); -} - -void TestParseRangeList() { - { - std::vector expected{ - "localhost-1", "localhost-3", "localhost-4", "localhost-5", - "localhost-7", "localhost-10", "localhost-11", "localhost-12" - }; - std::string yaml = - "rpc_server_base_name: localhost-\n" - "rpc_host_number_range: [1, 3-5, 7, 10-12]\n"; - RunHostNumbersTest(yaml, expected); - } - - { - std::vector expected{ - "localhost-001", "localhost-002", "localhost-003" - }; - std::string yaml = - "rpc_server_base_name: localhost-\n" - "rpc_host_number_range: [001-003]\n"; - RunHostNumbersTest(yaml, expected); - } - - { - std::vector expected{ - "localhost-1" - }; - std::string yaml = - "rpc_server_base_name: localhost-\n" - "rpc_host_number_range: [1]\n"; - RunHostNumbersTest(yaml, expected); - } - - { - std::vector expected{"localhost"}; - std::string yaml = - "rpc_server_base_name: localhost\n" - "rpc_host_number_range: []\n"; - RunHostNumbersTest(yaml, expected); - } -} - -void RunCapacityValuesTest(const std::string &config_string, - const std::vector &expected) { - Config config = ParseConfigStringTest(config_string); - Assert((size_t)config.num_devices == expected.size()); - for (int i = 0; i < config.num_devices; ++i) { - Assert(config.capacities[i] == expected[i]); - } -} - -void TestPathExclusions() { - std::vector expected{"/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:"}; - std::string config_string = "path_exclusions: [\n" - " \"/bin/\", \"/boot/\", \"/dev/\", \"/etc/\",\n" - " \"/lib/\", \"/opt/\", \"/proc/\", \"/sbin/\",\n" - " \"/sys/\", \"/usr/\", \"/var/\", \"/run/\",\n" - " \"pipe\", \"socket:\", \"anon_inode:\"\n" - "]"; - Config config = ParseConfigStringTest(config_string); - for (size_t i = 0; i < expected.size(); ++i) { - auto &e = expected[i]; - auto &e2 = config.path_exclusions[i]; - Assert(e == e2); - } -} - -void TestCapacityValues() { - std::string base_config = "num_devices: 4\n"; - - { - std::vector expected{50, 50, 50, 50}; - std::string config_string = "capacities_bytes: [50, 50, 50, 50]\n"; - RunCapacityValuesTest(base_config + config_string, expected); - } - - { - std::vector expected{KILOBYTES(50), KILOBYTES(50), KILOBYTES(50), - KILOBYTES(50)}; - std::string config_string = "capacities_kb: [50, 50, 50, 50]\n"; - RunCapacityValuesTest(base_config + config_string, expected); - } - - { - std::vector expected{MEGABYTES(50), MEGABYTES(50), MEGABYTES(50), - MEGABYTES(50)}; - std::string config_string = "capacities_mb: [50, 50, 50, 50]\n"; - RunCapacityValuesTest(base_config + config_string, expected); - } - - { - std::vector expected{GIGABYTES(50), GIGABYTES(50), GIGABYTES(50), - GIGABYTES(50)}; - std::string config_string = "capacities_gb: [50, 50, 50, 50]\n"; - RunCapacityValuesTest(base_config + config_string, expected); - } -} - -void RunBlockSizesTest(const std::string &config_string, - const std::vector &expected) { - Config config = ParseConfigStringTest(config_string); - Assert((size_t)config.num_devices == expected.size()); - for (int i = 0; i < config.num_devices; ++i) { - Assert(config.block_sizes[i] == expected[i]); - } -} - -void TestBlockSizes() { - std::string base_config = "num_devices: 4\n"; - - { - std::vector expected{50, 50, 50, 50}; - std::string config_string = "block_sizes_bytes: [50, 50, 50, 50]\n"; - RunBlockSizesTest(base_config + config_string, expected); - } - { - std::vector expected{KILOBYTES(50), KILOBYTES(50), KILOBYTES(50), - KILOBYTES(50)}; - std::string config_string = "block_sizes_kb: [50, 50, 50, 50]\n"; - RunBlockSizesTest(base_config + config_string, expected); - } - { - std::vector expected{MEGABYTES(50), MEGABYTES(50), MEGABYTES(50), - MEGABYTES(50)}; - std::string config_string = "block_sizes_mb: [50, 50, 50, 50]\n"; - RunBlockSizesTest(base_config + config_string, expected); - } - { - std::vector expected{GIGABYTES(1), GIGABYTES(1), GIGABYTES(1), - GIGABYTES(1)}; - std::string config_string = "block_sizes_gb: [1, 1, 1, 1]\n"; - RunBlockSizesTest(base_config + config_string, expected); - } -} - -void TestDefaultConfig(const char *config_file) { - hermes::Config config = {}; - hermes::ParseConfig(config_file, &config); - - Assert(config.num_devices == 4); - Assert(config.num_targets == 4); - for (int i = 0; i < config.num_devices; ++i) { - Assert(config.capacities[i] == MEGABYTES(50)); - Assert(config.block_sizes[i] == KILOBYTES(4)); - Assert(config.num_slabs[i] == 4); - - Assert(config.slab_unit_sizes[i][0] == 1); - Assert(config.slab_unit_sizes[i][1] == 4); - Assert(config.slab_unit_sizes[i][2] == 16); - Assert(config.slab_unit_sizes[i][3] == 32); - - for (int j = 0; j < config.num_slabs[i]; ++j) { - Assert(config.desired_slab_percentages[i][j] == 0.25f); - } - } - - Assert(config.bandwidths[0] == 6000.0f); - Assert(config.bandwidths[1] == 300.0f); - Assert(config.bandwidths[2] == 150.0f); - Assert(config.bandwidths[3] == 70.0f); - - Assert(config.latencies[0] == 15.0f); - Assert(config.latencies[1] == 250000.0f); - Assert(config.latencies[2] == 500000.0f); - Assert(config.latencies[3] == 1000000.0f); - - Assert(config.arena_percentages[hermes::kArenaType_BufferPool] == 0.85f); - Assert(config.arena_percentages[hermes::kArenaType_MetaData] == 0.04f); - Assert(config.arena_percentages[hermes::kArenaType_Transient] == 0.11f); - - Assert(config.mount_points[0] == ""); - Assert(config.mount_points[1] == "./"); - Assert(config.mount_points[2] == "./"); - Assert(config.mount_points[3] == "./"); - Assert(config.swap_mount == "./"); - Assert(config.num_buffer_organizer_retries == 3); - - Assert(config.max_buckets_per_node == 16); - Assert(config.max_vbuckets_per_node == 8); - Assert(config.system_view_state_update_interval_ms == 1000); - - Assert(config.rpc_protocol == "ofi+sockets"); - Assert(config.rpc_domain.empty()); - Assert(config.rpc_port == 8080); - Assert(config.buffer_organizer_port == 8081); - Assert(config.rpc_num_threads == 1); - - Assert(config.rpc_server_host_file == ""); - std::vector expected_host_names{"localhost"}; - Assert(config.host_names == expected_host_names); - - std::string expected_shm_name = "/hermes_buffer_pool_"; - std::string actual_shm_name = config.buffer_pool_shmem_name; - Assert(expected_shm_name == actual_shm_name); - - Assert(config.default_placement_policy == - hermes::api::PlacementPolicy::kMinimizeIoTime); - - Assert(config.is_shared_device[0] == 0); - Assert(config.is_shared_device[1] == 0); - Assert(config.is_shared_device[2] == 0); - Assert(config.is_shared_device[3] == 0); - - - for (int i = 0; i < config.num_devices; ++i) { - Assert(config.bo_capacity_thresholds[i].min == 0.0f); - Assert(config.bo_capacity_thresholds[i].max == 1.0f); - } - - Assert(config.bo_num_threads == 4); -} - -} // namespace testing -} // namespace hermes - -int main(int argc, char **argv) { - if (argc < 2) { - fprintf(stderr, "Expected a path to a hermes.yaml file\n"); - exit(-1); - } - - hermes::testing::TestDefaultConfig(argv[1]); - hermes::testing::TestParseRangeList(); - hermes::testing::TestCapacityValues(); - hermes::testing::TestBlockSizes(); - hermes::testing::TestPathExclusions(); - - printf("SUCCESS!"); - return 0; -} diff --git a/test/data/ares.yaml b/test/data/ares.yaml deleted file mode 100644 index 5bec27a6b..000000000 --- a/test/data/ares.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# Test configuration for Ares cluster - -num_devices: 4 -num_targets: 4 - -capacities_mb: [50, 50, 50, 50] -block_sizes_kb: [4, 4, 4, 4] -num_slabs: [4, 4, 4, 4] - -slab_unit_sizes: [ - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], -] - -desired_slab_percentages: [ - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], -] - -bandwidths_mbps: [6000, 300, 150, 70] -latencies_us: [15, 250000, 500000, 1000000] - -buffer_pool_arena_percentage: 0.85 -metadata_arena_percentage: 0.04 -transient_arena_percentage: 0.11 - -max_buckets_per_node: 16 -max_vbuckets_per_node: 8 -system_view_state_update_interval_ms: 1000 - -mount_points: ["", "./", "./", "./"] -swap_mount: "./" -num_buffer_organizer_retries: 3 -rpc_server_base_name: "ares-comp-" -rpc_server_suffix: "-40g" -rpc_protocol: "ofi+verbs" -rpc_domain: "mlx5_0" -rpc_port: 8080 -buffer_organizer_port: 8081 -rpc_host_number_range: {29-30} -rpc_num_threads: 4 -buffer_organizer_num_threads: 4 -buffer_pool_shmem_name: "/hermes_buffer_pool_" - -path_exclusions: ["/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:"] \ No newline at end of file diff --git a/test/data/bucket_test.yaml b/test/data/bucket_test.yaml deleted file mode 100644 index f884806b4..000000000 --- a/test/data/bucket_test.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# Test configuration - -num_devices: 4 -num_targets: 4 - -capacities_mb: [128, 512, 1024, 4096] -block_sizes_kb: [4, 4, 4, 4] -num_slabs: [4, 4, 4, 4] - -slab_unit_sizes: [ - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32] -] - -desired_slab_percentages: [ - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25] -] - -bandwidth_mbps: [6000, 300, 150, 70] -latencies_us: [15, 250000, 500000, 1000000] - -buffer_pool_arena_percentage: 0.85 -metadata_arena_percentage: 0.04 -transient_arena_percentage: 0.11 - -max_buckets_per_node: 16 -max_vbuckets_per_node: 8 -system_view_state_update_interval_ms: 1000 - -mount_points: ["", "./", "./", "./"] -swap_mount: "./" -num_buffer_organizer_retries: 3 - -rpc_server_base_name: "localhost" -rpc_protocol: "ofi+sockets" -rpc_port: 8080 -buffer_organizer_port: 8081 -rpc_host_number_range: null -rpc_num_threads: 1 -buffer_organizer_num_threads: 2 -buffer_pool_shmem_name: "/hermes_buffer_pool_" - -path_exclusions: [ - "/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:" -] \ No newline at end of file diff --git a/test/data/hermes.yaml b/test/data/hermes.yaml deleted file mode 100644 index 9544cf8ac..000000000 --- a/test/data/hermes.yaml +++ /dev/null @@ -1,140 +0,0 @@ -# Example Hermes configuration file - -# The number of buffering tiers available. For example, RAM, NVMe, burst -# buffer, and parallel file system would be 4 tiers. -num_devices: 4 -# For now this should be the same as num_devices. -num_targets: 4 - -# The maximum buffering capacity in MiB of each device. Here we say that all 4 -# devices get 50 MiB of buffering capacity. -capacities_mb: [50, 50, 50, 50] - -# The size of the smallest available buffer in KiB. In general this should be -# the page size of your system for byte addressable storage, and the block size -# of the storage device for block addressable storage. -block_sizes_kb: [4, 4, 4, 4] - -# The nummber of size categories for each device. Here we say that each of our 4 -# devices should have 4 different sizes of buffers. -num_slabs: [4, 4, 4, 4] - -# The number of blocks (the size of which is chosen in block_sizes_kb) that each -# device should contain for each slab (controlled by num_slabs). This allows for -# precise control of the distibution of buffer sizes. -slab_unit_sizes: [ - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32] -] - -# The percentage of buffering capacity per device to allocate for each slab. -# Each row should add up to 1. In this example, we have 4 devices, each with 4 -# slabs, and each slab is allotted 25% of the device's total buffering capacity. -desired_slab_percentages: [ - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25] -] - -# The maximum theoretical bandwidth (as advertised by the manufacturer) in -# MiB/sec. of each device. -bandwidth_mbps: [6000, 300, 150, 70] -# The latency in microseconds of each device (as advertised by the manufacturer). -latencies_us: [15, 250000, 500000, 1000000] - -# Hermes memory management. The following 4 values should add up to 1. -# The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage: 0.85 -# The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage: 0.04 -# The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage: 0.11 - -# The maxiumum number of buckets that can be created. -max_buckets_per_node: 16 -# The maxiumum number of virtual buckets that can be created. -max_vbuckets_per_node: 8 -# The interval in milliseconds at which to update the global system view. -system_view_state_update_interval_ms: 1000 - -# The mount point of each device. RAM should be the empty string. For block -# devices, this is the directory where Hermes will create buffering files. For -# object storage or cloud targets, this will be a url. -mount_points: ["", "./", "./", "./"] -# For each device, indicate '1' if it is shared among nodes (e.g., burst -# buffers), or '0' if it is per node (e.g., local NVMe). -is_shared_device: [0, 0, 0, 0] -# The mount point of a PFS or object store for swap space, in the event that -# Hermes buffers become full. -swap_mount: "./" -# The number of times the buffer organizer will attempt to place a blob from -# swap space into the hierarchy before giving up. -num_buffer_organizer_retries: 3 - -# A path to a file containing a list of server names, 1 per line. If your -# servers are named according to a pattern (e.g., server-1, server-2, etc.), -# prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this -# option is not empty, it will override anything in `rpc_server_base_name`. -rpc_server_host_file: "" -# Base hostname for the RPC servers. -rpc_server_base_name: "localhost" -# RPC server name suffix. This is appended to the the base name plus host -# number. -rpc_server_suffix: "" -# The RPC protocol. This must come from the documentation of the specific RPC -# library in use. -rpc_protocol: "ofi+sockets" -# RPC domain name for verbs transport. Blank for tcp. -rpc_domain: "" -# Desired RPC port number. -rpc_port: 8080 -# Desired RPC port number for buffer organizer. -buffer_organizer_port: 8081 -# A list of host numbers. Host names are constructed as "rpc_server_base_name + -# host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list -# can be either a single number, or a range, which is 2 numbers separated by a -# hyphen (-). For example the list {1, 3-5, 7, 8-10} will be expanded to -# {1, 3, 4, 5, 7, 8, 9, 10}. -rpc_host_number_range: [] -# The number of handler threads for each RPC server. -rpc_num_threads: 1 -# The number of threads used in the background organization of internal Hermes buffers. -buffer_organizer_num_threads: 4 -# The shared memory prefix for the hermes shared memory segment. A user name -# will be automatically appended. -buffer_pool_shmem_name: "/hermes_buffer_pool_" -# Choose Random, RoundRobin, or MinimizeIoTime -default_placement_policy: "MinimizeIoTime" -# If true (1) the RoundRobin placement policy algorithm will split each Blob -# into a random number of smaller Blobs. -default_rr_split: 0 - -# For each device, the minimum and maximum percent capacity threshold at which -# the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause -# the BufferOrganizer to move data to lower devices, making more room in faster -# devices (ideal for write-heavy workloads). Conversely, increasing the minimum -# threshold will cause data to be moved from slower devices into faster devices -# (ideal for read-heavy workloads). For example, a maximum capacity threshold of -# 0.8 would have the effect of always keeping 20% of the device's space free for -# incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure -# that the device is always at least 30% occupied. -bo_capacity_thresholds: [ - [0.0, 1.0], - [0.0, 1.0], - [0.0, 1.0], - [0.0, 1.0] -] - -#Paths which are ignored when buffering data -path_exclusions: [ - "/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:" -] -#Paths which are never ignored when buffering data -path_inclusions: ["/var/opt/cray/dws/mounts/"] - diff --git a/test/data/hermes_client.yaml b/test/data/hermes_client.yaml new file mode 100644 index 000000000..61f5a6146 --- /dev/null +++ b/test/data/hermes_client.yaml @@ -0,0 +1,2 @@ +stop_daemon: true +file_page_size_kb: 1024 \ No newline at end of file diff --git a/test/data/hermes_server.yaml b/test/data/hermes_server.yaml new file mode 100644 index 000000000..09e27c1e7 --- /dev/null +++ b/test/data/hermes_server.yaml @@ -0,0 +1,136 @@ +# Example Hermes configuration file + +### Define properties of the storage devices +devices: + # The name of the device. + # It can be whatever the user wants, there are no special names + ram: + # The mount point of each device. RAM should be the empty string. For block + # devices, this is the directory where Hermes will create buffering files. For + # object storage or cloud targets, this will be a url. + mount_point: "" + + # The maximum buffering capacity in MiB of each device. Here we say that all 4 + # devices get 50 MiB of buffering capacity. + capacity_mb: 50 + + # The size of the smallest available buffer in KiB. In general this should be + # the page size of your system for byte addressable storage, and the block size + # of the storage device for block addressable storage. + block_size_kb: 4 + + # The number of blocks (the size of which is chosen in block_sizes_kb) that each + # device should contain for each slab (controlled by num_slabs). This allows for + # precise control of the distibution of buffer sizes. + slab_units: [1, 4, 16, 32] + + # The maximum theoretical bandwidth (as advertised by the manufacturer) in + # MiB/sec. of each device. + bandwidth_mbps: 6000 + + # The latency in microseconds of each device (as advertised by the manufacturer). + latencies_us: 15 + + # For each device, indicate '1' if it is shared among nodes (e.g., burst + # buffers), or '0' if it is per node (e.g., local NVMe). + is_shared_device: 0 + + nvme: + mount_point: "./" + capacity_mb: 50 + block_size_kb: 4 + slab_units: [1, 4, 16, 32] + is_shared_device: 0 + + ssd: + mount_point: "./" + capacity_mb: 50 + block_size_kb: 4 + slab_units: [ 1, 4, 16, 32 ] + is_shared_device: 0 + + pfs: + mount_point: "./" + capacity_mb: inf + block_size_kb: 64 # Assume 64KB strip size + slab_units: [1, 4, 16, 32] + +### Define the network communication protocol +rpc: + # A path to a file containing a list of server names, 1 per line. If your + # servers are named according to a pattern (e.g., server-1, server-2, etc.), + # prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this + # option is not empty, it will override anything in `rpc_server_base_name`. + host_file: "" + + # Host names are constructed as "base_name + + # host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list + # can be either a single number, or a range, which is 2 numbers separated by a + # hyphen (-). For example the list {01, 03-05, 07, 08-10} will be expanded to + # {01, 03, 04, 05, 07, 08, 09, 10}. + server_base_name: "localhost" + server_host_number_range: [] + server_suffix: "" + + # The RPC protocol. This must come from the documentation of the specific RPC + # library in use. + protocol: "ofi+sockets" + + # RPC domain name for verbs transport. Blank for tcp. + domain: "" + + # Desired RPC port number. + port: 8080 + + # Desired RPC port number for buffer organizer. + buffer_organizer_port: 8081 + + # The number of handler threads for each RPC server. + num_threads: 1 + +### Define properties of the BORG +buffer_organizer: + # The number of threads used in the background organization of internal Hermes buffers. + num_threads: 4 + + # For each device, the minimum and maximum percent capacity threshold at which + # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause + # the BufferOrganizer to move data to lower devices, making more room in faster + # devices (ideal for write-heavy workloads). Conversely, increasing the minimum + # threshold will cause data to be moved from slower devices into faster devices + # (ideal for read-heavy workloads). For example, a maximum capacity threshold of + # 0.8 would have the effect of always keeping 20% of the device's space free for + # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure + # that the device is always at least 30% occupied. + capacity_thresholds: [ + [ 0.0, 1.0 ], + [ 0.0, 1.0 ], + [ 0.0, 1.0 ], + [ 0.0, 1.0 ] + ] + +### Define the default data placement policy +dpe: + # Choose Random, RoundRobin, or MinimizeIoTime + default_placement_policy: "MinimizeIoTime" + + # If true (1) the RoundRobin placement policy algorithm will split each Blob + # into a random number of smaller Blobs. + default_rr_split: 0 + +# The shared memory prefix for the hermes shared memory segment. A user name +# will be automatically appended. +shmem_name: "/hermes_shm_" +# The interval in milliseconds at which to update the global system view. +system_view_state_update_interval_ms: 1000 + +#Paths which are ignored when buffering data +path_exclusions: [ + "/bin/", "/boot/", "/dev/", "/etc/", + "/lib/", "/opt/", "/proc/", "/sbin/", + "/sys/", "/usr/", "/var/", "/run/", + "pipe", "socket:", "anon_inode:" +] +#Paths which are never ignored when buffering data +path_inclusions: ["/var/opt/cray/dws/mounts/"] + diff --git a/test/data/local.yaml b/test/data/local.yaml deleted file mode 100644 index 5b535674c..000000000 --- a/test/data/local.yaml +++ /dev/null @@ -1,140 +0,0 @@ -# Example Hermes configuration file - -# The number of buffering tiers available. For example, RAM, NVMe, burst -# buffer, and parallel file system would be 4 tiers. -num_devices: 4 -# For now this should be the same as num_devices. -num_targets: 4 - -# The maximum buffering capacity in MiB of each device. Here we say that all 4 -# devices get 50 MiB of buffering capacity. -capacities_mb: [50, 50, 50, 50] - -# The size of the smallest available buffer in KiB. In general this should be -# the page size of your system for byte addressable storage, and the block size -# of the storage device for block addressable storage. -block_sizes_kb: [4, 4, 4, 4] - -# The nummber of size categories for each device. Here we say that each of our 4 -# devices should have 4 different sizes of buffers. -num_slabs: [4, 4, 4, 4] - -# The number of blocks (the size of which is chosen in block_sizes_kb) that each -# device should contain for each slab (controlled by num_slabs). This allows for -# precise control of the distibution of buffer sizes. -slab_unit_sizes: [ - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32] -] - -# The percentage of buffering capacity per device to allocate for each slab. -# Each row should add up to 1. In this example, we have 4 devices, each with 4 -# slabs, and each slab is allotted 25% of the device's total buffering capacity. -desired_slab_percentages: [ - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25] -] - -# The maximum theoretical bandwidth (as advertised by the manufacturer) in -# MiB/sec. of each device. -bandwidth_mbps: [6000, 300, 150, 70] -# The latency in microseconds of each device (as advertised by the manufacturer). -latencies_us: [15, 250000, 500000, 1000000] - -# Hermes memory management. The following 4 values should add up to 1. -# The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage: 0.85 -# The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage: 0.04 -# The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage: 0.11 - -# The maxiumum number of buckets that can be created. -max_buckets_per_node: 16 -# The maxiumum number of virtual buckets that can be created. -max_vbuckets_per_node: 8 -# The interval in milliseconds at which to update the global system view. -system_view_state_update_interval_ms: 1000 - -# The mount point of each device. RAM should be the empty string. For block -# devices, this is the directory where Hermes will create buffering files. For -# object storage or cloud targets, this will be a url. -mount_points: ["", "./", "./", "./"] -# For each device, indicate '1' if it is shared among nodes (e.g., burst -# buffers), or '0' if it is per node (e.g., local NVMe). -is_shared_device: [0, 0, 0, 0] -# The mount point of a PFS or object store for swap space, in the event that -# Hermes buffers become full. -swap_mount: "./" -# The number of times the buffer organizer will attempt to place a blob from -# swap space into the hierarchy before giving up. -num_buffer_organizer_retries: 3 - -# A path to a file containing a list of server names, 1 per line. If your -# servers are named according to a pattern (e.g., server-1, server-2, etc.), -# prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this -# option is not empty, it will override anything in `rpc_server_base_name`. -rpc_server_host_file: "" -# Base hostname for the RPC servers. -rpc_server_base_name: "localhost" -# RPC server name suffix. This is appended to the the base name plus host -# number. -rpc_server_suffix: "" -# The RPC protocol. This must come from the documentation of the specific RPC -# library in use. -rpc_protocol: "ofi+sockets" -# RPC domain name for verbs transport. Blank for tcp. -rpc_domain: "" -# Desired RPC port number. -rpc_port: 8080 -# Desired RPC port number for buffer organizer. -buffer_organizer_port: 8081 -# A list of host numbers. Host names are constructed as "rpc_server_base_name + -# host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list -# can be either a single number, or a range, which is 2 numbers separated by a -# hyphen (-). For example the list {1, 3-5, 7, 8-10} will be expanded to -# {1, 3, 4, 5, 7, 8, 9, 10}. -rpc_host_number_range: [] -# The number of handler threads for each RPC server. -rpc_num_threads: 1 -# The number of threads used in the background organization of internal Hermes buffers. -buffer_organizer_num_threads: 4 -# The shared memory prefix for the hermes shared memory segment. A user name -# will be automatically appended. -buffer_pool_shmem_name: "/hermes_" -# Choose Random, RoundRobin, or MinimizeIoTime -default_placement_policy: "MinimizeIoTime" -# If true (1) the RoundRobin placement policy algorithm will split each Blob -# into a random number of smaller Blobs. -default_rr_split: 0 - -# For each device, the minimum and maximum percent capacity threshold at which -# the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause -# the BufferOrganizer to move data to lower devices, making more room in faster -# devices (ideal for write-heavy workloads). Conversely, increasing the minimum -# threshold will cause data to be moved from slower devices into faster devices -# (ideal for read-heavy workloads). For example, a maximum capacity threshold of -# 0.8 would have the effect of always keeping 20% of the device's space free for -# incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure -# that the device is always at least 30% occupied. -bo_capacity_thresholds: [ - [0.0, 1.0], - [0.0, 1.0], - [0.0, 1.0], - [0.0, 1.0] -] - -#Paths which are ignored when buffering data -path_exclusions: [ - "/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:" -] -#Paths which are never ignored when buffering data -path_inclusions: ["/var/opt/cray/dws/mounts/"] - diff --git a/test/data/prefetch.yaml b/test/data/prefetch.yaml deleted file mode 100644 index 0e24e682e..000000000 --- a/test/data/prefetch.yaml +++ /dev/null @@ -1,134 +0,0 @@ -# Example Hermes configuration file - -# The number of buffering tiers available. For example, RAM, NVMe, burst -# buffer, and parallel file system would be 4 tiers. -num_devices: 2 -# For now this should be the same as num_devices. -num_targets: 2 - -# The maximum buffering capacity in MiB of each device. Here we say that all 4 -# devices get 50 MiB of buffering capacity. -capacities_mb: [4000, 16000] - -# The size of the smallest available buffer in KiB. In general this should be -# the page size of your system for byte addressable storage, and the block size -# of the storage device for block addressable storage. -block_sizes_kb: [4, 4] - -# The nummber of size categories for each device. Here we say that each of our 4 -# devices should have 4 different sizes of buffers. -num_slabs: [2, 1] - -# The number of blocks (the size of which is chosen in block_sizes_kb) that each -# device should contain for each slab (controlled by num_slabs). This allows for -# precise control of the distibution of buffer sizes. -slab_unit_sizes: [ - [1, 256], - [256] -] - -# The percentage of buffering capacity per device to allocate for each slab. -# Each row should add up to 1. In this example, we have 2 devices, each with 4 -# slabs, and each slab is allotted 25% of the device's total buffering capacity. -desired_slab_percentages: [ - [0.1, 0.9], - [1.0] -] - -# The maximum theoretical bandwidth (as advertised by the manufacturer) in -# MiB/sec. of each device. -bandwidth_mbps: [4000, 500] -# The latency in microseconds of each device (as advertised by the manufacturer). -latencies_us: [10, 100] - -# Hermes memory management. The following 4 values should add up to 1. -# The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage: 0.8 -# The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage: 0.1 -# The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage: 0.1 - -# The maxiumum number of buckets that can be created. -max_buckets_per_node: 16 -# The maxiumum number of virtual buckets that can be created. -max_vbuckets_per_node: 8 -# The interval in milliseconds at which to update the global system view. -system_view_state_update_interval_ms: 1000 - -# The mount point of each device. RAM should be the empty string. For block -# devices, this is the directory where Hermes will create buffering files. For -# object storage or cloud targets, this will be a url. -mount_points: [""] -# For each device, indicate '1' if it is shared among nodes (e.g., burst -# buffers), or '0' if it is per node (e.g., local NVMe). -is_shared_device: [0,0] -# The mount point of a PFS or object store for swap space, in the event that -# Hermes buffers become full. -swap_mount: "./" -# The number of times the buffer organizer will attempt to place a blob from -# swap space into the hierarchy before giving up. -num_buffer_organizer_retries: 3 - -# A path to a file containing a list of server names, 1 per line. If your -# servers are named according to a pattern (e.g., server-1, server-2, etc.), -# prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this -# option is not empty, it will override anything in `rpc_server_base_name`. -rpc_server_host_file: "" -# Base hostname for the RPC servers. -rpc_server_base_name: "localhost" -# RPC server name suffix. This is appended to the the base name plus host -# number. -rpc_server_suffix: "" -# The RPC protocol. This must come from the documentation of the specific RPC -# library in use. -rpc_protocol: "ofi+sockets" -# RPC domain name for verbs transport. Blank for tcp. -rpc_domain: "" -# Desired RPC port number. -rpc_port: 8080 -# Desired RPC port number for buffer organizer. -buffer_organizer_port: 8081 -# A list of host numbers. Host names are constructed as "rpc_server_base_name + -# host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list -# can be either a single number, or a range, which is 2 numbers separated by a -# hyphen (-). For example the list {1, 3-5, 7, 8-10} will be expanded to -# {1, 3, 4, 5, 7, 8, 9, 10}. -rpc_host_number_range: [] -# The number of handler threads for each RPC server. -rpc_num_threads: 1 -# The number of threads used in the background organization of internal Hermes buffers. -buffer_organizer_num_threads: 1 -# The shared memory prefix for the hermes shared memory segment. A user name -# will be automatically appended. -buffer_pool_shmem_name: "/hermes_buffer_pool_" -# Choose Random, RoundRobin, or MinimizeIoTime -default_placement_policy: "MinimizeIoTime" -# If true (1) the RoundRobin placement policy algorithm will split each Blob -# into a random number of smaller Blobs. -default_rr_split: 0 - -# For each device, the minimum and maximum percent capacity threshold at which -# the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause -# the BufferOrganizer to move data to lower devices, making more room in faster -# devices (ideal for write-heavy workloads). Conversely, increasing the minimum -# threshold will cause data to be moved from slower devices into faster devices -# (ideal for read-heavy workloads). For example, a maximum capacity threshold of -# 0.8 would have the effect of always keeping 20% of the device's space free for -# incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure -# that the device is always at least 30% occupied. -bo_capacity_thresholds: [ - [0.0, 1.0], - [0.0, 1.0] -] - -#Paths which are ignored when buffering data -path_exclusions: [ - "/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:" -] -#Paths which are never ignored when buffering data -path_inclusions: ["/var/opt/cray/dws/mounts/"] - diff --git a/test/data/prefetch_ares.yaml b/test/data/prefetch_ares.yaml deleted file mode 100644 index 6b56e7c90..000000000 --- a/test/data/prefetch_ares.yaml +++ /dev/null @@ -1,134 +0,0 @@ -# Example Hermes configuration file - -# The number of buffering tiers available. For example, RAM, NVMe, burst -# buffer, and parallel file system would be 4 tiers. -num_devices: 2 -# For now this should be the same as num_devices. -num_targets: 2 - -# The maximum buffering capacity in MiB of each device. Here we say that all 4 -# devices get 50 MiB of buffering capacity. -capacities_mb: [2000, 16000] - -# The size of the smallest available buffer in KiB. In general this should be -# the page size of your system for byte addressable storage, and the block size -# of the storage device for block addressable storage. -block_sizes_kb: [4, 4] - -# The nummber of size categories for each device. Here we say that each of our 4 -# devices should have 4 different sizes of buffers. -num_slabs: [2, 1] - -# The number of blocks (the size of which is chosen in block_sizes_kb) that each -# device should contain for each slab (controlled by num_slabs). This allows for -# precise control of the distibution of buffer sizes. -slab_unit_sizes: [ - [1, 256], - [256] -] - -# The percentage of buffering capacity per device to allocate for each slab. -# Each row should add up to 1. In this example, we have 2 devices, each with 4 -# slabs, and each slab is allotted 25% of the device's total buffering capacity. -desired_slab_percentages: [ - [0.1, 0.9], - [1.0] -] - -# The maximum theoretical bandwidth (as advertised by the manufacturer) in -# MiB/sec. of each device. -bandwidth_mbps: [4000, 150] -# The latency in microseconds of each device (as advertised by the manufacturer). -latencies_us: [10, 10000] - -# Hermes memory management. The following 4 values should add up to 1. -# The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage: 0.8 -# The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage: 0.1 -# The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage: 0.1 - -# The maxiumum number of buckets that can be created. -max_buckets_per_node: 16 -# The maxiumum number of virtual buckets that can be created. -max_vbuckets_per_node: 8 -# The interval in milliseconds at which to update the global system view. -system_view_state_update_interval_ms: 1000 - -# The mount point of each device. RAM should be the empty string. For block -# devices, this is the directory where Hermes will create buffering files. For -# object storage or cloud targets, this will be a url. -mount_points: ["", "/mnt/hdd/llogan/borg"] -# For each device, indicate '1' if it is shared among nodes (e.g., burst -# buffers), or '0' if it is per node (e.g., local NVMe). -is_shared_device: [0, 0] -# The mount point of a PFS or object store for swap space, in the event that -# Hermes buffers become full. -swap_mount: "./" -# The number of times the buffer organizer will attempt to place a blob from -# swap space into the hierarchy before giving up. -num_buffer_organizer_retries: 3 - -# A path to a file containing a list of server names, 1 per line. If your -# servers are named according to a pattern (e.g., server-1, server-2, etc.), -# prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this -# option is not empty, it will override anything in `rpc_server_base_name`. -rpc_server_host_file: "" -# Base hostname for the RPC servers. -rpc_server_base_name: "localhost" -# RPC server name suffix. This is appended to the the base name plus host -# number. -rpc_server_suffix: "" -# The RPC protocol. This must come from the documentation of the specific RPC -# library in use. -rpc_protocol: "ofi+sockets" -# RPC domain name for verbs transport. Blank for tcp. -rpc_domain: "" -# Desired RPC port number. -rpc_port: 8080 -# Desired RPC port number for buffer organizer. -buffer_organizer_port: 8081 -# A list of host numbers. Host names are constructed as "rpc_server_base_name + -# host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list -# can be either a single number, or a range, which is 2 numbers separated by a -# hyphen (-). For example the list {1, 3-5, 7, 8-10} will be expanded to -# {1, 3, 4, 5, 7, 8, 9, 10}. -rpc_host_number_range: [] -# The number of handler threads for each RPC server. -rpc_num_threads: 1 -# The number of threads used in the background organization of internal Hermes buffers. -buffer_organizer_num_threads: 4 -# The shared memory prefix for the hermes shared memory segment. A user name -# will be automatically appended. -buffer_pool_shmem_name: "/hermes_buffer_pool_" -# Choose Random, RoundRobin, or MinimizeIoTime -default_placement_policy: "MinimizeIoTime" -# If true (1) the RoundRobin placement policy algorithm will split each Blob -# into a random number of smaller Blobs. -default_rr_split: 0 - -# For each device, the minimum and maximum percent capacity threshold at which -# the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause -# the BufferOrganizer to move data to lower devices, making more room in faster -# devices (ideal for write-heavy workloads). Conversely, increasing the minimum -# threshold will cause data to be moved from slower devices into faster devices -# (ideal for read-heavy workloads). For example, a maximum capacity threshold of -# 0.8 would have the effect of always keeping 20% of the device's space free for -# incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure -# that the device is always at least 30% occupied. -bo_capacity_thresholds: [ - [0.0, 1.0], - [0.0, 1.0] -] - -#Paths which are ignored when buffering data -path_exclusions: [ - "/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:" -] -#Paths which are never ignored when buffering data -path_inclusions: ["/var/opt/cray/dws/mounts/"] - diff --git a/test/data/prefetch_ares_ram.yaml b/test/data/prefetch_ares_ram.yaml deleted file mode 100644 index 40a0a3c9e..000000000 --- a/test/data/prefetch_ares_ram.yaml +++ /dev/null @@ -1,131 +0,0 @@ -# Example Hermes configuration file - -# The number of buffering tiers available. For example, RAM, NVMe, burst -# buffer, and parallel file system would be 4 tiers. -num_devices: 1 -# For now this should be the same as num_devices. -num_targets: 1 - -# The maximum buffering capacity in MiB of each device. Here we say that all 4 -# devices get 50 MiB of buffering capacity. -capacities_mb: [18000] - -# The size of the smallest available buffer in KiB. In general this should be -# the page size of your system for byte addressable storage, and the block size -# of the storage device for block addressable storage. -block_sizes_kb: [4] - -# The nummber of size categories for each device. Here we say that each of our 4 -# devices should have 4 different sizes of buffers. -num_slabs: [2] - -# The number of blocks (the size of which is chosen in block_sizes_kb) that each -# device should contain for each slab (controlled by num_slabs). This allows for -# precise control of the distibution of buffer sizes. -slab_unit_sizes: [ - [1,256], -] - -# The percentage of buffering capacity per device to allocate for each slab. -# Each row should add up to 1. In this example, we have 2 devices, each with 4 -# slabs, and each slab is allotted 25% of the device's total buffering capacity. -desired_slab_percentages: [ - [0.1, 0.9] -] - -# The maximum theoretical bandwidth (as advertised by the manufacturer) in -# MiB/sec. of each device. -bandwidth_mbps: [4000] -# The latency in microseconds of each device (as advertised by the manufacturer). -latencies_us: [10] - -# Hermes memory management. The following 4 values should add up to 1. -# The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage: 0.8 -# The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage: 0.1 -# The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage: 0.1 - -# The maxiumum number of buckets that can be created. -max_buckets_per_node: 16 -# The maxiumum number of virtual buckets that can be created. -max_vbuckets_per_node: 8 -# The interval in milliseconds at which to update the global system view. -system_view_state_update_interval_ms: 1000 - -# The mount point of each device. RAM should be the empty string. For block -# devices, this is the directory where Hermes will create buffering files. For -# object storage or cloud targets, this will be a url. -mount_points: ["", "/mnt/nvme/llogan/borg", "/mnt/ssd/llogan/borg", "/mnt/hdd/llogan/borg"] -# For each device, indicate '1' if it is shared among nodes (e.g., burst -# buffers), or '0' if it is per node (e.g., local NVMe). -is_shared_device: [0] -# The mount point of a PFS or object store for swap space, in the event that -# Hermes buffers become full. -swap_mount: "./" -# The number of times the buffer organizer will attempt to place a blob from -# swap space into the hierarchy before giving up. -num_buffer_organizer_retries: 3 - -# A path to a file containing a list of server names, 1 per line. If your -# servers are named according to a pattern (e.g., server-1, server-2, etc.), -# prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this -# option is not empty, it will override anything in `rpc_server_base_name`. -rpc_server_host_file: "" -# Base hostname for the RPC servers. -rpc_server_base_name: "localhost" -# RPC server name suffix. This is appended to the the base name plus host -# number. -rpc_server_suffix: "" -# The RPC protocol. This must come from the documentation of the specific RPC -# library in use. -rpc_protocol: "ofi+sockets" -# RPC domain name for verbs transport. Blank for tcp. -rpc_domain: "" -# Desired RPC port number. -rpc_port: 8080 -# Desired RPC port number for buffer organizer. -buffer_organizer_port: 8081 -# A list of host numbers. Host names are constructed as "rpc_server_base_name + -# host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list -# can be either a single number, or a range, which is 2 numbers separated by a -# hyphen (-). For example the list {1, 3-5, 7, 8-10} will be expanded to -# {1, 3, 4, 5, 7, 8, 9, 10}. -rpc_host_number_range: [] -# The number of handler threads for each RPC server. -rpc_num_threads: 1 -# The number of threads used in the background organization of internal Hermes buffers. -buffer_organizer_num_threads: 4 -# The shared memory prefix for the hermes shared memory segment. A user name -# will be automatically appended. -buffer_pool_shmem_name: "/hermes_buffer_pool_" -# Choose Random, RoundRobin, or MinimizeIoTime -default_placement_policy: "MinimizeIoTime" -# If true (1) the RoundRobin placement policy algorithm will split each Blob -# into a random number of smaller Blobs. -default_rr_split: 0 - -# For each device, the minimum and maximum percent capacity threshold at which -# the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause -# the BufferOrganizer to move data to lower devices, making more room in faster -# devices (ideal for write-heavy workloads). Conversely, increasing the minimum -# threshold will cause data to be moved from slower devices into faster devices -# (ideal for read-heavy workloads). For example, a maximum capacity threshold of -# 0.8 would have the effect of always keeping 20% of the device's space free for -# incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure -# that the device is always at least 30% occupied. -bo_capacity_thresholds: [ - [0.0, 1.0] -] - -#Paths which are ignored when buffering data -path_exclusions: [ - "/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:" -] -#Paths which are never ignored when buffering data -path_inclusions: ["/var/opt/cray/dws/mounts/"] - diff --git a/test/data/prefetch_ram.yaml b/test/data/prefetch_ram.yaml deleted file mode 100644 index f698056c0..000000000 --- a/test/data/prefetch_ram.yaml +++ /dev/null @@ -1,131 +0,0 @@ -# Example Hermes configuration file - -# The number of buffering tiers available. For example, RAM, NVMe, burst -# buffer, and parallel file system would be 4 tiers. -num_devices: 1 -# For now this should be the same as num_devices. -num_targets: 1 - -# The maximum buffering capacity in MiB of each device. Here we say that all 4 -# devices get 50 MiB of buffering capacity. -capacities_mb: [18000] - -# The size of the smallest available buffer in KiB. In general this should be -# the page size of your system for byte addressable storage, and the block size -# of the storage device for block addressable storage. -block_sizes_kb: [4] - -# The nummber of size categories for each device. Here we say that each of our 4 -# devices should have 4 different sizes of buffers. -num_slabs: [2] - -# The number of blocks (the size of which is chosen in block_sizes_kb) that each -# device should contain for each slab (controlled by num_slabs). This allows for -# precise control of the distibution of buffer sizes. -slab_unit_sizes: [ - [1, 256] -] - -# The percentage of buffering capacity per device to allocate for each slab. -# Each row should add up to 1. In this example, we have 2 devices, each with 4 -# slabs, and each slab is allotted 25% of the device's total buffering capacity. -desired_slab_percentages: [ - [0.1, 0.9] -] - -# The maximum theoretical bandwidth (as advertised by the manufacturer) in -# MiB/sec. of each device. -bandwidth_mbps: [4000] -# The latency in microseconds of each device (as advertised by the manufacturer). -latencies_us: [10] - -# Hermes memory management. The following 4 values should add up to 1. -# The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage: 0.8 -# The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage: 0.1 -# The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage: 0.1 - -# The maxiumum number of buckets that can be created. -max_buckets_per_node: 16 -# The maxiumum number of virtual buckets that can be created. -max_vbuckets_per_node: 8 -# The interval in milliseconds at which to update the global system view. -system_view_state_update_interval_ms: 1000 - -# The mount point of each device. RAM should be the empty string. For block -# devices, this is the directory where Hermes will create buffering files. For -# object storage or cloud targets, this will be a url. -mount_points: [""] -# For each device, indicate '1' if it is shared among nodes (e.g., burst -# buffers), or '0' if it is per node (e.g., local NVMe). -is_shared_device: [0] -# The mount point of a PFS or object store for swap space, in the event that -# Hermes buffers become full. -swap_mount: "./" -# The number of times the buffer organizer will attempt to place a blob from -# swap space into the hierarchy before giving up. -num_buffer_organizer_retries: 3 - -# A path to a file containing a list of server names, 1 per line. If your -# servers are named according to a pattern (e.g., server-1, server-2, etc.), -# prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this -# option is not empty, it will override anything in `rpc_server_base_name`. -rpc_server_host_file: "" -# Base hostname for the RPC servers. -rpc_server_base_name: "localhost" -# RPC server name suffix. This is appended to the the base name plus host -# number. -rpc_server_suffix: "" -# The RPC protocol. This must come from the documentation of the specific RPC -# library in use. -rpc_protocol: "ofi+sockets" -# RPC domain name for verbs transport. Blank for tcp. -rpc_domain: "" -# Desired RPC port number. -rpc_port: 8080 -# Desired RPC port number for buffer organizer. -buffer_organizer_port: 8081 -# A list of host numbers. Host names are constructed as "rpc_server_base_name + -# host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list -# can be either a single number, or a range, which is 2 numbers separated by a -# hyphen (-). For example the list {1, 3-5, 7, 8-10} will be expanded to -# {1, 3, 4, 5, 7, 8, 9, 10}. -rpc_host_number_range: [] -# The number of handler threads for each RPC server. -rpc_num_threads: 1 -# The number of threads used in the background organization of internal Hermes buffers. -buffer_organizer_num_threads: 1 -# The shared memory prefix for the hermes shared memory segment. A user name -# will be automatically appended. -buffer_pool_shmem_name: "/hermes_buffer_pool_" -# Choose Random, RoundRobin, or MinimizeIoTime -default_placement_policy: "MinimizeIoTime" -# If true (1) the RoundRobin placement policy algorithm will split each Blob -# into a random number of smaller Blobs. -default_rr_split: 0 - -# For each device, the minimum and maximum percent capacity threshold at which -# the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause -# the BufferOrganizer to move data to lower devices, making more room in faster -# devices (ideal for write-heavy workloads). Conversely, increasing the minimum -# threshold will cause data to be moved from slower devices into faster devices -# (ideal for read-heavy workloads). For example, a maximum capacity threshold of -# 0.8 would have the effect of always keeping 20% of the device's space free for -# incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure -# that the device is always at least 30% occupied. -bo_capacity_thresholds: [ - [0.0, 1.0] -] - -#Paths which are ignored when buffering data -path_exclusions: [ - "/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:" -] -#Paths which are never ignored when buffering data -path_inclusions: ["/var/opt/cray/dws/mounts/"] - diff --git a/test/data/staging.yaml b/test/data/staging.yaml deleted file mode 100644 index 0038cc457..000000000 --- a/test/data/staging.yaml +++ /dev/null @@ -1,195 +0,0 @@ -# Example Hermes configuration file - -# The number of buffering tiers available. For example, RAM, NVMe, burst -# buffer, and parallel file system would be 4 tiers. -<<<<<<< HEAD -num_devices: 2 -# For now this should be the same as num_devices. -num_targets: 2 - -# The maximum buffering capacity in MiB of each device. Here we say that all 4 -# devices get 50 MiB of buffering capacity. -capacities_mb: [2000, 18000] -======= -num_devices: 4 -# For now this should be the same as num_devices. -num_targets: 4 - -# The maximum buffering capacity in MiB of each device. Here we say that all 4 -# devices get 50 MiB of buffering capacity. -capacities_mb: [2000, 2000, 2000, 2000] ->>>>>>> master - -# The size of the smallest available buffer in KiB. In general this should be -# the page size of your system for byte addressable storage, and the block size -# of the storage device for block addressable storage. -<<<<<<< HEAD -block_sizes_kb: [4, 4] - -# The nummber of size categories for each device. Here we say that each of our 4 -# devices should have 4 different sizes of buffers. -num_slabs: [2, 1] -======= -block_sizes_kb: [4, 4, 4, 4] - -# The nummber of size categories for each device. Here we say that each of our 4 -# devices should have 4 different sizes of buffers. -num_slabs: [2, 1, 1, 1] ->>>>>>> master - -# The number of blocks (the size of which is chosen in block_sizes_kb) that each -# device should contain for each slab (controlled by num_slabs). This allows for -# precise control of the distibution of buffer sizes. -slab_unit_sizes: [ -<<<<<<< HEAD - [1, 256], - [256] -] - -# The percentage of buffering capacity per device to allocate for each slab. -# Each row should add up to 1. In this example, we have 2 devices, each with 4 -# slabs, and each slab is allotted 25% of the device's total buffering capacity. -desired_slab_percentages: [ - [0.1, 0.9], - [1.0] -======= - [1, 32], - [32], - [32], - [32] -] - -# The percentage of buffering capacity per device to allocate for each slab. -# Each row should add up to 1. In this example, we have 4 devices, each with 4 -# slabs, and each slab is allotted 25% of the device's total buffering capacity. -desired_slab_percentages: [ - [0.5, 0.5], - [1], - [1], - [1] ->>>>>>> master -] - -# The maximum theoretical bandwidth (as advertised by the manufacturer) in -# MiB/sec. of each device. -<<<<<<< HEAD -bandwidth_mbps: [4000, 500] -# The latency in microseconds of each device (as advertised by the manufacturer). -latencies_us: [10, 100] - -# Hermes memory management. The following 4 values should add up to 1. -# The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage: 0.6 -# The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage: 0.2 -# The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage: 0.2 -======= -bandwidth_mbps: [6000, 300, 150, 70] -# The latency in microseconds of each device (as advertised by the manufacturer). -latencies_us: [15, 250000, 500000, 1000000] - -# Hermes memory management. The following 4 values should add up to 1. -# The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage: 0.85 -# The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage: 0.04 -# The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage: 0.11 ->>>>>>> master - -# The maxiumum number of buckets that can be created. -max_buckets_per_node: 16 -# The maxiumum number of virtual buckets that can be created. -max_vbuckets_per_node: 8 -# The interval in milliseconds at which to update the global system view. -system_view_state_update_interval_ms: 1000 - -# The mount point of each device. RAM should be the empty string. For block -# devices, this is the directory where Hermes will create buffering files. For -# object storage or cloud targets, this will be a url. -<<<<<<< HEAD -mount_points: ["", "./"] -# For each device, indicate '1' if it is shared among nodes (e.g., burst -# buffers), or '0' if it is per node (e.g., local NVMe). -is_shared_device: [0, 0] -======= -mount_points: ["", "./hermes_dir", "./hermes_dir", "./hermes_dir"] -# For each device, indicate '1' if it is shared among nodes (e.g., burst -# buffers), or '0' if it is per node (e.g., local NVMe). -is_shared_device: [0, 0, 0, 0] ->>>>>>> master -# The mount point of a PFS or object store for swap space, in the event that -# Hermes buffers become full. -swap_mount: "./" -# The number of times the buffer organizer will attempt to place a blob from -# swap space into the hierarchy before giving up. -num_buffer_organizer_retries: 3 - -# A path to a file containing a list of server names, 1 per line. If your -# servers are named according to a pattern (e.g., server-1, server-2, etc.), -# prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this -# option is not empty, it will override anything in `rpc_server_base_name`. -rpc_server_host_file: "" -# Base hostname for the RPC servers. -rpc_server_base_name: "localhost" -# RPC server name suffix. This is appended to the the base name plus host -# number. -rpc_server_suffix: "" -# The RPC protocol. This must come from the documentation of the specific RPC -# library in use. -rpc_protocol: "ofi+sockets" -# RPC domain name for verbs transport. Blank for tcp. -rpc_domain: "" -# Desired RPC port number. -rpc_port: 8080 -# Desired RPC port number for buffer organizer. -buffer_organizer_port: 8081 -# A list of host numbers. Host names are constructed as "rpc_server_base_name + -# host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list -# can be either a single number, or a range, which is 2 numbers separated by a -# hyphen (-). For example the list {1, 3-5, 7, 8-10} will be expanded to -# {1, 3, 4, 5, 7, 8, 9, 10}. -rpc_host_number_range: [] -# The number of handler threads for each RPC server. -rpc_num_threads: 1 -# The number of threads used in the background organization of internal Hermes buffers. -buffer_organizer_num_threads: 4 -# The shared memory prefix for the hermes shared memory segment. A user name -# will be automatically appended. -buffer_pool_shmem_name: "/hermes_buffer_pool_" -# Choose Random, RoundRobin, or MinimizeIoTime -default_placement_policy: "MinimizeIoTime" -# If true (1) the RoundRobin placement policy algorithm will split each Blob -# into a random number of smaller Blobs. -default_rr_split: 0 - -# For each device, the minimum and maximum percent capacity threshold at which -# the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause -# the BufferOrganizer to move data to lower devices, making more room in faster -# devices (ideal for write-heavy workloads). Conversely, increasing the minimum -# threshold will cause data to be moved from slower devices into faster devices -# (ideal for read-heavy workloads). For example, a maximum capacity threshold of -# 0.8 would have the effect of always keeping 20% of the device's space free for -# incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure -# that the device is always at least 30% occupied. -bo_capacity_thresholds: [ - [0.0, 1.0], -<<<<<<< HEAD -======= - [0.0, 1.0], - [0.0, 1.0], ->>>>>>> master - [0.0, 1.0] -] - -#Paths which are ignored when buffering data -path_exclusions: [ - "/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:" -] -#Paths which are never ignored when buffering data -path_inclusions: ["/var/opt/cray/dws/mounts/"] - diff --git a/test/dpe_optimization_test.cc b/test/dpe_optimization_test.cc deleted file mode 100644 index e9fedb4ce..000000000 --- a/test/dpe_optimization_test.cc +++ /dev/null @@ -1,93 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include "hermes.h" -#include "data_placement_engine_factory.h" -#include "test_utils.h" -#include "utils.h" - -using namespace hermes; // NOLINT(*) - -void MinimizeIoTimePlaceBlob(std::vector &blob_sizes, - std::vector &schemas, - testing::TargetViewState &node_state, - double min_capacity = 0, - double capacity_change = 0, - bool use_placement_ratio = false) { - std::vector schemas_tmp; - - std::cout << "\nMinimizeIoTimePlacement to place blob of size " - << blob_sizes[0] / MEGABYTES(1) << " MB to targets\n" << std::flush; - std::vector targets = - testing::GetDefaultTargets(node_state.num_devices); - api::Context ctx; - ctx.policy = hermes::api::PlacementPolicy::kMinimizeIoTime; - ctx.minimize_io_time_options = api::MinimizeIoTimeOptions( - min_capacity, - capacity_change, - use_placement_ratio); - auto dpe = DPEFactory().Get(ctx.policy); - dpe->bandwidths = node_state.bandwidth; - Status result = dpe->Placement(blob_sizes, node_state.bytes_available, - targets, ctx, schemas_tmp); - if (result.Failed()) { - std::cout << "\nMinimizeIoTimePlacement failed\n" << std::flush; - exit(1); - } - - for (auto it = schemas_tmp.begin(); it != schemas_tmp.end(); ++it) { - PlacementSchema schema = AggregateBlobSchema((*it)); - Assert(schemas.size() <= static_cast(node_state.num_devices)); - schemas.push_back(schema); - } - - u64 placed_size {0}; - for (auto schema : schemas) { - placed_size += UpdateDeviceState(schema, node_state); - } - - std::cout << "\nUpdate Device State:\n"; - testing::PrintNodeState(node_state); - u64 total_sizes = std::accumulate(blob_sizes.begin(), blob_sizes.end(), 0ul); - Assert(placed_size == total_sizes); -} - -int main() { - testing::TargetViewState node_state = testing::InitDeviceState(); - - Assert(node_state.num_devices == 4); - std::cout << "Device Initial State:\n"; - testing::PrintNodeState(node_state); - - std::vector blob_sizes1(1, MEGABYTES(4096)); - std::vector schemas1; - MinimizeIoTimePlaceBlob(blob_sizes1, schemas1, node_state); - Assert(schemas1.size() == blob_sizes1.size()); - - std::vector blob_sizes2(1, MEGABYTES(1)); - std::vector schemas2; - MinimizeIoTimePlaceBlob(blob_sizes2, schemas2, node_state); - Assert(schemas2.size() == blob_sizes2.size()); - - - std::vector blob_sizes3(1, MEGABYTES(1024)); - std::vector schemas3; - MinimizeIoTimePlaceBlob(blob_sizes3, schemas3, node_state, - 0, 0, true); - Assert(schemas3.size() == blob_sizes3.size()); - - return 0; -} diff --git a/test/dpe_random_test.cc b/test/dpe_random_test.cc deleted file mode 100644 index 8d456ce07..000000000 --- a/test/dpe_random_test.cc +++ /dev/null @@ -1,80 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include "hermes.h" -#include "dpe/random.h" -#include "test_utils.h" -#include "utils.h" - -using namespace hermes; // NOLINT(*) - -void RandomPlaceBlob(std::vector &blob_sizes, - std::vector &schemas, - testing::TargetViewState &node_state) { - std::vector schemas_tmp; - - std::cout << "\nRandomPlacement to place blob of size " << blob_sizes[0] - << " to targets\n" << std::flush; - - api::Context ctx; - std::vector targets = - testing::GetDefaultTargets(node_state.num_devices); - ctx.policy = hermes::api::PlacementPolicy::kRandom; - Status result = Random().Placement( - blob_sizes, node_state.bytes_available, - targets, ctx, schemas_tmp); - - if (!result.Succeeded()) { - std::cout << "\nRandomPlacement failed\n" << std::flush; - exit(1); - } - - for (auto it = schemas_tmp.begin(); it != schemas_tmp.end(); ++it) { - PlacementSchema schema = AggregateBlobSchema((*it)); - Assert(schemas.size() <= static_cast(node_state.num_devices)); - schemas.push_back(schema); - } - - u64 placed_size {0}; - for (auto schema : schemas) { - placed_size += UpdateDeviceState(schema, node_state); - } - - std::cout << "\nUpdate Device State:\n"; - testing::PrintNodeState(node_state); - u64 total_sizes = std::accumulate(blob_sizes.begin(), blob_sizes.end(), 0); - Assert(placed_size == total_sizes); -} - -int main() { - testing::TargetViewState node_state = testing::InitDeviceState(); - - Assert(node_state.num_devices == 4); - std::cout << "Device Initial State:\n"; - testing::PrintNodeState(node_state); - - std::vector blob_sizes1(1, MEGABYTES(10)); - std::vector schemas1; - RandomPlaceBlob(blob_sizes1, schemas1, node_state); - Assert(schemas1.size() == blob_sizes1.size()); - - std::vector blob_sizes2(1, MEGABYTES(1)); - std::vector schemas2; - RandomPlaceBlob(blob_sizes2, schemas2, node_state); - Assert(schemas2.size() == blob_sizes1.size()); - - return 0; -} diff --git a/test/dpe_roundrobin_test.cc b/test/dpe_roundrobin_test.cc deleted file mode 100644 index c1863b972..000000000 --- a/test/dpe_roundrobin_test.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include -#include - -#include "hermes.h" -#include "data_placement_engine.h" -#include "test_utils.h" -#include "utils.h" - -using namespace hermes; // NOLINT(*) - -void RoundRobinPlaceBlob(std::vector &blob_sizes, - std::vector &schemas, - testing::TargetViewState &node_state) { - std::vector schemas_tmp; - std::cout << "\nRoundRobinPlacement to place blob of size " - << blob_sizes[0] << " to targets\n" << std::flush; - - std::vector targets = - testing::GetDefaultTargets(node_state.num_devices); - api::Context ctx; - ctx.rr_split = false; - ctx.policy = hermes::api::PlacementPolicy::kRoundRobin; - Status result = RoundRobin().Placement( - blob_sizes, node_state.bytes_available, - targets, ctx, schemas_tmp); - - if (!result.Succeeded()) { - std::cout << "\nRoundRobinPlacement failed\n" << std::flush; - exit(1); - } - - for (auto it = schemas_tmp.begin(); it != schemas_tmp.end(); ++it) { - PlacementSchema schema = AggregateBlobSchema((*it)); - Assert(schemas.size() <= static_cast(node_state.num_devices)); - schemas.push_back(schema); - } - - u64 placed_size {0}; - for (auto schema : schemas) { - placed_size += UpdateDeviceState(schema, node_state); - } - - std::cout << "\nUpdate Device State:\n"; - testing::PrintNodeState(node_state); - u64 total_sizes = std::accumulate(blob_sizes.begin(), blob_sizes.end(), 0); - Assert(placed_size == total_sizes); -} - -int main() { - testing::TargetViewState node_state{testing::InitDeviceState()}; - - Assert(node_state.num_devices == 4); - std::cout << "Device Initial State:\n"; - testing::PrintNodeState(node_state); - - RoundRobin::InitDevices(node_state.num_devices); - - std::vector blob_sizes1(1, MEGABYTES(10)); - std::vector schemas1; - RoundRobinPlaceBlob(blob_sizes1, schemas1, node_state); - Assert(schemas1.size() == blob_sizes1.size()); - - std::vector blob_sizes2(1, MEGABYTES(1)); - std::vector schemas2; - RoundRobinPlaceBlob(blob_sizes2, schemas2, node_state); - Assert(schemas2.size() == blob_sizes2.size()); - - return 0; -} diff --git a/test/end_to_end_test.cc b/test/end_to_end_test.cc deleted file mode 100644 index d1523c8bc..000000000 --- a/test/end_to_end_test.cc +++ /dev/null @@ -1,136 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -#include - -#include "hermes.h" -#include "bucket.h" -#include "test_utils.h" - -namespace hapi = hermes::api; - -void TestPutGetBucket(hapi::Bucket &bucket, int app_rank, int app_size) { - size_t bytes_per_rank = KILOBYTES(8); - if (app_size) { - size_t data_size = KILOBYTES(8); - bytes_per_rank = data_size / app_size; - size_t remaining_bytes = data_size % app_size; - - if (app_rank == app_size - 1) { - bytes_per_rank += remaining_bytes; - } - } - - hapi::Blob put_data(bytes_per_rank, rand() % 255); - - std::string blob_name = "test_blob" + std::to_string(app_rank); - hermes::api::Status status = bucket.Put(blob_name, put_data); - Assert(status.Succeeded()); - - hapi::Blob get_result; - size_t blob_size = bucket.Get(blob_name, get_result); - get_result.resize(blob_size); - blob_size = bucket.Get(blob_name, get_result); - - Assert(put_data == get_result); -} - -void TestBulkTransfer(std::shared_ptr hermes, int app_rank) { - size_t transfer_size = KILOBYTES(8); - - hapi::Bucket bucket(std::string("bulk_bucket"), hermes); - std::string blob_name = "1"; - - hapi::Blob put_data(transfer_size, 'x'); - - if (app_rank == 0) { - hermes::api::Status status = bucket.Put(blob_name, put_data); - Assert(status.Succeeded()); - } - - hermes->AppBarrier(); - - if (app_rank != 0) { - hapi::Blob get_result; - size_t blob_size = bucket.Get(blob_name, get_result); - get_result.resize(blob_size); - blob_size = bucket.Get(blob_name, get_result); - - Assert(get_result == put_data); - - bucket.Release(); - } - - hermes->AppBarrier(); - - if (app_rank == 0) { - bucket.Destroy(); - } -} - -int main(int argc, char **argv) { - int mpi_threads_provided; - MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &mpi_threads_provided); - if (mpi_threads_provided < MPI_THREAD_MULTIPLE) { - fprintf(stderr, "Didn't receive appropriate MPI threading specification\n"); - return 1; - } - - char *config_file = 0; - if (argc == 2) { - config_file = argv[1]; - } - - std::shared_ptr hermes = hapi::InitHermes(config_file); - - std::string version = hapi::GetVersion(); - Assert(!version.empty()); - - if (hermes->IsApplicationCore()) { - int app_rank = hermes->GetProcessRank(); - int app_size = hermes->GetNumProcesses(); - - // Each rank puts and gets its portion of a blob to a shared bucket - hapi::Bucket shared_bucket(std::string("test_bucket"), hermes); - TestPutGetBucket(shared_bucket, app_rank, app_size); - - if (app_rank != 0) { - shared_bucket.Release(); - } - - hermes->AppBarrier(); - - if (app_rank == 0) { - shared_bucket.Destroy(); - } - - hermes->AppBarrier(); - - // Each rank puts a whole blob to its own bucket - hapi::Bucket own_bucket(std::string("test_bucket_") + - std::to_string(app_rank), hermes); - TestPutGetBucket(own_bucket, app_rank, 0); - own_bucket.Destroy(); - - TestBulkTransfer(hermes, app_rank); - } else { - // Hermes core. No user code here. - } - - hermes->Finalize(); - - MPI_Finalize(); - - return 0; -} diff --git a/test/mdm_test.cc b/test/mdm_test.cc deleted file mode 100644 index d475f4474..000000000 --- a/test/mdm_test.cc +++ /dev/null @@ -1,464 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -#include - -#include "hermes.h" -#include "bucket.h" -#include "vbucket.h" -#include "buffer_pool_internal.h" -#include "metadata_management_internal.h" -#include "metadata_storage.h" -#include "test_utils.h" - -using namespace hermes; // NOLINT(*) -namespace hapi = hermes::api; -using HermesPtr = std::shared_ptr; - -static void TestNullIds() { - BucketID bkt_id = {}; - VBucketID vbkt_id = {}; - BlobID blob_id = {}; - - Assert(IsNullBucketId(bkt_id)); - Assert(IsNullVBucketId(vbkt_id)); - Assert(IsNullBlobId(blob_id)); -} - -static void TestGetMapMutex() { - MetadataManager mdm = {}; - - for (int i = 0; i < kMapType_Count; ++i) { - Assert(GetMapMutex(&mdm, (MapType)i)); - } -} - -static void TestLocalGetNextFreeBucketId(HermesPtr hermes) { - // NOTE(chogan): Test that the app doesn't fail when creating more buckets - // than the maximum allowed by the configuration. - - MetadataManager *mdm = GetMetadataManagerFromContext(&hermes->context_); - - for (u32 i = 0; i < mdm->max_buckets; ++i) { - std::string bucket_name = "bucket" + std::to_string(i); - hapi::Bucket bucket(bucket_name, hermes); - } - - std::string fail_name = "this_should_fail"; - bool threw_runtime_error = false; - try { - hapi::Bucket bucket(fail_name, hermes); - } - catch (const std::runtime_error& e) { - threw_runtime_error = true; - } - Assert(threw_runtime_error); - - for (u32 i = 0; i < mdm->max_buckets; ++i) { - std::string name = "bucket" + std::to_string(i); - hapi::Bucket bucket(name, hermes); - bucket.Destroy(); - } -} - -static void TestGetOrCreateBucketId(HermesPtr hermes) { - // NOTE(chogan): Create a bucket, close it, then open it again and ensure the - // IDs are the same. - std::string bucket_name = "bucket"; - hapi::Bucket new_bucket(bucket_name, hermes); - u64 id = new_bucket.GetId(); - new_bucket.Release(); - - hapi::Bucket existing_bucket(bucket_name, hermes); - Assert(existing_bucket.GetId() == id); - existing_bucket.Destroy(); -} - -static void TestRenameBlob(HermesPtr hermes) { - std::string bucket_name = "rename_blob_test"; - hapi::Bucket bucket(bucket_name, hermes); - - u8 data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - static_assert(sizeof(data[0]) == sizeof(u8)); - - std::string old_blob_name = "old_blob_name"; - Assert(bucket.Put(old_blob_name, data, sizeof(data)).Succeeded()); - - std::string new_blob_name = "new_blob_name"; - bucket.RenameBlob(old_blob_name, new_blob_name); - Assert(!bucket.ContainsBlob(old_blob_name)); - - hapi::Context ctx; - size_t blob_size = bucket.GetBlobSize(&hermes->trans_arena_, new_blob_name, - ctx); - Assert(blob_size == sizeof(data)); - - hapi::Blob retrieved_data(blob_size); - bucket.Get(new_blob_name, retrieved_data); - - for (size_t i = 0; i < retrieved_data.size(); ++i) { - Assert(retrieved_data[i] == data[i]); - } - bucket.Destroy(); -} - -static void TestRenameBucket(HermesPtr hermes) { - std::string old_bucket_name = "old_bucket"; - hapi::Bucket bucket(old_bucket_name, hermes); - - u8 data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - static_assert(sizeof(data[0]) == sizeof(u8)); - std::string blob_name = "renamed_bucket_blob"; - Assert(bucket.Put(blob_name, data, sizeof(data)).Succeeded()); - - std::string new_bucket_name = "new_bucket"; - bucket.Rename(new_bucket_name); - bucket.Release(); - - hapi::Bucket renamed_bucket(new_bucket_name, hermes); - hapi::Context ctx; - size_t blob_size = renamed_bucket.GetBlobSize(&hermes->trans_arena_, - blob_name, ctx); - Assert(blob_size == sizeof(data)); - - hapi::Blob retrieved_data(blob_size); - renamed_bucket.Get(blob_name, retrieved_data); - - for (size_t i = 0; i < retrieved_data.size(); ++i) { - Assert(retrieved_data[i] == data[i]); - } - renamed_bucket.Destroy(); -} - -static void TestBucketRefCounting(HermesPtr hermes) { - std::string name = "refcounted_bucket"; - - hapi::Bucket bucket1(name, hermes); - hapi::Bucket bucket2(name, hermes); - - // Refcount of "refcounted_bucket" is 2 - bucket1.Destroy(); - - // Bucket should not have been destroyed - Assert(bucket1.IsValid()); - - bucket1.Release(); - // Refcount is 1 - - bucket2.Destroy(); - - Assert(!bucket2.IsValid()); - Assert(!bucket1.IsValid()); -} - -static void TestMaxNameLength(HermesPtr hermes) { - // Bucket with a name that's too large is invalid. - std::string long_bucket_name(kMaxBucketNameSize + 1, 'x'); - bool threw_length_error = false; - try { - hapi::Bucket invalid_bucket(long_bucket_name, hermes); - } - catch (const std::length_error& e) { - threw_length_error = true; - } - Assert(threw_length_error); - - // Put fails when a blob name is too long - std::string name = "b1"; - std::string long_blob_name(kMaxBlobNameSize + 1, 'x'); - hapi::Bucket bucket(name, hermes); - hapi::Blob blob('x'); - Status status = bucket.Put(long_blob_name, blob); - Assert(status.Failed()); - Assert(!bucket.ContainsBlob(long_blob_name)); - - // Vector Put fails if one name is too long - std::string a = "a"; - std::string b = "b"; - std::string c = "c"; - std::vector blob_names = {a, b, long_blob_name, c}; - std::vector blobs = {blob, blob, blob, blob}; - status = bucket.Put(blob_names, blobs); - Assert(status.Failed()); - Assert(!bucket.ContainsBlob(long_blob_name)); - Assert(!bucket.ContainsBlob(a)); - Assert(!bucket.ContainsBlob(b)); - Assert(!bucket.ContainsBlob(c)); - - bucket.Destroy(); -} - -static void TestGetRelativeNodeId() { - RpcContext rpc = {}; - rpc.num_nodes = 10; - rpc.node_id = 1; - - Assert(GetNextNode(&rpc) == 2); - Assert(GetPreviousNode(&rpc) == 10); - - rpc.node_id = 10; - Assert(GetNextNode(&rpc) == 1); - Assert(GetPreviousNode(&rpc) == 9); -} - -static void TestDuplicateBlobNames(HermesPtr hermes) { - const size_t blob_size = 8; - hapi::Bucket b1("b1", hermes); - hapi::Bucket b2("b2", hermes); - std::string blob_name("duplicate"); - hapi::Blob blob1(blob_size, 'x'); - hapi::Blob blob2(blob_size, 'z'); - - Assert(b1.Put(blob_name, blob1).Succeeded()); - Assert(!b2.ContainsBlob(blob_name)); - - Assert(b2.Put(blob_name, blob2).Succeeded()); - - Assert(b1.ContainsBlob(blob_name)); - Assert(b2.ContainsBlob(blob_name)); - - hapi::Blob result(blob_size, '0'); - Assert(b1.Get(blob_name, result) == blob_size); - Assert(result == blob1); - Assert(b2.Get(blob_name, result) == blob_size); - Assert(result == blob2); - - Assert(b1.Destroy().Succeeded()); - Assert(b2.Destroy().Succeeded()); -} - -static void TestGetBucketIdFromBlobId(HermesPtr hermes) { - const size_t blob_size = 8; - hapi::Bucket b1("b1", hermes); - std::string blob_name("blob1"); - hapi::Blob blob1(blob_size, 'x'); - Assert(b1.Put(blob_name, blob1).Succeeded()); - - BucketID b1_id = {}; - b1_id.as_int = b1.GetId(); - BlobID blob_id = - hermes::GetBlobId(&hermes->context_, &hermes->rpc_, blob_name, b1_id); - - BucketID bucket_id = - hermes::GetBucketIdFromBlobId(&hermes->context_, &hermes->rpc_, blob_id); - - Assert(bucket_id.as_int == b1.GetId()); - Assert(b1.Destroy().Succeeded()); -} - -static void TestHexStringToU64() { - std::string zero1("0"); - std::string zero2 = zero1 + zero1; - std::string zero4 = zero2 + zero2; - std::string zero8 = zero4 + zero4; - - std::string one_str = zero8 + zero4 + zero2 + "01"; - std::string ff_str = zero8 + zero4 + zero2 + "ff"; - std::string all_f_str("ffffffffffffffff"); - std::string bucket_id_str = zero4 + zero2 + "01" + zero4 + zero2 + "0e"; - std::string count_str("123456789abcdef0"); - - u64 one = 0x1ULL; - u64 ff = 0xffULL; - u64 bucket_id = 0x10000000eULL; - u64 all_f = 0xffffffffffffffffULL; - u64 count = 0x123456789abcdef0ULL; - - BucketID id = {}; - id.as_int = 1311768467463790320; - std::string blob_name = MakeInternalBlobName(std::string("my_blob"), id); - - Assert(HexStringToU64(one_str) == one); - Assert(HexStringToU64(ff_str) == ff); - Assert(HexStringToU64(bucket_id_str) == bucket_id); - Assert(HexStringToU64(all_f_str) == all_f); - Assert(HexStringToU64(count_str) == count); - Assert(HexStringToU64(blob_name) == count); -} - -void TestSwapBlobsExistInBucket() { - hermes::Config config = {}; - hermes::InitDefaultConfig(&config); - const int kNumDevices = 4; - for (int i = 0; i < kNumDevices; ++i) { - // NOTE(chogan): Restrict buffering capacity so blobs go to swap - config.capacities[i] = MEGABYTES(1); - } - std::shared_ptr hermes = hermes::InitHermes(&config, true); - - hermes::api::Bucket swap_bucket("swap_test", hermes); - hermes::api::Blob blob(128*1024, 255); - auto success_blob_names = std::vector(); - for (int i = 0; i < 32; i++) { - std::string blob_name = "Blob" + std::to_string(i); - hapi::Status status = swap_bucket.Put(blob_name, blob); - if (!status.Failed()) { - success_blob_names.push_back(blob_name); - } - } - for (const auto &blob_name : success_blob_names) { - bool exists = swap_bucket.ContainsBlob(blob_name); - Assert(exists); - } - - hermes->Finalize(true); -} - -static void TestBlobInfoMap() { - HermesPtr hermes = hapi::InitHermes(NULL, true); - - const int kIters = 4; - hapi::Bucket bkt("test_blob_info_map", hermes); - - hapi::Blob data(64, 'x'); - - for (int i = 0; i < kIters; ++i) { - std::string name = "blob_" + std::to_string(i); - bkt.Put(name, data); - } - - for (int i = 0; i < kIters; ++i) { - std::string name = "blob_" + std::to_string(i); - bkt.DeleteBlob(name); - } - - bkt.Destroy(); - - hermes->Finalize(true); -} - -static void TestMdmViz() { - using namespace hermes; // NOLINT(*) - - Config config = {}; - InitDefaultConfig(&config); - config.num_devices = 1; - config.num_targets = 1; - config.block_sizes[0] = 4096; - config.num_slabs[0] = 1; - config.desired_slab_percentages[0][0] = 1.0f; - - HermesPtr hermes = InitHermesDaemon(&config); - SharedMemoryContext *context = &hermes->context_; - MetadataManager *mdm = GetMetadataManagerFromContext(context); - IdList ids1 = AllocateIdList(mdm, KILOBYTES(4)); - FreeIdList(mdm, ids1); - IdList ids2 = AllocateIdList(mdm, KILOBYTES(1)); - IdList ids3 = AllocateIdList(mdm, KILOBYTES(1)); - IdList ids4 = AllocateIdList(mdm, KILOBYTES(1)); - IdList ids5 = AllocateIdList(mdm, KILOBYTES(1)); - IdList ids6 = AllocateIdList(mdm, KILOBYTES(1)); - IdList ids7 = AllocateIdList(mdm, KILOBYTES(1)); - - FreeIdList(mdm, ids5); - FreeIdList(mdm, ids6); - FreeIdList(mdm, ids4); - FreeIdList(mdm, ids3); - FreeIdList(mdm, ids2); - FreeIdList(mdm, ids7); - - std::string base_name("xxxxxxxxxxxxxxx"); - hapi::Bucket bucket(std::string(base_name + "bkt"), hermes); - - hapi::Blob data(255, 'z'); - - for (int i = 0; i < 10; ++i) { - bucket.Put(std::string(base_name + std::to_string(i)), data); - } - - bucket.Destroy(); - - hermes->Finalize(true); -} - -static void TestEffectiveTarget() { - using namespace hermes; // NOLINT(*) - - hermes::Config config = {}; - hermes::InitDefaultConfig(&config); - config.default_placement_policy = hapi::PlacementPolicy::kRoundRobin; - config.default_rr_split = 0; - HermesPtr hermes = hermes::InitHermesDaemon(&config); - - hermes::RoundRobin rr_state; - rr_state.SetCurrentDeviceIndex(0); - - std::string bucket_name(__func__); - hapi::Bucket bucket(bucket_name, hermes); - hapi::Blob data(4 * 1024, 'z'); - std::string blob_name("1"); - bool success = bucket.Put(blob_name, data).Succeeded(); - Assert(success); - - SharedMemoryContext *context = &hermes->context_; - RpcContext *rpc = &hermes->rpc_; - MetadataManager *mdm = GetMetadataManagerFromContext(context); - - // Check BlobInfo::effective_target - BucketID bucket_id = GetBucketId(context, rpc, bucket_name.c_str()); - BlobID blob_id = GetBlobId(context, rpc, blob_name, bucket_id, false); - BlobInfo *info = GetBlobInfoPtr(mdm, blob_id); - TargetID expected_target_id = {{1, 0, 0}}; - Assert(info->effective_target.as_int == expected_target_id.as_int); - ReleaseBlobInfoPtr(mdm); - - // Check Target::effective_blobs - Target *ram_target = GetTarget(context, 0); - Assert(ram_target->effective_blobs.length == 1); - u64 *ids = GetIdsPtr(mdm, ram_target->effective_blobs); - BlobID effective_blob_id = {}; - effective_blob_id.as_int = ids[0]; - Assert(effective_blob_id.as_int == blob_id.as_int); - ReleaseIdsPtr(mdm); - - bucket.Destroy(); - - hermes->Finalize(true); -} - -int main(int argc, char **argv) { - int mpi_threads_provided; - MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &mpi_threads_provided); - if (mpi_threads_provided < MPI_THREAD_MULTIPLE) { - fprintf(stderr, "Didn't receive appropriate MPI threading specification\n"); - return 1; - } - - HermesPtr hermes = hapi::InitHermes(NULL, true); - - HERMES_ADD_TEST(TestNullIds); - HERMES_ADD_TEST(TestGetMapMutex); - HERMES_ADD_TEST(TestLocalGetNextFreeBucketId, hermes); - HERMES_ADD_TEST(TestGetOrCreateBucketId, hermes); - HERMES_ADD_TEST(TestRenameBlob, hermes); - HERMES_ADD_TEST(TestRenameBucket, hermes); - HERMES_ADD_TEST(TestBucketRefCounting, hermes); - HERMES_ADD_TEST(TestMaxNameLength, hermes); - HERMES_ADD_TEST(TestGetRelativeNodeId); - HERMES_ADD_TEST(TestDuplicateBlobNames, hermes); - HERMES_ADD_TEST(TestGetBucketIdFromBlobId, hermes); - HERMES_ADD_TEST(TestHexStringToU64); - - hermes->Finalize(true); - - HERMES_ADD_TEST(TestSwapBlobsExistInBucket); - HERMES_ADD_TEST(TestBlobInfoMap); - HERMES_ADD_TEST(TestMdmViz); - HERMES_ADD_TEST(TestEffectiveTarget); - - MPI_Finalize(); - - printf("SUCCESS!\n"); - return 0; -} diff --git a/test/memory_test.cc b/test/memory_test.cc deleted file mode 100644 index 52b5915dd..000000000 --- a/test/memory_test.cc +++ /dev/null @@ -1,96 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "test_utils.h" - -using namespace hermes; // NOLINT(*) - -const int kNumVals = 8; - -struct SixtyFourBytes { - u64 vals[kNumVals]; -}; - -void FillArrayU64(SixtyFourBytes *s, u64 val) { - for (int i = 0; i < kNumVals; ++i) { - s->vals[i] = val; - } -} - -void CheckArrayU64(SixtyFourBytes *s, u64 val) { - for (int i = 0; i < kNumVals; ++i) { - Assert(s->vals[i] == val); - } -} -void TestFillFreeBlocks(Heap *heap) { - SixtyFourBytes *s1 = HeapPushStruct(heap); - FillArrayU64(s1, 1); - SixtyFourBytes *s2 = HeapPushStruct(heap); - FillArrayU64(s2, 2); - SixtyFourBytes *s3 = HeapPushStruct(heap); - FillArrayU64(s3, 3); - SixtyFourBytes *s4 = HeapPushStruct(heap); - FillArrayU64(s4, 4); - - CheckArrayU64(s1, 1); - CheckArrayU64(s2, 2); - CheckArrayU64(s3, 3); - CheckArrayU64(s4, 4); - - HeapFree(heap, s2); - HeapFree(heap, s3); - - CheckArrayU64(s1, 1); - CheckArrayU64(s4, 4); - - SixtyFourBytes *s5 = HeapPushStruct(heap); - FillArrayU64(s5, 5); - SixtyFourBytes *s6 = HeapPushStruct(heap); - FillArrayU64(s6, 6); - - CheckArrayU64(s1, 1); - CheckArrayU64(s4, 4); - CheckArrayU64(s5, 5); - CheckArrayU64(s6, 6); - - HeapFree(heap, s1); - HeapFree(heap, s4); - HeapFree(heap, s5); - HeapFree(heap, s6); - - SixtyFourBytes *s7 = HeapPushArray(heap, 2); - FillArrayU64(s7, 7); - FillArrayU64(s7 + 1, 7); - - CheckArrayU64(s7, 7); - CheckArrayU64(s7 + 1, 7); - - HeapFree(heap, s7); -} - -int main() { - Arena arena = InitArenaAndAllocate(KILOBYTES(4)); - - TemporaryMemory temporary_memory = BeginTemporaryMemory(&arena); - Heap *heap = InitHeapInArena(temporary_memory.arena); - TestFillFreeBlocks(heap); - EndTemporaryMemory(&temporary_memory); - - temporary_memory = BeginTemporaryMemory(&arena); - Heap *reverse_heap = InitHeapInArena(temporary_memory.arena, false); - TestFillFreeBlocks(reverse_heap); - EndTemporaryMemory(&temporary_memory); - - DestroyArena(&arena); - - return 0; -} diff --git a/test/mpi_test.c b/test/mpi_test.c deleted file mode 100644 index dc7bce925..000000000 --- a/test/mpi_test.c +++ /dev/null @@ -1,37 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -#include "mpi.h" - -#include "gotcha_mpi_io.h" - -int main(int argc, char *argv[]) { - MPI_File fh; - int buf[1000], rank; - - init_gotcha_mpi_io(); - - MPI_Init(0, 0); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_File_open(MPI_COMM_WORLD, "test.out", - MPI_MODE_CREATE|MPI_MODE_WRONLY, MPI_INFO_NULL, &fh); - - if (rank == 0) - MPI_File_write(fh, buf, 1000, MPI_INT, MPI_STATUS_IGNORE); - - MPI_File_close(&fh); - MPI_Finalize(); - - return 0; -} diff --git a/test/prefetch_test.cc b/test/prefetch_test.cc deleted file mode 100644 index 0db1ae882..000000000 --- a/test/prefetch_test.cc +++ /dev/null @@ -1,117 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "hermes.h" -#include "bucket.h" -#include "vbucket.h" -#include -#include -#include "timer.h" - -namespace hapi = hermes::api; - -bool VerifyBlob(hapi::Blob &blob, int nonce, size_t ret_size) { - if (ret_size != blob.size()) { - LOG(INFO) << "The blob get did not get full blob: " - << " ret_size: " << ret_size - << " blob_size: " << std::endl; - return false; - } - for (auto &c : blob) { - if (c != static_cast(nonce)) { - LOG(INFO) << "The blob get was not successful" - << " nonce: " << (int)nonce - << " ret: " << (int)c; - return false; - } - } - return true; -} - -int main(int argc, char **argv) { - MPI_Init(&argc, &argv); - std::shared_ptr hermes = - hermes::InitHermesDaemon(getenv("HERMES_CONF")); - - if (argc != 6) { - std::cout << "USAGE: ./prefetch_test" - << "[with_prefetch] [dataset_mb] [blob_size_mb]" - << "[read_ahead] [phase] [clear_cache_path]" << std::endl; - } - - bool with_prefetch = atoi(argv[1]); - size_t dataset_size = MEGABYTES(atoi(argv[2])); - size_t blob_size = MEGABYTES(atoi(argv[3])); - size_t blob_count = dataset_size / blob_size; - int read_ahead = atoi(argv[4]); - int phase = atoi(argv[5]); - std::string clear_cache = argv[6]; - std::string clear_cache_script = ("bash " + clear_cache); - - std::cout << clear_cache_script << std::endl; - system(clear_cache_script.c_str()); - - std::cout << "Dataset Size: " << dataset_size / MEGABYTES(1) - << " Blob Size: " << blob_size / MEGABYTES(1) - << " Blob Count: " << blob_count << std::endl; - - hapi::Context ctx; - if (with_prefetch) { - ctx.pctx_.hint_ = hapi::PrefetchHint::kFileSequential; - ctx.pctx_.read_ahead_ = read_ahead; - printf("Prefetch is enabled\n"); - } - std::string bkt_name = "PREFETCH"; - auto bkt = std::make_shared( - bkt_name, hermes, ctx); - - // Place blobs - for (int i = 0; i < blob_count; ++i) { - hapi::Blob blob; - blob.resize(blob_size, i); - hermes::adapter::BlobPlacement p; - p.page_ = i; - std::string blob_name = p.CreateBlobName(); - bkt->Put(blob_name, blob); - } - LOG(INFO) << "FINISHED PUTTING ALL BLOBS" << std::endl; - - //std::cout << clear_cache_script << std::endl; - //system(clear_cache_script.c_str()); - - // Get blobs (sequentially) - hermes::HighResMonotonicTimer t; - t.Resume(); - for (int i = 0; i < blob_count; ++i) { - hapi::Blob blob; - blob.resize(blob_size, -1); - hermes::adapter::BlobPlacement p; - p.page_ = i; - std::string blob_name = p.CreateBlobName(); - size_t ret = bkt->Get(blob_name, blob); - assert(VerifyBlob(blob, i, ret)); - if (phase > 0) { - hermes::HighResMonotonicTimer t2; - t2.Resume(); - while(t2.GetMsecFromStart() < phase) { - ABT_thread_yield(); - } - } - } - t.Pause(); - LOG(INFO) << "FINISHED GETTING ALL BLOBS" << std::endl; - std::cout <<"TIME: " << t.GetMsec() << std::endl; - - hermes->Finalize(true); - MPI_Finalize(); -} diff --git a/test/stdio_test.c b/test/stdio_test.c deleted file mode 100644 index 3cc745ccd..000000000 --- a/test/stdio_test.c +++ /dev/null @@ -1,28 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include - -#include "gotcha_stdio.h" - -int main() { - FILE * pFile; - char buffer[] = { 'x' , 'y' , 'z' }; - - init_gotcha_stdio(); - - pFile = fopen("myfile.bin", "wb"); - fwrite(buffer , sizeof(char), sizeof(buffer), pFile); - fclose(pFile); - return 0; -} diff --git a/test/test_rpc.cc b/test/test_rpc.cc new file mode 100644 index 000000000..c79ce1fe6 --- /dev/null +++ b/test/test_rpc.cc @@ -0,0 +1,6 @@ +// +// Created by lukemartinlogan on 12/2/22. +// + +int main() { +} \ No newline at end of file diff --git a/test/test_utils.h b/test/test_utils.h deleted file mode 100644 index 15edbf6d5..000000000 --- a/test/test_utils.h +++ /dev/null @@ -1,98 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_TEST_UTILS_H_ -#define HERMES_TEST_UTILS_H_ - -#include -#include - -#include -#include -#include -#include - -#include "bucket.h" -#include "hermes_types.h" - -#define HERMES_ADD_TEST(test_name, ...) \ - if (argc == 1 || std::string(argv[1]) == #test_name) { \ - fprintf(stdout, "### Running %s\n", #test_name); \ - test_name(__VA_ARGS__); \ - } - -namespace hermes { -namespace testing { - -// TODO(chogan): Keep time in generic units and only convert the duration at the -// end -class Timer { - public: - Timer() : elapsed_time(0) {} - void resumeTime() { t1 = std::chrono::high_resolution_clock::now(); } - double pauseTime() { - auto t2 = std::chrono::high_resolution_clock::now(); - elapsed_time += std::chrono::duration(t2 - t1).count(); - return elapsed_time; - } - double getElapsedTime() { return elapsed_time; } - void reset() { elapsed_time = 0; } - - private: - std::chrono::high_resolution_clock::time_point t1; - double elapsed_time; -}; - -void Assert(bool expr, const char *file, int lineno, const char *message) { - if (!expr) { - fprintf(stderr, "Assertion failed at %s: line %d: %s\n", file, lineno, - message); - exit(-1); - } -} - -#define Assert(expr) hermes::testing::Assert((expr), __FILE__, __LINE__, #expr) - -TargetID DefaultRamTargetId() { - TargetID result = {}; - result.bits.node_id = 1; - result.bits.device_id = 0; - result.bits.index = 0; - - return result; -} - -TargetID DefaultFileTargetId() { - TargetID result = {}; - result.bits.node_id = 1; - result.bits.device_id = 1; - result.bits.index = 1; - - return result; -} - -void GetAndVerifyBlob(api::Bucket &bucket, const std::string &blob_name, - const api::Blob &expected) { - api::Blob retrieved_blob; - size_t expected_size = expected.size(); - size_t retrieved_size = bucket.Get(blob_name, retrieved_blob); - Assert(expected_size == retrieved_size); - retrieved_blob.resize(retrieved_size); - retrieved_size = bucket.Get(blob_name, retrieved_blob); - Assert(expected_size == retrieved_size); - Assert(retrieved_blob == expected); -} - -} // namespace testing -} // namespace hermes - -#endif // HERMES_TEST_UTILS_H_ diff --git a/test/timer.h b/test/timer.h deleted file mode 100644 index 4df1ebd2f..000000000 --- a/test/timer.h +++ /dev/null @@ -1,201 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_TIMER_H -#define HERMES_TIMER_H - -#include -#include -#include - -namespace hermes { - -template -class Timer { - private: - std::chrono::time_point start_, end_; - double time_ns_; - - public: - Timer() : time_ns_(0) {} - - void Resume() { - start_ = T::now(); - } - double Pause() { - time_ns_ += GetNsecFromStart(); - return time_ns_; - } - double Pause(double &dt) { - dt = GetNsecFromStart(); - time_ns_ += dt; - return time_ns_; - } - void Reset() { - time_ns_ = 0; - } - - double GetNsecFromStart() { - end_ = T::now(); - double elapsed = std::chrono::duration_cast( - end_ - start_).count(); - return elapsed; - } - double GetUsecFromStart() { - end_ = T::now(); - return std::chrono::duration_cast( - end_ - start_).count(); - } - double GetMsecFromStart() { - end_ = T::now(); - return std::chrono::duration_cast( - end_ - start_).count(); - } - double GetSecFromStart() { - end_ = T::now(); - return std::chrono::duration_cast( - end_ - start_).count(); - } - - double GetNsec() const { - return time_ns_; - } - double GetUsec() const { - return time_ns_/1000; - } - double GetMsec() const { - return time_ns_/1000000; - } - double GetSec() const { - return time_ns_/1000000000; - } - - double GetUsFromEpoch() const { - std::chrono::time_point point = - std::chrono::system_clock::now(); - return std::chrono::duration_cast( - point.time_since_epoch()).count(); - } -}; - -template -class ThreadedTimer { - private: - std::vector> timers_; - - public: - ThreadedTimer() = default; - - void Resume(int tid) { - MinimumTID(tid); - timers_[tid].Resume(); - } - double Pause(int tid) { - MinimumTID(tid); - return timers_[tid].Pause(); - } - double Pause(int tid, double &dt) { - MinimumTID(tid); - return timers_[tid].Pause(dt); - } - void Reset(int tid) { - MinimumTID(tid); - timers_[tid].Reset(); - } - - double GetMsecFromStart(int tid) { - MinimumTID(tid); - return timers_[tid].GetMsecFromStart(); - } - - double GetNsec(int tid) { - MinimumTID(tid); - return timers_[tid].GetNsec(); - } - double GetUsec(int tid) { - MinimumTID(tid); - return timers_[tid].GetUsec(); - } - double GetMsec(int tid) { - MinimumTID(tid); - return timers_[tid].GetMsec(); - } - double GetSec(int tid) { - MinimumTID(tid); - return timers_[tid].GetSec(); - } - double GetUsFromEpoch(int tid) { - MinimumTID(tid); - return timers_[tid].GetUsFromEpoch(); - } - - double GetMsecFromStart() const { - auto iter = std::max_element(timers_.begin(), timers_.end(), - [] (Timer const& lhs, Timer const& rhs) { - return lhs.GetMsecFromStart() < rhs.GetMsecFromStart(); - }); - return iter->GetMsecFromStart(); - } - double GetNsec() const { - auto iter = std::max_element(timers_.begin(), timers_.end(), - [] (Timer const& lhs, Timer const& rhs) { - return lhs.GetNsec() < rhs.GetNsec(); - }); - return iter->GetNsec(); - } - double GetUsec() const { - auto iter = std::max_element(timers_.begin(), timers_.end(), - [] (Timer const& lhs, Timer const& rhs) { - return lhs.GetUsec() < rhs.GetUsec(); - }); - return iter->GetUsec(); - } - double GetMsec() const { - auto iter = std::max_element(timers_.begin(), timers_.end(), - [] (Timer const& lhs, Timer const& rhs) { - return lhs.GetMsec() < rhs.GetMsec(); - }); - return iter->GetMsec(); - } - double GetSec() const { - auto iter = std::max_element(timers_.begin(), timers_.end(), - [] (Timer const& lhs, Timer const& rhs) { - return lhs.GetSec() < rhs.GetSec(); - }); - return iter->GetSec(); - } - double GetUsFromEpoch() const { - auto iter = std::max_element(timers_.begin(), timers_.end(), - [] (Timer const& lhs, Timer const& rhs) { - return lhs.GetUsFromEpoch() < rhs.GetUsFromEpoch(); - }); - return iter->GetUsFromEpoch(); - } - - private: - void MinimumTID(int tid) { - if ((size_t)tid >= timers_.size()) { - timers_.resize(tid+1); - } - } -}; - -typedef Timer HighResCpuTimer; -typedef Timer HighResMonotonicTimer; -typedef ThreadedTimer - ThreadedHighResCpuTimer; -typedef ThreadedTimer - ThreadedHighResMonotonicTimer; - -} // namespace labstor - -#endif // HERMES_TIMER_H diff --git a/test/trait_test.cc b/test/trait_test.cc deleted file mode 100644 index ff99351d8..000000000 --- a/test/trait_test.cc +++ /dev/null @@ -1,144 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -#include "catch_config.h" - -#include "bucket.h" -#include "hermes.h" -#include "vbucket.h" -#include "test_utils.h" - -namespace stdfs = std::experimental::filesystem; -namespace hapi = hermes::api; - -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp"; - std::string config = "./hermes.yaml"; - size_t request_size = 16 * 1024; - size_t iterations = 1024; -}; - -struct Info { - int rank; - int comm_size; - hapi::Blob write_blob; - const size_t FILE_PAGE = 16 * 1024; -}; - -Arguments args; -Info info; - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.config, - "config")["-c"]["--config"]("Configuration file for hermes") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size for each operation") | - cl::Opt(args.iterations, - "iterations")["-z"]["--iterations"]("Number of iterations"); -} - -int init() { - MPI_Comm_rank(MPI_COMM_WORLD, &info.rank); - MPI_Comm_size(MPI_COMM_WORLD, &info.comm_size); - return 0; -} - -int finalize() { return 0; } - -std::string gen_random(const int len) { - std::string tmp_s; - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - - srand((unsigned)time(NULL) * getpid()); - - tmp_s.reserve(len); - - for (int i = 0; i < len; ++i) - tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)]; - - return tmp_s; -} - -int pretest() { - args.filename += "_" + std::to_string(getpid()); - auto str = gen_random(args.request_size); - info.write_blob = hapi::Blob(str.begin(), str.end()); - return 0; -} -int posttest() { return 0; } - -TEST_CASE("CustomTrait", - "[module=trait][type=meta][trait=FileBacked]" - "[process=" + - std::to_string(info.comm_size) + "]") { - pretest(); - - using HermesPtr = std::shared_ptr; - HermesPtr hermes_app = hapi::InitHermes(args.config.c_str(), true); - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - std::string fullpath_str = fullpath.string(); - - SECTION("Basic") { - hapi::Bucket file_bucket(args.filename, hermes_app); - hapi::VBucket file_vbucket(args.filename, hermes_app); - auto offset_map = std::unordered_map(); - auto blob_cmp = [](std::string a, std::string b) { - return std::stol(a) < std::stol(b); - }; - auto blob_names = std::set(blob_cmp); - auto check_write = hapi::Blob(); - for (size_t i = 0; i < args.iterations; ++i) { - hapi::Status status = - file_bucket.Put(std::to_string(i), info.write_blob); - Assert(status.Succeeded()); - blob_names.insert(std::to_string(i)); - check_write.insert(check_write.end(), info.write_blob.begin(), - info.write_blob.end()); - } - for (const auto& blob_name : blob_names) { - file_vbucket.Link(blob_name, args.filename); - offset_map.emplace(blob_name, std::stol(blob_name) * info.FILE_PAGE); - } - bool flush_synchronously = true; - hapi::PersistTrait persist_trait(fullpath_str, offset_map, - flush_synchronously); - file_vbucket.Attach(&persist_trait); - file_vbucket.Destroy(); - file_bucket.Destroy(); - REQUIRE(stdfs::exists(fullpath_str)); - - size_t total_bytes = args.iterations * args.request_size; - REQUIRE(stdfs::file_size(fullpath_str) == total_bytes); - auto read_blob = hapi::Blob(total_bytes, '0'); - FILE* fh = fopen(fullpath_str.c_str(), "r+"); - REQUIRE(fh != nullptr); - auto read_size = fread(read_blob.data(), total_bytes, 1, fh); - REQUIRE(read_size == 1); - bool is_same = read_blob == check_write; - REQUIRE(is_same); - auto status = fclose(fh); - REQUIRE(status == 0); - } - hermes_app->Finalize(true); - posttest(); -} diff --git a/test/vbucket_test.cc b/test/vbucket_test.cc deleted file mode 100644 index 3b712028a..000000000 --- a/test/vbucket_test.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include "bucket.h" -#include "hermes.h" -#include "test_utils.h" - -namespace hapi = hermes::api; - -int main(int argc, char **argv) { - int mpi_threads_provided; - MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &mpi_threads_provided); - if (mpi_threads_provided < MPI_THREAD_MULTIPLE) { - fprintf(stderr, "Didn't receive appropriate MPI threading specification\n"); - return 1; - } - - char *config_file = 0; - if (argc == 2) { - config_file = argv[1]; - } - - std::shared_ptr hermes = hapi::InitHermes(config_file); - - int num_blobs_per_rank = 16; - int data_size = 8 * 1024; - hapi::Blob put_data(data_size, rand() % 255); - hapi::Blob get_data(data_size, 255); - if (hermes->IsApplicationCore()) { - int app_rank = hermes->GetProcessRank(); - int app_size = hermes->GetNumProcesses(); - - hapi::Context ctx; - - // Each rank puts and gets its portion of a blob to a shared bucket - std::string bucket_name = "test_bucket" + std::to_string(app_rank); - hapi::Bucket rank_bucket(bucket_name, hermes, ctx); - for (int i = 0; i < num_blobs_per_rank; ++i) { - std::string blob_name = - "Blob_" + std::to_string(app_rank) + "_" + std::to_string(i); - rank_bucket.Put(blob_name, put_data, ctx); - } - hapi::VBucket shared("shared_vbucket", hermes, ctx); - for (int i = 0; i < num_blobs_per_rank; ++i) { - std::string blob_name = - "Blob_" + std::to_string(app_rank) + "_" + std::to_string(i); - shared.Link(blob_name, bucket_name, ctx); - } - hermes->AppBarrier(); - if (app_rank == 0) { - auto blob_ids = shared.GetLinks(ctx); - Assert(blob_ids.size() == (unsigned long)app_size * num_blobs_per_rank); - for (int rank = 0; rank < app_size; ++rank) { - std::string bucket_name_temp = "test_bucket" + std::to_string(rank); - for (int i = 0; i < num_blobs_per_rank; ++i) { - std::string blob_name = - "Blob_" + std::to_string(rank) + "_" + std::to_string(i); - auto exists = shared.ContainsBlob(blob_name, bucket_name_temp); - Assert(exists); - } - } - } - hermes->AppBarrier(); - rank_bucket.Destroy(ctx); - hermes->AppBarrier(); - if (app_rank == 0) { - auto blob_ids = shared.GetLinks(ctx); - Assert(blob_ids.size() == (unsigned long)app_size * num_blobs_per_rank); - for (int rank = 0; rank < app_size; ++rank) { - std::string bucket_name_temp = "test_bucket" + std::to_string(rank); - for (int i = 0; i < num_blobs_per_rank; ++i) { - std::string blob_name = - "Blob_" + std::to_string(rank) + "_" + std::to_string(i); - auto exists = shared.ContainsBlob(blob_name, bucket_name_temp); - Assert(!exists); - } - } - } - if (app_rank == 0) { - shared.Destroy(ctx); - } - hermes->AppBarrier(); - } else { - // Hermes core. No user code here. - } - - hermes->Finalize(); - - MPI_Finalize(); - - return 0; -} From 96eba9f9cf3bd1317ecc360e29f07f7cde645d8d Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 2 Dec 2022 17:19:48 -0600 Subject: [PATCH 042/511] Size parsing for config. New config format. --- config/hermes_server_default.yaml | 68 +++++---- src/config.h | 138 ++++++++++++------ src/config_server.cc | 235 ++---------------------------- src/data_structures.h | 16 ++ src/hermes_types.h | 13 -- 5 files changed, 162 insertions(+), 308 deletions(-) create mode 100644 src/data_structures.h diff --git a/config/hermes_server_default.yaml b/config/hermes_server_default.yaml index 09e27c1e7..061683ea8 100644 --- a/config/hermes_server_default.yaml +++ b/config/hermes_server_default.yaml @@ -12,12 +12,12 @@ devices: # The maximum buffering capacity in MiB of each device. Here we say that all 4 # devices get 50 MiB of buffering capacity. - capacity_mb: 50 + capacity: 50MB # The size of the smallest available buffer in KiB. In general this should be # the page size of your system for byte addressable storage, and the block size # of the storage device for block addressable storage. - block_size_kb: 4 + block_size: 4KB # The number of blocks (the size of which is chosen in block_sizes_kb) that each # device should contain for each slab (controlled by num_slabs). This allows for @@ -25,35 +25,57 @@ devices: slab_units: [1, 4, 16, 32] # The maximum theoretical bandwidth (as advertised by the manufacturer) in - # MiB/sec. of each device. - bandwidth_mbps: 6000 + # Possible units: KBps, MBps, GBps + bandwidth: 6000MBps - # The latency in microseconds of each device (as advertised by the manufacturer). - latencies_us: 15 + # The latency of each device (as advertised by the manufacturer). + # Possible units: ns, us, ms, s + latency: 15us # For each device, indicate '1' if it is shared among nodes (e.g., burst # buffers), or '0' if it is per node (e.g., local NVMe). is_shared_device: 0 + # For each device, the minimum and maximum percent capacity threshold at which + # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause + # the BufferOrganizer to move data to lower devices, making more room in faster + # devices (ideal for write-heavy workloads). Conversely, increasing the minimum + # threshold will cause data to be moved from slower devices into faster devices + # (ideal for read-heavy workloads). For example, a maximum capacity threshold of + # 0.8 would have the effect of always keeping 20% of the device's space free for + # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure + # that the device is always at least 30% occupied. + borg_capacity_thresh: [0.0, 1.0] + nvme: mount_point: "./" - capacity_mb: 50 - block_size_kb: 4 - slab_units: [1, 4, 16, 32] + capacity: 50MB + block_size: 4KB + slab_units: [ 1, 4, 16, 32 ] + bandwidth: 1GBps + latency: 600us is_shared_device: 0 + borg_capacity_thresh: [ 0.0, 1.0 ] ssd: mount_point: "./" - capacity_mb: 50 - block_size_kb: 4 + capacity: 50MB + block_size: 4KB slab_units: [ 1, 4, 16, 32 ] + bandwidth: 500MBps + latency: 1200us is_shared_device: 0 + borg_capacity_thresh: [ 0.0, 1.0 ] pfs: mount_point: "./" - capacity_mb: inf - block_size_kb: 64 # Assume 64KB strip size - slab_units: [1, 4, 16, 32] + capacity: inf + block_size: 64KB # The stripe size of PFS + slab_units: [ 1, 4, 16, 32 ] + bandwidth: 100MBps # Per-device bandwidth + latency: 200ms + is_shared_device: 0 + borg_capacity_thresh: [ 0.0, 1.0 ] ### Define the network communication protocol rpc: @@ -93,22 +115,6 @@ buffer_organizer: # The number of threads used in the background organization of internal Hermes buffers. num_threads: 4 - # For each device, the minimum and maximum percent capacity threshold at which - # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause - # the BufferOrganizer to move data to lower devices, making more room in faster - # devices (ideal for write-heavy workloads). Conversely, increasing the minimum - # threshold will cause data to be moved from slower devices into faster devices - # (ideal for read-heavy workloads). For example, a maximum capacity threshold of - # 0.8 would have the effect of always keeping 20% of the device's space free for - # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure - # that the device is always at least 30% occupied. - capacity_thresholds: [ - [ 0.0, 1.0 ], - [ 0.0, 1.0 ], - [ 0.0, 1.0 ], - [ 0.0, 1.0 ] - ] - ### Define the default data placement policy dpe: # Choose Random, RoundRobin, or MinimizeIoTime @@ -121,6 +127,7 @@ dpe: # The shared memory prefix for the hermes shared memory segment. A user name # will be automatically appended. shmem_name: "/hermes_shm_" + # The interval in milliseconds at which to update the global system view. system_view_state_update_interval_ms: 1000 @@ -131,6 +138,7 @@ path_exclusions: [ "/sys/", "/usr/", "/var/", "/run/", "pipe", "socket:", "anon_inode:" ] + #Paths which are never ignored when buffering data path_inclusions: ["/var/opt/cray/dws/mounts/"] diff --git a/src/config.h b/src/config.h index 6525542dc..1d597f948 100644 --- a/src/config.h +++ b/src/config.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include "data_structures.h" #include "hermes_types.h" @@ -40,70 +40,52 @@ struct ClientConfig { void LoadDefault(); }; +struct DeviceInfo { + /** The minimum transfer size of each device */ + size_t block_size_; + /** The unit of each slab, a multiple of the Device's block size */ + lipcl::vector slab_sizes_; + /** The mount point of a device */ + lipcl::string mount_point_; + /** Device capacity (bytes) */ + size_t capacity_; + /** Bandwidth of a device (MBps) */ + f32 bandwidth_; + /** Latency of the device (us)*/ + f32 latency_; + /** Whether or not the device is shared among all nodes */ + bool is_shared_; + /** */ +}; + /** * System and user configuration that is used to initialize Hermes. */ class ServerConfig { public: - /** The total capacity of each buffering Device */ - size_t capacities_[kMaxDevices]; - /** The block sizes for each device */ - lipcl::vector block_sizes_; + /** The device information */ + lipcl::vector devices_; - /** The block sizes of each Device */ - int block_sizes_[kMaxDevices]; - /** The unit of each slab, a multiple of the Device's block size */ - int slab_unit_sizes[kMaxDevices][kMaxBufferPoolSlabs]; - /** The percentage of space each slab should occupy per Device. The values - * for each Device should add up to 1.0. - */ - f32 desired_slab_percentages[kMaxDevices][kMaxBufferPoolSlabs]; - /** The bandwidth of each Device */ - f32 bandwidths[kMaxDevices]; - /** The latency of each Device */ - f32 latencies[kMaxDevices]; - /** The number of Devices */ - int num_devices; - /** The number of Targets */ - int num_targets; - - /** The maximum number of buckets per node */ - u32 max_buckets_per_node; - /** The maximum number of vbuckets per node */ - u32 max_vbuckets_per_node; /** The length of a view state epoch */ u32 system_view_state_update_interval_ms; - /** The mount point or desired directory for each Device. RAM Device should - * be the empty string. - */ - std::string mount_points[kMaxDevices]; - /** The mount point of the swap target. */ - std::string swap_mount; - /** The number of times the BufferOrganizer will attempt to place a swap - * blob into the hierarchy before giving up. */ - int num_buffer_organizer_retries; - - /** If non-zero, the device is shared among all nodes (e.g., burst buffs) */ - int is_shared_device[kMaxDevices]; - /** The name of a file that contains host names, 1 per line */ - std::string rpc_server_host_file; + lipcl::string rpc_server_host_file; /** The hostname of the RPC server, minus any numbers that Hermes may * auto-generate when the rpc_hostNumber_range is specified. */ - std::string rpc_server_base_name; + lipcl::string rpc_server_base_name; /** The list of numbers from all server names. E.g., '{1, 3}' if your servers * are named ares-comp-1 and ares-comp-3 */ - std::vector host_numbers; + lipcl::vector host_numbers; /** The RPC server name suffix. This is appended to the base name plus host number. */ - std::string rpc_server_suffix; + lipcl::string rpc_server_suffix; /** The parsed hostnames from the hermes conf */ - std::vector host_names; + lipcl::vector host_names; /** The RPC protocol to be used. */ - std::string rpc_protocol; + lipcl::string rpc_protocol; /** The RPC domain name for verbs transport. */ - std::string rpc_domain; + lipcl::string rpc_domain; /** The RPC port number. */ int rpc_port; /** The RPC port number for the buffer organizer. */ @@ -142,6 +124,11 @@ class ServerConfig { void LoadText(const std::string &text); void LoadFromFile(const char *path); void LoadDefault(); + + private: + void ParseYAML(YAML::Node &yaml_conf); + void CheckConstraints(); + void ParseHostNames(YAML::Node yaml_conf); }; /** print \a expected value and fail when an error occurs */ @@ -251,5 +238,64 @@ void ParseRangeList(YAML::Node list_node, std::string var, } } +std::string ParseNumberSuffix(const std::string &num_text) { + int i; + for (i = 0; i < num_text.size(); ++i) { + char c = num_text[i]; + if ('0' <= c && c <= '9') continue; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue; + break; + } + return std::string(num_text.begin() + i, num_text.end());; +} + +size_t ParseNumber(const std::string &num_text) { + size_t size; + std::stringstream(num_text) >> size; + return size; +} + +/** Returns size (bytes) */ +size_t ParseSize(const std::string &size_text) { + size_t size = ParseNumber(size_text); + std::string suffix = ParseNumberSuffix(size_text); + if (suffix.size() == 0) { + return size; + } else if (suffix[0] == 'k' || suffix[0] == 'k') { + return KILOBYTES(size); + } else if (suffix[0] == 'm' || suffix[0] == 'M') { + return MEGABYTES(size); + } else if (suffix[0] == 'g' || suffix[0] == 'G') { + return GIGABYTES(size); + } else { + LOG(FATAL) << "Could not parse the size: " << size_text << std::endl; + } +} + +/** Returns bandwidth (bytes / second) */ +size_t ParseBandwidth(const std::string &size_text) { + return ParseSize(size_text); +} + +/** Returns latency (nanoseconds) */ +size_t ParseLatency(const std::string &latency_text) { + size_t size = ParseNumber(latency_text); + std::string suffix = ParseNumberSuffix(latency_text); + if (suffix.size() == 0) { + return size; + } else if (suffix[0] == 'n' || suffix[0] == 'N') { + return size; + } else if (suffix[0] == 'u' || suffix[0] == 'U') { + return KILOBYTES(size); + } else if (suffix[0] == 'm' || suffix[0] == 'M') { + return MEGABYTES(size); + } else if (suffix[0] == 's' || suffix[0] == 'S') { + return GIGABYTES(size); + } + else { + LOG(FATAL) << "Could not parse the latency: " << latency_text << std::endl; + } +} + } // namespace hermes #endif // HERMES_CONFIG_PARSER_H_ diff --git a/src/config_server.cc b/src/config_server.cc index 0990711e8..9006bcb6a 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -19,71 +19,6 @@ namespace hermes { -/** log an error message when the number of devices is 0 in \a config */ -void ServerConfig::RequireNumDevices() { - if (num_devices == 0) { - LOG(FATAL) << "The configuration variable 'num_devices' must be defined " - << "first" << std::endl; - } -} - -/** log an error message when the number of slabs is 0 in \a config */ -void ServerConfig::RequireNumSlabs() { - if (num_slabs == 0) { - LOG(FATAL) << "The configuration variable 'num_slabs' must be defined first" - << std::endl; - } -} - -/** log an error message when capacities are specified multiple times */ -void ServerConfig::RequireCapacitiesUnset(bool &already_specified) { - if (already_specified) { - LOG(FATAL) << "Capacities are specified multiple times in the configuration" - << " file. Only use one of 'capacities_bytes', 'capacities_kb'," - << "'capacities_mb', or 'capacities_gb'\n"; - } else { - already_specified = true; - } -} - -/** log an error message when block sizes are specified multiple times */ -void ServerConfig::RequireBlockSizesUnset(bool &already_specified) { - if (already_specified) { - LOG(FATAL) << "Block sizes are specified multiple times in the " - << "configuration file. Only use one of 'block_sizes_bytes'," - << "'block_sizes_kb', 'block_sizes_mb', or 'block_sizes_gb'\n"; - } else { - already_specified = true; - } -} - -/** parse capacities from configuration file in YAML */ -void ServerConfig::ParseCapacities(YAML::Node capacities, int unit_conversion, - bool &already_specified) { - int i = 0; - RequireNumDevices(config); - RequireCapacitiesUnset(already_specified); - for (auto val_node : capacities) { - capacities[i++] = val_node.as() * unit_conversion; - } -} - -/** parse block sizes from configuration file in YAML */ -void ServerConfig::ParseBlockSizes(YAML::Node block_sizes, int unit_conversion, - bool &already_specified) { - int i = 0; - RequireNumDevices(config); - RequireBlockSizesUnset(already_specified); - for (auto val_node : block_sizes) { - size_t block_size = val_node.as() * unit_conversion; - if (block_size > INT_MAX) { - LOG(FATAL) << "Max supported block size is " << INT_MAX << " bytes. " - << "Config file requested " << block_size << " bytes\n"; - } - block_sizes[i++] = block_size; - } -} - /** parse host names from configuration file in YAML */ void ServerConfig::ParseHostNames(YAML::Node yaml_conf) { if (yaml_conf["rpc_server_host_file"]) { @@ -108,52 +43,13 @@ void ServerConfig::ParseHostNames(YAML::Node yaml_conf) { if (host_numbers.size() == 0) { host_numbers.emplace_back(""); } - for (auto &host_number : host_numbers) { + for (auto host_number : host_numbers) { host_names.emplace_back(rpc_server_base_name + host_number + rpc_server_suffix); } } } -/** check constraints in \a config configuration */ -void ServerConfig::CheckConstraints() { - // rpc_domain must be present if rpc_protocol is "verbs" - if (rpc_protocol.find("verbs") != std::string::npos && - rpc_domain.empty()) { - PrintExpectedAndFail("a non-empty value for rpc_domain"); - } - - double tolerance = 0.0000001; - - // arena_percentages must add up to 1.0 - /*double arena_percentage_sum = 0; - for (int i = 0; i < kArenaType_Count; ++i) { - arena_percentage_sum += arena_percentages[i]; - } - if (fabs(1.0 - arena_percentage_sum) > tolerance) { - std::ostringstream msg; - msg << "the values in arena_percentages to add up to 1.0 but got "; - msg << arena_percentage_sum << "\n"; - PrintExpectedAndFail(msg.str()); - }*/ - - // Each slab's desired_slab_percentages should add up to 1.0 - for (int device = 0; device < num_devices; ++device) { - double total_slab_percentage = 0; - for (int slab = 0; slab < num_slabs[device]; ++slab) { - total_slab_percentage += desired_slab_percentages[device][slab]; - } - if (fabs(1.0 - total_slab_percentage) > tolerance) { - std::ostringstream msg; - msg << "the values in desired_slab_percentages["; - msg << device; - msg << "] to add up to 1.0 but got "; - msg << total_slab_percentage << "\n"; - PrintExpectedAndFail(msg.str()); - } - } -} - /** parse the YAML node */ void ServerConfig::ParseYAML(YAML::Node &yaml_conf) { bool capcities_specified = false, block_sizes_specified = false; @@ -161,116 +57,26 @@ void ServerConfig::ParseYAML(YAML::Node &yaml_conf) { std::vector host_basename; std::string host_suffix; - if (yaml_conf["num_devices"]) { - num_devices = yaml_conf["num_devices"].as(); - num_targets = num_devices; - } - if (yaml_conf["num_targets"]) { - num_targets = yaml_conf["num_targets"].as(); - } - - if (yaml_conf["capacities_bytes"]) { - ParseCapacities(yaml_conf["capacities_bytes"], 1, - capcities_specified); - } - if (yaml_conf["capacities_kb"]) { - ParseCapacities(yaml_conf["capacities_kb"], KILOBYTES(1), - capcities_specified); - } - if (yaml_conf["capacities_mb"]) { - ParseCapacities(yaml_conf["capacities_mb"], MEGABYTES(1), - capcities_specified); - } - if (yaml_conf["capacities_gb"]) { - ParseCapacities(yaml_conf["capacities_gb"], GIGABYTES(1), - capcities_specified); - } - - if (yaml_conf["block_sizes_bytes"]) { - ParseBlockSizes(yaml_conf["block_sizes_bytes"], 1, - block_sizes_specified); - } - if (yaml_conf["block_sizes_kb"]) { - ParseBlockSizes(yaml_conf["block_sizes_kb"], KILOBYTES(1), - block_sizes_specified); - } - if (yaml_conf["block_sizes_mb"]) { - ParseBlockSizes(yaml_conf["block_sizes_mb"], MEGABYTES(1), - block_sizes_specified); - } - if (yaml_conf["block_sizes_gb"]) { - ParseBlockSizes(yaml_conf["block_sizes_gb"], GIGABYTES(1), - block_sizes_specified); - } - - if (yaml_conf["num_slabs"]) { - RequireNumDevices(); - ParseArray(yaml_conf["num_slabs"], "num_slabs", num_slabs, - num_devices); - } - if (yaml_conf["slab_unit_sizes"]) { - RequireNumDevices(); - RequireNumSlabs(); - ParseMatrix(yaml_conf["slab_unit_sizes"], "slab_unit_sizes", - reinterpret_cast(slab_unit_sizes), - kMaxDevices, kMaxBufferPoolSlabs, num_slabs); - } - if (yaml_conf["desired_slab_percentages"]) { - RequireNumDevices(); - RequireNumSlabs(); - ParseMatrix(yaml_conf["desired_slab_percentages"], - "desired_slab_percentages", - reinterpret_cast(desired_slab_percentages), - kMaxDevices, kMaxBufferPoolSlabs, num_slabs); - } - if (yaml_conf["bandwidth_mbps"]) { - RequireNumDevices(); - ParseArray(yaml_conf["bandwidth_mbps"], "bandwidth_mbps", - bandwidths, num_devices); - } - if (yaml_conf["latencies"]) { - RequireNumDevices(); - ParseArray(yaml_conf["latencies"], "latencies", latencies, - num_devices); - } - /*if (yaml_conf["buffer_pool_arena_percentage"]) { - arena_percentages[hermes::kArenaType_BufferPool] = - yaml_conf["buffer_pool_arena_percentage"].as(); - } - if (yaml_conf["metadata_arena_percentage"]) { - arena_percentages[hermes::kArenaType_MetaData] = - yaml_conf["metadata_arena_percentage"].as(); - } - if (yaml_conf["transient_arena_percentage"]) { - arena_percentages[hermes::kArenaType_Transient] = - yaml_conf["transient_arena_percentage"].as(); - }*/ - if (yaml_conf["mount_points"]) { - RequireNumDevices(); - ParseArray(yaml_conf["mount_points"], "mount_points", - mount_points, num_devices); - } - if (yaml_conf["swap_mount"]) { - swap_mount = yaml_conf["swap_mount"].as(); - } - if (yaml_conf["num_buffer_organizer_retries"]) { - num_buffer_organizer_retries = - yaml_conf["num_buffer_organizer_retries"].as(); - } - if (yaml_conf["max_buckets_per_node"]) { - max_buckets_per_node = yaml_conf["max_buckets_per_node"].as(); - } - if (yaml_conf["max_vbuckets_per_node"]) { - max_vbuckets_per_node = - yaml_conf["max_vbuckets_per_node"].as(); + if (yaml_conf["devices"]) { + for (auto device : yaml_conf["devices"]) { + DeviceInfo dev; + auto dev_info = device.second; + dev.mount_point_ = dev_info["mount_point"].as(); + dev.capacity_ = + ParseSize(dev_info["capacity"].as()); + dev.bandwidth_ = + ParseSize(dev_info["bandwidth"].as()); + dev.latency_ = + ParseLatency(dev_info["latency"].as()); + } } if (yaml_conf["system_view_state_update_interval_ms"]) { system_view_state_update_interval_ms = yaml_conf["system_view_state_update_interval_ms"].as(); } - if (yaml_conf["buffer_pool_shmem_name"]) { - std::string name = yaml_conf["buffer_pool_shmem_name"].as(); - std::snprintf(buffer_pool_shmem_name, kMaxBufferPoolShmemNameLength, + if (yaml_conf["shmem_name"]) { + std::string name = yaml_conf["shmem_name"].as(); + std::snprintf(shmem_name_, kMaxBufferPoolShmemNameLength, "%s", name.c_str()); } if (yaml_conf["rpc_protocol"]) { @@ -320,15 +126,6 @@ void ServerConfig::ParseYAML(YAML::Node &yaml_conf) { bo_num_threads = yaml_conf["bo_num_threads"].as(); } if (yaml_conf["bo_capacity_thresholds"]) { - RequireNumDevices(); - f32 thresholds[kMaxDevices][2] = {0}; - ParseMatrix(yaml_conf["bo_capacity_thresholds"], - "bo_capacity_thresholds", - reinterpret_cast(thresholds), kMaxDevices, 2); - for (int i = 0; i < num_devices; ++i) { - bo_capacity_thresholds[i].min = thresholds[i][0]; - bo_capacity_thresholds[i].max = thresholds[i][1]; - } } if (yaml_conf["path_exclusions"]) { ParseVector(yaml_conf["path_exclusions"], diff --git a/src/data_structures.h b/src/data_structures.h new file mode 100644 index 000000000..edd0a6f48 --- /dev/null +++ b/src/data_structures.h @@ -0,0 +1,16 @@ +// +// Created by lukemartinlogan on 12/2/22. +// + +#ifndef HERMES_SRC_DATA_STRUCTURES_H_ +#define HERMES_SRC_DATA_STRUCTURES_H_ + +#include +#include +#include +#include + +namespace lipc = labstor::ipc; +namespace lipcl = labstor::ipc::lockless; + +#endif // HERMES_SRC_DATA_STRUCTURES_H_ diff --git a/src/hermes_types.h b/src/hermes_types.h index 14ba1227e..bb4756ed7 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -254,19 +254,6 @@ struct Context { } // namespace api -// TODO(chogan): These constants impose limits on the number of slabs, -// devices, file path lengths, and shared memory name lengths, but eventually -// we should allow arbitrary sizes of each. -static constexpr int kMaxBufferPoolSlabs = 8; /**< max. buffer pool slabs */ -constexpr int kMaxPathLength = 256; /**< max. path length */ -/** max. buffer pool shared memory name length */ -constexpr int kMaxBufferPoolShmemNameLength = 64; -constexpr int kMaxDevices = 8; /**< max. devices */ -constexpr int kMaxBucketNameSize = 256; /**< max. bucket name size */ -constexpr int kMaxVBucketNameSize = 256; /**< max. virtual bucket name size */ -/** a string to represent the place in hierarchy */ -constexpr char kPlaceInHierarchy[] = "PlaceInHierarchy"; - /** A definition for logging something that is not yet implemented */ #define HERMES_NOT_IMPLEMENTED_YET \ LOG(FATAL) << __func__ << " not implemented yet\n" From f617cb9c03255a785dc859dbd6c16d22ce58f839 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 2 Dec 2022 19:26:33 -0600 Subject: [PATCH 043/511] New conf compiling --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 8 ++- src/api/hermes.h | 42 ++++++----- src/config.h | 165 +++++++++++++++++-------------------------- src/config_client.cc | 4 -- src/config_server.cc | 165 +++++++++++++++++++++---------------------- src/constants.cc | 9 +++ src/constants.h | 14 ++++ src/hermes_daemon.cc | 11 ++- src/hermes_types.h | 3 +- src/utils.h | 149 -------------------------------------- 11 files changed, 205 insertions(+), 367 deletions(-) create mode 100644 src/constants.cc create mode 100644 src/constants.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 18e7d0288..53c5d0601 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -456,7 +456,7 @@ endif() # Benchmarks #----------------------------------------------------------------------------- if(HERMES_BUILD_BENCHMARKS) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/benchmarks) + # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/benchmarks) endif() #----------------------------------------------------------------------------- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 51c7ae975..04bfc6997 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,11 @@ endif() # Set sources #------------------------------------------------------------------------------ set(HERMES_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/constants.cc + ${CMAKE_CURRENT_SOURCE_DIR}/config_client.cc + ${CMAKE_CURRENT_SOURCE_DIR}/config_server.cc + ${CMAKE_CURRENT_SOURCE_DIR}/hermes_daemon.cc + #${CMAKE_CURRENT_SOURCE_DIR}/rpc_thallium.cc #${CMAKE_CURRENT_SOURCE_DIR}/api/bucket.cc #${CMAKE_CURRENT_SOURCE_DIR}/api/hermes.cc #${CMAKE_CURRENT_SOURCE_DIR}/api/vbucket.cc @@ -34,9 +39,6 @@ set(HERMES_SRCS #${CMAKE_CURRENT_SOURCE_DIR}/dpe/random.cc #${CMAKE_CURRENT_SOURCE_DIR}/dpe/round_robin.cc #${CMAKE_CURRENT_SOURCE_DIR}/dpe/minimize_io_time.cc - ${CMAKE_CURRENT_SOURCE_DIR}/config_parser.cc - ${CMAKE_CURRENT_SOURCE_DIR}/rpc_thallium.cc - ${CMAKE_CURRENT_SOURCE_DIR}/hermes_daemon.cc ) #------------------------------------------------------------------------------ diff --git a/src/api/hermes.h b/src/api/hermes.h index 8011ef909..e8c479687 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -6,12 +6,10 @@ #define HERMES_SRC_API_HERMES_H_ #include "config.h" +#include "constants.h" namespace hermes::api { -const char* kHermesConf = "HERMES_CONF"; -const char* kHermesClientConf = "HERMES_CLIENT_CONF"; - enum class HermesType { kDaemon, kClient, @@ -21,30 +19,28 @@ enum class HermesType { class Hermes { public: HermesType mode_; - Config config_; + ServerConfig server_config_; + ClientConfig client_config_; public: Hermes() = default; + Hermes(HermesType mode, std::string config_path) { + Init(mode, std::move(config_path)); + } void Init(HermesType mode, std::string config_path) { - // Load the Hermes Configuration - if (config_path.size() == 0) { - config_path = getenv(kHermesConf); - } - InitConfig(&config_, config_path.c_str()); - mode_ = mode; switch (mode) { case HermesType::kDaemon: { - InitDaemon(); + InitDaemon(std::move(config_path)); break; } case HermesType::kClient: { - InitClient(); + InitClient(std::move(config_path)); break; } case HermesType::kColocated: { - InitColocated(); + InitColocated(std::move(config_path)); break; } } @@ -57,13 +53,18 @@ class Hermes { } private: - void InitDaemon() { + void InitDaemon(std::string config_path) { + // Load the Hermes Configuration + if (config_path.size() == 0) { + config_path = GetEnvSafe(kHermesServerConf); + } + server_config_.LoadFromFile(config_path); } - void InitClient() { + void InitClient(std::string config_path) { } - void InitColocated() { + void InitColocated(std::string config_path) { } void FinalizeDaemon() { @@ -74,6 +75,15 @@ class Hermes { void FinalizeColocated() { } + + private: + inline std::string GetEnvSafe(const char *env_name) { + char *val = getenv(env_name); + if (val == nullptr){ + return ""; + } + return val; + } }; } diff --git a/src/config.h b/src/config.h index 1d597f948..2136330cd 100644 --- a/src/config.h +++ b/src/config.h @@ -22,6 +22,7 @@ #include "data_structures.h" #include "hermes_types.h" +#include "constants.h" namespace hermes { @@ -34,9 +35,9 @@ struct ClientConfig { bool stop_daemon_; public: - ClientConfig(); + ClientConfig() = default; void LoadText(const std::string &text); - void LoadFromFile(const char *path); + void LoadFromFile(const std::string &path); void LoadDefault(); }; @@ -44,9 +45,9 @@ struct DeviceInfo { /** The minimum transfer size of each device */ size_t block_size_; /** The unit of each slab, a multiple of the Device's block size */ - lipcl::vector slab_sizes_; + std::vector slab_sizes_; /** The mount point of a device */ - lipcl::string mount_point_; + std::string mount_point_; /** Device capacity (bytes) */ size_t capacity_; /** Bandwidth of a device (MBps) */ @@ -55,7 +56,38 @@ struct DeviceInfo { f32 latency_; /** Whether or not the device is shared among all nodes */ bool is_shared_; - /** */ + /** BORG's minimum and maximum capacity threshold for device */ + f32 borg_min_thresh_, borg_max_thresh_; +}; + +struct RpcInfo { + /** The name of a file that contains host names, 1 per line */ + std::string host_file_; + /** The parsed hostnames from the hermes conf */ + std::vector host_names_; + /** The RPC protocol to be used. */ + std::string protocol_; + /** The RPC domain name for verbs transport. */ + std::string domain_; + /** The RPC port number. */ + int port_; + /** The number of handler threads per RPC server. */ + int num_threads_; +}; + +struct DpeInfo { + /** The default blob placement policy. */ + api::PlacementPolicy default_policy_; + + /** Whether blob splitting is enabled for Round-Robin blob placement. */ + bool default_rr_split_; +}; + +struct BorgInfo { + /** The RPC port number for the buffer organizer. */ + int port_; + /** The number of buffer organizer threads. */ + int num_threads_; }; /** @@ -64,47 +96,24 @@ struct DeviceInfo { class ServerConfig { public: /** The device information */ - lipcl::vector devices_; + std::vector devices_; + + /** The RPC information */ + RpcInfo rpc_; + + /** The DPE information */ + DpeInfo dpe_; + + /** Buffer organizer (BORG) information */ + BorgInfo borg_; /** The length of a view state epoch */ u32 system_view_state_update_interval_ms; - /** The name of a file that contains host names, 1 per line */ - lipcl::string rpc_server_host_file; - /** The hostname of the RPC server, minus any numbers that Hermes may - * auto-generate when the rpc_hostNumber_range is specified. */ - lipcl::string rpc_server_base_name; - /** The list of numbers from all server names. E.g., '{1, 3}' if your servers - * are named ares-comp-1 and ares-comp-3 */ - lipcl::vector host_numbers; - /** The RPC server name suffix. This is appended to the base name plus host - number. */ - lipcl::string rpc_server_suffix; - /** The parsed hostnames from the hermes conf */ - lipcl::vector host_names; - /** The RPC protocol to be used. */ - lipcl::string rpc_protocol; - /** The RPC domain name for verbs transport. */ - lipcl::string rpc_domain; - /** The RPC port number. */ - int rpc_port; - /** The RPC port number for the buffer organizer. */ - int buffer_organizer_port; - /** The number of handler threads per RPC server. */ - int rpc_num_threads; - /** The number of buffer organizer threads. */ - int bo_num_threads; - /** The default blob placement policy. */ - api::PlacementPolicy default_placement_policy; - /** Whether blob splitting is enabled for Round-Robin blob placement. */ - bool default_rr_split; - /** The min and max capacity threshold in MiB for each device at which the - * BufferOrganizer will trigger. */ - Thresholds bo_capacity_thresholds[kMaxDevices]; /** A base name for the BufferPool shared memory segement. Hermes appends the * value of the USER environment variable to this string. */ - char buffer_pool_shmem_name[kMaxBufferPoolShmemNameLength]; + std::string shmem_name_; /** * Paths prefixed with the following directories are not tracked in Hermes @@ -120,19 +129,22 @@ class ServerConfig { std::vector path_inclusions; public: - ServerConfig(); + ServerConfig() = default; void LoadText(const std::string &text); - void LoadFromFile(const char *path); + void LoadFromFile(const std::string &path); void LoadDefault(); private: void ParseYAML(YAML::Node &yaml_conf); void CheckConstraints(); - void ParseHostNames(YAML::Node yaml_conf); + void ParseRpcInfo(YAML::Node yaml_conf); + void ParseDeviceInfo(YAML::Node yaml_conf); + void ParseDpeInfo(YAML::Node yaml_conf); + void ParseBorgInfo(YAML::Node yaml_conf); }; /** print \a expected value and fail when an error occurs */ -void PrintExpectedAndFail(const std::string &expected, u32 line_number = 0) { +static void PrintExpectedAndFail(const std::string &expected, u32 line_number = 0) { std::ostringstream msg; msg << "Configuration parser expected '" << expected << "'"; if (line_number > 0) { @@ -143,64 +155,17 @@ void PrintExpectedAndFail(const std::string &expected, u32 line_number = 0) { LOG(FATAL) << msg.str(); } -/** parse \a var array from configuration file in YAML */ -template -void ParseArray(YAML::Node list_node, const std::string var, - T *list, int max_list_len) { - int i = 0; - if (max_list_len < (int)list_node.size()) { - LOG(FATAL) << var << " (array) had " - << list_node.size() << " arguments " - << "but up to " << max_list_len << " expected\n"; - } - for (auto val_node : list_node) { - list[i++] = val_node.as(); - } -} - /** parse \a list_node vector from configuration file in YAML */ template -void ParseVector(YAML::Node list_node, std::vector &list) { +static void ParseVector(YAML::Node list_node, std::vector &list) { for (auto val_node : list_node) { list.emplace_back(val_node.as()); } } -/** parse \a matrix_node matrix using \a col_len column length */ -template -void ParseMatrix(YAML::Node matrix_node, const std::string var, T *matrix, - int max_row_len, int max_col_len, int *col_len) { - int i = 0; - if (max_row_len < (int)matrix_node.size()) { - LOG(FATAL) << var << " (matrix) had " - << matrix_node.size() << " arguments " - << "but up to " << max_row_len << " expected\n"; - } - for (auto row : matrix_node) { - ParseArray(row, var, &matrix[i*max_col_len], col_len[i]); - ++i; - } -} - -/** parse \a matrix_node matrix from configuration file in YAML */ -template -void ParseMatrix(YAML::Node matrix_node, std::string var, T *matrix, - int max_row_len, int max_col_len) { - int i = 0; - if (max_row_len < (int)matrix_node.size()) { - LOG(FATAL) << var << " (matrix) had " - << matrix_node.size() << " arguments " - << "but up to " << max_row_len << " expected\n"; - } - for (auto row : matrix_node) { - ParseArray(row, var, &matrix[i*max_col_len], max_col_len); - ++i; - } -} - /** parse range list from configuration file in YAML */ -void ParseRangeList(YAML::Node list_node, std::string var, - std::vector &list) { +static void ParseRangeList(YAML::Node list_node, std::string var, + std::vector &list) { int min, max, width = 0; for (auto val_node : list_node) { std::string val = val_node.as(); @@ -238,7 +203,7 @@ void ParseRangeList(YAML::Node list_node, std::string var, } } -std::string ParseNumberSuffix(const std::string &num_text) { +static std::string ParseNumberSuffix(const std::string &num_text) { int i; for (i = 0; i < num_text.size(); ++i) { char c = num_text[i]; @@ -249,14 +214,14 @@ std::string ParseNumberSuffix(const std::string &num_text) { return std::string(num_text.begin() + i, num_text.end());; } -size_t ParseNumber(const std::string &num_text) { +static size_t ParseNumber(const std::string &num_text) { size_t size; std::stringstream(num_text) >> size; return size; } /** Returns size (bytes) */ -size_t ParseSize(const std::string &size_text) { +static size_t ParseSize(const std::string &size_text) { size_t size = ParseNumber(size_text); std::string suffix = ParseNumberSuffix(size_text); if (suffix.size() == 0) { @@ -273,12 +238,12 @@ size_t ParseSize(const std::string &size_text) { } /** Returns bandwidth (bytes / second) */ -size_t ParseBandwidth(const std::string &size_text) { +static size_t ParseBandwidth(const std::string &size_text) { return ParseSize(size_text); } /** Returns latency (nanoseconds) */ -size_t ParseLatency(const std::string &latency_text) { +static size_t ParseLatency(const std::string &latency_text) { size_t size = ParseNumber(latency_text); std::string suffix = ParseNumberSuffix(latency_text); if (suffix.size() == 0) { @@ -292,9 +257,7 @@ size_t ParseLatency(const std::string &latency_text) { } else if (suffix[0] == 's' || suffix[0] == 'S') { return GIGABYTES(size); } - else { - LOG(FATAL) << "Could not parse the latency: " << latency_text << std::endl; - } + LOG(FATAL) << "Could not parse the latency: " << latency_text << std::endl; } } // namespace hermes diff --git a/src/config_client.cc b/src/config_client.cc index 8c1bc96e6..5b090966d 100644 --- a/src/config_client.cc +++ b/src/config_client.cc @@ -7,8 +7,4 @@ namespace hermes { -ClientConfig::ClientConfig() { - -} - } // namespace hermes \ No newline at end of file diff --git a/src/config_server.cc b/src/config_server.cc index 9006bcb6a..776cf6fe0 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -19,37 +19,84 @@ namespace hermes { -/** parse host names from configuration file in YAML */ -void ServerConfig::ParseHostNames(YAML::Node yaml_conf) { - if (yaml_conf["rpc_server_host_file"]) { - rpc_server_host_file = - yaml_conf["rpc_server_host_file"].as(); +/** parse device information from YAML config */ +void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { + devices_.clear(); + for (auto device : yaml_conf["devices"]) { + DeviceInfo dev; + auto dev_info = device.second; + dev.mount_point_ = dev_info["mount_point"].as(); + dev.capacity_ = + ParseSize(dev_info["capacity"].as()); + dev.bandwidth_ = + ParseSize(dev_info["bandwidth"].as()); + dev.latency_ = + ParseLatency(dev_info["latency"].as()); + ParseVector(dev_info["slab_sizes"], dev.slab_sizes_); + devices_.emplace_back(dev); } - if (yaml_conf["rpc_server_base_name"]) { - rpc_server_base_name = - yaml_conf["rpc_server_base_name"].as(); +} + +/** parse RPC information from YAML config */ +void ServerConfig::ParseRpcInfo(YAML::Node yaml_conf) { + std::string base_name; + std::string suffix; + std::vector host_numbers; + + if (yaml_conf["domain"]) { + rpc_.domain_ = yaml_conf["domain"].as(); + } + if (yaml_conf["protocol"]) { + rpc_.protocol_ = yaml_conf["protocol"].as(); + } + if (yaml_conf["num_threads"]) { + rpc_.num_threads_ = yaml_conf["num_threads"].as(); } - if (yaml_conf["rpc_server_suffix"]) { - rpc_server_suffix = - yaml_conf["rpc_server_suffix"].as(); + if (yaml_conf["host_file"]) { + rpc_.host_file_ = + yaml_conf["host_file"].as(); } - if (yaml_conf["rpc_host_number_range"]) { + if (yaml_conf["base_name"]) { + base_name = yaml_conf["base_name"].as(); + } + if (yaml_conf["suffix"]) { + suffix = yaml_conf["suffix"].as(); + } + if (yaml_conf["number_range"]) { ParseRangeList(yaml_conf["rpc_host_number_range"], "rpc_host_number_range", host_numbers); } - if (rpc_server_host_file.empty()) { - host_names.clear(); + // Remove all default host names + if (rpc_.host_file_.size() > 0 || base_name.size() > 0) { + rpc_.host_names_.clear(); + } + + if (base_name.size()) { if (host_numbers.size() == 0) { host_numbers.emplace_back(""); } for (auto host_number : host_numbers) { - host_names.emplace_back(rpc_server_base_name + - host_number + rpc_server_suffix); + rpc_.host_names_.emplace_back(base_name + host_number + suffix); } } } +/** parse dpe information from YAML config */ +void ServerConfig::ParseDpeInfo(YAML::Node yaml_conf) { + if (yaml_conf["default_placement_policy"]) { + std::string policy = + yaml_conf["default_placement_policy"].as(); + dpe_.default_policy_ = api::PlacementPolicyConv::to_enum(policy); + } +} + +/** parse buffer organizer information from YAML config */ +void ServerConfig::ParseBorgInfo(YAML::Node yaml_conf) { + borg_.port_ = yaml_conf["port"].as(); + borg_.num_threads_ = yaml_conf["num_threads"].as(); +} + /** parse the YAML node */ void ServerConfig::ParseYAML(YAML::Node &yaml_conf) { bool capcities_specified = false, block_sizes_specified = false; @@ -58,17 +105,16 @@ void ServerConfig::ParseYAML(YAML::Node &yaml_conf) { std::string host_suffix; if (yaml_conf["devices"]) { - for (auto device : yaml_conf["devices"]) { - DeviceInfo dev; - auto dev_info = device.second; - dev.mount_point_ = dev_info["mount_point"].as(); - dev.capacity_ = - ParseSize(dev_info["capacity"].as()); - dev.bandwidth_ = - ParseSize(dev_info["bandwidth"].as()); - dev.latency_ = - ParseLatency(dev_info["latency"].as()); - } + ParseDeviceInfo(yaml_conf["devices"]); + } + if (yaml_conf["rpc"]) { + } + if (yaml_conf["dpe"]) { + ParseDpeInfo(yaml_conf["dpe"]); + } + if (yaml_conf["buffer_organizer"]) { + auto borg_yaml = yaml_conf["buffer_organizer"]; + } if (yaml_conf["system_view_state_update_interval_ms"]) { system_view_state_update_interval_ms = @@ -76,57 +122,8 @@ void ServerConfig::ParseYAML(YAML::Node &yaml_conf) { } if (yaml_conf["shmem_name"]) { std::string name = yaml_conf["shmem_name"].as(); - std::snprintf(shmem_name_, kMaxBufferPoolShmemNameLength, - "%s", name.c_str()); - } - if (yaml_conf["rpc_protocol"]) { - rpc_protocol = yaml_conf["rpc_protocol"].as(); - } - if (yaml_conf["rpc_domain"]) { - rpc_domain = yaml_conf["rpc_domain"].as(); - } - if (yaml_conf["rpc_port"]) { - rpc_port = yaml_conf["rpc_port"].as(); - } - if (yaml_conf["buffer_organizer_port"]) { - buffer_organizer_port = - yaml_conf["buffer_organizer_port"].as(); - } - if (yaml_conf["rpc_num_threads"]) { - rpc_num_threads = yaml_conf["rpc_num_threads"].as(); } - if (yaml_conf["default_placement_policy"]) { - std::string policy = - yaml_conf["default_placement_policy"].as(); - if (policy == "MinimizeIoTime") { - default_placement_policy = api::PlacementPolicy::kMinimizeIoTime; - } else if (policy == "Random") { - default_placement_policy = api::PlacementPolicy::kRandom; - } else if (policy == "RoundRobin") { - default_placement_policy = api::PlacementPolicy::kRoundRobin; - } else { - LOG(FATAL) << "Unknown default_placement_policy: '" << policy << "'" - << std::endl; - } - } - if (yaml_conf["is_shared_device"]) { - RequireNumDevices(); - ParseArray(yaml_conf["is_shared_device"], "is_shared_device", - is_shared_device, num_devices); - } - if (yaml_conf["buffer_organizer_num_threads"]) { - bo_num_threads = - yaml_conf["buffer_organizer_num_threads"].as(); - } - if (yaml_conf["default_rr_split"]) { - default_rr_split = yaml_conf["default_rr_split"].as(); - } - if (yaml_conf["bo_num_threads"]) { - bo_num_threads = yaml_conf["bo_num_threads"].as(); - } - if (yaml_conf["bo_capacity_thresholds"]) { - } if (yaml_conf["path_exclusions"]) { ParseVector(yaml_conf["path_exclusions"], path_exclusions); @@ -135,19 +132,22 @@ void ServerConfig::ParseYAML(YAML::Node &yaml_conf) { ParseVector(yaml_conf["path_inclusions"], path_inclusions); } - ParseHostNames(yaml_conf); - CheckConstraints(); } /** load configuration from a string */ void ServerConfig::LoadText(const std::string &config_string) { + LoadDefault(); + if (config_string.size() == 0) { + return; + } YAML::Node yaml_conf = YAML::Load(config_string); ParseYAML(yaml_conf); } /** load configuration from file */ -void ServerConfig::LoadFromFile(const char *path) { - if (path == nullptr) { +void ServerConfig::LoadFromFile(const std::string &path) { + LoadDefault(); + if (path.size() == 0) { return; } LOG(INFO) << "ParseConfig-LoadFile" << std::endl; @@ -156,9 +156,4 @@ void ServerConfig::LoadFromFile(const char *path) { ParseYAML(yaml_conf); } -/** The default server config */ -ServerConfig::ServerConfig() { - -} - } // namespace hermes diff --git a/src/constants.cc b/src/constants.cc new file mode 100644 index 000000000..784f0eb69 --- /dev/null +++ b/src/constants.cc @@ -0,0 +1,9 @@ +// +// Created by lukemartinlogan on 12/2/22. +// + +#include "constants.h" + +const char* kHermesServerConf = "HERMES_CONF"; +const char* kHermesClientConf = "HERMES_CLIENT_CONF"; +const size_t kMaxPathLength = 4096; \ No newline at end of file diff --git a/src/constants.h b/src/constants.h new file mode 100644 index 000000000..c1f5c2b58 --- /dev/null +++ b/src/constants.h @@ -0,0 +1,14 @@ +// +// Created by lukemartinlogan on 12/2/22. +// + +#ifndef HERMES_SRC_CONSTANTS_H_ +#define HERMES_SRC_CONSTANTS_H_ + +#include + +extern const char* kHermesServerConf; +extern const char* kHermesClientConf; +extern const size_t kMaxPathLength; + +#endif // HERMES_SRC_CONSTANTS_H_ diff --git a/src/hermes_daemon.cc b/src/hermes_daemon.cc index 2eb4d6ff3..958314245 100644 --- a/src/hermes_daemon.cc +++ b/src/hermes_daemon.cc @@ -15,12 +15,9 @@ #include #include +#include "hermes.h" -/** - * kHermesConf env variable is used to define path to kHermesConf in adapters. - * This is used for initialization of Hermes. - */ -const char* kHermesConf = "HERMES_CONF"; +namespace hapi = hermes::api; int main(int argc, char* argv[]) { MPI_Init(&argc, &argv); @@ -29,8 +26,8 @@ int main(int argc, char* argv[]) { hermes_config = argv[1]; } - auto hermes = hermes::InitHermesDaemon(hermes_config); - hermes->RunDaemon(); + auto hermes = hapi::Hermes(hapi::HermesType::kDaemon, hermes_config); + hermes.RunDaemon(); MPI_Finalize(); diff --git a/src/hermes_types.h b/src/hermes_types.h index bb4756ed7..182589191 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -22,6 +22,7 @@ #include #include "hermes_version.h" +#include "data_structures.h" /** * \file hermes_types.h @@ -143,7 +144,7 @@ enum class PlacementPolicy { class PlacementPolicyConv { public: /** A function to return string representation of \a policy */ - static std::string str(PlacementPolicy policy) { + static std::string to_str(PlacementPolicy policy) { switch (policy) { case PlacementPolicy::kRandom: { return "PlacementPolicy::kRandom"; diff --git a/src/utils.h b/src/utils.h index ef412bdda..87f941c06 100644 --- a/src/utils.h +++ b/src/utils.h @@ -20,153 +20,4 @@ #include "hermes_types.h" -/** - * @file utils.h - * - * Utility classes and functions for Hermes. - */ - -#if HERMES_ENABLE_TIMING - -#define HERMES_BEGIN_TIMED_BLOCK(func_name) \ - auto hermes_timed_block_start_ = std::chrono::high_resolution_clock::now(); \ - const char *hermes_timed_block_func_name_ = (func_name); - -// TODO(chogan): Probably want to prepend rank to output -#define HERMES_END_TIMED_BLOCK() \ - auto hermes_timed_block_end_ = std::chrono::high_resolution_clock::now(); \ - auto hermes_timed_block_elapsed_ = \ - hermes_timed_block_end_ - hermes_timed_block_start_; \ - double hermes_timed_block_seconds_ = \ - std::chrono::duration(hermes_timed_block_elapsed_).count(); \ - VLOG(1) << hermes_timed_block_func_name_ << " took " \ - << hermes_timed_block_seconds_ << " seconds\n"; - -#else -#define HERMES_BEGIN_TIMED_BLOCK(func_name) /**< begin timing */ -#define HERMES_END_TIMED_BLOCK() /**< end timing */ -#endif // HERMES_ENABLE_TIMING - -namespace hermes { - -/** - * Rounds a value up to the next given multiple. - * - * Returns the original value if it is already divisible by multiple. - * - * Example: - * ```cpp - * size_t result = RoundUpToMultiple(2000, 4096); - * assert(result == 4096); - * ``` - * - * @param val The initial value to round. - * @param multiple The multiple to round up to. - * - * @return The next multiple of multiple that is greater than or equal to val. - */ -size_t RoundUpToMultiple(size_t val, size_t multiple); - -/** - * Rounds a value down to the previous given multiple. - * - * Returns the original value if it is already divisible by multiple. - * - * Example: - * ```cpp - * size_t result = RoundDownToMultiple(4097, 4096); - * assert(result == 4096); - * ``` - * - * @param val The initial value to round. - * @param multiple The multiple to round down to. - * - * @return The previous multiple of multiple that is less than or equal to val. - */ -size_t RoundDownToMultiple(size_t val, size_t multiple); - -/** - * Fills out a Config struct with default values. - * - * @param config The Config to populate. - */ -void InitDefaultConfig(Config *config); - -void FailedLibraryCall(std::string func); - -namespace testing { -/** - A class to represent BLOB size - */ -enum class BlobSizeRange { - kSmall, - kMedium, - kLarge, - kXLarge, - kHuge, -}; - -/** - A structure to represent target view state -*/ -struct TargetViewState { - std::vector bytes_capacity; /**< a vector of capacities */ - std::vector bytes_available; /**< a vector of available bytes */ - std::vector bandwidth; /**< a vector of bandwidths */ - int num_devices; /**< number of devices */ -}; - -/** - * Initialize device state with default values. - * - * @param total_target Total number of target. - * - * @param homo_dist The device distribution is homogeneous or not. - * - * @return The TargetViewState struct with device information. - */ -TargetViewState InitDeviceState(u64 total_target = 4, bool homo_dist = true); - -/** - * Update device state. - * - * @param schema The PlacementSchema return from a data placement - * engine calculation. - * - * @param node_state The device status after schema is placed. - * - * @return Total size of placed blobs. - */ -u64 UpdateDeviceState(PlacementSchema &schema, TargetViewState &node_state); - -/** - * Print device state. - * - * @param node_state The TargetViewState with current state. - */ -void PrintNodeState(TargetViewState &node_state); - -/** - * Get default targets. - * - * @param n The number of target type. - * - @ @return The vector of default targets. - */ -std::vector GetDefaultTargets(size_t n); - -/** - * Generate a vector of blob size with fixed total blob size. - * - * @param total_size The number of target type. - * - * @param range The blob size range for test. - * - * @ @return The vector blob size. - */ -std::vector GenFixedTotalBlobSize(size_t total_size, - BlobSizeRange range); - -} // namespace testing -} // namespace hermes #endif // HERMES_UTILS_H_ From c11ec86c82ff9f941bddf3a6d25eca4fa29f1fa3 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sat, 3 Dec 2022 06:32:51 -0600 Subject: [PATCH 044/511] Compiling again --- adapter/test/CMakeLists.txt | 16 -- config/hermes_server_default.yaml | 6 +- src/CMakeLists.txt | 18 +- src/api/hermes.h | 9 +- src/communication.h | 24 +-- src/communication_mpi.h | 217 ++---------------------- src/config.h | 44 ++++- src/config_client.cc | 9 + src/config_server.cc | 23 +-- src/constants.cc | 6 +- src/constants.h | 11 ++ src/hermes_daemon.cc | 3 +- src/hermes_types.h | 136 +++++++-------- src/rpc.h | 73 ++++---- src/rpc_thallium.cc | 102 +++-------- src/rpc_thallium.h | 273 ++++++------------------------ src/rpc_thallium_defs.cc | 14 ++ src/rpc_thallium_serialization.h | 19 +++ src/utils.cc | 203 ---------------------- src/utils.h | 4 + 20 files changed, 327 insertions(+), 883 deletions(-) create mode 100644 src/rpc_thallium_defs.cc create mode 100644 src/rpc_thallium_serialization.h diff --git a/adapter/test/CMakeLists.txt b/adapter/test/CMakeLists.txt index 4f38bb8b2..69d1b9e95 100644 --- a/adapter/test/CMakeLists.txt +++ b/adapter/test/CMakeLists.txt @@ -2,12 +2,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHERMES_PRELOAD -DHERMES_RPC_THALLIUM") set(ADAPTER_COMMON ${CMAKE_CURRENT_SOURCE_DIR}/catch_config.h) set(HERMES_ADAPTER_TEST_DIR ${HERMES_ADAPTER_DIR}/test) -find_package(Catch2 REQUIRED) -add_executable(hermes_daemon ../../src/hermes_daemon.cc) -target_link_libraries(hermes_daemon -ldl -lc MPI::MPI_CXX glog::glog) -target_link_libraries(hermes_daemon hermes) -add_dependencies(hermes_daemon hermes) - function(gcc exec args) add_test(NAME Test${exec} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${args}) set_property(TEST Test${exec} @@ -63,13 +57,3 @@ endif() if(HERMES_ENABLE_VFD) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vfd) endif() - -install( - TARGETS - hermes_daemon - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) diff --git a/config/hermes_server_default.yaml b/config/hermes_server_default.yaml index 061683ea8..0b3b395c3 100644 --- a/config/hermes_server_default.yaml +++ b/config/hermes_server_default.yaml @@ -90,9 +90,9 @@ rpc: # can be either a single number, or a range, which is 2 numbers separated by a # hyphen (-). For example the list {01, 03-05, 07, 08-10} will be expanded to # {01, 03, 04, 05, 07, 08, 09, 10}. - server_base_name: "localhost" - server_host_number_range: [] - server_suffix: "" + base_name: "localhost" + host_number_range: [] + suffix: "" # The RPC protocol. This must come from the documentation of the specific RPC # library in use. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 04bfc6997..0bd3e6330 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,7 @@ set(HERMES_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/config_client.cc ${CMAKE_CURRENT_SOURCE_DIR}/config_server.cc ${CMAKE_CURRENT_SOURCE_DIR}/hermes_daemon.cc + ${CMAKE_CURRENT_SOURCE_DIR}/utils.cc #${CMAKE_CURRENT_SOURCE_DIR}/rpc_thallium.cc #${CMAKE_CURRENT_SOURCE_DIR}/api/bucket.cc #${CMAKE_CURRENT_SOURCE_DIR}/api/hermes.cc @@ -87,6 +88,12 @@ endif() set(HERMES_EXPORTED_LIBS hermes ${HERMES_EXPORTED_LIBS}) +# HERMES DAEMON +find_package(Catch2 REQUIRED) +add_executable(hermes_daemon hermes_daemon.cc) +add_dependencies(hermes_daemon hermes) +target_link_libraries(hermes_daemon hermes -ldl -lc MPI::MPI_CXX glog::glog) + #----------------------------------------------------------------------------- # Specify project header files to be installed #----------------------------------------------------------------------------- @@ -127,6 +134,15 @@ install( ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} ) +install( + TARGETS + hermes_daemon + EXPORT + ${HERMES_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} +) #----------------------------------------------------------------------------- # Add Target(s) to CMake Install for import into other projects @@ -168,4 +184,4 @@ set(HERMES_INCLUDES_INSTALL_TIME ${HERMES_INSTALL_INCLUDE_DIR} ${HERMES_EXT_INCLUDE_DEPENDENCIES} PARENT_SCOPE -) +) \ No newline at end of file diff --git a/src/api/hermes.h b/src/api/hermes.h index e8c479687..f2712ee2e 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -7,15 +7,10 @@ #include "config.h" #include "constants.h" +#include "hermes_types.h" namespace hermes::api { -enum class HermesType { - kDaemon, - kClient, - kColocated -}; - class Hermes { public: HermesType mode_; @@ -31,7 +26,7 @@ class Hermes { void Init(HermesType mode, std::string config_path) { mode_ = mode; switch (mode) { - case HermesType::kDaemon: { + case HermesType::kServer: { InitDaemon(std::move(config_path)); break; } diff --git a/src/communication.h b/src/communication.h index f33cf0809..26c8aa6c8 100644 --- a/src/communication.h +++ b/src/communication.h @@ -31,27 +31,13 @@ namespace hermes { class CommunicationContext { public: /** A unique identifier for each rank, relative to all ranks. */ - i32 world_proc_id; - /** a unique identifier for each rank, releative to each ProcessKind. */ - i32 sub_proc_id; + i32 world_proc_id_; /** The total number of ranks. */ - i32 world_size; - /** The total number of Hermes cores. Currently this is only defined on ranks - * that have ProcessKind::kHermes */ - i32 hermes_size; - /** The total number of application cores. Currently this is only defined on - * ranks that have ProcessKind::kApp */ - i32 app_size; + i32 world_size_; /** The total number of nodes. */ - i32 num_nodes; - /** A unique index for each node. Starts at 1, not 0. */ - i32 node_id; - /** Distinguishes between Hermes ranks and application ranks. */ - ProcessKind proc_kind; - /** True if this rank is the lowest numbered rank on the current node. Lowest - * is not relative to all ranks, but to each ProcessKind. This is useful for - * operations that only need to happen once per node. */ - bool first_on_node; + i32 num_nodes_; + /** The type of communicator this is */ + HermesType type_; public: virtual void WorldBarrier() = 0; /** E.g., MPI_Barrier(MPI_COMM_WORLD)*/ diff --git a/src/communication_mpi.h b/src/communication_mpi.h index 2a9b96872..3203636c4 100644 --- a/src/communication_mpi.h +++ b/src/communication_mpi.h @@ -27,238 +27,55 @@ namespace hermes { class MpiCommunicator : public CommunicationContext { public: - MPI_Comm world_comm; /**< MPI world communicator */ - /** This communicator is in one of two groups, depending on the value of the - * rank's ProcessKind. When its kHermes, sub_comm groups all Hermes cores, and - * when its kApp, it groups all application cores. */ - MPI_Comm sub_comm; + MPI_Comm world_comm_; /**< MPI world communicator */ public: - /** - * get the MPI process ID of \a comm MPI communicator. - */ + /** get the MPI process ID of \a comm MPI communicator. */ inline int GetProcId(MPI_Comm comm) { int result; MPI_Comm_rank(comm, &result); return result; } - /** - get the MPI process ID of MPI world communicator from \a MPI. -*/ + /** get the MPI process ID of MPI world communicator from \a MPI. */ inline int GetWorldProcId() { - int result = GetProcId(world_comm); + int result = GetProcId(world_comm_); return result; } - /** - get the MPI process ID of MPI sub-communicator from \a MPI. - */ - inline int GetSubProcId() { - int result = GetProcId(sub_comm); - return result; - } - - /** - get the number of MPI processes of \a comm MPI communicator. - */ + /** get the number of MPI processes of \a comm MPI communicator. */ inline int GetNumProcs(MPI_Comm comm) { int result; MPI_Comm_size(comm, &result); return result; } - /** - get the number of MPI processes of MPI world communicator. - */ + /** get the number of MPI processes of MPI world communicator. */ inline int GetNumWorldProcs() { - return GetNumProcs(world_comm); + return GetNumProcs(world_comm_); } - /** - a wrapper for MPI_Barrier() fucntion - */ + /** a wrapper for MPI_Barrier() fucntion */ inline void Barrier(MPI_Comm comm) { MPI_Barrier(comm); } - /** - a wrapper for MPI global communicator's MPI_Barrier() function - */ + /** a wrapper for MPI global communicator's MPI_Barrier() function */ inline void WorldBarrier() override { - Barrier(world_comm); - } - - /** - a wrapper for MPI sub-communicator's MPI_Barrier() function - */ - inline void SubBarrier() override { - Barrier(sub_comm); - } - - /** - * Returns true if the calling rank is the lowest numbered rank on its node in - * communicator @p comm. - */ - bool FirstOnNode(MPI_Comm comm) { - int rank = GetProcId(comm); - int size = GetNumProcs(comm); - - // TODO(llogan): arena -> labstor allocator - size_t scratch_size = (size * sizeof(char *) + - size * sizeof(char) * MPI_MAX_PROCESSOR_NAME); - std::vector node_names(size); - for (size_t i = 0; i < size; ++i) { - node_names[i] = new char[MPI_MAX_PROCESSOR_NAME]; - } - - int length; - MPI_Get_processor_name(node_names[rank], &length); - - MPI_Allgather(MPI_IN_PLACE, 0, 0, node_names[0], MPI_MAX_PROCESSOR_NAME, - MPI_CHAR, comm); - - int first_on_node = 0; - while (strncmp(node_names[rank], node_names[first_on_node], - MPI_MAX_PROCESSOR_NAME) != 0) { - first_on_node++; - } - - bool result = false; - if (first_on_node == rank) { - result = true; - } - - return result; - } - - /** - * Assigns each node an ID and returns the size in bytes of the transient arena - * for the calling rank. - */ - size_t AssignIDsToNodes(size_t trans_arena_size_per_node) { - int rank = world_proc_id; - int size = world_size; - - // TODO(llogan): arena -> labstor allocator - size_t scratch_size = (size * sizeof(char *) + - size * sizeof(char) * MPI_MAX_PROCESSOR_NAME); - std::vector node_names; - node_names.resize(size); - for (size_t i = 0; i < size; ++i) { - node_names[i] = new char[MPI_MAX_PROCESSOR_NAME]; - } - - int length; - MPI_Get_processor_name(node_names[rank], &length); - - MPI_Allgather(MPI_IN_PLACE, 0, 0, node_names[0], MPI_MAX_PROCESSOR_NAME, - MPI_CHAR, world_comm); - - // NOTE(chogan): Assign the first rank on each node to be the process that - // runs the Hermes core. The other ranks become application cores. - int first_on_node = 0; - while (strncmp(node_names[rank], node_names[first_on_node], - MPI_MAX_PROCESSOR_NAME) != 0) { - first_on_node++; - } - - if (first_on_node == rank) { - proc_kind = ProcessKind::kHermes; - } else { - proc_kind = ProcessKind::kApp; - } - - // NOTE(chogan): Create a set of unique node names - std::set names; - for (int i = 0; i < size; ++i) { - std::string name(node_names[i], length); - names.insert(name); - } - - num_nodes = names.size(); - - std::vector ranks_per_node_local(num_nodes, 0); - - // NOTE(chogan): 1-based index so 0 can be the NULL BufferID - int index = 1; - for (auto &name : names) { - if (name == node_names[rank]) { - node_id = index; - ranks_per_node_local[index - 1]++; - break; - } - ++index; - } - - // NOTE(chogan): We're returning the transient arena size in bytes for the - // calling rank. To calculate that, we need to divide the total transient - // arena size for each node by the number of ranks on that node. - std::vector ranks_per_node(num_nodes); - MPI_Allreduce(ranks_per_node_local.data(), ranks_per_node.data(), - num_nodes, MPI_INT, MPI_SUM, world_comm); - - size_t result = - trans_arena_size_per_node / (size_t)ranks_per_node[node_id - 1]; - - return result; + Barrier(world_comm_); } - /** - a wrapper for MPI_Finalize() function - */ + /** a wrapper for MPI_Finalize() function */ void Finalize() override { MPI_Finalize(); } - /** - initialize MPI communication. - */ - MpiCommunicator(size_t trans_arena_size_per_node, bool is_daemon, - bool is_adapter) { - world_comm = MPI_COMM_WORLD; - world_proc_id = GetWorldProcId(); - world_size = GetNumWorldProcs(); - - size_t trans_arena_size_for_rank = - AssignIDsToNodes(trans_arena_size_per_node); - - if (is_daemon || is_adapter) { - sub_comm = world_comm; - sub_proc_id = world_proc_id; - if (is_daemon) { - hermes_size = world_size; - proc_kind = ProcessKind::kHermes; - } else { - app_size = world_size; - proc_kind = ProcessKind::kApp; - } - first_on_node = FirstOnNode(world_comm); - } else { - int color = (int)proc_kind; - MPI_Comm_split(world_comm, color, world_proc_id, - &sub_comm); - - first_on_node = FirstOnNode(sub_comm); - sub_proc_id = GetSubProcId(); - - switch (proc_kind) { - case ProcessKind::kHermes: { - MPI_Comm_size(sub_comm, &hermes_size); - break; - } - case ProcessKind::kApp: { - MPI_Comm_size(sub_comm, &app_size); - break; - } - default: { - HERMES_INVALID_CODE_PATH; - break; - } - } - } - - // return trans_arena_size_for_rank; + /** initialize MPI communication. */ + MpiCommunicator(HermesType type) { + world_comm_ = MPI_COMM_WORLD; + world_proc_id_ = GetWorldProcId(); + world_size_ = GetNumWorldProcs(); + type_ = type; } }; diff --git a/src/config.h b/src/config.h index 2136330cd..742db39a5 100644 --- a/src/config.h +++ b/src/config.h @@ -26,19 +26,51 @@ namespace hermes { +class BaseConfig { + public: + /** load configuration from a string */ + void LoadText(const std::string &config_string, bool with_default = true) { + if (with_default) { LoadDefault(); } + if (config_string.size() == 0) { + return; + } + YAML::Node yaml_conf = YAML::Load(config_string); + ParseYAML(yaml_conf); + } + + /** load configuration from file */ + void LoadFromFile(const std::string &path, bool with_default = true) { + if (with_default) { LoadDefault(); } + if (path.size() == 0) { + return; + } + LOG(INFO) << "ParseConfig-LoadFile" << std::endl; + YAML::Node yaml_conf = YAML::LoadFile(path); + LOG(INFO) << "ParseConfig-LoadComplete" << std::endl; + ParseYAML(yaml_conf); + } + + /** load the default configuration */ + virtual void LoadDefault() = 0; + + private: + virtual void ParseYAML(YAML::Node &yaml_conf) = 0; +}; + /** * Configuration used to intialize client * */ -struct ClientConfig { +class ClientConfig : public BaseConfig { public: bool stop_daemon_; public: ClientConfig() = default; - void LoadText(const std::string &text); - void LoadFromFile(const std::string &path); - void LoadDefault(); + void LoadDefault() override; + + private: + void ParseYAML(YAML::Node &yaml_conf) override; }; struct DeviceInfo { @@ -93,7 +125,7 @@ struct BorgInfo { /** * System and user configuration that is used to initialize Hermes. */ -class ServerConfig { +class ServerConfig : public BaseConfig { public: /** The device information */ std::vector devices_; @@ -130,8 +162,6 @@ class ServerConfig { public: ServerConfig() = default; - void LoadText(const std::string &text); - void LoadFromFile(const std::string &path); void LoadDefault(); private: diff --git a/src/config_client.cc b/src/config_client.cc index 5b090966d..ee2706bef 100644 --- a/src/config_client.cc +++ b/src/config_client.cc @@ -7,4 +7,13 @@ namespace hermes { +/** parse the YAML node */ +void ClientConfig::ParseYAML(YAML::Node &yaml_conf) { +} + +/** Load the default configuration */ +void ClientConfig::LoadDefault() { + LoadText(kClientDefaultConfigStr, false); +} + } // namespace hermes \ No newline at end of file diff --git a/src/config_server.cc b/src/config_server.cc index 776cf6fe0..05f2fdf82 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -134,26 +134,9 @@ void ServerConfig::ParseYAML(YAML::Node &yaml_conf) { } } -/** load configuration from a string */ -void ServerConfig::LoadText(const std::string &config_string) { - LoadDefault(); - if (config_string.size() == 0) { - return; - } - YAML::Node yaml_conf = YAML::Load(config_string); - ParseYAML(yaml_conf); -} - -/** load configuration from file */ -void ServerConfig::LoadFromFile(const std::string &path) { - LoadDefault(); - if (path.size() == 0) { - return; - } - LOG(INFO) << "ParseConfig-LoadFile" << std::endl; - YAML::Node yaml_conf = YAML::LoadFile(path); - LOG(INFO) << "ParseConfig-LoadComplete" << std::endl; - ParseYAML(yaml_conf); +/** Load the default configuration */ +void ServerConfig::LoadDefault() { + LoadText(kServerDefaultConfigStr, false); } } // namespace hermes diff --git a/src/constants.cc b/src/constants.cc index 784f0eb69..008422a05 100644 --- a/src/constants.cc +++ b/src/constants.cc @@ -4,6 +4,10 @@ #include "constants.h" +namespace hermes { + const char* kHermesServerConf = "HERMES_CONF"; const char* kHermesClientConf = "HERMES_CLIENT_CONF"; -const size_t kMaxPathLength = 4096; \ No newline at end of file +const size_t kMaxPathLength = 4096; + +} // namespace hermes \ No newline at end of file diff --git a/src/constants.h b/src/constants.h index c1f5c2b58..83015f8af 100644 --- a/src/constants.h +++ b/src/constants.h @@ -7,8 +7,19 @@ #include +namespace hermes { + extern const char* kHermesServerConf; extern const char* kHermesClientConf; extern const size_t kMaxPathLength; +const int kMaxServerNamePrefix = 32; /**< max. server name prefix */ +const int kMaxServerNamePostfix = 8; /**< max. server name suffix */ +const char kBoPrefix[] = "BO::"; /**< buffer organizer prefix */ + +/** buffer organizer prefix length */ +const int kBoPrefixLength = sizeof(kBoPrefix) - 1; + +} + #endif // HERMES_SRC_CONSTANTS_H_ diff --git a/src/hermes_daemon.cc b/src/hermes_daemon.cc index 958314245..337fbea79 100644 --- a/src/hermes_daemon.cc +++ b/src/hermes_daemon.cc @@ -26,7 +26,8 @@ int main(int argc, char* argv[]) { hermes_config = argv[1]; } - auto hermes = hapi::Hermes(hapi::HermesType::kDaemon, hermes_config); + auto hermes = hapi::Hermes(hermes::HermesType::kServer, + hermes_config); hermes.RunDaemon(); MPI_Finalize(); diff --git a/src/hermes_types.h b/src/hermes_types.h index 182589191..d7b5b5fb6 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -23,6 +23,7 @@ #include "hermes_version.h" #include "data_structures.h" +#include "constants.h" /** * \file hermes_types.h @@ -57,6 +58,19 @@ typedef int64_t i64; /**< 64-bit signed integer */ typedef float f32; /**< 32-bit float */ typedef double f64; /**< 64-bit float */ +/** The mode Hermes is launched in */ +enum class HermesType { + kServer, + kClient, + kColocated +}; + +/** The types of I/O that can be performed (for IoCall RPC) */ +enum class IoType { + kRead, + kWrite +}; + typedef u16 DeviceID; /**< device id in unsigned 16-bit integer */ union BucketID { @@ -114,15 +128,61 @@ union BlobID { /** The BlobID as an unsigned 64-bit integer */ u64 as_int; - bool IsNull() const { return as_int == 0; } + bool IsNull() const { return as_int == 0; } bool InSwap() const { return bits.node_id < 0; } i32 GetNodeId() const { return bits.node_id; } }; +/** A definition for logging something that is not yet implemented */ +#define HERMES_NOT_IMPLEMENTED_YET \ + LOG(FATAL) << __func__ << " not implemented yet\n" + +/** A definition for logging invalid code path */ +#define HERMES_INVALID_CODE_PATH LOG(FATAL) << "Invalid code path." << std::endl + +/** A TargetID uniquely identifies a buffering target within the system. */ +union TargetID { + /** The Target ID as bitfield */ + struct { + /** The ID of the node in charge of this target. */ + u32 node_id; + /** The ID of the virtual device that backs this target. It is an index into + * the Device array starting at BufferPool::devices_offset (on the node with + * ID node_id). */ + u16 device_id; + /** The index into the Target array starting at BufferPool::targets_offset + * (on the node with ID node_id). */ + u16 index; + } bits; + + /** The TargetID as a unsigned 64-bit integer */ + u64 as_int; + + bool IsNull() const { return as_int == 0; } +}; + +/** + * A PlacementSchema is a vector of (size, target) pairs where size is the + * number of bytes to buffer and target is the TargetID where to buffer those + * bytes. + */ +using PlacementSchema = std::vector>; + /** - * \namespace api + * A structure to represent thesholds with mimimum and maximum values */ -namespace api { +struct Thresholds { + float min; /**< minimum threshold value */ + float max; /**< maximum threshold value */ +}; + +/** Trait ID type */ +typedef u64 TraitID; + +} // namespace hermes + + +namespace hermes::api { /** * A Blob is simply an uninterpreted vector of bytes. @@ -253,68 +313,6 @@ struct Context { vbkt_id_({0, 0}) {} }; -} // namespace api - -/** A definition for logging something that is not yet implemented */ -#define HERMES_NOT_IMPLEMENTED_YET \ - LOG(FATAL) << __func__ << " not implemented yet\n" - -/** A definition for logging invalid code path */ -#define HERMES_INVALID_CODE_PATH LOG(FATAL) << "Invalid code path." << std::endl - -/** A TargetID uniquely identifies a buffering target within the system. */ -union TargetID { - /** The Target ID as bitfield */ - struct { - /** The ID of the node in charge of this target. */ - u32 node_id; - /** The ID of the virtual device that backs this target. It is an index into - * the Device array starting at BufferPool::devices_offset (on the node with - * ID node_id). */ - u16 device_id; - /** The index into the Target array starting at BufferPool::targets_offset - * (on the node with ID node_id). */ - u16 index; - } bits; - - /** The TargetID as a unsigned 64-bit integer */ - u64 as_int; - - bool IsNull() const { return as_int == 0; } -}; - -/** - * A PlacementSchema is a vector of (size, target) pairs where size is the - * number of bytes to buffer and target is the TargetID where to buffer those - * bytes. - */ -using PlacementSchema = std::vector>; - -/** - * Distinguishes whether the process (or rank) is part of the application cores - * or the Hermes core(s). - */ -enum class ProcessKind { - kApp, /**< Application process */ - kHermes, /**< Hermes core process */ - - kCount /**< Sentinel value */ -}; - - -/** - * A structure to represent thesholds with mimimum and maximum values - */ -struct Thresholds { - float min; /**< minimum threshold value */ - float max; /**< maximum threshold value */ -}; - -/** Trait ID type */ -typedef u64 TraitID; - -namespace api { - /** \brief Trait types. * */ @@ -324,8 +322,12 @@ enum class TraitType : u8 { PERSIST = 2, }; -} // namespace api -} // namespace hermes +} // namespace hermes::api + + +/** + * HASH FUNCTIONS + * */ namespace std { template <> diff --git a/src/rpc.h b/src/rpc.h index 7918ef03c..74f8d76e8 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -18,14 +18,14 @@ #include "hermes_types.h" #include "communication.h" +#include "rpc_decorator.h" +#include "config.h" + #include #include namespace hermes { -const int kMaxServerNameSize = 128; /**< maximum size of server name */ -const int kMaxServerSuffixSize = 16; /**< maximum size of server suffix */ - /** RPC types */ enum class RpcType { kThallium @@ -34,45 +34,54 @@ enum class RpcType { /** A structure to represent RPC context. */ -namespace lipcl = labstor::ipc::lockless; - class RpcContext { public: - COMM_TYPE *comm_; - Config *config_; /** The hermes configuration used to initialize this RPC */ + COMM_TYPE &comm_; + /** The hermes configuration used to initialize this RPC */ + ServerConfig &config_; /** Array of host names stored in shared memory. This array size is * RpcContext::num_nodes. */ - lipcl::vector host_names; - u32 node_id_; /**< node ID */ - u32 num_nodes_; /**< number of nodes */ - // The number of host numbers in the rpc_host_number_range entry of the - // configuration file. Not necessarily the number of nodes because when there - // is only 1 node, the entry can be left blank, or contain 1 host number. - int port_; /**< port number */ - bool use_host_file_; /**< use host file if true */ - - // TODO(chogan): Also allow reading hostnames from a file for heterogeneous or - // non-contiguous hostnames (e.g., compute-node-20, compute-node-30, - // storage-node-16, storage-node-24) - // char *host_file_name; + lipcl::vector host_names_; + int port_; /**< port number */ public: - explicit RpcContext(COMM_TYPE *comm, - u32 num_nodes, u32 node_id, Config *config) : - comm_(comm), num_nodes_(num_nodes), - node_id_(node_id), config_(config) { - port_ = config->rpc_port; - if (!config->rpc_server_host_file.empty()) { - use_host_file_ = true; + explicit RpcContext(COMM_TYPE &comm, ServerConfig &config, u32 num_nodes, + u32 node_id) : comm_(comm), config_(config) { + port_ = config.rpc_.port_; + switch (comm.type_) { + case HermesType::kColocated + case HermesType::kServer: { + // Load configuration from either file or config + break; + } + case HermesType::kClient: { + // Load hostnames from SHMEM + break; + } + } + } + + /** Check if we should skip an RPC and call a function locally */ + bool ShouldDoLocalCall(int node_id) { + switch (comm_.type_) { + case HermesType::kClient: { + return false; + } + case HermesType::kServer: { + return node_id == comm_->node_id_; + } + case HermesType::kColocated: { + return true; + } } } /** get RPC address */ std::string GetRpcAddress(u32 node_id, int port) { - std::string result = config_->rpc_protocol + "://"; + std::string result = config_.rpc_.protocol_ + "://"; - if (!config_->rpc_domain.empty()) { - result += config_->rpc_domain + "/"; + if (!config_.rpc_.domain_.empty()) { + result += config_.rpc_.domain_ + "/"; } std::string host_name = GetHostNameFromNodeId(node_id); result += host_name + ":" + std::to_string(port); @@ -85,15 +94,13 @@ class RpcContext { std::string result; // NOTE(chogan): node_id 0 is reserved as the NULL node u32 index = node_id - 1; - result = host_names[index].str(); + result = host_names_[index].str(); return result; } }; } // namespace hermes -// TODO(chogan): I don't like that code similar to this is in buffer_pool.cc. -// I'd like to only have it in one place. #if defined(HERMES_RPC_THALLIUM) #include "rpc_thallium.h" #define RPC_TYPE ThalliumRpc diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 8ec65489a..5d43c6608 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -12,94 +12,35 @@ #include -#include "rpc.h" -#include "buffer_organizer.h" -#include "prefetcher.h" +#include "rpc_thallium.h" #include "singleton.h" namespace tl = thallium; namespace hermes { -/** Get protocol */ -std::string ThalliumRpc::GetProtocol() { - std::string prefix = std::string(server_name_prefix); - // NOTE(chogan): Chop "://" off the end of the server_name_prefix to get the - // protocol - std::string result = prefix.substr(0, prefix.length() - 3); - return result; +/** start Thallium RPC server */ +void ThalliumRpc::InitServer() { + // Load the host names + + DefineRpcs(); } /** initialize RPC clients */ void ThalliumRpc::InitClients() { std::string protocol = GetProtocol(); // TODO(chogan): This should go in a per-client persistent arena - client_engine_ = new tl::engine(protocol, THALLIUM_CLIENT_MODE, true, 1); -} - -/** shut down RPC clients */ -void ThalliumRpc::ShutdownClients() { - if (client_engine_) { - delete client_engine_; - client_engine_ = 0; - } + client_engine_ = tl::engine(protocol, + THALLIUM_CLIENT_MODE, + true, 1); } /** finalize RPC context */ -void ThalliumRpc::Finalize(bool is_daemon) { - if (is_daemon) { - engine->wait_for_finalize(); - bo_engine->wait_for_finalize(); - } else { - engine->finalize(); - bo_engine->finalize(); - } - delete engine; - delete bo_engine; +void ThalliumRpc::Finalize() { } /** run daemon */ void ThalliumRpc::RunDaemon(const char *shmem_name) { - engine->enable_remote_shutdown(); - bo_engine->enable_remote_shutdown(); - - auto prefinalize_callback = [this, &comm = comm_]() { - comm->SubBarrier(); - this->StopPrefetcher(); - this->StopGlobalSystemViewStateUpdateThread(); - comm->SubBarrier(); - ShutdownClients(); - }; - - engine->push_prefinalize_callback(prefinalize_callback); - - bo_engine->wait_for_finalize(); - engine->wait_for_finalize(); - - LocalShutdownBufferOrganizer(); - delete engine; - delete bo_engine; - - // TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 - // google::ShutdownGoogleLogging(); -} - -/** finalize client */ -void ThalliumRpc::FinalizeClient(bool stop_daemon) { - comm_->SubBarrier(); - if (stop_daemon && comm_->first_on_node) { - std::string bo_server_name = GetServerName(node_id_, true); - tl::endpoint bo_server = engine->lookup(bo_server_name); - engine->shutdown_remote_engine(bo_server); - - std::string server_name = GetServerName(node_id_, true); - tl::endpoint server = engine->lookup(server_name); - engine->shutdown_remote_engine(server); - } - comm_->SubBarrier(); - ShutdownClients(); - // TODO(chogan): https://github.com/HDFGroup/hermes/issues/323 - // google::ShutdownGoogleLogging(); } /** get server name */ @@ -113,7 +54,7 @@ std::string ThalliumRpc::GetServerName(u32 node_id) { char hostname_buffer[4096] = {}; #ifdef __APPLE__ hostname_result = gethostbyname(host_name.c_str()); - in_addr **addr_list = (struct in_addr **)hostname_result->h_addr_list; + in_addr **addr_list = (struct in_addr **)hostname_result->h_addr_list; #else int gethostbyname_result = gethostbyname_r(host_name.c_str(), &hostname_info, hostname_buffer, 4096, @@ -136,23 +77,18 @@ std::string ThalliumRpc::GetServerName(u32 node_id) { FailedLibraryCall("inet_ntop"); } - std::string result = std::string(server_name_prefix); - result += std::string(ip_address); - - if (is_buffer_organizer) { - result += std::string(bo_server_name_postfix); - } else { - result += std::string(server_name_postfix); - } + result = config_.prefix_ std::string(ip_address); return result; } -/** start Thallium RPC server */ -void ThalliumRpc::StartServer(const char *addr, - i32 num_rpc_threads) { - RPC_AUTOGEN_START - RPC_AUTOGEN_END +/** Get protocol */ +std::string ThalliumRpc::GetProtocol() { + std::string prefix = std::string(server_name_prefix); + // NOTE(chogan): Chop "://" off the end of the server_name_prefix to get the + // protocol + std::string result = prefix.substr(0, prefix.length() - 3); + return result; } } // namespace hermes \ No newline at end of file diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index 699ab7548..708e43ece 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -19,263 +19,92 @@ #include #include -#include -#include -#include +#include "rpc_thallium_serialization.h" +#include "communication.h" +#include "config.h" +#include "utils.h" #include "rpc.h" -#include "buffer_organizer.h" namespace tl = thallium; namespace hermes { -const int kMaxServerNamePrefix = 32; /**< max. server name prefix */ -const int kMaxServerNamePostfix = 8; /**< max. server name suffix */ -const char kBoPrefix[] = "BO::"; /**< buffer organizer prefix */ -/** buffer organizer prefix length */ -const int kBoPrefixLength = sizeof(kBoPrefix) - 1; - -std::string GetRpcAddress(RpcContext *rpc, Config *config, u32 node_id, - int port); - -/** is \a func_name buffer organizer function? */ -static bool IsBoFunction(const char *func_name) { - bool result = false; - int i = 0; - - while (func_name && *func_name != '\0' && i < kBoPrefixLength) { - if (func_name[i] != kBoPrefix[i]) { - break; - } - ++i; - } - - if (i == kBoPrefixLength) { - result = true; - } - - return result; -} - /** A structure to represent Thallium state */ class ThalliumRpc : public RpcContext { public: - char server_name_prefix[kMaxServerNamePrefix]; /**< server prefix */ - char server_name_postfix[kMaxServerNamePostfix]; /**< server suffix */ - char bo_server_name_postfix[kMaxServerNamePostfix]; /**< buf. org. suffix */ - std::atomic kill_requested; /**< is kill requested? */ - tl::engine *engine; /**< pointer to engine */ - tl::engine *bo_engine; /**< pointer to buf. org. engine */ - ABT_xstream execution_stream; /**< Argobots execution stream */ - tl::engine *client_engine_; /**< pointer to engine */ + std::atomic kill_requested_; /**< is kill requested? */ + tl::engine server_engine_; /**< pointer to engine */ + tl::engine bo_engine_; /**< pointer to buf. org. engine */ + ABT_xstream execution_stream_; /**< Argobots execution stream */ + tl::engine client_engine_; /**< pointer to engine */ + tl::engine io_engine_; /**< pointer to engine */ /** initialize RPC context */ - explicit ThalliumRpc(COMM_TYPE *comm, - u32 num_nodes, u32 node_id, Config *config) : - RpcContext(comm, num_nodes, node_id, config) { - } + explicit ThalliumRpc(COMM_TYPE *comm, u32 num_nodes, u32 node_id, + ServerConfig &config) + : RpcContext(comm, num_nodes, node_id, config) {} /** Get protocol */ + void InitClients(); + void InitServer(); + void Finalize(); + void RunDaemon(const char *shmem_name); + std::string GetServerName(u32 node_id); std::string GetProtocol(); - - /** RPC call */ template ReturnType Call(u32 node_id, const char *func_name, Ts... args) { - VLOG(1) << "Calling " << func_name << " on node " << node_id << " from node " - << node_id << std::endl; - bool is_bo_func = IsBoFunction(func_name); - std::string server_name = GetServerName(node_id, is_bo_func); - - if (is_bo_func) { - func_name += kBoPrefixLength; - } - - tl::remote_procedure remote_proc = client_engine_->define(func_name); - // TODO(chogan): @optimization We can save a little work by storing the - // endpoint instead of looking it up on every call - tl::endpoint server = client_engine_->lookup(server_name); - + VLOG(1) << "Calling " << func_name << " on node " << node_id + << " from node " << node_id << std::endl; + std::string server_name = GetServerName(node_id); + tl::remote_procedure remote_proc = client_engine_.define(func_name); + tl::endpoint server = client_engine_.lookup(server_name); if constexpr (std::is_same::value) { remote_proc.disable_response(); remote_proc.on(server)(std::forward(args)...); } else { ReturnType result = remote_proc.on(server)(std::forward(args)...); - return result; } } -}; - -/** - * Lets Thallium know how to serialize a BucketID. - * - * This function is called implicitly by Thallium. - * - * @param ar An archive provided by Thallium. - * @param bucket_id The BucketID to serialize. - */ -template -void serialize(A &ar, BucketID &bucket_id) { - ar &bucket_id.as_int; -} - -/** - * Lets Thallium know how to serialize a VBucketID. - * - * This function is called implicitly by Thallium. - * - * @param ar An archive provided by Thallium. - * @param vbucket_id The VBucketID to serialize. - */ -template -void serialize(A &ar, VBucketID &vbucket_id) { - ar &vbucket_id.as_int; -} - -/** - * Lets Thallium know how to serialize a BlobID. - * - * This function is called implicitly by Thallium. - * - * @param ar An archive provided by Thallium. - * @param blob_id The BlobID to serialize. - */ -template -void serialize(A &ar, BlobID &blob_id) { - ar &blob_id.as_int; -} - -/** - * Lets Thallium know how to serialize a TargetID. - * - * This function is called implicitly by Thallium. - * - * @param ar An archive provided by Thallium. - * @param target_id The TargetID to serialize. - */ -template -void serialize(A &ar, TargetID &target_id) { - ar &target_id.as_int; -} - -/** serialize \a info */ -template -void serialize(A &ar, BufferInfo &info) { - ar &info.target_; - ar &info.bandwidth_mbps; - ar &info.size; -} - -#ifndef THALLIUM_USE_CEREAL - -// NOTE(chogan): Thallium's default serialization doesn't handle enums by -// default so we must write serialization code for all enums when we're not -// using cereal. -/** save \a priority */ -template -void save(A &ar, BoPriority &priority) { - int val = (int)priority; - ar.write(&val, 1); -} - -/** load \a priority */ -template -void load(A &ar, BoPriority &priority) { - int val = 0; - ar.read(&val, 1); - priority = (BoPriority)val; -} - -/** save \a violation */ -/* template -void save(A &ar, ThresholdViolation &violation) { - int val = (int)violation; - ar.write(&val, 1); -} */ - -/** load \a violation */ -/* template -void load(A &ar, ThresholdViolation &violation) { - int val = 0; - ar.read(&val, 1); - violation = (ThresholdViolation)val; -} */ -#endif // #ifndef THALLIUM_USE_CEREAL - -/** save buffer organizer \a op */ -template -void save(A &ar, BoOperation &op) { - int val = (int)op; - ar.write(&val, 1); -} - -/** load buffer organizer \a op */ -template -void load(A &ar, BoOperation &op) { - int val = 0; - ar.read(&val, 1); - op = (BoOperation)val; -} - -/** serialize buffer organizer task */ -template -void serialize(A &ar, BoTask &bo_task) { - ar &bo_task.op; -} + size_t IoCall(u32 node_id, IoType type, u8 *data, + TargetID id, size_t off, size_t size) { + std::string server_name = GetServerName(node_id); + const char *func_name; + tl::bulk_mode flag; + + switch (type) { + case IoType::kRead: { + func_name = "BulkRead"; + flag = tl::bulk_mode::read_only; + } + case IoType::kWrite: { + func_name = "BulkWrite"; + flag = tl::bulk_mode::write_only; + } + } -/** serialize violation information */ -/*template -void serialize(A &ar, ViolationInfo &info) { - ar &info.target_id; - ar &info.violation; - ar &info.violation_size; -}*/ + tl::remote_procedure remote_proc = io_engine_.define(func_name); + tl::endpoint server = io_engine_.lookup(server_name); -namespace api { + std::vector> segments(1); + segments[0].first = data; + segments[0].second = size; -// PrefetchHint -template -void save(A &ar, PrefetchHint &hint) { - ar << static_cast(hint); -} -template -void load(A &ar, PrefetchHint &hint) { - int hint_i; - ar >> hint_i; - hint = static_cast(hint_i); -} + tl::bulk bulk = io_engine_.expose(segments, flag); + size_t result = remote_proc.on(server)(bulk, id); -// PrefetchContext -template -void serialize(A &ar, PrefetchContext &pctx) { - ar & pctx.hint_; - ar & pctx.read_ahead_; -} + return result; + } -template -#ifndef THALLIUM_USE_CEREAL -void save(A &ar, api::Context &ctx) { -#else -void save(A &ar, const api::Context &ctx) { -#endif // #ifndef THALLIUM_USE_CEREAL - ar.write(&ctx.buffer_organizer_retries, 1); - int val = (int)ctx.policy; - ar.write(&val, 1); -} -template -void load(A &ar, api::Context &ctx) { - int val = 0; - ar.read(&ctx.buffer_organizer_retries, 1); - ar.read(&val, 1); - ctx.policy = (PlacementPolicy)val; -} -} // namespace api + private: + void DefineRpcs(); +}; } // namespace hermes diff --git a/src/rpc_thallium_defs.cc b/src/rpc_thallium_defs.cc new file mode 100644 index 000000000..8ce4d9ffa --- /dev/null +++ b/src/rpc_thallium_defs.cc @@ -0,0 +1,14 @@ +// +// Created by lukemartinlogan on 12/3/22. +// + +#include "rpc_thallium.h" + +namespace hermes { + +void ThalliumRpc::DefineRpcs() { + RPC_AUTOGEN_START + RPC_AUTOGEN_END +} + +} // namespace hermes \ No newline at end of file diff --git a/src/rpc_thallium_serialization.h b/src/rpc_thallium_serialization.h new file mode 100644 index 000000000..dd81c0e8d --- /dev/null +++ b/src/rpc_thallium_serialization.h @@ -0,0 +1,19 @@ +// +// Created by lukemartinlogan on 12/2/22. +// + +#ifndef HERMES_SRC_RPC_THALLIUM_SERIALIZATION_H_ +#define HERMES_SRC_RPC_THALLIUM_SERIALIZATION_H_ + +#include +#include +#include +#include + +namespace hermes { +} // namespace hermes + +namespace hermes::api { +} // namespace hermes::api + +#endif // HERMES_SRC_RPC_THALLIUM_SERIALIZATION_H_ diff --git a/src/utils.cc b/src/utils.cc index 4d003c745..52217f007 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -46,86 +46,6 @@ size_t RoundDownToMultiple(size_t val, size_t multiple) { return result; } -void InitDefaultConfig(Config *config) { - config->num_devices = 4; - config->num_targets = 4; - assert(config->num_devices < kMaxDevices); - - for (int dev = 0; dev < config->num_devices; ++dev) { - config->capacities[dev] = MEGABYTES(50); - config->block_sizes[dev] = KILOBYTES(4); - config->num_slabs[dev] = 4; - - config->slab_unit_sizes[dev][0] = 1; - config->slab_unit_sizes[dev][1] = 4; - config->slab_unit_sizes[dev][2] = 16; - config->slab_unit_sizes[dev][3] = 32; - - config->desired_slab_percentages[dev][0] = 0.25f; - config->desired_slab_percentages[dev][1] = 0.25f; - config->desired_slab_percentages[dev][2] = 0.25f; - config->desired_slab_percentages[dev][3] = 0.25f; - } - - config->bandwidths[0] = 6000.0f; - config->bandwidths[1] = 300.f; - config->bandwidths[2] = 150.0f; - config->bandwidths[3] = 70.0f; - - config->latencies[0] = 15.0f; - config->latencies[1] = 250000; - config->latencies[2] = 500000.0f; - config->latencies[3] = 1000000.0f; - - // TODO(chogan): Express these in bytes instead of percentages to avoid - // rounding errors? - config->arena_percentages[kArenaType_BufferPool] = 0.85f; - config->arena_percentages[kArenaType_MetaData] = 0.04f; - config->arena_percentages[kArenaType_Transient] = 0.11f; - - config->mount_points[0] = ""; - config->mount_points[1] = "./"; - config->mount_points[2] = "./"; - config->mount_points[3] = "./"; - config->swap_mount = "./"; - - config->num_buffer_organizer_retries = 3; - - config->rpc_server_host_file = ""; - config->rpc_server_base_name = "localhost"; - config->rpc_server_suffix = ""; - config->host_numbers = std::vector(); - config->host_names.emplace_back("localhost"); - config->rpc_protocol = "ofi+sockets"; - config->rpc_domain = ""; - config->rpc_port = 8080; - config->buffer_organizer_port = 8081; - config->rpc_num_threads = 1; - - config->max_buckets_per_node = 16; - config->max_vbuckets_per_node = 8; - config->system_view_state_update_interval_ms = 100; - - const std::string buffer_pool_shmem_name = "/hermes_buffer_pool_"; - std::snprintf(config->buffer_pool_shmem_name, - kMaxBufferPoolShmemNameLength, - "%s", buffer_pool_shmem_name.c_str()); - - config->default_placement_policy = api::PlacementPolicy::kMinimizeIoTime; - - config->is_shared_device[0] = 0; - config->is_shared_device[1] = 0; - config->is_shared_device[2] = 0; - config->is_shared_device[3] = 0; - - config->bo_num_threads = 4; - config->default_rr_split = false; - - for (int i = 0; i < config->num_devices; ++i) { - config->bo_capacity_thresholds[i].min = 0.0f; - config->bo_capacity_thresholds[i].max = 1.0f; - } -} /** print an error message for \a func function that failed */ @@ -135,127 +55,4 @@ void FailedLibraryCall(std::string func) { << std::endl; } -namespace testing { - -TargetViewState InitDeviceState(u64 total_target, bool homo_dist) { - TargetViewState result = {}; - result.num_devices = total_target; - std::vector tgt_fraction; - std::vector tgt_homo_dist {0.25, 0.25, 0.25, 0.25}; - std::vector tgt_heto_dist {0.1, 0.2, 0.3, 0.4}; - /** Use Megabytes */ - std::vector device_size {128, 1024, 4096, 16384}; - /** Use Megabytes/Sec */ - std::vector device_bandwidth {8192, 3072, 550, 120}; - - if (homo_dist) - tgt_fraction = tgt_homo_dist; - else - tgt_fraction = tgt_heto_dist; - - std::vector tgt_num_per_type; - u64 used_tgt {0}; - for (size_t i {0}; i < tgt_fraction.size()-1; ++i) { - u64 used_tgt_tmp {static_cast(tgt_fraction[i] * total_target)}; - tgt_num_per_type.push_back(used_tgt_tmp); - used_tgt += used_tgt_tmp; - } - tgt_num_per_type.push_back(total_target - used_tgt); - - using hermes::TargetID; - std::vector targets = GetDefaultTargets(total_target); - - for (size_t i {0}; i < tgt_num_per_type.size(); ++i) { - for (size_t j {0}; j < tgt_num_per_type[i]; ++j) { - result.bandwidth.push_back(device_bandwidth[i]); - - result.bytes_available.push_back(MEGABYTES(device_size[i])); - result.bytes_capacity.push_back(MEGABYTES(device_size[i])); - } - } - - return result; -} - -u64 UpdateDeviceState(PlacementSchema &schema, - TargetViewState &node_state) { - u64 result {0}; - for (auto [size, target] : schema) { - result += size; - node_state.bytes_available[target.bits.device_id] -= size; - } - return result; -} - -void PrintNodeState(TargetViewState &node_state) { - for (int i {0}; i < node_state.num_devices; ++i) { - std::cout << " capacity of device[" << i << "]: " - << node_state.bytes_available[i] / MEGABYTES(1) - << " MB\n" << std::flush; - std::cout << " available ratio of device["<< i << "]: " - << static_cast(node_state.bytes_available[i])/ - node_state.bytes_capacity[i] - << "\n\n" << std::flush; - } -} - -std::vector GetDefaultTargets(size_t n) { - std::vector result(n); - for (size_t i = 0; i < n; ++i) { - TargetID id = {}; - id.bits.node_id = 1; - id.bits.device_id = (DeviceID)i; - id.bits.index = i; - result[i] = id; - } - - return result; -} - -std::pair GetBlobBound(BlobSizeRange blob_size_range) { - if (blob_size_range == BlobSizeRange::kSmall) - return {0, KILOBYTES(64)}; - else if (blob_size_range == BlobSizeRange::kMedium) - return {KILOBYTES(64), MEGABYTES(1)}; - else if (blob_size_range == BlobSizeRange::kLarge) - return {MEGABYTES(1), MEGABYTES(4)}; - else if (blob_size_range == BlobSizeRange::kXLarge) - return {MEGABYTES(4), MEGABYTES(64)}; - else if (blob_size_range == BlobSizeRange::kHuge) - return {GIGABYTES(1), GIGABYTES(1)}; - - std::cout << "No specified blob range is found.\n" - << "Use small blob range (0, 64KB]."; - return {0, KILOBYTES(64)}; -} - -std::vector GenFixedTotalBlobSize(size_t total_size, - BlobSizeRange range) { - std::vector result; - size_t used_size {}; - size_t size {}; - std::random_device dev; - std::mt19937 rng(dev()); - - std::pair bound = GetBlobBound(range); - size_t lo_bound = bound.first; - size_t hi_bound = bound.second; - - while (used_size < total_size) { - std::vector input_blobs; - if (total_size - used_size > hi_bound) { - std::uniform_int_distribution - distribution(lo_bound, hi_bound); - size = distribution(rng); - used_size += size; - } else { - size = total_size - used_size; - used_size = total_size; - } - result.push_back(size); - } - return result; -} - -} // namespace testing } // namespace hermes diff --git a/src/utils.h b/src/utils.h index 87f941c06..04c9da8e3 100644 --- a/src/utils.h +++ b/src/utils.h @@ -20,4 +20,8 @@ #include "hermes_types.h" +size_t RoundUpToMultiple(size_t val, size_t multiple); +size_t RoundDownToMultiple(size_t val, size_t multiple); +void FailedLibraryCall(std::string func); + #endif // HERMES_UTILS_H_ From 3b3200659d1a905b7ec3cb550c7e7ca2706ad11e Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 4 Dec 2022 04:51:14 -0600 Subject: [PATCH 045/511] Thallium factory. Simplify comm factory. --- CMakeLists.txt | 2 +- adapter/test/pubsub/CMakeLists.txt | 4 - benchmarks/CMakeLists.txt | 2 - src/CMakeLists.txt | 33 +++++-- src/api/hermes.cc | 98 ++++++++++++++++++++ src/api/hermes.h | 70 ++++++-------- src/communication.h | 20 ++-- src/communication_factory.h.in | 20 ++++ src/communication_mpi.h | 44 ++++----- src/constants.cc | 13 --- src/constants.h | 16 ++-- src/rpc.h | 143 ++++++++++++++++++++-------- src/rpc_factory.h.in | 17 ++++ src/rpc_thallium.cc | 60 +++--------- src/rpc_thallium.h | 17 ++-- src/utils.h | 4 + test/CMakeLists.txt | 144 +---------------------------- test/test_rpc.cc | 30 +++++- wrapper/CMakeLists.txt | 2 - 19 files changed, 388 insertions(+), 351 deletions(-) create mode 100644 src/api/hermes.cc create mode 100644 src/communication_factory.h.in delete mode 100644 src/constants.cc create mode 100644 src/rpc_factory.h.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 53c5d0601..58624bb65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -423,7 +423,7 @@ if(CMAKE_PROJECT_NAME STREQUAL HERMES AND BUILD_TESTING) set(HERMES_HAVE_IOR "NO") endif() enable_testing() - # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test) # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/data_stager/test) endif() diff --git a/adapter/test/pubsub/CMakeLists.txt b/adapter/test/pubsub/CMakeLists.txt index 32f868453..9224dc707 100644 --- a/adapter/test/pubsub/CMakeLists.txt +++ b/adapter/test/pubsub/CMakeLists.txt @@ -16,8 +16,6 @@ foreach(program ${SINGLE_NODE_PUBSUB_TESTS}) add_dependencies(${program} hermes_pubsub) target_link_libraries(${program} ${LIBRT} hermes MPI::MPI_CXX $<$:thallium> hermes_pubsub) - target_compile_definitions(${program} - PRIVATE $<$:HERMES_RPC_THALLIUM>) mpi_daemon(${program} 1 "" "" 1) endforeach() @@ -26,8 +24,6 @@ foreach(program ${MULTI_NODE_PUBSUB_TESTS}) add_dependencies(${program} hermes_pubsub) target_link_libraries(${program} ${LIBRT} hermes MPI::MPI_CXX $<$:thallium> hermes_pubsub) - target_compile_definitions(${program} - PRIVATE $<$:HERMES_RPC_THALLIUM>) mpi_daemon(${program} 2 "" "" 1) endforeach() diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 57ae9c3ff..d7bde67c0 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -9,6 +9,4 @@ foreach(benchmark ${BENCHMARKS}) add_executable(${benchmark} ${benchmark}.cc) target_link_libraries(${benchmark} hermes MPI::MPI_CXX $<$:thallium> glog::glog) - target_compile_definitions(${benchmark} - PRIVATE $<$:HERMES_RPC_THALLIUM>) endforeach() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0bd3e6330..224b5a90c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,6 +2,22 @@ include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/adapter) configure_file(hermes_version.h.in hermes_version.h) +# Create communication factory +set(CMAKE_HERMES_COMMUNICATION_TYPE HERMES_RPC_NONE) +if (HERMES_COMMUNICATION_MPI) + set(CMAKE_HERMES_COMMUNICATION_TYPE HERMES_COMMUNICATION_MPI) + set(CMAKE_HERMES_COMMUNICATION_TYPE_LIB MPI::MPI_CXX) +endif() +configure_file(communication_factory.h.in communication_factory.h) + +# Create rpc factory +set(CMAKE_HERMES_COMMUNICATION_TYPE HERMES_RPC_NONE) +if (HERMES_RPC_THALLIUM) + set(CMAKE_HERMES_RPC_TYPE HERMES_RPC_THALLIUM) + set(CMAKE_HERMES_RPC_TYPE_LIB thallium) +endif() +configure_file(rpc_factory.h.in rpc_factory.h) + #------------------------------------------------------------------------------ # External dependencies #------------------------------------------------------------------------------ @@ -23,12 +39,12 @@ endif() # Set sources #------------------------------------------------------------------------------ set(HERMES_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/constants.cc + ${CMAKE_CURRENT_SOURCE_DIR}/api/hermes.cc ${CMAKE_CURRENT_SOURCE_DIR}/config_client.cc ${CMAKE_CURRENT_SOURCE_DIR}/config_server.cc - ${CMAKE_CURRENT_SOURCE_DIR}/hermes_daemon.cc ${CMAKE_CURRENT_SOURCE_DIR}/utils.cc - #${CMAKE_CURRENT_SOURCE_DIR}/rpc_thallium.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rpc_thallium.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rpc_thallium_defs.cc #${CMAKE_CURRENT_SOURCE_DIR}/api/bucket.cc #${CMAKE_CURRENT_SOURCE_DIR}/api/hermes.cc #${CMAKE_CURRENT_SOURCE_DIR}/api/vbucket.cc @@ -65,18 +81,15 @@ target_include_directories(hermes target_link_libraries(hermes PUBLIC ${GLPK_LIBRARIES} - PUBLIC thallium + PUBLIC ${CMAKE_HERMES_COMMUNICATION_TYPE_LIB} + PUBLIC ${CMAKE_HERMES_RPC_TYPE_LIB} PUBLIC glog::glog PUBLIC yaml-cpp + PUBLIC labstor_client labstor_data_structures PUBLIC "$<$:${GOTCHA_MODULE_LIBS}>" - PRIVATE $<$:MPI::MPI_CXX> ) target_compile_definitions(hermes - PRIVATE $<$:HERMES_COMMUNICATION_MPI> - PRIVATE $<$:HERMES_RPC_THALLIUM> - PRIVATE $<$:HERMES_DEBUG_HEAP> - PRIVATE $<$:HERMES_MDM_STORAGE_STBDS> PRIVATE $<$:HERMES_ENABLE_TIMING> ) @@ -93,6 +106,8 @@ find_package(Catch2 REQUIRED) add_executable(hermes_daemon hermes_daemon.cc) add_dependencies(hermes_daemon hermes) target_link_libraries(hermes_daemon hermes -ldl -lc MPI::MPI_CXX glog::glog) +target_compile_definitions(hermes_daemon + PRIVATE $<$:HERMES_ENABLE_TIMING>) #----------------------------------------------------------------------------- # Specify project header files to be installed diff --git a/src/api/hermes.cc b/src/api/hermes.cc new file mode 100644 index 000000000..ef77bae96 --- /dev/null +++ b/src/api/hermes.cc @@ -0,0 +1,98 @@ +// +// Created by lukemartinlogan on 12/3/22. +// + +#include "hermes.h" + +namespace hermes::api { + +Hermes::Hermes(HermesType mode, + std::string server_config_path, + std::string client_config_path) + : comm_(mode), + rpc_(&comm_, &server_config_) { + Init(mode, std::move(server_config_path), std::move(client_config_path)); +} + +void Hermes::Init(HermesType mode, + std::string server_config_path, + std::string client_config_path) { + mode_ = mode; + switch (mode) { + case HermesType::kServer: { + InitDaemon(std::move(server_config_path)); + break; + } + case HermesType::kClient: { + InitClient(std::move(client_config_path)); + break; + } + case HermesType::kColocated: { + InitColocated(std::move(server_config_path), + std::move(client_config_path)); + break; + } + } +} + +void Hermes::Finalize() {} + +void Hermes::RunDaemon() {} + +void Hermes::InitDaemon(std::string server_config_path) { + LoadServerConfig(server_config_path); + InitSharedMemory(); +} + +void Hermes::InitColocated(std::string server_config_path, + std::string client_config_path) { + LoadServerConfig(server_config_path); + LoadClientConfig(client_config_path); + InitSharedMemory(); +} + +void Hermes::InitClient(std::string client_config_path) { + LoadClientConfig(client_config_path); + LoadSharedMemory(); +} + +void Hermes::LoadServerConfig(std::string config_path) { + if (config_path.size() == 0) { + config_path = GetEnvSafe(kHermesServerConf); + } + server_config_.LoadFromFile(config_path); +} + +void Hermes::LoadClientConfig(std::string config_path) { + if (config_path.size() == 0) { + config_path = GetEnvSafe(kHermesClientConf); + } + client_config_.LoadFromFile(config_path); +} + +void Hermes::InitSharedMemory() { + // Create shared-memory allocator + auto mem_mngr = LABSTOR_MEMORY_MANAGER; + mem_mngr->CreateBackend(lipc::MemoryBackendType::kPosixShmMmap, + server_config_.shmem_name_); + main_alloc_ = + mem_mngr->CreateAllocator(lipc::AllocatorType::kPageAllocator, + server_config_.shmem_name_, main_alloc_id); +} + +void Hermes::LoadSharedMemory() { + // Load shared-memory allocator + auto mem_mngr = LABSTOR_MEMORY_MANAGER; + mem_mngr->CreateBackend(lipc::MemoryBackendType::kPosixShmMmap, + server_config_.shmem_name_); + mem_mngr->ScanBackends(); + main_alloc_ = mem_mngr->GetAllocator(main_alloc_id); +} + +void Hermes::FinalizeDaemon() {} + +void Hermes::FinalizeClient() {} + +void Hermes::FinalizeColocated() {} + +} // namespace hermes::api \ No newline at end of file diff --git a/src/api/hermes.h b/src/api/hermes.h index f2712ee2e..00f55f871 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -8,6 +8,7 @@ #include "config.h" #include "constants.h" #include "hermes_types.h" +#include "rpc.h" namespace hermes::api { @@ -16,60 +17,45 @@ class Hermes { HermesType mode_; ServerConfig server_config_; ClientConfig client_config_; + COMM_TYPE comm_; + RPC_TYPE rpc_; + lipc::Allocator *main_alloc_; public: Hermes() = default; - Hermes(HermesType mode, std::string config_path) { - Init(mode, std::move(config_path)); - } + Hermes(HermesType mode, + std::string server_config_path = "", + std::string client_config_path = ""); - void Init(HermesType mode, std::string config_path) { - mode_ = mode; - switch (mode) { - case HermesType::kServer: { - InitDaemon(std::move(config_path)); - break; - } - case HermesType::kClient: { - InitClient(std::move(config_path)); - break; - } - case HermesType::kColocated: { - InitColocated(std::move(config_path)); - break; - } - } - } + void Init(HermesType mode, + std::string server_config_path = "", + std::string client_config_path = ""); - void Finalize() { - } + void Finalize(); - void RunDaemon() { - } + void RunDaemon(); private: - void InitDaemon(std::string config_path) { - // Load the Hermes Configuration - if (config_path.size() == 0) { - config_path = GetEnvSafe(kHermesServerConf); - } - server_config_.LoadFromFile(config_path); - } + void InitDaemon(std::string server_config_path); - void InitClient(std::string config_path) { - } + void InitColocated(std::string server_config_path, + std::string client_config_path); - void InitColocated(std::string config_path) { - } + void InitClient(std::string client_config_path); - void FinalizeDaemon() { - } + void LoadServerConfig(std::string config_path); - void FinalizeClient() { - } + void LoadClientConfig(std::string config_path); - void FinalizeColocated() { - } + void InitSharedMemory(); + + void LoadSharedMemory(); + + void FinalizeDaemon(); + + void FinalizeClient(); + + void FinalizeColocated(); private: inline std::string GetEnvSafe(const char *env_name) { @@ -81,6 +67,6 @@ class Hermes { } }; -} +} // namespace hermes::api #endif // HERMES_SRC_API_HERMES_H_ diff --git a/src/communication.h b/src/communication.h index 26c8aa6c8..b83ccb283 100644 --- a/src/communication.h +++ b/src/communication.h @@ -21,6 +21,12 @@ * A generic communication interface for Hermes that can be implemented by * multiple backends. See communication_mpi.cc for an example of how to * implement a communication backend. + * + * NOTE: this file is only applied to HermesType::kServer. + * This does not get used in kColocated or kClient modes. + * It is used almost solely to ensure RPC servers remain + * running until all nodes want to terminate their + * Hermes core. */ namespace hermes { @@ -34,27 +40,17 @@ class CommunicationContext { i32 world_proc_id_; /** The total number of ranks. */ i32 world_size_; - /** The total number of nodes. */ - i32 num_nodes_; /** The type of communicator this is */ HermesType type_; public: + CommunicationContext() : world_proc_id_(0), world_size_(0) {} virtual void WorldBarrier() = 0; /** E.g., MPI_Barrier(MPI_COMM_WORLD)*/ - virtual void SubBarrier() = 0; /** E.g., MPI_Barrier(something else)*/ virtual void Finalize() = 0; /** E.g., MPI_Finalize() */ }; } // namespace hermes -#if defined(HERMES_COMMUNICATION_MPI) -#include "communication_mpi.h" -#define COMM_TYPE MpiCommunicator -#elif defined(HERMES_COMMUNICATION_ZMQ) -#include "communication_zmq.cc" -#else -#error "Communication implementation required " \ - "(e.g., -DHERMES_COMMUNICATION_MPI)." -#endif +#include "communication_factory.h" #endif // HERMES_COMMUNICATION_H_ diff --git a/src/communication_factory.h.in b/src/communication_factory.h.in new file mode 100644 index 000000000..a6799516c --- /dev/null +++ b/src/communication_factory.h.in @@ -0,0 +1,20 @@ +// +// Created by lukemartinlogan on 12/4/22. +// + +#ifndef HERMES_SRC_COMMUNICATION_FACTORY_H_ +#define HERMES_SRC_COMMUNICATION_FACTORY_H_ + +#define @CMAKE_HERMES_COMMUNICATION_TYPE@ + +#if defined(HERMES_COMMUNICATION_MPI) +#include "communication_mpi.h" +#define COMM_TYPE MpiCommunicator +#elif defined(HERMES_COMMUNICATION_ZMQ) +#include "communication_zmq.cc" +#else +#error "Communication implementation required " \ + "(e.g., -DHERMES_COMMUNICATION_MPI)." +#endif + +#endif // HERMES_SRC_COMMUNICATION_FACTORY_H_ diff --git a/src/communication_mpi.h b/src/communication_mpi.h index 3203636c4..777ecc26c 100644 --- a/src/communication_mpi.h +++ b/src/communication_mpi.h @@ -14,7 +14,7 @@ #define HERMES_SRC_COMMUNICATION_MPI_H #include "communication.h" -#include "mpi.h" +#include #include /** @@ -27,9 +27,29 @@ namespace hermes { class MpiCommunicator : public CommunicationContext { public: - MPI_Comm world_comm_; /**< MPI world communicator */ + MPI_Comm world_comm_; /**< Represents all processes */ + MPI_Comm node_comm_; /**< Represents all nodes */ public: + /** a wrapper for MPI global communicator's MPI_Barrier() function */ + inline void WorldBarrier() override { + Barrier(world_comm_); + } + + /** a wrapper for MPI_Finalize() function */ + void Finalize() override { + MPI_Finalize(); + } + + /** initialize MPI communication. */ + MpiCommunicator(HermesType type) { + world_comm_ = MPI_COMM_WORLD; + world_proc_id_ = GetWorldProcId(); + world_size_ = GetNumWorldProcs(); + type_ = type; + } + + private: /** get the MPI process ID of \a comm MPI communicator. */ inline int GetProcId(MPI_Comm comm) { int result; @@ -55,28 +75,10 @@ class MpiCommunicator : public CommunicationContext { return GetNumProcs(world_comm_); } - /** a wrapper for MPI_Barrier() fucntion */ + /** a wrapper for MPI_Barrier() function */ inline void Barrier(MPI_Comm comm) { MPI_Barrier(comm); } - - /** a wrapper for MPI global communicator's MPI_Barrier() function */ - inline void WorldBarrier() override { - Barrier(world_comm_); - } - - /** a wrapper for MPI_Finalize() function */ - void Finalize() override { - MPI_Finalize(); - } - - /** initialize MPI communication. */ - MpiCommunicator(HermesType type) { - world_comm_ = MPI_COMM_WORLD; - world_proc_id_ = GetWorldProcId(); - world_size_ = GetNumWorldProcs(); - type_ = type; - } }; } // namespace hermes diff --git a/src/constants.cc b/src/constants.cc deleted file mode 100644 index 008422a05..000000000 --- a/src/constants.cc +++ /dev/null @@ -1,13 +0,0 @@ -// -// Created by lukemartinlogan on 12/2/22. -// - -#include "constants.h" - -namespace hermes { - -const char* kHermesServerConf = "HERMES_CONF"; -const char* kHermesClientConf = "HERMES_CLIENT_CONF"; -const size_t kMaxPathLength = 4096; - -} // namespace hermes \ No newline at end of file diff --git a/src/constants.h b/src/constants.h index 83015f8af..f4ee2eb18 100644 --- a/src/constants.h +++ b/src/constants.h @@ -9,16 +9,18 @@ namespace hermes { -extern const char* kHermesServerConf; -extern const char* kHermesClientConf; -extern const size_t kMaxPathLength; +static const lipc::allocator_id_t main_alloc_id(0, 0); -const int kMaxServerNamePrefix = 32; /**< max. server name prefix */ -const int kMaxServerNamePostfix = 8; /**< max. server name suffix */ -const char kBoPrefix[] = "BO::"; /**< buffer organizer prefix */ +static const char* kHermesServerConf = "HERMES_CONF"; +static const char* kHermesClientConf = "HERMES_CLIENT_CONF"; +static const size_t kMaxPathLength = 4096; + +static const int kMaxServerNamePrefix = 32; /**< max. server name prefix */ +static const int kMaxServerNamePostfix = 8; /**< max. server name suffix */ +static const char kBoPrefix[] = "BO::"; /**< buffer organizer prefix */ /** buffer organizer prefix length */ -const int kBoPrefixLength = sizeof(kBoPrefix) - 1; +static const int kBoPrefixLength = sizeof(kBoPrefix) - 1; } diff --git a/src/rpc.h b/src/rpc.h index 74f8d76e8..e7898c657 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -13,6 +13,11 @@ #ifndef HERMES_RPC_H_ #define HERMES_RPC_H_ +#include +#include +#include +#include + #include #include @@ -20,6 +25,7 @@ #include "communication.h" #include "rpc_decorator.h" #include "config.h" +#include "utils.h" #include #include @@ -31,44 +37,42 @@ enum class RpcType { kThallium }; +struct HostInfo { + int node_id_; + std::string hostname_; + std::string ip_addr_; + + HostInfo() = default; + explicit HostInfo(const std::string &hostname, const std::string &ip_addr) + : hostname_(hostname), ip_addr_(ip_addr) {} +}; + /** A structure to represent RPC context. */ class RpcContext { public: - COMM_TYPE &comm_; - /** The hermes configuration used to initialize this RPC */ - ServerConfig &config_; - /** Array of host names stored in shared memory. This array size is - * RpcContext::num_nodes. */ - lipcl::vector host_names_; + COMM_TYPE *comm_; + /** the hermes configuration used to initialize this RPC */ + ServerConfig *config_; int port_; /**< port number */ + int node_id_; /**< the ID of this node*/ + std::vector hosts_; /**< Hostname and ip addr per-node */ public: - explicit RpcContext(COMM_TYPE &comm, ServerConfig &config, u32 num_nodes, - u32 node_id) : comm_(comm), config_(config) { - port_ = config.rpc_.port_; - switch (comm.type_) { - case HermesType::kColocated - case HermesType::kServer: { - // Load configuration from either file or config - break; - } - case HermesType::kClient: { - // Load hostnames from SHMEM - break; - } - } + explicit RpcContext(COMM_TYPE *comm, ServerConfig *config) : + comm_(comm), config_(config) { + port_ = config->rpc_.port_; } /** Check if we should skip an RPC and call a function locally */ bool ShouldDoLocalCall(int node_id) { - switch (comm_.type_) { + switch (comm_->type_) { case HermesType::kClient: { return false; } case HermesType::kServer: { - return node_id == comm_->node_id_; + return node_id == node_id_; } case HermesType::kColocated: { return true; @@ -78,34 +82,101 @@ class RpcContext { /** get RPC address */ std::string GetRpcAddress(u32 node_id, int port) { - std::string result = config_.rpc_.protocol_ + "://"; - - if (!config_.rpc_.domain_.empty()) { - result += config_.rpc_.domain_ + "/"; + std::string result = config_->rpc_.protocol_ + "://"; + if (!config_->rpc_.domain_.empty()) { + result += config_->rpc_.domain_ + "/"; } std::string host_name = GetHostNameFromNodeId(node_id); result += host_name + ":" + std::to_string(port); - return result; } + /** Get RPC address for this node */ + std::string GetMyRpcAddress() { + return GetRpcAddress(node_id_, port_); + } + + /** initialize host info list */ + void InitHostInfo() { + auto &hosts = config_->rpc_.host_names_; + // Load hosts from hostfile + if (!config_->rpc_.host_file_.empty()) { + // TODO(llogan): load host names from hostfile + } + + // Get all host info + hosts_.resize(hosts.size()); + for (const auto& name : hosts) { + hosts_.emplace_back(name, _GetIpAddress(name)); + } + + // Get id of current host + int node_id = 1; // NOTE(llogan): node_ids start from 1 (0 is NULL) + std::string my_ip = _GetMyIpAddress(); + for (const auto& host_info : hosts_) { + if (host_info.ip_addr_ == my_ip) { + node_id_ = node_id; + break; + } + ++node_id; + } + } + /** get host name from node ID */ std::string GetHostNameFromNodeId(u32 node_id) { - std::string result; // NOTE(chogan): node_id 0 is reserved as the NULL node u32 index = node_id - 1; - result = host_names_[index].str(); - return result; + return hosts_[index].hostname_; } -}; -} // namespace hermes + /** get host name from node ID */ + std::string GetIpAddressFromNodeId(u32 node_id) { + // NOTE(chogan): node_id 0 is reserved as the NULL node + u32 index = node_id - 1; + return hosts_[index].ip_addr_; + } -#if defined(HERMES_RPC_THALLIUM) -#include "rpc_thallium.h" -#define RPC_TYPE ThalliumRpc + + private: + /** Get the IPv4 address of this machine */ + std::string _GetMyIpAddress() { + return _GetIpAddress("localhost"); + } + + /** Get IPv4 address from the host with "host_name" */ + std::string _GetIpAddress(const std::string &host_name) { + struct hostent hostname_info = {}; + struct hostent *hostname_result; + int hostname_error = 0; + char hostname_buffer[4096] = {}; +#ifdef __APPLE__ + hostname_result = gethostbyname(host_name.c_str()); + in_addr **addr_list = (struct in_addr **)hostname_result->h_addr_list; #else -#error "RPC implementation required (e.g., -DHERMES_RPC_THALLIUM)." + int gethostbyname_result = + gethostbyname_r(host_name.c_str(), &hostname_info, hostname_buffer, + 4096, &hostname_result, &hostname_error); + if (gethostbyname_result != 0) { + LOG(FATAL) << hstrerror(h_errno); + } + in_addr **addr_list = (struct in_addr **)hostname_info.h_addr_list; #endif + if (!addr_list[0]) { + LOG(FATAL) << hstrerror(h_errno); + } + + char ip_address[INET_ADDRSTRLEN]; + const char *inet_result = + inet_ntop(AF_INET, addr_list[0], ip_address, INET_ADDRSTRLEN); + if (!inet_result) { + FailedLibraryCall("inet_ntop"); + } + return ip_address; + } +}; + +} // namespace hermes + +#include "rpc_factory.h" #endif // HERMES_RPC_H_ diff --git a/src/rpc_factory.h.in b/src/rpc_factory.h.in new file mode 100644 index 000000000..9f848ba47 --- /dev/null +++ b/src/rpc_factory.h.in @@ -0,0 +1,17 @@ +// +// Created by lukemartinlogan on 12/4/22. +// + +#ifndef HERMES_SRC_RPC_FACTORY_H_ +#define HERMES_SRC_RPC_FACTORY_H_ + +#define @CMAKE_HERMES_RPC_TYPE@ + +#if defined(HERMES_RPC_THALLIUM) +#include "rpc_thallium.h" +#define RPC_TYPE ThalliumRpc +#else +#error "RPC implementation required (e.g., -DHERMES_RPC_THALLIUM)." +#endif + +#endif // HERMES_SRC_RPC_FACTORY_H_ diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 5d43c6608..6c77d476c 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -21,15 +21,20 @@ namespace hermes { /** start Thallium RPC server */ void ThalliumRpc::InitServer() { - // Load the host names - + std::string addr = GetMyRpcAddress(); + server_engine_ = tl::engine(addr, + THALLIUM_SERVER_MODE, + true, + config_->rpc_.num_threads_); + std::string rpc_server_name = server_engine_.self(); + LOG(INFO) << "Serving at " << rpc_server_name << " with " + << config_->rpc_.num_threads_ << " RPC threads" << std::endl; DefineRpcs(); } /** initialize RPC clients */ -void ThalliumRpc::InitClients() { +void ThalliumRpc::InitClient() { std::string protocol = GetProtocol(); - // TODO(chogan): This should go in a per-client persistent arena client_engine_ = tl::engine(protocol, THALLIUM_CLIENT_MODE, true, 1); @@ -40,55 +45,20 @@ void ThalliumRpc::Finalize() { } /** run daemon */ -void ThalliumRpc::RunDaemon(const char *shmem_name) { +void ThalliumRpc::RunDaemon() { } /** get server name */ std::string ThalliumRpc::GetServerName(u32 node_id) { - std::string host_name = GetHostNameFromNodeId(node_id); - // TODO(chogan): @optimization Could cache the last N hostname->IP mappings to - // avoid excessive syscalls. Should profile first. - struct hostent hostname_info = {}; - struct hostent *hostname_result; - int hostname_error = 0; - char hostname_buffer[4096] = {}; -#ifdef __APPLE__ - hostname_result = gethostbyname(host_name.c_str()); - in_addr **addr_list = (struct in_addr **)hostname_result->h_addr_list; -#else - int gethostbyname_result = gethostbyname_r(host_name.c_str(), &hostname_info, - hostname_buffer, 4096, - &hostname_result, &hostname_error); - if (gethostbyname_result != 0) { - LOG(FATAL) << hstrerror(h_errno); - } - in_addr **addr_list = (struct in_addr **)hostname_info.h_addr_list; -#endif - if (!addr_list[0]) { - LOG(FATAL) << hstrerror(h_errno); - } - - char ip_address[INET_ADDRSTRLEN]; - const char *inet_result = inet_ntop(AF_INET, - addr_list[0], - ip_address, - INET_ADDRSTRLEN); - if (!inet_result) { - FailedLibraryCall("inet_ntop"); - } - - result = config_.prefix_ std::string(ip_address); - - return result; + std::string ip_address = GetIpAddressFromNodeId(node_id); + return config_->rpc_.protocol_ + "://" + + std::string(ip_address) + + ":" + std::to_string(config_->rpc_.port_); } /** Get protocol */ std::string ThalliumRpc::GetProtocol() { - std::string prefix = std::string(server_name_prefix); - // NOTE(chogan): Chop "://" off the end of the server_name_prefix to get the - // protocol - std::string result = prefix.substr(0, prefix.length() - 3); - return result; + return config_->rpc_.protocol_; } } // namespace hermes \ No newline at end of file diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index 708e43ece..2bf9d1fd6 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -13,11 +13,6 @@ #ifndef HERMES_RPC_THALLIUM_H_ #define HERMES_RPC_THALLIUM_H_ -#include -#include -#include -#include - #include #include "rpc_thallium_serialization.h" #include "communication.h" @@ -43,15 +38,14 @@ class ThalliumRpc : public RpcContext { tl::engine io_engine_; /**< pointer to engine */ /** initialize RPC context */ - explicit ThalliumRpc(COMM_TYPE *comm, u32 num_nodes, u32 node_id, - ServerConfig &config) - : RpcContext(comm, num_nodes, node_id, config) {} + explicit ThalliumRpc(COMM_TYPE *comm, ServerConfig *config) + : RpcContext(comm, config) {} /** Get protocol */ - void InitClients(); + void InitClient(); void InitServer(); void Finalize(); - void RunDaemon(const char *shmem_name); + void RunDaemon(); std::string GetServerName(u32 node_id); std::string GetProtocol(); @@ -97,7 +91,8 @@ class ThalliumRpc : public RpcContext { segments[0].second = size; tl::bulk bulk = io_engine_.expose(segments, flag); - size_t result = remote_proc.on(server)(bulk, id); + // size_t result = remote_proc.on(server)(bulk, id); + size_t result = remote_proc.on(server)(bulk); return result; } diff --git a/src/utils.h b/src/utils.h index 04c9da8e3..702de8e01 100644 --- a/src/utils.h +++ b/src/utils.h @@ -20,8 +20,12 @@ #include "hermes_types.h" +namespace hermes { + size_t RoundUpToMultiple(size_t val, size_t multiple); size_t RoundDownToMultiple(size_t val, size_t multiple); void FailedLibraryCall(std::string func); +} // namespace hermes + #endif // HERMES_UTILS_H_ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index af6bacfcf..bc90c2948 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,155 +11,15 @@ include_directories( #------------------------------------------------------------------------------ # API tests #------------------------------------------------------------------------------ -set(API_TESTS dpe_optimization_test dpe_random_test - dpe_roundrobin_test end_to_end_test vbucket_test) +set(API_TESTS test_rpc) foreach(program ${API_TESTS}) add_executable(${program} ${program}.cc) target_link_libraries(${program} ${LIBRT} hermes MPI::MPI_CXX $<$:thallium> glog::glog) - target_compile_definitions(${program} - PRIVATE $<$:HERMES_RPC_THALLIUM>) add_test(NAME "Test${program}" COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2 "${CMAKE_BINARY_DIR}/bin/${program}") set_tests_properties("Test${program}" PROPERTIES ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_SOURCE_DIR}/data/asan.supp) -endforeach() - -#------------------------------------------------------------------------------ -# Bucket test -#------------------------------------------------------------------------------ -find_package(ZLIB) -if(ZLIB_FOUND) - message(STATUS "found zlib") -endif() - -add_executable(bucket_test bucket_test.cc) -target_link_libraries(bucket_test ${LIBRT} hermes MPI::MPI_CXX ZLIB::ZLIB - $<$:thallium> glog::glog) -target_compile_definitions(bucket_test - PRIVATE $<$:HERMES_RPC_THALLIUM>) -add_test(NAME "Testbucket_test" - COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2 - "${CMAKE_BINARY_DIR}/bin/bucket_test" - "${CMAKE_CURRENT_SOURCE_DIR}/data/bucket_test.yaml") -set_tests_properties("Testbucket_test" PROPERTIES ENVIRONMENT - LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_SOURCE_DIR}/data/asan.supp) - -#------------------------------------------------------------------------------ -# POSIX GOTCHA test -#------------------------------------------------------------------------------ -if(HERMES_HAVE_GOTCHA) - add_executable(stdio_test stdio_test.c) - target_link_libraries(stdio_test hermes) - add_executable(mpi_test mpi_test.c) - target_link_libraries(mpi_test hermes MPI::MPI_CXX) -endif() - -#------------------------------------------------------------------------------ -# BufferPool tests -#------------------------------------------------------------------------------ -add_executable(bp buffer_pool_test.cc) -target_link_libraries(bp ${LIBRT} hermes MPI::MPI_CXX - $<$:thallium> glog::glog) -target_compile_definitions(bp - PRIVATE $<$:HERMES_RPC_THALLIUM>) -add_test(NAME "TestBufferPool" COMMAND "${CMAKE_BINARY_DIR}/bin/bp") -set_tests_properties("TestBufferPool" PROPERTIES ENVIRONMENT - LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_SOURCE_DIR}/data/asan.supp) - -add_executable(bp_test buffer_pool_client_test.cc) -target_link_libraries(bp_test hermes MPI::MPI_CXX - $<$:thallium> glog::glog) -target_compile_definitions(bp_test - PRIVATE $<$:HERMES_RPC_THALLIUM>) - -#------------------------------------------------------------------------------ -# Config Parser tests -#------------------------------------------------------------------------------ -add_executable(config_parser_test config_parser_test.cc) -target_link_libraries(config_parser_test hermes - $<$:thallium> glog::glog) - -add_test(NAME TestConfigParser - COMMAND config_parser_test ${CMAKE_CURRENT_SOURCE_DIR}/data/hermes_server.yaml) -target_compile_definitions(config_parser_test - PRIVATE $<$:HERMES_RPC_THALLIUM>) - -#------------------------------------------------------------------------------ -# Memory Management tests -#------------------------------------------------------------------------------ -add_executable(mem memory_test.cc) -target_link_libraries(mem hermes $<$:thallium> glog::glog) -add_test(NAME TestMemoryManagement COMMAND mem) -target_compile_definitions(mem - PRIVATE $<$:HERMES_RPC_THALLIUM>) - -#------------------------------------------------------------------------------ -# Metadata Manager tests -#------------------------------------------------------------------------------ -add_executable(mdm mdm_test.cc) -target_link_libraries(mdm hermes ${LIBRT} - $<$:thallium> MPI::MPI_CXX glog::glog) -target_compile_definitions(mdm - PRIVATE $<$:HERMES_RPC_THALLIUM>) -add_test(NAME TestMDM COMMAND mdm) -set_tests_properties("TestMDM" PROPERTIES ENVIRONMENT - LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_SOURCE_DIR}/data/asan.supp) - -#------------------------------------------------------------------------------ -# Trait tests -#------------------------------------------------------------------------------ -add_executable(trait trait_test.cc) -target_link_libraries(trait ${LIBRT} hermes MPI::MPI_CXX -$<$:thallium> Catch2::Catch2 glog::glog -lstdc++fs) -target_compile_definitions(trait -PRIVATE $<$:HERMES_RPC_THALLIUM>) -add_test(NAME "TestTrait" COMMAND "${CMAKE_BINARY_DIR}/bin/trait" "-s" "--reporter" "compact" - "--config" "${CMAKE_CURRENT_SOURCE_DIR}/data/bucket_test.yaml") -set_tests_properties("TestTrait" PROPERTIES ENVIRONMENT -LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_SOURCE_DIR}/data/asan.supp) - -#------------------------------------------------------------------------------ -# BufferOrganizer tests -#------------------------------------------------------------------------------ -add_executable(bo buffer_organizer_test.cc) -target_link_libraries(bo ${LIBRT} hermes MPI::MPI_CXX - $<$:thallium> glog::glog) -target_compile_definitions(bo - PRIVATE $<$:HERMES_RPC_THALLIUM>) -add_test(NAME TestBufferOrganizer COMMAND bo) -set_tests_properties("TestBufferOrganizer" PROPERTIES ENVIRONMENT - LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_SOURCE_DIR}/data/asan.supp) - -#------------------------------------------------------------------------------ -# Custom Targets -#------------------------------------------------------------------------------ -add_custom_target(ares - COMMAND LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_SOURCE_DIR}/data/asan.supp - ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 4 -ppn 2 - "${CMAKE_BINARY_DIR}/bin/end_to_end_test" - "${CMAKE_CURRENT_SOURCE_DIR}/data/ares.yaml" -) -if(HERMES_INSTALL_TESTS) - set(TEST_EXECS dpe_optimization_test dpe_random_test - dpe_roundrobin_test end_to_end_test - bucket_test bp bp_test config_parser_test stb_map mdm trait) - foreach(program ${TEST_EXECS}) - install( - TARGETS - ${program} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} - ) - endforeach() -endif() - -include_directories(${CMAKE_SOURCE_DIR}/adapter) -add_executable(prefetch_test prefetch_test.cc) -target_compile_definitions(prefetch_test - PRIVATE $<$:HERMES_RPC_THALLIUM>) -add_dependencies(prefetch_test hermes) -target_link_libraries(prefetch_test hermes MPI::MPI_CXX glog::glog) \ No newline at end of file +endforeach() \ No newline at end of file diff --git a/test/test_rpc.cc b/test/test_rpc.cc index c79ce1fe6..be64b3f14 100644 --- a/test/test_rpc.cc +++ b/test/test_rpc.cc @@ -1,6 +1,28 @@ -// -// Created by lukemartinlogan on 12/2/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -int main() { +#include +#include + +#include +#include +#include "hermes.h" + +namespace hapi = hermes::api; + +int main(int argc, char* argv[]) { + MPI_Init(&argc, &argv); + auto hermes = hapi::Hermes(hermes::HermesType::kClient); + hermes.Finalize(); + MPI_Finalize(); + return 0; } \ No newline at end of file diff --git a/wrapper/CMakeLists.txt b/wrapper/CMakeLists.txt index f5e3eca89..ccd2df186 100644 --- a/wrapper/CMakeLists.txt +++ b/wrapper/CMakeLists.txt @@ -12,8 +12,6 @@ include_directories( #------------------------------------------------------------------------------ add_library(hermes_wrapper hermes_wrapper.cpp) target_link_libraries(hermes_wrapper ${LIBRT} hermes) -target_compile_definitions(hermes_wrapper - PRIVATE $<$:HERMES_RPC_THALLIUM>) set(HERMES_EXPORTED_LIBS hermes_wrapper ${HERMES_EXPORTED_LIBS}) From 1f98ca86e5b5ac4f0cbe2505581e28cb0ecde5d3 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 4 Dec 2022 06:12:48 -0600 Subject: [PATCH 046/511] Add finalize for RPC server --- src/api/hermes.cc | 44 ++++++++++++++++++++++++++------ src/api/hermes.h | 4 +-- src/hermes_daemon.cc | 3 +-- src/rpc.h | 61 ++++++++++++++++++++++++-------------------- src/rpc_thallium.cc | 23 +++++++++++++++++ src/rpc_thallium.h | 6 ++--- 6 files changed, 98 insertions(+), 43 deletions(-) diff --git a/src/api/hermes.cc b/src/api/hermes.cc index ef77bae96..f5e268512 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -18,9 +18,9 @@ void Hermes::Init(HermesType mode, std::string server_config_path, std::string client_config_path) { mode_ = mode; - switch (mode) { + switch (mode_) { case HermesType::kServer: { - InitDaemon(std::move(server_config_path)); + InitServer(std::move(server_config_path)); break; } case HermesType::kClient: { @@ -35,13 +35,32 @@ void Hermes::Init(HermesType mode, } } -void Hermes::Finalize() {} +void Hermes::Finalize() { + switch (mode_) { + case HermesType::kServer: { + FinalizeServer(); + break; + } + case HermesType::kClient: { + FinalizeClient(); + break; + } + case HermesType::kColocated: { + FinalizeColocated(); + break; + } + } +} -void Hermes::RunDaemon() {} +void Hermes::RunDaemon() { + rpc_.RunDaemon(); +} -void Hermes::InitDaemon(std::string server_config_path) { +void Hermes::InitServer(std::string server_config_path) { LoadServerConfig(server_config_path); InitSharedMemory(); + rpc_.InitServer(); + rpc_.InitClient(); } void Hermes::InitColocated(std::string server_config_path, @@ -49,11 +68,13 @@ void Hermes::InitColocated(std::string server_config_path, LoadServerConfig(server_config_path); LoadClientConfig(client_config_path); InitSharedMemory(); + rpc_.InitClient(); } void Hermes::InitClient(std::string client_config_path) { LoadClientConfig(client_config_path); LoadSharedMemory(); + rpc_.InitClient(); } void Hermes::LoadServerConfig(std::string config_path) { @@ -89,10 +110,17 @@ void Hermes::LoadSharedMemory() { main_alloc_ = mem_mngr->GetAllocator(main_alloc_id); } -void Hermes::FinalizeDaemon() {} +void Hermes::FinalizeServer() { + rpc_.Finalize(); + LABSTOR_MEMORY_MANAGER->DestroyBackend(server_config_.shmem_name_); +} -void Hermes::FinalizeClient() {} +void Hermes::FinalizeClient() { + rpc_.Finalize(); +} -void Hermes::FinalizeColocated() {} +void Hermes::FinalizeColocated() { + rpc_.Finalize(); +} } // namespace hermes::api \ No newline at end of file diff --git a/src/api/hermes.h b/src/api/hermes.h index 00f55f871..d1f3a974b 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -36,7 +36,7 @@ class Hermes { void RunDaemon(); private: - void InitDaemon(std::string server_config_path); + void InitServer(std::string server_config_path); void InitColocated(std::string server_config_path, std::string client_config_path); @@ -51,7 +51,7 @@ class Hermes { void LoadSharedMemory(); - void FinalizeDaemon(); + void FinalizeServer(); void FinalizeClient(); diff --git a/src/hermes_daemon.cc b/src/hermes_daemon.cc index 337fbea79..7967c6090 100644 --- a/src/hermes_daemon.cc +++ b/src/hermes_daemon.cc @@ -29,8 +29,7 @@ int main(int argc, char* argv[]) { auto hermes = hapi::Hermes(hermes::HermesType::kServer, hermes_config); hermes.RunDaemon(); - + hermes.Finalize(); MPI_Finalize(); - return 0; } diff --git a/src/rpc.h b/src/rpc.h index e7898c657..622a8e994 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -60,11 +60,38 @@ class RpcContext { std::vector hosts_; /**< Hostname and ip addr per-node */ public: - explicit RpcContext(COMM_TYPE *comm, ServerConfig *config) : - comm_(comm), config_(config) { + explicit RpcContext(COMM_TYPE *comm, ServerConfig *config) + : comm_(comm), config_(config) { port_ = config->rpc_.port_; } + /** initialize host info list */ + void InitHostInfo() { + if (hosts_.size()) { return; } + auto &hosts = config_->rpc_.host_names_; + // Load hosts from hostfile + if (!config_->rpc_.host_file_.empty()) { + // TODO(llogan): load host names from hostfile + } + + // Get all host info + hosts_.resize(hosts.size()); + for (const auto& name : hosts) { + hosts_.emplace_back(name, _GetIpAddress(name)); + } + + // Get id of current host + int node_id = 1; // NOTE(llogan): node_ids start from 1 (0 is NULL) + std::string my_ip = _GetMyIpAddress(); + for (const auto& host_info : hosts_) { + if (host_info.ip_addr_ == my_ip) { + node_id_ = node_id; + break; + } + ++node_id; + } + } + /** Check if we should skip an RPC and call a function locally */ bool ShouldDoLocalCall(int node_id) { switch (comm_->type_) { @@ -96,32 +123,6 @@ class RpcContext { return GetRpcAddress(node_id_, port_); } - /** initialize host info list */ - void InitHostInfo() { - auto &hosts = config_->rpc_.host_names_; - // Load hosts from hostfile - if (!config_->rpc_.host_file_.empty()) { - // TODO(llogan): load host names from hostfile - } - - // Get all host info - hosts_.resize(hosts.size()); - for (const auto& name : hosts) { - hosts_.emplace_back(name, _GetIpAddress(name)); - } - - // Get id of current host - int node_id = 1; // NOTE(llogan): node_ids start from 1 (0 is NULL) - std::string my_ip = _GetMyIpAddress(); - for (const auto& host_info : hosts_) { - if (host_info.ip_addr_ == my_ip) { - node_id_ = node_id; - break; - } - ++node_id; - } - } - /** get host name from node ID */ std::string GetHostNameFromNodeId(u32 node_id) { // NOTE(chogan): node_id 0 is reserved as the NULL node @@ -173,6 +174,10 @@ class RpcContext { } return ip_address; } + + public: + virtual void InitServer() = 0; + virtual void InitClient() = 0; }; } // namespace hermes diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 6c77d476c..0011623ba 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -21,6 +21,7 @@ namespace hermes { /** start Thallium RPC server */ void ThalliumRpc::InitServer() { + InitHostInfo(); std::string addr = GetMyRpcAddress(); server_engine_ = tl::engine(addr, THALLIUM_SERVER_MODE, @@ -34,6 +35,7 @@ void ThalliumRpc::InitServer() { /** initialize RPC clients */ void ThalliumRpc::InitClient() { + InitHostInfo(); std::string protocol = GetProtocol(); client_engine_ = tl::engine(protocol, THALLIUM_CLIENT_MODE, @@ -42,10 +44,31 @@ void ThalliumRpc::InitClient() { /** finalize RPC context */ void ThalliumRpc::Finalize() { + switch (comm_->type_) { + case HermesType::kServer: { + comm_->WorldBarrier(); + server_engine_.finalize(); + client_engine_.finalize(); + } + case HermesType::kClient: { + std::string server_name = GetServerName(node_id_); + tl::endpoint server = client_engine_.lookup(server_name); + client_engine_.shutdown_remote_engine(server); + client_engine_.finalize(); + } + case HermesType::kColocated: { + } + } } /** run daemon */ void ThalliumRpc::RunDaemon() { + server_engine_.enable_remote_shutdown(); + auto prefinalize_callback = [this]() { + this->comm_->WorldBarrier(); + }; + server_engine_.push_prefinalize_callback(prefinalize_callback); + server_engine_.wait_for_finalize(); } /** get server name */ diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index 2bf9d1fd6..f6cbb7734 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -41,9 +41,8 @@ class ThalliumRpc : public RpcContext { explicit ThalliumRpc(COMM_TYPE *comm, ServerConfig *config) : RpcContext(comm, config) {} - /** Get protocol */ - void InitClient(); - void InitServer(); + void InitClient() override; + void InitServer() override; void Finalize(); void RunDaemon(); std::string GetServerName(u32 node_id); @@ -66,6 +65,7 @@ class ThalliumRpc : public RpcContext { } } + /** I/O transfers */ size_t IoCall(u32 node_id, IoType type, u8 *data, TargetID id, size_t off, size_t size) { std::string server_name = GetServerName(node_id); From 1b455becf6a7310a6b931ae49fa23d28fcb50558 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 4 Dec 2022 08:17:50 -0600 Subject: [PATCH 047/511] RPC test passes, but client fails to de-initialize margo --- code_generators/hermes_config_gen/generate.py | 51 ++++ config/default_config_gen/generate.py | 53 ---- config/hermes_server_default.yaml | 6 +- src/CMakeLists.txt | 2 +- src/api/hermes.cc | 20 +- src/api/hermes.h | 3 +- src/{ => api}/hermes_daemon.cc | 0 src/config_client_default.h | 4 +- src/config_server.cc | 40 +-- src/config_server_default.h | 280 +++++++++--------- src/rpc.h | 6 +- src/rpc_thallium.cc | 13 +- src/rpc_thallium.h | 3 +- 13 files changed, 251 insertions(+), 230 deletions(-) create mode 100644 code_generators/hermes_config_gen/generate.py delete mode 100644 config/default_config_gen/generate.py rename src/{ => api}/hermes_daemon.cc (100%) diff --git a/code_generators/hermes_config_gen/generate.py b/code_generators/hermes_config_gen/generate.py new file mode 100644 index 000000000..3d4a9fff5 --- /dev/null +++ b/code_generators/hermes_config_gen/generate.py @@ -0,0 +1,51 @@ +""" +USAGE: + cd /path/to/hermes_config_gen + python3 generate.py + +OUTPUT: + ../../config_client_default.h (if client) + ../../config_server_default.h (if server) +""" + +import sys, os + +def create_config(path, var_name, config_path, macro_name): + with open(path) as fp: + yaml_config_lines = fp.read().splitlines() + + # Create the hermes config string + string_lines = [] + string_lines.append(f"const char* {var_name} = ") + for line in yaml_config_lines: + line = line.replace('\"', '\\\"') + line = line.replace('\'', '\\\'') + string_lines.append(f"\"{line}\\n\"") + string_lines[-1] = string_lines[-1] + ';' + + # Create the configuration + config_lines = [] + config_lines.append(f"#ifndef HERMES_SRC_CONFIG_{macro_name}_DEFAULT_H_") + config_lines.append(f"#define HERMES_SRC_CONFIG_{macro_name}_DEFAULT_H_") + config_lines += string_lines + config_lines.append(f"#endif // HERMES_SRC_CONFIG_{macro_name}_DEFAULT_H_") + + # Persist + config = "\n".join(config_lines) + with open(config_path, 'w') as fp: + fp.write(config) + +create_config( + path="../../config/hermes_client_default.yaml", + var_name="kClientDefaultConfigStr", + config_path="../../src/config_client_default.h", + macro_name="CLIENT" +) + +create_config( + path="../../config/hermes_server_default.yaml", + var_name="kServerDefaultConfigStr", + config_path="../../src/config_server_default.h", + macro_name="SERVER" +) + diff --git a/config/default_config_gen/generate.py b/config/default_config_gen/generate.py deleted file mode 100644 index 10fcd17d5..000000000 --- a/config/default_config_gen/generate.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -USAGE: - cd /path/to/default_config_gen - ./config_gen [client/server] - -OUTPUT: - ../../config_client_default.h (if client) - ../../config_server_default.h (if server) -""" - -import sys, os - -if len(sys.argv) != 2: - print("USAGE: ./config_gen [client/server]") - exit(1) - -config_type = sys.argv[1] -if config_type == 'client': - path = "../hermes_client_default.yaml" - var_name = "kClientDefaultConfigStr" - config_path = "../../src/config_client_default.h" - macro_name = "CLIENT" -elif config_type == 'server': - path = "../hermes_server_default.yaml" - var_name = "kServerDefaultConfigStr" - config_path = "../../src/config_server_default.h" - macro_name = "SERVER" -else: - print(f"{config_type} is not either \"client\" or \"server\"") - exit(1) - -with open(path) as fp: - yaml_config_lines = fp.read().splitlines() - -# Create the hermes config string -string_lines = [] -string_lines.append(f"const char* {var_name} = ") -for line in yaml_config_lines: - line = line.replace('\"', '\\\"') - line = line.replace('\'', '\\\'') - string_lines.append(f"\"{line}\"") -string_lines[-1] = string_lines[-1] + ';' -final_string = "\n".join(string_lines) - -# Create the configuration -config_lines = [] -config_lines.append(f"#ifndef HERMES_SRC_CONFIG_{macro_name}_DEFAULT_H_") -config_lines.append(f"#define HERMES_SRC_CONFIG_{macro_name}_DEFAULT_H_") -config_lines.append(final_string) -config_lines.append(f"#endif // HERMES_SRC_CONFIG_{macro_name}_DEFAULT_H_") -config = "\n".join(config_lines) -with open(config_path, 'w') as fp: - fp.write(config) \ No newline at end of file diff --git a/config/hermes_server_default.yaml b/config/hermes_server_default.yaml index 0b3b395c3..6ecd2975e 100644 --- a/config/hermes_server_default.yaml +++ b/config/hermes_server_default.yaml @@ -104,9 +104,6 @@ rpc: # Desired RPC port number. port: 8080 - # Desired RPC port number for buffer organizer. - buffer_organizer_port: 8081 - # The number of handler threads for each RPC server. num_threads: 1 @@ -115,6 +112,9 @@ buffer_organizer: # The number of threads used in the background organization of internal Hermes buffers. num_threads: 4 + # Desired RPC port number for buffer organizer. + port: 8081 + ### Define the default data placement policy dpe: # Choose Random, RoundRobin, or MinimizeIoTime diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 224b5a90c..9fc8d97b3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,7 +103,7 @@ set(HERMES_EXPORTED_LIBS hermes ${HERMES_EXPORTED_LIBS}) # HERMES DAEMON find_package(Catch2 REQUIRED) -add_executable(hermes_daemon hermes_daemon.cc) +add_executable(hermes_daemon api/hermes_daemon.cc) add_dependencies(hermes_daemon hermes) target_link_libraries(hermes_daemon hermes -ldl -lc MPI::MPI_CXX glog::glog) target_compile_definitions(hermes_daemon diff --git a/src/api/hermes.cc b/src/api/hermes.cc index f5e268512..549050846 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -24,7 +24,8 @@ void Hermes::Init(HermesType mode, break; } case HermesType::kClient: { - InitClient(std::move(client_config_path)); + InitClient(std::move(server_config_path), + std::move(client_config_path)); break; } case HermesType::kColocated: { @@ -63,18 +64,20 @@ void Hermes::InitServer(std::string server_config_path) { rpc_.InitClient(); } -void Hermes::InitColocated(std::string server_config_path, - std::string client_config_path) { +void Hermes::InitClient(std::string server_config_path, + std::string client_config_path) { LoadServerConfig(server_config_path); LoadClientConfig(client_config_path); - InitSharedMemory(); + LoadSharedMemory(); rpc_.InitClient(); } -void Hermes::InitClient(std::string client_config_path) { +void Hermes::InitColocated(std::string server_config_path, + std::string client_config_path) { + LoadServerConfig(server_config_path); LoadClientConfig(client_config_path); - LoadSharedMemory(); - rpc_.InitClient(); + InitSharedMemory(); + rpc_.InitColocated(); } void Hermes::LoadServerConfig(std::string config_path) { @@ -104,9 +107,8 @@ void Hermes::InitSharedMemory() { void Hermes::LoadSharedMemory() { // Load shared-memory allocator auto mem_mngr = LABSTOR_MEMORY_MANAGER; - mem_mngr->CreateBackend(lipc::MemoryBackendType::kPosixShmMmap, + mem_mngr->AttachBackend(lipc::MemoryBackendType::kPosixShmMmap, server_config_.shmem_name_); - mem_mngr->ScanBackends(); main_alloc_ = mem_mngr->GetAllocator(main_alloc_id); } diff --git a/src/api/hermes.h b/src/api/hermes.h index d1f3a974b..4d00efe1c 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -41,7 +41,8 @@ class Hermes { void InitColocated(std::string server_config_path, std::string client_config_path); - void InitClient(std::string client_config_path); + void InitClient(std::string server_config_path, + std::string client_config_path); void LoadServerConfig(std::string config_path); diff --git a/src/hermes_daemon.cc b/src/api/hermes_daemon.cc similarity index 100% rename from src/hermes_daemon.cc rename to src/api/hermes_daemon.cc diff --git a/src/config_client_default.h b/src/config_client_default.h index 5787a7e89..d339335ba 100644 --- a/src/config_client_default.h +++ b/src/config_client_default.h @@ -1,6 +1,6 @@ #ifndef HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ #define HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ const char* kClientDefaultConfigStr = -"stop_daemon: true" -"file_page_size_kb: 1024"; +"stop_daemon: true\n" +"file_page_size_kb: 1024\n"; #endif // HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ \ No newline at end of file diff --git a/src/config_server.cc b/src/config_server.cc index 05f2fdf82..3db7b117b 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -43,15 +43,6 @@ void ServerConfig::ParseRpcInfo(YAML::Node yaml_conf) { std::string suffix; std::vector host_numbers; - if (yaml_conf["domain"]) { - rpc_.domain_ = yaml_conf["domain"].as(); - } - if (yaml_conf["protocol"]) { - rpc_.protocol_ = yaml_conf["protocol"].as(); - } - if (yaml_conf["num_threads"]) { - rpc_.num_threads_ = yaml_conf["num_threads"].as(); - } if (yaml_conf["host_file"]) { rpc_.host_file_ = yaml_conf["host_file"].as(); @@ -66,6 +57,18 @@ void ServerConfig::ParseRpcInfo(YAML::Node yaml_conf) { ParseRangeList(yaml_conf["rpc_host_number_range"], "rpc_host_number_range", host_numbers); } + if (yaml_conf["domain"]) { + rpc_.domain_ = yaml_conf["domain"].as(); + } + if (yaml_conf["protocol"]) { + rpc_.protocol_ = yaml_conf["protocol"].as(); + } + if (yaml_conf["port"]) { + rpc_.port_ = yaml_conf["port"].as(); + } + if (yaml_conf["num_threads"]) { + rpc_.num_threads_ = yaml_conf["num_threads"].as(); + } // Remove all default host names if (rpc_.host_file_.size() > 0 || base_name.size() > 0) { @@ -93,35 +96,34 @@ void ServerConfig::ParseDpeInfo(YAML::Node yaml_conf) { /** parse buffer organizer information from YAML config */ void ServerConfig::ParseBorgInfo(YAML::Node yaml_conf) { - borg_.port_ = yaml_conf["port"].as(); - borg_.num_threads_ = yaml_conf["num_threads"].as(); + if (yaml_conf["port"]) { + borg_.port_ = yaml_conf["port"].as(); + } + if (yaml_conf["num_threads"]) { + borg_.num_threads_ = yaml_conf["num_threads"].as(); + } } /** parse the YAML node */ void ServerConfig::ParseYAML(YAML::Node &yaml_conf) { - bool capcities_specified = false, block_sizes_specified = false; - std::vector host_numbers; - std::vector host_basename; - std::string host_suffix; - if (yaml_conf["devices"]) { ParseDeviceInfo(yaml_conf["devices"]); } if (yaml_conf["rpc"]) { + ParseRpcInfo(yaml_conf["rpc"]); } if (yaml_conf["dpe"]) { ParseDpeInfo(yaml_conf["dpe"]); } if (yaml_conf["buffer_organizer"]) { - auto borg_yaml = yaml_conf["buffer_organizer"]; - + ParseBorgInfo(yaml_conf["buffer_organizer"]); } if (yaml_conf["system_view_state_update_interval_ms"]) { system_view_state_update_interval_ms = yaml_conf["system_view_state_update_interval_ms"].as(); } if (yaml_conf["shmem_name"]) { - std::string name = yaml_conf["shmem_name"].as(); + shmem_name_ = yaml_conf["shmem_name"].as(); } if (yaml_conf["path_exclusions"]) { diff --git a/src/config_server_default.h b/src/config_server_default.h index 0902288ce..e85d88b00 100644 --- a/src/config_server_default.h +++ b/src/config_server_default.h @@ -1,140 +1,148 @@ #ifndef HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ #define HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ const char* kServerDefaultConfigStr = -"# Example Hermes configuration file" -"" -"### Define properties of the storage devices" -"devices:" -" # The name of the device." -" # It can be whatever the user wants, there are no special names" -" ram:" -" # The mount point of each device. RAM should be the empty string. For block" -" # devices, this is the directory where Hermes will create buffering files. For" -" # object storage or cloud targets, this will be a url." -" mount_point: \"\"" -"" -" # The maximum buffering capacity in MiB of each device. Here we say that all 4" -" # devices get 50 MiB of buffering capacity." -" capacity_mb: 50" -"" -" # The size of the smallest available buffer in KiB. In general this should be" -" # the page size of your system for byte addressable storage, and the block size" -" # of the storage device for block addressable storage." -" block_size_kb: 4" -"" -" # The number of blocks (the size of which is chosen in block_sizes_kb) that each" -" # device should contain for each slab (controlled by num_slabs). This allows for" -" # precise control of the distibution of buffer sizes." -" slab_units: [1, 4, 16, 32]" -"" -" # The maximum theoretical bandwidth (as advertised by the manufacturer) in" -" # MiB/sec. of each device." -" bandwidth_mbps: 6000" -"" -" # The latency in microseconds of each device (as advertised by the manufacturer)." -" latencies_us: 15" -"" -" # For each device, indicate \'1\' if it is shared among nodes (e.g., burst" -" # buffers), or \'0\' if it is per node (e.g., local NVMe)." -" is_shared_device: 0" -"" -" nvme:" -" mount_point: \"./\"" -" capacity_mb: 50" -" block_size_kb: 4" -" slab_units: [1, 4, 16, 32]" -" is_shared_device: 0" -"" -" ssd:" -" mount_point: \"./\"" -" capacity_mb: 50" -" block_size_kb: 4" -" slab_units: [ 1, 4, 16, 32 ]" -" is_shared_device: 0" -"" -" pfs:" -" mount_point: \"./\"" -" capacity_mb: inf" -" block_size_kb: 64 # Assume 64KB strip size" -" slab_units: [1, 4, 16, 32]" -"" -"### Define the network communication protocol" -"rpc:" -" # A path to a file containing a list of server names, 1 per line. If your" -" # servers are named according to a pattern (e.g., server-1, server-2, etc.)," -" # prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this" -" # option is not empty, it will override anything in `rpc_server_base_name`." -" host_file: \"\"" -"" -" # Host names are constructed as \"base_name +" -" # host_number + rpc_server_suffix.\" Each entry in the rpc_host_number_range_list" -" # can be either a single number, or a range, which is 2 numbers separated by a" -" # hyphen (-). For example the list {01, 03-05, 07, 08-10} will be expanded to" -" # {01, 03, 04, 05, 07, 08, 09, 10}." -" server_base_name: \"localhost\"" -" server_host_number_range: []" -" server_suffix: \"\"" -"" -" # The RPC protocol. This must come from the documentation of the specific RPC" -" # library in use." -" protocol: \"ofi+sockets\"" -"" -" # RPC domain name for verbs transport. Blank for tcp." -" domain: \"\"" -"" -" # Desired RPC port number." -" port: 8080" -"" -" # Desired RPC port number for buffer organizer." -" buffer_organizer_port: 8081" -"" -" # The number of handler threads for each RPC server." -" num_threads: 1" -"" -"### Define properties of the BORG" -"buffer_organizer:" -" # The number of threads used in the background organization of internal Hermes buffers." -" num_threads: 4" -"" -" # For each device, the minimum and maximum percent capacity threshold at which" -" # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause" -" # the BufferOrganizer to move data to lower devices, making more room in faster" -" # devices (ideal for write-heavy workloads). Conversely, increasing the minimum" -" # threshold will cause data to be moved from slower devices into faster devices" -" # (ideal for read-heavy workloads). For example, a maximum capacity threshold of" -" # 0.8 would have the effect of always keeping 20% of the device\'s space free for" -" # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure" -" # that the device is always at least 30% occupied." -" capacity_thresholds: [" -" [ 0.0, 1.0 ]," -" [ 0.0, 1.0 ]," -" [ 0.0, 1.0 ]," -" [ 0.0, 1.0 ]" -" ]" -"" -"### Define the default data placement policy" -"dpe:" -" # Choose Random, RoundRobin, or MinimizeIoTime" -" default_placement_policy: \"MinimizeIoTime\"" -"" -" # If true (1) the RoundRobin placement policy algorithm will split each Blob" -" # into a random number of smaller Blobs." -" default_rr_split: 0" -"" -"# The shared memory prefix for the hermes shared memory segment. A user name" -"# will be automatically appended." -"shmem_name: \"/hermes_shm_\"" -"# The interval in milliseconds at which to update the global system view." -"system_view_state_update_interval_ms: 1000" -"" -"#Paths which are ignored when buffering data" -"path_exclusions: [" -" \"/bin/\", \"/boot/\", \"/dev/\", \"/etc/\"," -" \"/lib/\", \"/opt/\", \"/proc/\", \"/sbin/\"," -" \"/sys/\", \"/usr/\", \"/var/\", \"/run/\"," -" \"pipe\", \"socket:\", \"anon_inode:\"" -"]" -"#Paths which are never ignored when buffering data" -"path_inclusions: [\"/var/opt/cray/dws/mounts/\"]" -""; +"# Example Hermes configuration file\n" +"\n" +"### Define properties of the storage devices\n" +"devices:\n" +" # The name of the device.\n" +" # It can be whatever the user wants, there are no special names\n" +" ram:\n" +" # The mount point of each device. RAM should be the empty string. For block\n" +" # devices, this is the directory where Hermes will create buffering files. For\n" +" # object storage or cloud targets, this will be a url.\n" +" mount_point: \"\"\n" +"\n" +" # The maximum buffering capacity in MiB of each device. Here we say that all 4\n" +" # devices get 50 MiB of buffering capacity.\n" +" capacity: 50MB\n" +"\n" +" # The size of the smallest available buffer in KiB. In general this should be\n" +" # the page size of your system for byte addressable storage, and the block size\n" +" # of the storage device for block addressable storage.\n" +" block_size: 4KB\n" +"\n" +" # The number of blocks (the size of which is chosen in block_sizes_kb) that each\n" +" # device should contain for each slab (controlled by num_slabs). This allows for\n" +" # precise control of the distibution of buffer sizes.\n" +" slab_units: [1, 4, 16, 32]\n" +"\n" +" # The maximum theoretical bandwidth (as advertised by the manufacturer) in\n" +" # Possible units: KBps, MBps, GBps\n" +" bandwidth: 6000MBps\n" +"\n" +" # The latency of each device (as advertised by the manufacturer).\n" +" # Possible units: ns, us, ms, s\n" +" latency: 15us\n" +"\n" +" # For each device, indicate \'1\' if it is shared among nodes (e.g., burst\n" +" # buffers), or \'0\' if it is per node (e.g., local NVMe).\n" +" is_shared_device: 0\n" +"\n" +" # For each device, the minimum and maximum percent capacity threshold at which\n" +" # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause\n" +" # the BufferOrganizer to move data to lower devices, making more room in faster\n" +" # devices (ideal for write-heavy workloads). Conversely, increasing the minimum\n" +" # threshold will cause data to be moved from slower devices into faster devices\n" +" # (ideal for read-heavy workloads). For example, a maximum capacity threshold of\n" +" # 0.8 would have the effect of always keeping 20% of the device\'s space free for\n" +" # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure\n" +" # that the device is always at least 30% occupied.\n" +" borg_capacity_thresh: [0.0, 1.0]\n" +"\n" +" nvme:\n" +" mount_point: \"./\"\n" +" capacity: 50MB\n" +" block_size: 4KB\n" +" slab_units: [ 1, 4, 16, 32 ]\n" +" bandwidth: 1GBps\n" +" latency: 600us\n" +" is_shared_device: 0\n" +" borg_capacity_thresh: [ 0.0, 1.0 ]\n" +"\n" +" ssd:\n" +" mount_point: \"./\"\n" +" capacity: 50MB\n" +" block_size: 4KB\n" +" slab_units: [ 1, 4, 16, 32 ]\n" +" bandwidth: 500MBps\n" +" latency: 1200us\n" +" is_shared_device: 0\n" +" borg_capacity_thresh: [ 0.0, 1.0 ]\n" +"\n" +" pfs:\n" +" mount_point: \"./\"\n" +" capacity: inf\n" +" block_size: 64KB # The stripe size of PFS\n" +" slab_units: [ 1, 4, 16, 32 ]\n" +" bandwidth: 100MBps # Per-device bandwidth\n" +" latency: 200ms\n" +" is_shared_device: 0\n" +" borg_capacity_thresh: [ 0.0, 1.0 ]\n" +"\n" +"### Define the network communication protocol\n" +"rpc:\n" +" # A path to a file containing a list of server names, 1 per line. If your\n" +" # servers are named according to a pattern (e.g., server-1, server-2, etc.),\n" +" # prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this\n" +" # option is not empty, it will override anything in `rpc_server_base_name`.\n" +" host_file: \"\"\n" +"\n" +" # Host names are constructed as \"base_name +\n" +" # host_number + rpc_server_suffix.\" Each entry in the rpc_host_number_range_list\n" +" # can be either a single number, or a range, which is 2 numbers separated by a\n" +" # hyphen (-). For example the list {01, 03-05, 07, 08-10} will be expanded to\n" +" # {01, 03, 04, 05, 07, 08, 09, 10}.\n" +" base_name: \"localhost\"\n" +" host_number_range: []\n" +" suffix: \"\"\n" +"\n" +" # The RPC protocol. This must come from the documentation of the specific RPC\n" +" # library in use.\n" +" protocol: \"ofi+sockets\"\n" +"\n" +" # RPC domain name for verbs transport. Blank for tcp.\n" +" domain: \"\"\n" +"\n" +" # Desired RPC port number.\n" +" port: 8080\n" +"\n" +" # The number of handler threads for each RPC server.\n" +" num_threads: 1\n" +"\n" +"### Define properties of the BORG\n" +"buffer_organizer:\n" +" # The number of threads used in the background organization of internal Hermes buffers.\n" +" num_threads: 4\n" +"\n" +" # Desired RPC port number for buffer organizer.\n" +" port: 8081\n" +"\n" +"### Define the default data placement policy\n" +"dpe:\n" +" # Choose Random, RoundRobin, or MinimizeIoTime\n" +" default_placement_policy: \"MinimizeIoTime\"\n" +"\n" +" # If true (1) the RoundRobin placement policy algorithm will split each Blob\n" +" # into a random number of smaller Blobs.\n" +" default_rr_split: 0\n" +"\n" +"# The shared memory prefix for the hermes shared memory segment. A user name\n" +"# will be automatically appended.\n" +"shmem_name: \"/hermes_shm_\"\n" +"\n" +"# The interval in milliseconds at which to update the global system view.\n" +"system_view_state_update_interval_ms: 1000\n" +"\n" +"#Paths which are ignored when buffering data\n" +"path_exclusions: [\n" +" \"/bin/\", \"/boot/\", \"/dev/\", \"/etc/\",\n" +" \"/lib/\", \"/opt/\", \"/proc/\", \"/sbin/\",\n" +" \"/sys/\", \"/usr/\", \"/var/\", \"/run/\",\n" +" \"pipe\", \"socket:\", \"anon_inode:\"\n" +"]\n" +"\n" +"#Paths which are never ignored when buffering data\n" +"path_inclusions: [\"/var/opt/cray/dws/mounts/\"]\n" +"\n"; #endif // HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ \ No newline at end of file diff --git a/src/rpc.h b/src/rpc.h index 622a8e994..0ef1225e3 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -61,12 +61,11 @@ class RpcContext { public: explicit RpcContext(COMM_TYPE *comm, ServerConfig *config) - : comm_(comm), config_(config) { - port_ = config->rpc_.port_; - } + : comm_(comm), config_(config) {} /** initialize host info list */ void InitHostInfo() { + port_ = config_->rpc_.port_; if (hosts_.size()) { return; } auto &hosts = config_->rpc_.host_names_; // Load hosts from hostfile @@ -178,6 +177,7 @@ class RpcContext { public: virtual void InitServer() = 0; virtual void InitClient() = 0; + virtual void InitColocated() = 0; }; } // namespace hermes diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 0011623ba..569d6f41f 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -42,21 +42,29 @@ void ThalliumRpc::InitClient() { true, 1); } +/** initialize RPC for colocated mode */ +void ThalliumRpc::InitColocated() { + InitHostInfo(); + // NOTE(llogan): RPCs are never used in colocated mode. +} + /** finalize RPC context */ void ThalliumRpc::Finalize() { switch (comm_->type_) { case HermesType::kServer: { comm_->WorldBarrier(); - server_engine_.finalize(); - client_engine_.finalize(); + break; } case HermesType::kClient: { std::string server_name = GetServerName(node_id_); tl::endpoint server = client_engine_.lookup(server_name); client_engine_.shutdown_remote_engine(server); client_engine_.finalize(); + break; } case HermesType::kColocated: { + //TODO(llogan) + break; } } } @@ -69,6 +77,7 @@ void ThalliumRpc::RunDaemon() { }; server_engine_.push_prefinalize_callback(prefinalize_callback); server_engine_.wait_for_finalize(); + client_engine_.finalize(); } /** get server name */ diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index f6cbb7734..5927ce053 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -41,8 +41,9 @@ class ThalliumRpc : public RpcContext { explicit ThalliumRpc(COMM_TYPE *comm, ServerConfig *config) : RpcContext(comm, config) {} - void InitClient() override; void InitServer() override; + void InitClient() override; + void InitColocated() override; void Finalize(); void RunDaemon(); std::string GetServerName(u32 node_id); From ff1b2e9752505fc73bf1332b7b4a8b207229226a Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 4 Dec 2022 08:31:54 -0600 Subject: [PATCH 048/511] I assume the leak is unavoidable for now --- src/rpc_thallium.cc | 20 ++++++++++---------- src/rpc_thallium.h | 18 +++++++++--------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 569d6f41f..5b17e6d11 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -23,11 +23,11 @@ namespace hermes { void ThalliumRpc::InitServer() { InitHostInfo(); std::string addr = GetMyRpcAddress(); - server_engine_ = tl::engine(addr, + server_engine_ = std::make_unique(addr, THALLIUM_SERVER_MODE, true, config_->rpc_.num_threads_); - std::string rpc_server_name = server_engine_.self(); + std::string rpc_server_name = server_engine_->self(); LOG(INFO) << "Serving at " << rpc_server_name << " with " << config_->rpc_.num_threads_ << " RPC threads" << std::endl; DefineRpcs(); @@ -37,7 +37,7 @@ void ThalliumRpc::InitServer() { void ThalliumRpc::InitClient() { InitHostInfo(); std::string protocol = GetProtocol(); - client_engine_ = tl::engine(protocol, + client_engine_ = std::make_unique(protocol, THALLIUM_CLIENT_MODE, true, 1); } @@ -57,9 +57,9 @@ void ThalliumRpc::Finalize() { } case HermesType::kClient: { std::string server_name = GetServerName(node_id_); - tl::endpoint server = client_engine_.lookup(server_name); - client_engine_.shutdown_remote_engine(server); - client_engine_.finalize(); + tl::endpoint server = client_engine_->lookup(server_name.c_str()); + client_engine_->shutdown_remote_engine(server); + client_engine_->finalize(); break; } case HermesType::kColocated: { @@ -71,13 +71,13 @@ void ThalliumRpc::Finalize() { /** run daemon */ void ThalliumRpc::RunDaemon() { - server_engine_.enable_remote_shutdown(); + server_engine_->enable_remote_shutdown(); auto prefinalize_callback = [this]() { this->comm_->WorldBarrier(); }; - server_engine_.push_prefinalize_callback(prefinalize_callback); - server_engine_.wait_for_finalize(); - client_engine_.finalize(); + server_engine_->push_prefinalize_callback(prefinalize_callback); + server_engine_->wait_for_finalize(); + client_engine_->finalize(); } /** get server name */ diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index 5927ce053..9ab253d16 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -31,11 +31,11 @@ namespace hermes { class ThalliumRpc : public RpcContext { public: std::atomic kill_requested_; /**< is kill requested? */ - tl::engine server_engine_; /**< pointer to engine */ - tl::engine bo_engine_; /**< pointer to buf. org. engine */ + std::unique_ptr client_engine_; /**< pointer to engine */ + std::unique_ptr server_engine_; /**< pointer to engine */ + std::unique_ptr bo_engine_; /**< pointer to buf. org. engine */ + std::unique_ptr io_engine_; /**< pointer to engine */ ABT_xstream execution_stream_; /**< Argobots execution stream */ - tl::engine client_engine_; /**< pointer to engine */ - tl::engine io_engine_; /**< pointer to engine */ /** initialize RPC context */ explicit ThalliumRpc(COMM_TYPE *comm, ServerConfig *config) @@ -55,8 +55,8 @@ class ThalliumRpc : public RpcContext { VLOG(1) << "Calling " << func_name << " on node " << node_id << " from node " << node_id << std::endl; std::string server_name = GetServerName(node_id); - tl::remote_procedure remote_proc = client_engine_.define(func_name); - tl::endpoint server = client_engine_.lookup(server_name); + tl::remote_procedure remote_proc = client_engine_->define(func_name); + tl::endpoint server = client_engine_->lookup(server_name); if constexpr (std::is_same::value) { remote_proc.disable_response(); remote_proc.on(server)(std::forward(args)...); @@ -84,14 +84,14 @@ class ThalliumRpc : public RpcContext { } } - tl::remote_procedure remote_proc = io_engine_.define(func_name); - tl::endpoint server = io_engine_.lookup(server_name); + tl::remote_procedure remote_proc = io_engine_->define(func_name); + tl::endpoint server = io_engine_->lookup(server_name); std::vector> segments(1); segments[0].first = data; segments[0].second = size; - tl::bulk bulk = io_engine_.expose(segments, flag); + tl::bulk bulk = io_engine_->expose(segments, flag); // size_t result = remote_proc.on(server)(bulk, id); size_t result = remote_proc.on(server)(bulk); From 8f23beb7a7bf1ecf0fba894a9d544dc08b22a3ee Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 4 Dec 2022 08:36:55 -0600 Subject: [PATCH 049/511] Move finalize to RPC for server --- src/api/hermes.cc | 2 +- src/rpc_thallium.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 549050846..dac938de0 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -113,7 +113,7 @@ void Hermes::LoadSharedMemory() { } void Hermes::FinalizeServer() { - rpc_.Finalize(); + // NOTE(llogan): Finalize() is called internally by daemon in this case LABSTOR_MEMORY_MANAGER->DestroyBackend(server_config_.shmem_name_); } diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 5b17e6d11..e2346a1ae 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -53,6 +53,7 @@ void ThalliumRpc::Finalize() { switch (comm_->type_) { case HermesType::kServer: { comm_->WorldBarrier(); + this->kill_requested_.store(true); break; } case HermesType::kClient: { @@ -73,7 +74,7 @@ void ThalliumRpc::Finalize() { void ThalliumRpc::RunDaemon() { server_engine_->enable_remote_shutdown(); auto prefinalize_callback = [this]() { - this->comm_->WorldBarrier(); + Finalize(); }; server_engine_->push_prefinalize_callback(prefinalize_callback); server_engine_->wait_for_finalize(); From de6f0465ee57a6b5e01c83f1770f7c90d65f1acc Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 4 Dec 2022 08:51:34 -0600 Subject: [PATCH 050/511] Stop daemon client conf works --- src/api/hermes.cc | 7 ++ src/api/hermes.h | 2 + src/config.h | 19 ++++- src/config_client.cc | 3 + src/rpc.h | 4 ++ src/rpc_thallium.cc | 49 +++++++------ src/rpc_thallium.h | 2 +- test/data/hermes_client.yaml | 2 - test/data/hermes_server.yaml | 136 ----------------------------------- 9 files changed, 58 insertions(+), 166 deletions(-) delete mode 100644 test/data/hermes_client.yaml delete mode 100644 test/data/hermes_server.yaml diff --git a/src/api/hermes.cc b/src/api/hermes.cc index dac938de0..2863c2c93 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -57,6 +57,10 @@ void Hermes::RunDaemon() { rpc_.RunDaemon(); } +void Hermes::StopDaemon() { + rpc_.StopDaemon(); +} + void Hermes::InitServer(std::string server_config_path) { LoadServerConfig(server_config_path); InitSharedMemory(); @@ -118,6 +122,9 @@ void Hermes::FinalizeServer() { } void Hermes::FinalizeClient() { + if (client_config_.stop_daemon_) { + StopDaemon(); + } rpc_.Finalize(); } diff --git a/src/api/hermes.h b/src/api/hermes.h index 4d00efe1c..5fb2a7306 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -35,6 +35,8 @@ class Hermes { void RunDaemon(); + void StopDaemon(); + private: void InitServer(std::string server_config_path); diff --git a/src/config.h b/src/config.h index 742db39a5..81003e3a2 100644 --- a/src/config.h +++ b/src/config.h @@ -26,6 +26,9 @@ namespace hermes { +/** + * Base class for configuration files + * */ class BaseConfig { public: /** load configuration from a string */ @@ -60,7 +63,6 @@ class BaseConfig { /** * Configuration used to intialize client * */ - class ClientConfig : public BaseConfig { public: bool stop_daemon_; @@ -73,6 +75,10 @@ class ClientConfig : public BaseConfig { void ParseYAML(YAML::Node &yaml_conf) override; }; + +/** + * Device information defined in server config + * */ struct DeviceInfo { /** The minimum transfer size of each device */ size_t block_size_; @@ -92,6 +98,9 @@ struct DeviceInfo { f32 borg_min_thresh_, borg_max_thresh_; }; +/** + * RPC information defined in server config + * */ struct RpcInfo { /** The name of a file that contains host names, 1 per line */ std::string host_file_; @@ -107,6 +116,9 @@ struct RpcInfo { int num_threads_; }; +/** + * DPE information defined in server config + * */ struct DpeInfo { /** The default blob placement policy. */ api::PlacementPolicy default_policy_; @@ -115,6 +127,9 @@ struct DpeInfo { bool default_rr_split_; }; +/** + * Buffer organizer information defined in server config + * */ struct BorgInfo { /** The RPC port number for the buffer organizer. */ int port_; @@ -123,7 +138,7 @@ struct BorgInfo { }; /** - * System and user configuration that is used to initialize Hermes. + * System configuration for Hermes */ class ServerConfig : public BaseConfig { public: diff --git a/src/config_client.cc b/src/config_client.cc index ee2706bef..d2352447b 100644 --- a/src/config_client.cc +++ b/src/config_client.cc @@ -9,6 +9,9 @@ namespace hermes { /** parse the YAML node */ void ClientConfig::ParseYAML(YAML::Node &yaml_conf) { + if (yaml_conf["stop_daemon"]) { + stop_daemon_ = yaml_conf["stop_daemon"].as(); + } } /** Load the default configuration */ diff --git a/src/rpc.h b/src/rpc.h index 0ef1225e3..b9bd4dc37 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -136,6 +136,10 @@ class RpcContext { return hosts_[index].ip_addr_; } + /** Get RPC protocol */ + std::string GetProtocol() { + return config_->rpc_.protocol_; + } private: /** Get the IPv4 address of this machine */ diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index e2346a1ae..f56330b5b 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -48,28 +48,6 @@ void ThalliumRpc::InitColocated() { // NOTE(llogan): RPCs are never used in colocated mode. } -/** finalize RPC context */ -void ThalliumRpc::Finalize() { - switch (comm_->type_) { - case HermesType::kServer: { - comm_->WorldBarrier(); - this->kill_requested_.store(true); - break; - } - case HermesType::kClient: { - std::string server_name = GetServerName(node_id_); - tl::endpoint server = client_engine_->lookup(server_name.c_str()); - client_engine_->shutdown_remote_engine(server); - client_engine_->finalize(); - break; - } - case HermesType::kColocated: { - //TODO(llogan) - break; - } - } -} - /** run daemon */ void ThalliumRpc::RunDaemon() { server_engine_->enable_remote_shutdown(); @@ -81,6 +59,13 @@ void ThalliumRpc::RunDaemon() { client_engine_->finalize(); } +/** stop daemon (from client) */ +void ThalliumRpc::StopDaemon() { + std::string server_name = GetServerName(node_id_); + tl::endpoint server = client_engine_->lookup(server_name.c_str()); + client_engine_->shutdown_remote_engine(server); +} + /** get server name */ std::string ThalliumRpc::GetServerName(u32 node_id) { std::string ip_address = GetIpAddressFromNodeId(node_id); @@ -89,9 +74,23 @@ std::string ThalliumRpc::GetServerName(u32 node_id) { ":" + std::to_string(config_->rpc_.port_); } -/** Get protocol */ -std::string ThalliumRpc::GetProtocol() { - return config_->rpc_.protocol_; +/** finalize RPC context */ +void ThalliumRpc::Finalize() { + switch (comm_->type_) { + case HermesType::kServer: { + comm_->WorldBarrier(); + this->kill_requested_.store(true); + break; + } + case HermesType::kClient: { + client_engine_->finalize(); + break; + } + case HermesType::kColocated: { + //TODO(llogan) + break; + } + } } } // namespace hermes \ No newline at end of file diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index 9ab253d16..8780b9bfd 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -46,8 +46,8 @@ class ThalliumRpc : public RpcContext { void InitColocated() override; void Finalize(); void RunDaemon(); + void StopDaemon(); std::string GetServerName(u32 node_id); - std::string GetProtocol(); /** RPC call */ template diff --git a/test/data/hermes_client.yaml b/test/data/hermes_client.yaml deleted file mode 100644 index 61f5a6146..000000000 --- a/test/data/hermes_client.yaml +++ /dev/null @@ -1,2 +0,0 @@ -stop_daemon: true -file_page_size_kb: 1024 \ No newline at end of file diff --git a/test/data/hermes_server.yaml b/test/data/hermes_server.yaml deleted file mode 100644 index 09e27c1e7..000000000 --- a/test/data/hermes_server.yaml +++ /dev/null @@ -1,136 +0,0 @@ -# Example Hermes configuration file - -### Define properties of the storage devices -devices: - # The name of the device. - # It can be whatever the user wants, there are no special names - ram: - # The mount point of each device. RAM should be the empty string. For block - # devices, this is the directory where Hermes will create buffering files. For - # object storage or cloud targets, this will be a url. - mount_point: "" - - # The maximum buffering capacity in MiB of each device. Here we say that all 4 - # devices get 50 MiB of buffering capacity. - capacity_mb: 50 - - # The size of the smallest available buffer in KiB. In general this should be - # the page size of your system for byte addressable storage, and the block size - # of the storage device for block addressable storage. - block_size_kb: 4 - - # The number of blocks (the size of which is chosen in block_sizes_kb) that each - # device should contain for each slab (controlled by num_slabs). This allows for - # precise control of the distibution of buffer sizes. - slab_units: [1, 4, 16, 32] - - # The maximum theoretical bandwidth (as advertised by the manufacturer) in - # MiB/sec. of each device. - bandwidth_mbps: 6000 - - # The latency in microseconds of each device (as advertised by the manufacturer). - latencies_us: 15 - - # For each device, indicate '1' if it is shared among nodes (e.g., burst - # buffers), or '0' if it is per node (e.g., local NVMe). - is_shared_device: 0 - - nvme: - mount_point: "./" - capacity_mb: 50 - block_size_kb: 4 - slab_units: [1, 4, 16, 32] - is_shared_device: 0 - - ssd: - mount_point: "./" - capacity_mb: 50 - block_size_kb: 4 - slab_units: [ 1, 4, 16, 32 ] - is_shared_device: 0 - - pfs: - mount_point: "./" - capacity_mb: inf - block_size_kb: 64 # Assume 64KB strip size - slab_units: [1, 4, 16, 32] - -### Define the network communication protocol -rpc: - # A path to a file containing a list of server names, 1 per line. If your - # servers are named according to a pattern (e.g., server-1, server-2, etc.), - # prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this - # option is not empty, it will override anything in `rpc_server_base_name`. - host_file: "" - - # Host names are constructed as "base_name + - # host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list - # can be either a single number, or a range, which is 2 numbers separated by a - # hyphen (-). For example the list {01, 03-05, 07, 08-10} will be expanded to - # {01, 03, 04, 05, 07, 08, 09, 10}. - server_base_name: "localhost" - server_host_number_range: [] - server_suffix: "" - - # The RPC protocol. This must come from the documentation of the specific RPC - # library in use. - protocol: "ofi+sockets" - - # RPC domain name for verbs transport. Blank for tcp. - domain: "" - - # Desired RPC port number. - port: 8080 - - # Desired RPC port number for buffer organizer. - buffer_organizer_port: 8081 - - # The number of handler threads for each RPC server. - num_threads: 1 - -### Define properties of the BORG -buffer_organizer: - # The number of threads used in the background organization of internal Hermes buffers. - num_threads: 4 - - # For each device, the minimum and maximum percent capacity threshold at which - # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause - # the BufferOrganizer to move data to lower devices, making more room in faster - # devices (ideal for write-heavy workloads). Conversely, increasing the minimum - # threshold will cause data to be moved from slower devices into faster devices - # (ideal for read-heavy workloads). For example, a maximum capacity threshold of - # 0.8 would have the effect of always keeping 20% of the device's space free for - # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure - # that the device is always at least 30% occupied. - capacity_thresholds: [ - [ 0.0, 1.0 ], - [ 0.0, 1.0 ], - [ 0.0, 1.0 ], - [ 0.0, 1.0 ] - ] - -### Define the default data placement policy -dpe: - # Choose Random, RoundRobin, or MinimizeIoTime - default_placement_policy: "MinimizeIoTime" - - # If true (1) the RoundRobin placement policy algorithm will split each Blob - # into a random number of smaller Blobs. - default_rr_split: 0 - -# The shared memory prefix for the hermes shared memory segment. A user name -# will be automatically appended. -shmem_name: "/hermes_shm_" -# The interval in milliseconds at which to update the global system view. -system_view_state_update_interval_ms: 1000 - -#Paths which are ignored when buffering data -path_exclusions: [ - "/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:" -] -#Paths which are never ignored when buffering data -path_inclusions: ["/var/opt/cray/dws/mounts/"] - From 90b56a17fb74b8b397f334eb9fd6d5678c5bd061 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 5 Dec 2022 01:06:56 -0600 Subject: [PATCH 051/511] Make Hermes a singleton --- code_generators/singleton/generate.py | 90 ++++++++++++++++++ src/CMakeLists.txt | 12 ++- src/api/bucket.cc | 14 +++ src/api/bucket.h | 37 ++++++++ src/api/hermes.cc | 20 ++-- src/api/hermes.h | 26 +++++- src/api/hermes_daemon.cc | 9 +- src/api/traits.h | 8 ++ src/api/vbucket.cc | 12 +++ src/api/vbucket.h | 43 +++++++++ src/communication_mpi.h | 4 +- src/hermes_status.h | 96 +------------------ src/hermes_types.cc | 17 ++++ src/hermes_types.h | 22 +---- src/metadata_manager.cc | 5 + src/metadata_manager.h | 25 +++++ src/rpc.cc | 127 ++++++++++++++++++++++++++ src/rpc.h | 118 ++++-------------------- src/rpc_thallium.cc | 1 + src/rpc_thallium.h | 3 +- src/rpc_thallium_defs.cc | 9 ++ src/singleton.cc | 4 + src/singleton.h | 48 +++------- src/singleton_macros.h | 9 ++ test/test_rpc.cc | 5 +- 25 files changed, 489 insertions(+), 275 deletions(-) create mode 100644 code_generators/singleton/generate.py create mode 100644 src/api/bucket.cc create mode 100644 src/api/bucket.h create mode 100644 src/api/traits.h create mode 100644 src/api/vbucket.cc create mode 100644 src/api/vbucket.h create mode 100644 src/hermes_types.cc create mode 100644 src/metadata_manager.cc create mode 100644 src/metadata_manager.h create mode 100644 src/rpc.cc create mode 100644 src/singleton.cc create mode 100644 src/singleton_macros.h diff --git a/code_generators/singleton/generate.py b/code_generators/singleton/generate.py new file mode 100644 index 000000000..6c1747a87 --- /dev/null +++ b/code_generators/singleton/generate.py @@ -0,0 +1,90 @@ + +""" +Create the .h and .cc files for defining Singletons +USAGE: + cd hermes/code_generators/singleton + python3 generate.py +""" + +import re + +def ToCamelCase(string): + if string is None: + return + words = re.sub(r"(_|-)+", " ", string).split() + words = [word.capitalize() for word in words] + return "".join(words) + +def ToSnakeCase(string): + if string is None: + return + string = re.sub('(\.|-)+', '_', string) + words = re.split('([A-Z][^A-Z]*)', string) + words = [word for word in words if len(word)] + string = "_".join(words) + return string.lower() + +class SingletonDefinition: + def __init__(self, namespace, class_name, include): + snake = ToSnakeCase(class_name).upper() + if snake == "HERMES": + self.macro_name = f"HERMES" + else: + self.macro_name = f"HERMES_{snake}" + self.type_name = f"{self.macro_name}_T" + if namespace is not None: + self.class_name = f"{namespace}::{class_name}" + else: + self.class_name = class_name + self.include = include + +class SingletonGenerator: + def __init__(self, guard_name, singleton_include): + self.singleton_include = singleton_include + self.guard_name = guard_name + self.defs = [] + + def add(self, namespace, class_name, include): + self.defs.append(SingletonDefinition( + namespace, class_name, include + )) + + def generate(self, cc_file, h_file): + self._generate_cc(cc_file) + self._generate_h(h_file) + + def _generate_cc(self, path): + lines = [] + lines.append(f"#include {self.singleton_include}") + lines.append("") + for defn in self.defs: + lines.append(f"#include <{defn.include}>") + lines.append(f"template<> std::unique_ptr<{defn.class_name}> hermes::Singleton<{defn.class_name}>::obj_ = nullptr;") + self._save_lines(lines, path) + + def _generate_h(self, path): + lines = [] + lines.append(f"#ifndef HERMES_SINGLETON_{self.guard_name}_MACROS_H") + lines.append(f"#define HERMES_SINGLETON_{self.guard_name}_MACROS_H") + lines.append("") + lines.append(f"#include {self.singleton_include}") + lines.append("") + for defn in self.defs: + lines.append(f"#define {defn.macro_name} hermes::Singleton<{defn.class_name}>::GetInstance()") + lines.append(f"#define {defn.type_name} {defn.class_name}*") + lines.append("") + lines.append(f"#endif // HERMES_SINGLETON_{self.guard_name}_MACROS_H") + self._save_lines(lines, path) + + def _save_lines(self, lines, path): + text = "\n".join(lines) + "\n" + if path is None: + print(text) + return + with open(path, 'w') as fp: + fp.write(text) + +gen = SingletonGenerator("SRC", "\"singleton.h\"") +gen.add("hermes::api", "Hermes", "hermes.h") +gen.generate("../../src/singleton.cc", + "../../src/singleton_macros.h") \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9fc8d97b3..016f1dd8e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/adapter) +include_directories(${CMAKE_SOURCE_DIR}) configure_file(hermes_version.h.in hermes_version.h) @@ -39,15 +39,17 @@ endif() # Set sources #------------------------------------------------------------------------------ set(HERMES_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/api/hermes.cc + ${CMAKE_CURRENT_SOURCE_DIR}/singleton.cc ${CMAKE_CURRENT_SOURCE_DIR}/config_client.cc ${CMAKE_CURRENT_SOURCE_DIR}/config_server.cc + ${CMAKE_CURRENT_SOURCE_DIR}/hermes_types.cc ${CMAKE_CURRENT_SOURCE_DIR}/utils.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rpc.cc ${CMAKE_CURRENT_SOURCE_DIR}/rpc_thallium.cc ${CMAKE_CURRENT_SOURCE_DIR}/rpc_thallium_defs.cc - #${CMAKE_CURRENT_SOURCE_DIR}/api/bucket.cc - #${CMAKE_CURRENT_SOURCE_DIR}/api/hermes.cc - #${CMAKE_CURRENT_SOURCE_DIR}/api/vbucket.cc + ${CMAKE_CURRENT_SOURCE_DIR}/api/bucket.cc + ${CMAKE_CURRENT_SOURCE_DIR}/api/hermes.cc + ${CMAKE_CURRENT_SOURCE_DIR}/api/vbucket.cc #${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cc #${CMAKE_CURRENT_SOURCE_DIR}/prefetcher.cc #${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/sequential.cc diff --git a/src/api/bucket.cc b/src/api/bucket.cc new file mode 100644 index 000000000..c5e65f906 --- /dev/null +++ b/src/api/bucket.cc @@ -0,0 +1,14 @@ +// +// Created by lukemartinlogan on 12/4/22. +// + +#include "bucket.h" + +namespace hermes::api { + +Bucket::Bucket(std::string name, + Context &ctx, + Hermes *hermes) { +} + +} // namespace hermes::api \ No newline at end of file diff --git a/src/api/bucket.h b/src/api/bucket.h new file mode 100644 index 000000000..a6d2f0d77 --- /dev/null +++ b/src/api/bucket.h @@ -0,0 +1,37 @@ +// +// Created by lukemartinlogan on 12/4/22. +// + +#ifndef HERMES_SRC_API_BUCKET_H_ +#define HERMES_SRC_API_BUCKET_H_ + +#include "hermes_types.h" +#include "hermes_status.h" +#include "hermes.h" + +namespace hermes::api { + +class Bucket { + private: + + + public: + Bucket(std::string name, + Context &ctx, + Hermes *hermes); + + /* std::string GetName() const; + + u64 GetId() const; */ + + private: + RPC void LocalGetOrCreateBucket(); + + public: + RPC_AUTOGEN_START + RPC_AUTOGEN_END +}; + +} + +#endif // HERMES_SRC_API_BUCKET_H_ diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 2863c2c93..1d0bfce36 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -3,17 +3,11 @@ // #include "hermes.h" +#include "bucket.h" +#include "vbucket.h" namespace hermes::api { -Hermes::Hermes(HermesType mode, - std::string server_config_path, - std::string client_config_path) - : comm_(mode), - rpc_(&comm_, &server_config_) { - Init(mode, std::move(server_config_path), std::move(client_config_path)); -} - void Hermes::Init(HermesType mode, std::string server_config_path, std::string client_config_path) { @@ -132,4 +126,14 @@ void Hermes::FinalizeColocated() { rpc_.Finalize(); } +std::shared_ptr Hermes::GetBucket(std::string name, + Context ctx) { + return std::make_shared(name, ctx, this); +} + +std::shared_ptr Hermes::GetVBucket(std::string name, + Context ctx) { + return std::make_shared(name, ctx, this); +} + } // namespace hermes::api \ No newline at end of file diff --git a/src/api/hermes.h b/src/api/hermes.h index 5fb2a7306..8aa003aa8 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -8,26 +8,38 @@ #include "config.h" #include "constants.h" #include "hermes_types.h" + +#include "communication_factory.h" #include "rpc.h" +#include "metadata_manager.h" namespace hermes::api { +class Bucket; +class VBucket; + class Hermes { public: HermesType mode_; ServerConfig server_config_; ClientConfig client_config_; + MetadataManager mdm_; COMM_TYPE comm_; RPC_TYPE rpc_; lipc::Allocator *main_alloc_; public: Hermes() = default; - Hermes(HermesType mode, - std::string server_config_path = "", - std::string client_config_path = ""); - void Init(HermesType mode, + static Hermes* Create(HermesType mode = HermesType::kClient, + std::string server_config_path = "", + std::string client_config_path = "") { + auto hermes = HERMES; + hermes->Init(mode, server_config_path, client_config_path); + return hermes; + } + + void Init(HermesType mode = HermesType::kClient, std::string server_config_path = "", std::string client_config_path = ""); @@ -37,6 +49,12 @@ class Hermes { void StopDaemon(); + public: + std::shared_ptr GetBucket(std::string name, + Context ctx = Context()); + std::shared_ptr GetVBucket(std::string name, + Context ctx = Context()); + private: void InitServer(std::string server_config_path); diff --git a/src/api/hermes_daemon.cc b/src/api/hermes_daemon.cc index 7967c6090..7ad25c129 100644 --- a/src/api/hermes_daemon.cc +++ b/src/api/hermes_daemon.cc @@ -26,10 +26,11 @@ int main(int argc, char* argv[]) { hermes_config = argv[1]; } - auto hermes = hapi::Hermes(hermes::HermesType::kServer, - hermes_config); - hermes.RunDaemon(); - hermes.Finalize(); + auto hermes = hapi::Hermes::Create( + hermes::HermesType::kServer, + hermes_config); + hermes->RunDaemon(); + hermes->Finalize(); MPI_Finalize(); return 0; } diff --git a/src/api/traits.h b/src/api/traits.h new file mode 100644 index 000000000..c3e6aa933 --- /dev/null +++ b/src/api/traits.h @@ -0,0 +1,8 @@ +// +// Created by lukemartinlogan on 12/4/22. +// + +#ifndef HERMES_SRC_API_TRAITS_H_ +#define HERMES_SRC_API_TRAITS_H_ + +#endif // HERMES_SRC_API_TRAITS_H_ diff --git a/src/api/vbucket.cc b/src/api/vbucket.cc new file mode 100644 index 000000000..0799f0c27 --- /dev/null +++ b/src/api/vbucket.cc @@ -0,0 +1,12 @@ +// +// Created by lukemartinlogan on 12/4/22. +// + +#include "vbucket.h" + +namespace hermes::api { + +VBucket::VBucket(std::string name, Context &ctx, Hermes *hermes) { +} + +} // namespace hermes::api \ No newline at end of file diff --git a/src/api/vbucket.h b/src/api/vbucket.h new file mode 100644 index 000000000..e448f9c1f --- /dev/null +++ b/src/api/vbucket.h @@ -0,0 +1,43 @@ +// +// Created by lukemartinlogan on 12/4/22. +// + +#ifndef HERMES_SRC_API_VBUCKET_H_ +#define HERMES_SRC_API_VBUCKET_H_ + +#include "hermes_types.h" +#include "hermes_status.h" +#include "hermes.h" + +namespace hermes::api { + +class VBucket { + public: + VBucket(std::string name, Context &ctx, Hermes *hermes); + + /*void Link(std::string bucket_name, + std::string blob_name, Context ctx = Context()); + + void Link(std::shared_ptr &bucket, + std::string blob_name, Context ctx = Context()); + + void Unlink(std::string bucket_name, + std::string blob_name, Context ctx = Context()); + + void Unlink(std::shared_ptr &bucket, + std::string blob_name, Context ctx = Context()); + + Status Destroy(); + + bool ContainsBlob(std::string bucket_name, std::string blob_name); + + size_t Get(); + + template + void Attach(Args ...args) { + }*/ +}; + +} // namespace hermes::api + +#endif // HERMES_SRC_API_VBUCKET_H_ diff --git a/src/communication_mpi.h b/src/communication_mpi.h index 777ecc26c..6072a9478 100644 --- a/src/communication_mpi.h +++ b/src/communication_mpi.h @@ -42,7 +42,9 @@ class MpiCommunicator : public CommunicationContext { } /** initialize MPI communication. */ - MpiCommunicator(HermesType type) { + MpiCommunicator() : CommunicationContext() {} + + void Init(HermesType type) { world_comm_ = MPI_COMM_WORLD; world_proc_id_ = GetWorldProcId(); world_size_ = GetNumWorldProcs(); diff --git a/src/hermes_status.h b/src/hermes_status.h index 793696901..7a8c8e876 100644 --- a/src/hermes_status.h +++ b/src/hermes_status.h @@ -18,104 +18,10 @@ /** \file hermes_status.h */ namespace hermes { -/** a macro for returning error code */ -#define RETURN_CODES(X) \ - X(2, HERMES_OK_MAX, \ - "Maximum supported HERMES success with " \ - "caveat.") \ - X(1, BLOB_IN_SWAP_PLACE, "Blob is placed into swap place.") \ - X(0, HERMES_SUCCESS, "No error!") \ - X(-1, INVALID_BUCKET, "Bucket ID is invalid.") \ - X(-2, BUCKET_NAME_TOO_LONG, "Bucket name exceeds max length (256).") \ - X(-3, VBUCKET_NAME_TOO_LONG, "VBucket name exceeds max length (256).") \ - X(-4, BLOB_NAME_TOO_LONG, "Blob name exceeds max length (64).") \ - X(-5, INVALID_BLOB, \ - "Blob data is invalid. Please check " \ - "address and size.") \ - X(-6, BLOB_NOT_IN_BUCKET, "Blob is not in this bucket.") \ - X(-7, BLOB_NOT_LINKED_TO_VBUCKET, "Blob is not linked to this vbucket.") \ - X(-8, TRAIT_NOT_VALID, "Selected trait is not valid.") \ - X(-9, TRAIT_EXISTS_ALREADY, "Selected trait already exists.") \ - X(-10, OFFSET_MAP_EMPTY, "Offset_map is empty.") \ - X(-11, BLOB_NOT_LINKED_IN_MAP, "Map doesn't have the blob linked.") \ - X(-12, BUCKET_IN_USE, \ - "Bucket cannot be destroyed because its " \ - "reference count is greater than 1.") \ - X(-13, DPE_RANDOM_FOUND_NO_TGT, \ - "DPE random found no target with enough " \ - "space for blob.") \ - X(-14, DPE_GET_INVALID_TGT, "DPE got an invalid target ID.") \ - X(-15, DPE_ORTOOLS_NO_SOLUTION, \ - "DPE GLPK does not find a solution " \ - "with provided constraints.") \ - X(-16, DPE_PLACEMENTSCHEMA_EMPTY, "DPE PlacementSchema is empty.") \ - X(-17, READ_BLOB_FAILED, "Read blob from its id failed.") \ - X(-18, STDIO_OFFSET_ERROR, "Offset invalid or fseek() failed.") \ - X(-19, STDIO_FWRITE_FAILED, "Func fwrite failed. System err msg: ") \ - X(-20, STDIO_FOPEN_FAILED, "Func fopen failed. System err msg: ") \ - X(-21, STDIO_FCLOSE_FAILED, "Func fclose failed. System err msg: ") \ - X(-23, INVALID_FILE, "File is not valid.") \ - X(-24, PLACE_SWAP_BLOB_TO_BUF_FAILED, \ - "Place blob from swap space into " \ - "buffering system failed.") \ - X(-25, DPE_RR_FIND_TGT_FAILED, \ - "DPE round-robin failed to find " \ - "proper target for blob.") \ - X(-26, HERMES_ERROR_MAX, "Maximum supported HERMES errors.") -/** a macro for returning enum */ -#define RETURN_ENUM(ID, NAME, TEXT) NAME = ID, - -/** a macro for returning text */ -#define RETURN_TEXT(ID, NAME, TEXT) \ - case ID: \ - return TEXT; - -/** Hermes status codes. */ -enum StatusCode { RETURN_CODES(RETURN_ENUM) }; - -namespace api { - -/** Represents the return status of Hermes class methods and function calls. */ class Status { public: - /** Create an object representing success status. */ - explicit Status(StatusCode ret_code = HERMES_SUCCESS) : status_(ret_code) {} - - /** Returns true if the call did exactly what the user expected */ - bool Succeeded() const { return (status_ == HERMES_SUCCESS); } - - /** Returns true if the call was success with caveat. */ - bool Acceptable() const { - return (status_ > HERMES_SUCCESS && status_ < HERMES_OK_MAX); - } - - /** Returns true if the call failed with error. */ - bool Failed() const { - return (status_ < HERMES_SUCCESS && status_ > HERMES_ERROR_MAX); - } - - /** Custom equality check against a StatusCode */ - bool operator==(StatusCode code) { return (status_ == code); } - - /** Custom assignment operator from StatusCode */ - void operator=(StatusCode code) { status_ = code; } - - /** StatusCode Getter */ - StatusCode GetStatus() const { return status_; } - - /** Returns a message string */ - std::string Msg() const { - switch (status_) { RETURN_CODES(RETURN_TEXT) } - - return "Unknown error"; /**< status is unknown */ - } - - private: - StatusCode status_; /**< StatusCode state variable */ }; -} // namespace api - -} // namespace hermes +} // hermes #endif // HERMES_STATUS_H_ diff --git a/src/hermes_types.cc b/src/hermes_types.cc new file mode 100644 index 000000000..1a81c7243 --- /dev/null +++ b/src/hermes_types.cc @@ -0,0 +1,17 @@ +// +// Created by lukemartinlogan on 12/5/22. +// + +#include "hermes_types.h" +#include "hermes.h" + +namespace hermes::api { + +Context::Context() + : policy(HERMES->server_config_.dpe_.default_policy_), + rr_split(HERMES->server_config_.dpe_.default_rr_split_), + rr_retry(false), + disable_swap(false), + vbkt_id_({0, 0}) {} + +} // namespace hermes::api \ No newline at end of file diff --git a/src/hermes_types.h b/src/hermes_types.h index d7b5b5fb6..fe79b63b5 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -24,6 +24,7 @@ #include "hermes_version.h" #include "data_structures.h" #include "constants.h" +#include "singleton_macros.h" /** * \file hermes_types.h @@ -272,26 +273,12 @@ struct PrefetchContext { /** Hermes API call context */ struct Context { - /** The default maximum number of buffer organizer retries */ - static int default_buffer_organizer_retries; - - /** The default blob placement policy */ - static PlacementPolicy default_placement_policy; - - /** Whether random splitting of blobs is enabled for Round-Robin blob - * placement. - */ - static bool default_rr_split; - /** The blob placement policy */ PlacementPolicy policy; /** Options for controlling the MinimizeIoTime PlacementPolicy */ MinimizeIoTimeOptions minimize_io_time_options; - /** The maximum number of buffer organizer retries */ - int buffer_organizer_retries; - /** Whether random splitting of blobs is enabled for Round-Robin */ bool rr_split; @@ -305,12 +292,7 @@ struct Context { VBucketID vbkt_id_; PrefetchContext pctx_; - Context() : policy(default_placement_policy), - buffer_organizer_retries(default_buffer_organizer_retries), - rr_split(default_rr_split), - rr_retry(false), - disable_swap(false), - vbkt_id_({0, 0}) {} + Context(); }; /** \brief Trait types. diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc new file mode 100644 index 000000000..85ba44cf3 --- /dev/null +++ b/src/metadata_manager.cc @@ -0,0 +1,5 @@ +// +// Created by lukemartinlogan on 12/4/22. +// + +#include "metadata_manager.h" diff --git a/src/metadata_manager.h b/src/metadata_manager.h new file mode 100644 index 000000000..11febfa15 --- /dev/null +++ b/src/metadata_manager.h @@ -0,0 +1,25 @@ +// +// Created by lukemartinlogan on 12/4/22. +// + +#ifndef HERMES_SRC_METADATA_MANAGER_H_ +#define HERMES_SRC_METADATA_MANAGER_H_ + +#include "rpc_decorator.h" +#include "hermes_types.h" +#include "hermes_status.h" + +namespace hermes { + +class MetadataManager { + public: + MetadataManager() = default; + + RPC void LocalGetOrCreateBucket(std::string bucket_name) { + std::cout << bucket_name << std::endl; + } +}; + +} // namespace hermes + +#endif // HERMES_SRC_METADATA_MANAGER_H_ diff --git a/src/rpc.cc b/src/rpc.cc new file mode 100644 index 000000000..d39067c58 --- /dev/null +++ b/src/rpc.cc @@ -0,0 +1,127 @@ +// +// Created by lukemartinlogan on 12/4/22. +// + +#include "rpc.h" +#include "hermes.h" + +namespace hermes { + +RpcContext::RpcContext() + : comm_(&HERMES->comm_), config_(&HERMES->server_config_) {} + +/** initialize host info list */ +void RpcContext::InitHostInfo() { + port_ = config_->rpc_.port_; + if (hosts_.size()) { return; } + auto &hosts = config_->rpc_.host_names_; + // Load hosts from hostfile + if (!config_->rpc_.host_file_.empty()) { + // TODO(llogan): load host names from hostfile + } + + // Get all host info + hosts_.resize(hosts.size()); + for (const auto& name : hosts) { + hosts_.emplace_back(name, _GetIpAddress(name)); + } + + // Get id of current host + int node_id = 1; // NOTE(llogan): node_ids start from 1 (0 is NULL) + std::string my_ip = _GetMyIpAddress(); + for (const auto& host_info : hosts_) { + if (host_info.ip_addr_ == my_ip) { + node_id_ = node_id; + break; + } + ++node_id; + } +} + +/** Check if we should skip an RPC and call a function locally */ +bool RpcContext::ShouldDoLocalCall(int node_id) { + switch (comm_->type_) { + case HermesType::kClient: { + return false; + } + case HermesType::kServer: { + return node_id == node_id_; + } + case HermesType::kColocated: { + return true; + } + } +} + +/** get RPC address */ +std::string RpcContext::GetRpcAddress(u32 node_id, int port) { + std::string result = config_->rpc_.protocol_ + "://"; + if (!config_->rpc_.domain_.empty()) { + result += config_->rpc_.domain_ + "/"; + } + std::string host_name = GetHostNameFromNodeId(node_id); + result += host_name + ":" + std::to_string(port); + return result; +} + +/** Get RPC address for this node */ +std::string RpcContext::GetMyRpcAddress() { + return GetRpcAddress(node_id_, port_); +} + +/** get host name from node ID */ +std::string RpcContext::GetHostNameFromNodeId(u32 node_id) { + // NOTE(chogan): node_id 0 is reserved as the NULL node + u32 index = node_id - 1; + return hosts_[index].hostname_; +} + +/** get host name from node ID */ +std::string RpcContext::GetIpAddressFromNodeId(u32 node_id) { + // NOTE(chogan): node_id 0 is reserved as the NULL node + u32 index = node_id - 1; + return hosts_[index].ip_addr_; +} + +/** Get RPC protocol */ +std::string RpcContext::GetProtocol() { + return config_->rpc_.protocol_; +} + +/** Get the IPv4 address of this machine */ +std::string RpcContext::_GetMyIpAddress() { + return _GetIpAddress("localhost"); +} + +/** Get IPv4 address from the host with "host_name" */ +std::string RpcContext::_GetIpAddress(const std::string &host_name) { + struct hostent hostname_info = {}; + struct hostent *hostname_result; + int hostname_error = 0; + char hostname_buffer[4096] = {}; +#ifdef __APPLE__ + hostname_result = gethostbyname(host_name.c_str()); + in_addr **addr_list = (struct in_addr **)hostname_result->h_addr_list; +#else + int gethostbyname_result = + gethostbyname_r(host_name.c_str(), &hostname_info, hostname_buffer, + 4096, &hostname_result, &hostname_error); + if (gethostbyname_result != 0) { + LOG(FATAL) << hstrerror(h_errno); + } + in_addr **addr_list = (struct in_addr **)hostname_info.h_addr_list; +#endif + if (!addr_list[0]) { + LOG(FATAL) << hstrerror(h_errno); + } + + char ip_address[INET_ADDRSTRLEN]; + const char *inet_result = + inet_ntop(AF_INET, addr_list[0], ip_address, INET_ADDRSTRLEN); + if (!inet_result) { + FailedLibraryCall("inet_ntop"); + } + return ip_address; +} + +} \ No newline at end of file diff --git a/src/rpc.h b/src/rpc.h index b9bd4dc37..321c0a2cf 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -30,8 +30,15 @@ #include #include +namespace hermes::api { +class Hermes; +} // namespace hermes::api + namespace hermes { +struct MetadataManager; +using api::Hermes; + /** RPC types */ enum class RpcType { kThallium @@ -52,131 +59,44 @@ struct HostInfo { */ class RpcContext { public: + Hermes *hermes_; COMM_TYPE *comm_; - /** the hermes configuration used to initialize this RPC */ ServerConfig *config_; + MetadataManager *mdm_; int port_; /**< port number */ int node_id_; /**< the ID of this node*/ std::vector hosts_; /**< Hostname and ip addr per-node */ public: - explicit RpcContext(COMM_TYPE *comm, ServerConfig *config) - : comm_(comm), config_(config) {} + explicit RpcContext(); /** initialize host info list */ - void InitHostInfo() { - port_ = config_->rpc_.port_; - if (hosts_.size()) { return; } - auto &hosts = config_->rpc_.host_names_; - // Load hosts from hostfile - if (!config_->rpc_.host_file_.empty()) { - // TODO(llogan): load host names from hostfile - } - - // Get all host info - hosts_.resize(hosts.size()); - for (const auto& name : hosts) { - hosts_.emplace_back(name, _GetIpAddress(name)); - } - - // Get id of current host - int node_id = 1; // NOTE(llogan): node_ids start from 1 (0 is NULL) - std::string my_ip = _GetMyIpAddress(); - for (const auto& host_info : hosts_) { - if (host_info.ip_addr_ == my_ip) { - node_id_ = node_id; - break; - } - ++node_id; - } - } + void InitHostInfo(); /** Check if we should skip an RPC and call a function locally */ - bool ShouldDoLocalCall(int node_id) { - switch (comm_->type_) { - case HermesType::kClient: { - return false; - } - case HermesType::kServer: { - return node_id == node_id_; - } - case HermesType::kColocated: { - return true; - } - } - } + bool ShouldDoLocalCall(int node_id); /** get RPC address */ - std::string GetRpcAddress(u32 node_id, int port) { - std::string result = config_->rpc_.protocol_ + "://"; - if (!config_->rpc_.domain_.empty()) { - result += config_->rpc_.domain_ + "/"; - } - std::string host_name = GetHostNameFromNodeId(node_id); - result += host_name + ":" + std::to_string(port); - return result; - } + std::string GetRpcAddress(u32 node_id, int port); /** Get RPC address for this node */ - std::string GetMyRpcAddress() { - return GetRpcAddress(node_id_, port_); - } + std::string GetMyRpcAddress(); /** get host name from node ID */ - std::string GetHostNameFromNodeId(u32 node_id) { - // NOTE(chogan): node_id 0 is reserved as the NULL node - u32 index = node_id - 1; - return hosts_[index].hostname_; - } + std::string GetHostNameFromNodeId(u32 node_id); /** get host name from node ID */ - std::string GetIpAddressFromNodeId(u32 node_id) { - // NOTE(chogan): node_id 0 is reserved as the NULL node - u32 index = node_id - 1; - return hosts_[index].ip_addr_; - } + std::string GetIpAddressFromNodeId(u32 node_id); /** Get RPC protocol */ - std::string GetProtocol() { - return config_->rpc_.protocol_; - } + std::string GetProtocol(); private: /** Get the IPv4 address of this machine */ - std::string _GetMyIpAddress() { - return _GetIpAddress("localhost"); - } + std::string _GetMyIpAddress(); /** Get IPv4 address from the host with "host_name" */ - std::string _GetIpAddress(const std::string &host_name) { - struct hostent hostname_info = {}; - struct hostent *hostname_result; - int hostname_error = 0; - char hostname_buffer[4096] = {}; -#ifdef __APPLE__ - hostname_result = gethostbyname(host_name.c_str()); - in_addr **addr_list = (struct in_addr **)hostname_result->h_addr_list; -#else - int gethostbyname_result = - gethostbyname_r(host_name.c_str(), &hostname_info, hostname_buffer, - 4096, &hostname_result, &hostname_error); - if (gethostbyname_result != 0) { - LOG(FATAL) << hstrerror(h_errno); - } - in_addr **addr_list = (struct in_addr **)hostname_info.h_addr_list; -#endif - if (!addr_list[0]) { - LOG(FATAL) << hstrerror(h_errno); - } - - char ip_address[INET_ADDRSTRLEN]; - const char *inet_result = - inet_ntop(AF_INET, addr_list[0], ip_address, INET_ADDRSTRLEN); - if (!inet_result) { - FailedLibraryCall("inet_ntop"); - } - return ip_address; - } + std::string _GetIpAddress(const std::string &host_name); public: virtual void InitServer() = 0; diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index f56330b5b..4e07cdaf5 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -12,6 +12,7 @@ #include +#include "metadata_manager.h" #include "rpc_thallium.h" #include "singleton.h" diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index 8780b9bfd..4f7de3594 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -38,8 +38,7 @@ class ThalliumRpc : public RpcContext { ABT_xstream execution_stream_; /**< Argobots execution stream */ /** initialize RPC context */ - explicit ThalliumRpc(COMM_TYPE *comm, ServerConfig *config) - : RpcContext(comm, config) {} + ThalliumRpc() : RpcContext() {} void InitServer() override; void InitClient() override; diff --git a/src/rpc_thallium_defs.cc b/src/rpc_thallium_defs.cc index 8ce4d9ffa..693fdad47 100644 --- a/src/rpc_thallium_defs.cc +++ b/src/rpc_thallium_defs.cc @@ -3,11 +3,20 @@ // #include "rpc_thallium.h" +#include "metadata_manager.h" namespace hermes { +using thallium::request; + void ThalliumRpc::DefineRpcs() { RPC_AUTOGEN_START + auto get_or_create_bucket = + [this](const request &req, std::string name) { + this->mdm_->LocalGetOrCreateBucket(name); + req.respond(true); + }; + server_engine_->define("GetOrCreateBucket", get_or_create_bucket); RPC_AUTOGEN_END } diff --git a/src/singleton.cc b/src/singleton.cc new file mode 100644 index 000000000..836f05fe3 --- /dev/null +++ b/src/singleton.cc @@ -0,0 +1,4 @@ +#include "singleton.h" + +#include +template<> std::unique_ptr hermes::Singleton::obj_ = nullptr; diff --git a/src/singleton.h b/src/singleton.h index 807fa2894..5a287f727 100644 --- a/src/singleton.h +++ b/src/singleton.h @@ -16,50 +16,28 @@ #include #include #include + +namespace hermes { /** * Make a class singleton when used with the class. format for class name T * Singleton::GetInstance() * @tparam T */ -namespace hermes { -template -/** - A class to represent singleton pattern - */ -class Singleton { - public: - /** - * Uses unique pointer to build a static global instance of variable. - * @tparam T - * @return instance of T - */ - template - static T* GetInstance(Args... args) { - if (instance == nullptr) - instance = std::make_unique(std::forward(args)...); - return instance.get(); - } - - /** - * Operators - */ - Singleton& operator=(const Singleton) = delete; /* deleting = operators*/ +template +class Singleton { + private: + static std::unique_ptr obj_; public: - /** - * Constructor - */ - Singleton(const Singleton&) = delete; /* deleting copy constructor. */ + Singleton() = default; - protected: - /** - * static instance. - */ - static std::unique_ptr instance; - Singleton() {} /* hidden default constructor. */ + /** Get or create an instance of type T */ + template + inline static T* GetInstance(Args ...args) { + if(!obj_) { obj_ = std::make_unique(args...); } + return obj_.get(); + } }; -template -std::unique_ptr Singleton::instance = nullptr; } // namespace hermes #endif // HERMES_ADAPTER_SINGLETON_H diff --git a/src/singleton_macros.h b/src/singleton_macros.h new file mode 100644 index 000000000..221c7b84d --- /dev/null +++ b/src/singleton_macros.h @@ -0,0 +1,9 @@ +#ifndef HERMES_SINGLETON_SRC_MACROS_H +#define HERMES_SINGLETON_SRC_MACROS_H + +#include "singleton.h" + +#define HERMES hermes::Singleton::GetInstance() +#define HERMES_T hermes::api::Hermes* + +#endif // HERMES_SINGLETON_SRC_MACROS_H diff --git a/test/test_rpc.cc b/test/test_rpc.cc index be64b3f14..92f79a800 100644 --- a/test/test_rpc.cc +++ b/test/test_rpc.cc @@ -21,8 +21,9 @@ namespace hapi = hermes::api; int main(int argc, char* argv[]) { MPI_Init(&argc, &argv); - auto hermes = hapi::Hermes(hermes::HermesType::kClient); - hermes.Finalize(); + auto hermes = hapi::Hermes::Create(hermes::HermesType::kClient); + auto bkt = hermes->GetBucket("hello"); + hermes->Finalize(); MPI_Finalize(); return 0; } \ No newline at end of file From 2e246e5d8ac0ac57c23af37f04f0bf9740348cdf Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 5 Dec 2022 02:05:26 -0600 Subject: [PATCH 052/511] RPCs work --- src/CMakeLists.txt | 1 + src/api/bucket.cc | 4 ++-- src/api/bucket.h | 8 ++------ src/api/hermes.cc | 7 +++++-- src/api/vbucket.cc | 2 +- src/api/vbucket.h | 2 +- src/hermes_types.h | 1 + src/metadata_manager.cc | 19 +++++++++++++++++++ src/metadata_manager.h | 14 +++++++++++--- src/rpc.cc | 10 ++++++---- src/rpc.h | 5 ++--- src/rpc_thallium.cc | 6 +++--- 12 files changed, 54 insertions(+), 25 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 016f1dd8e..39215a34e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,6 +47,7 @@ set(HERMES_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/rpc.cc ${CMAKE_CURRENT_SOURCE_DIR}/rpc_thallium.cc ${CMAKE_CURRENT_SOURCE_DIR}/rpc_thallium_defs.cc + ${CMAKE_CURRENT_SOURCE_DIR}/metadata_manager.cc ${CMAKE_CURRENT_SOURCE_DIR}/api/bucket.cc ${CMAKE_CURRENT_SOURCE_DIR}/api/hermes.cc ${CMAKE_CURRENT_SOURCE_DIR}/api/vbucket.cc diff --git a/src/api/bucket.cc b/src/api/bucket.cc index c5e65f906..e4e2a6fcf 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -7,8 +7,8 @@ namespace hermes::api { Bucket::Bucket(std::string name, - Context &ctx, - Hermes *hermes) { + Context &ctx) : mdm_(&HERMES->mdm_) { + mdm_->GetOrCreateBucket(name); } } // namespace hermes::api \ No newline at end of file diff --git a/src/api/bucket.h b/src/api/bucket.h index a6d2f0d77..cfdc307e1 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -13,20 +13,16 @@ namespace hermes::api { class Bucket { private: - + MetadataManager *mdm_; public: Bucket(std::string name, - Context &ctx, - Hermes *hermes); + Context &ctx); /* std::string GetName() const; u64 GetId() const; */ - private: - RPC void LocalGetOrCreateBucket(); - public: RPC_AUTOGEN_START RPC_AUTOGEN_END diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 1d0bfce36..afa8bef3d 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -58,6 +58,7 @@ void Hermes::StopDaemon() { void Hermes::InitServer(std::string server_config_path) { LoadServerConfig(server_config_path); InitSharedMemory(); + mdm_.Init(); rpc_.InitServer(); rpc_.InitClient(); } @@ -67,6 +68,7 @@ void Hermes::InitClient(std::string server_config_path, LoadServerConfig(server_config_path); LoadClientConfig(client_config_path); LoadSharedMemory(); + mdm_.Init(); rpc_.InitClient(); } @@ -75,6 +77,7 @@ void Hermes::InitColocated(std::string server_config_path, LoadServerConfig(server_config_path); LoadClientConfig(client_config_path); InitSharedMemory(); + mdm_.Init(); rpc_.InitColocated(); } @@ -128,12 +131,12 @@ void Hermes::FinalizeColocated() { std::shared_ptr Hermes::GetBucket(std::string name, Context ctx) { - return std::make_shared(name, ctx, this); + return std::make_shared(name, ctx); } std::shared_ptr Hermes::GetVBucket(std::string name, Context ctx) { - return std::make_shared(name, ctx, this); + return std::make_shared(name, ctx); } } // namespace hermes::api \ No newline at end of file diff --git a/src/api/vbucket.cc b/src/api/vbucket.cc index 0799f0c27..693d85d9a 100644 --- a/src/api/vbucket.cc +++ b/src/api/vbucket.cc @@ -6,7 +6,7 @@ namespace hermes::api { -VBucket::VBucket(std::string name, Context &ctx, Hermes *hermes) { +VBucket::VBucket(std::string name, Context &ctx) { } } // namespace hermes::api \ No newline at end of file diff --git a/src/api/vbucket.h b/src/api/vbucket.h index e448f9c1f..f93e26c29 100644 --- a/src/api/vbucket.h +++ b/src/api/vbucket.h @@ -13,7 +13,7 @@ namespace hermes::api { class VBucket { public: - VBucket(std::string name, Context &ctx, Hermes *hermes); + VBucket(std::string name, Context &ctx); /*void Link(std::string bucket_name, std::string blob_name, Context ctx = Context()); diff --git a/src/hermes_types.h b/src/hermes_types.h index fe79b63b5..702382388 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -61,6 +61,7 @@ typedef double f64; /**< 64-bit float */ /** The mode Hermes is launched in */ enum class HermesType { + kNone, kServer, kClient, kColocated diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 85ba44cf3..a180d3aee 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -2,4 +2,23 @@ // Created by lukemartinlogan on 12/4/22. // +#include "hermes.h" #include "metadata_manager.h" + +namespace hermes { + +void MetadataManager::Init() { + rpc_ = &HERMES->rpc_; +} + +bool MetadataManager::LocalGetOrCreateBucket(std::string name) { + std::cout << "In bucket!" << std::endl; + return true; +} + +bool MetadataManager::GetOrCreateBucket(std::string name) { + return rpc_->Call( + rpc_->node_id_, "GetOrCreateBucket", name); +} + +} // namespace hermes \ No newline at end of file diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 11febfa15..a010ba217 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -8,16 +8,24 @@ #include "rpc_decorator.h" #include "hermes_types.h" #include "hermes_status.h" +#include "rpc.h" namespace hermes { class MetadataManager { + private: + RPC_TYPE *rpc_; + public: MetadataManager() = default; + void Init(); + + RPC bool LocalGetOrCreateBucket(std::string bucket_name); - RPC void LocalGetOrCreateBucket(std::string bucket_name) { - std::cout << bucket_name << std::endl; - } + public: + RPC_AUTOGEN_START + bool GetOrCreateBucket(std::string bucket_name); + RPC_AUTOGEN_END }; } // namespace hermes diff --git a/src/rpc.cc b/src/rpc.cc index d39067c58..220269c67 100644 --- a/src/rpc.cc +++ b/src/rpc.cc @@ -7,11 +7,10 @@ namespace hermes { -RpcContext::RpcContext() - : comm_(&HERMES->comm_), config_(&HERMES->server_config_) {} - /** initialize host info list */ -void RpcContext::InitHostInfo() { +void RpcContext::InitRpcContext() { + comm_ = &HERMES->comm_; + config_ = &HERMES->server_config_; port_ = config_->rpc_.port_; if (hosts_.size()) { return; } auto &hosts = config_->rpc_.host_names_; @@ -50,6 +49,9 @@ bool RpcContext::ShouldDoLocalCall(int node_id) { case HermesType::kColocated: { return true; } + default: { + LOG(FATAL) << "Invalid HermesType" << std::endl; + } } } diff --git a/src/rpc.h b/src/rpc.h index 321c0a2cf..1b0d382ec 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -59,7 +59,6 @@ struct HostInfo { */ class RpcContext { public: - Hermes *hermes_; COMM_TYPE *comm_; ServerConfig *config_; MetadataManager *mdm_; @@ -68,10 +67,10 @@ class RpcContext { std::vector hosts_; /**< Hostname and ip addr per-node */ public: - explicit RpcContext(); + RpcContext() = default; /** initialize host info list */ - void InitHostInfo(); + void InitRpcContext(); /** Check if we should skip an RPC and call a function locally */ bool ShouldDoLocalCall(int node_id); diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 4e07cdaf5..58dfc1234 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -22,7 +22,7 @@ namespace hermes { /** start Thallium RPC server */ void ThalliumRpc::InitServer() { - InitHostInfo(); + InitRpcContext(); std::string addr = GetMyRpcAddress(); server_engine_ = std::make_unique(addr, THALLIUM_SERVER_MODE, @@ -36,7 +36,7 @@ void ThalliumRpc::InitServer() { /** initialize RPC clients */ void ThalliumRpc::InitClient() { - InitHostInfo(); + InitRpcContext(); std::string protocol = GetProtocol(); client_engine_ = std::make_unique(protocol, THALLIUM_CLIENT_MODE, @@ -45,7 +45,7 @@ void ThalliumRpc::InitClient() { /** initialize RPC for colocated mode */ void ThalliumRpc::InitColocated() { - InitHostInfo(); + InitRpcContext(); // NOTE(llogan): RPCs are never used in colocated mode. } From 945923910e797452d744c14a145643d0abdbc63b Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 5 Dec 2022 03:13:30 -0600 Subject: [PATCH 053/511] Restructure API generators. Use absolute pathing. --- .../hermes_config/generator.py} | 24 -- .../code_generators/rpc/generator.py | 256 ++++++++++++++++++ .../singleton/generator.py} | 25 +- code_generators/code_generators/util/api.py | 66 +++++ .../code_generators/util/naming.py | 17 ++ code_generators/code_generators/util/paths.py | 11 + code_generators/hermes_config.py | 26 ++ code_generators/rpc.py | 23 ++ code_generators/singleton.py | 16 ++ src/rpc_decorator.h | 2 + src/rpc_thallium_defs.cc | 4 + 11 files changed, 423 insertions(+), 47 deletions(-) rename code_generators/{hermes_config_gen/generate.py => code_generators/hermes_config/generator.py} (62%) create mode 100644 code_generators/code_generators/rpc/generator.py rename code_generators/{singleton/generate.py => code_generators/singleton/generator.py} (76%) create mode 100644 code_generators/code_generators/util/api.py create mode 100644 code_generators/code_generators/util/naming.py create mode 100644 code_generators/code_generators/util/paths.py create mode 100644 code_generators/hermes_config.py create mode 100644 code_generators/rpc.py create mode 100644 code_generators/singleton.py diff --git a/code_generators/hermes_config_gen/generate.py b/code_generators/code_generators/hermes_config/generator.py similarity index 62% rename from code_generators/hermes_config_gen/generate.py rename to code_generators/code_generators/hermes_config/generator.py index 3d4a9fff5..a59951050 100644 --- a/code_generators/hermes_config_gen/generate.py +++ b/code_generators/code_generators/hermes_config/generator.py @@ -1,13 +1,3 @@ -""" -USAGE: - cd /path/to/hermes_config_gen - python3 generate.py - -OUTPUT: - ../../config_client_default.h (if client) - ../../config_server_default.h (if server) -""" - import sys, os def create_config(path, var_name, config_path, macro_name): @@ -35,17 +25,3 @@ def create_config(path, var_name, config_path, macro_name): with open(config_path, 'w') as fp: fp.write(config) -create_config( - path="../../config/hermes_client_default.yaml", - var_name="kClientDefaultConfigStr", - config_path="../../src/config_client_default.h", - macro_name="CLIENT" -) - -create_config( - path="../../config/hermes_server_default.yaml", - var_name="kServerDefaultConfigStr", - config_path="../../src/config_server_default.h", - macro_name="SERVER" -) - diff --git a/code_generators/code_generators/rpc/generator.py b/code_generators/code_generators/rpc/generator.py new file mode 100644 index 000000000..899202aea --- /dev/null +++ b/code_generators/code_generators/rpc/generator.py @@ -0,0 +1,256 @@ +import sys, os, re +from code_generators.util.api import Api +from code_generators.util.naming import to_snake_case + +rpc_func_text = """ +{RET} {GLOBAL_NAME}({PARAMS}) {{ + u32 target_node = {TARGET_NODE}; + if (target_node == rpc_->node_id_) {{ + return {LOCAL_NAME}( + {PASS_PARAMS}); + }} else {{ + return rpc_->Call( + target_node, "{GLOBAL_NAME}", + {PASS_PARAMS}); + }} +}} +""" + +# Will add this to rpc_thallium.cc +rpc_lambda_text = """ +auto {LAMBDA_NAME} = + [{class_instance}](const request &req, {PARAMS}) {{ + auto result = {class_instance}->{LOCAL_NAME}({PASS_PARAMS}); + req.respond(result); + }}; +server_engine_->define("{GLOBAL_NAME}", {LAMBDA_NAME}); +""" + +class RpcGenerator: + def __init__(self, rpc_defs_path, modify): + """ + Automatically inserts RPC code into class files and builds + rpc_thallium_defs.cc. + + :param modify: Whether or not to modify class files directly or + store temporary output in the working directory. + """ + + if modify != "True": + self.modify = False + else: + self.modify = True + + self.path = None + self.rpc_defs_path = rpc_defs_path + self.macro = None + self.class_instance = None + self.rpcs = {} # [class_path][class_name] -> + # tuple(local_rpc_name, target_node, + # class_instance) + + def set_file(self, path, class_name, class_instance): + """ + Sets information used in subsequent calls to "add". + + :param path: the path to the class containing RPC prototypes + (e.g., metadata_manager.h) + :param class_name: the name of the class to scan prototypes from + (e.g., MetadataManager) + :param class_instance: The name of the C++ class instance to input + into the RPC lambda in rpc_thallium_defs.cc (e.g., mdm). These are + encapsulated in RPC_CLASS_INSTANCE_DEFS in rpc_thallium_defs.cc. + :return: None + """ + + self.path = path + self.class_name = class_name + self.class_instance = class_instance + + def add(self, local_rpc_name, target_node): + """ + Register an RPC to scan for. + + :param local_rpc_name: The local name of the RPC in a C++ class + (e.g., LocalGetOrCreateBucket) + :param target_node: The C++ code to determine the node to execute an RPC + :return: None + """ + + if self.path not in self.rpcs: + self.rpcs[self.path] = {} + if self.class_name not in self.rpcs[self.path]: + self.rpcs[self.path][self.class_name] = [] + self.rpcs[self.path][self.class_name].append( + (local_rpc_name, target_node, self.class_instance)) + + def generate(self): + """ + Generate the RPCs based on the local function prototypes. + + :return: None. + """ + + rpc_lambdas = [] + for path, class_rpcs in self.rpcs.items(): + self.generate_class_file(path, class_rpcs, rpc_lambdas) + self.generate_rpc_file(rpc_lambdas) + + def generate_class_file(self, path, class_rpcs, rpc_lambdas): + """ + Generates the RPCs for a particular class file + (e.g., metadata_manager.h) + + :param path: the path to the C++ class file (e.g., metadata_manager.h) + :param class_rpcs: the set of RPCs names belonging to the class + :param rpc_lambdas: (output) + :return: Modifies rpc_lambdas and the C++ class file. + """ + + with open(path) as fp: + class_lines = fp.read().splitlines() + rpc_map = self.get_rpcs_from_class(class_lines) + for class_name, rpcs in class_rpcs.items(): + # Find RPC_AUTOGEN_START and RPC_AUTOGEN_END + gen_start = rpc_map[class_name]['gen_start'] + gen_end = rpc_map[class_name]['gen_end'] + # Get the amount of space in front of RPC_AUTOGEN_START + space = self.get_macro_space(class_lines[gen_start]) + # + global_rpc_funcs = [] + for rpc in rpcs: + local_rpc_name = rpc[0] + target_node = rpc[1] + class_instance = rpc[2] + local_rpc_api = rpc_map[class_name]['apis'][local_rpc_name] + self.create_global_rpc_func(local_rpc_api, target_node, + space, global_rpc_funcs) + self.create_rpc_lambda(local_rpc_api, class_instance, + space, rpc_lambdas) + + class_lines = class_lines[:gen_start+1] + class_lines[gen_end:] + class_lines = class_lines[:gen_start + 1] + \ + global_rpc_funcs + \ + class_lines[gen_start + 1:] + + if self.modify: + with open(path, 'w') as fp: + fp.write("\n".join(class_lines)) + else: + tmp_path = os.path.basename(path) + with open(f"tmp_{tmp_path}", 'w') as fp: + fp.write("\n".join(class_lines)) + + def generate_rpc_file(self, rpc_lambdas): + """ + Generate rpc_thallium_defs.cc + + :param rpc_lambdas: + :return: + """ + + path = self.rpc_defs_path + with open(path) as fp: + rpc_lines = fp.read().splitlines() + gen_start = self.find_macro("RPC_AUTOGEN_START", rpc_lines) + gen_end = self.find_macro("RPC_AUTOGEN_END", rpc_lines) + rpc_lines = rpc_lines[:gen_start+1] + rpc_lines[gen_end:] + rpc_lines = rpc_lines[:gen_start+1] + \ + rpc_lambdas + \ + rpc_lines[gen_start+1:] + if self.modify: + with open(path, 'w') as fp: + fp.write("\n".join(rpc_lines)) + else: + tmp_path = os.path.basename(path) + with open(tmp_path, 'w') as fp: + fp.write("\n".join(rpc_lines)) + + def get_rpcs_from_class(self, class_lines): + """ + Loads the prototypes of all RPCs in a particular class file + + :param class_lines: The parsed lines of the class file + (e.g., metadata_manager.h) + :return: rpc_map. Stores the set of RPC Apis of a particular class. + [class_name]['apis'][local_rpc_name] -> Api + """ + + cur_class = None + rpc_map = {} + for i, line in enumerate(class_lines): + toks = line.split() + first_tok = "" + if len(toks) > 0: + first_tok = toks[0].strip() + + if "class" == first_tok: + cur_class = self.get_class_name(line) + rpc_map[cur_class] = {'apis': {}, + 'gen_start': None, + 'gen_end': None} + elif "RPC_AUTOGEN_START" in line: + rpc_map[cur_class]['gen_start'] = i + elif "RPC_AUTOGEN_END" in line: + rpc_map[cur_class]['gen_end'] = i + elif "RPC" == first_tok: + text_proto = self.get_rpc_prototype(class_lines[i:]) + api = Api(text_proto) + api.global_name = api.name.replace("Local", "") + api.lambda_name = to_snake_case(f"Rpc{api.global_name}") + local_rpc_name = api.name + rpc_map[cur_class]['apis'][local_rpc_name] = api + return rpc_map + + def get_class_name(self, line): + toks = re.split("[\:\*+ ]", line) + toks = [tok.strip() for tok in toks if tok is not None and len(tok)] + class_name = toks[1] + return class_name + + def get_rpc_prototype(self, lines): + proto_toks = [] + for line in lines: + proto_toks.append(line.strip()) + if ';' in line: + break + proto = " ".join(proto_toks) + return proto + + def find_macro(self, macro, lines): + for i, line in enumerate(lines): + if macro in line: + return i + + def get_macro_space(self, line): + space_len = len(line) - len(line.lstrip()) + return " " * space_len + + def add_space(self, space, text): + lines = text.splitlines() + for j, line in enumerate(lines): + lines[j] = f"{space}{line}" + return "\n".join(lines) + + def create_global_rpc_func(self, rpc, target_node, space, lines): + lines.append(rpc_func_text.format( + RET=rpc.ret, + LOCAL_NAME=rpc.name, + GLOBAL_NAME=rpc.global_name, + PARAMS=rpc.get_args(), + PASS_PARAMS=rpc.pass_args(), + TARGET_NODE=target_node + ).strip()) + lines[-1] = self.add_space(space, lines[-1]) + + def create_rpc_lambda(self, rpc, class_instance, space, lines): + lines.append(rpc_lambda_text.format( + GLOBAL_NAME=rpc.global_name, + LAMBDA_NAME=rpc.lambda_name, + class_instance=class_instance, + PARAMS=rpc.get_args(), + PASS_PARAMS=rpc.pass_args(), + LOCAL_NAME=rpc.name + ).strip()) + lines[-1] = self.add_space(space, lines[-1]) + diff --git a/code_generators/singleton/generate.py b/code_generators/code_generators/singleton/generator.py similarity index 76% rename from code_generators/singleton/generate.py rename to code_generators/code_generators/singleton/generator.py index 6c1747a87..dfe841834 100644 --- a/code_generators/singleton/generate.py +++ b/code_generators/code_generators/singleton/generator.py @@ -8,25 +8,9 @@ import re -def ToCamelCase(string): - if string is None: - return - words = re.sub(r"(_|-)+", " ", string).split() - words = [word.capitalize() for word in words] - return "".join(words) - -def ToSnakeCase(string): - if string is None: - return - string = re.sub('(\.|-)+', '_', string) - words = re.split('([A-Z][^A-Z]*)', string) - words = [word for word in words if len(word)] - string = "_".join(words) - return string.lower() - class SingletonDefinition: def __init__(self, namespace, class_name, include): - snake = ToSnakeCase(class_name).upper() + snake = to_snake_case(class_name).upper() if snake == "HERMES": self.macro_name = f"HERMES" else: @@ -82,9 +66,4 @@ def _save_lines(self, lines, path): print(text) return with open(path, 'w') as fp: - fp.write(text) - -gen = SingletonGenerator("SRC", "\"singleton.h\"") -gen.add("hermes::api", "Hermes", "hermes.h") -gen.generate("../../src/singleton.cc", - "../../src/singleton_macros.h") \ No newline at end of file + fp.write(text) \ No newline at end of file diff --git a/code_generators/code_generators/util/api.py b/code_generators/code_generators/util/api.py new file mode 100644 index 000000000..e05634490 --- /dev/null +++ b/code_generators/code_generators/util/api.py @@ -0,0 +1,66 @@ +import sys, os, re + +class Api: + def __init__(self, api_str): + self.api_str = api_str + self.name = None # The name of the API + self.ret = None # Return value of the API + self.var_defs = None # The variables in the API + self.decompose_prototype(api_str) + + def _is_text(self, tok): + first_is_text = re.match("[_a-zA-Z]", tok[0]) is not None + if not first_is_text: + return False + return re.match("[_a-zA-Z0-9]+", tok) is not None + + def _clean(self, toks): + return [tok for tok in toks if tok is not None and len(tok) > 0] + + def get_arg_tuple(self, arg): + arg_toks = self._clean(re.split("[ ]|(\*+)", arg)) + if len(arg_toks) == 1: + if arg_toks[0] == '...': + type = "" + name = "..." + return (type, name) + type = " ".join(arg_toks[:-1]) + name = arg_toks[-1] + return (type, name) + + def decompose_prototype(self, api_str): + toks = self._clean(re.split("[()]|;", api_str)) + proto, args = toks[0], toks[1] + + try: + proto = self._clean(re.split("[ ]|(\*+)", proto)) + self.name = proto[-1] + self.ret = " ".join(proto[:-1]) + except: + print(f"Failed to decompose proto name: {proto}") + exit() + + try: + self.var_defs = [] + args = args.split(',') + for arg in args: + self.var_defs.append(self.get_arg_tuple(arg)) + except: + print(f"Failed to decompose proto args: {args}") + exit(1) + + def get_args(self): + if len(self.var_defs) == 0: + return "" + try: + args = [" ".join(arg_tuple) for arg_tuple in self.var_defs] + except: + print(f"Failed to get arg list: {self.var_defs}") + exit(1) + return ", ".join(args) + + def pass_args(self): + if self.var_defs is None: + return "" + args = [arg[-1] for arg in self.var_defs if arg[0] != ''] + return ", ".join(args) \ No newline at end of file diff --git a/code_generators/code_generators/util/naming.py b/code_generators/code_generators/util/naming.py new file mode 100644 index 000000000..54472af4e --- /dev/null +++ b/code_generators/code_generators/util/naming.py @@ -0,0 +1,17 @@ +import re + +def to_camel_case(string): + if string is None: + return + words = re.sub(r"(_|-)+", " ", string).split() + words = [word.capitalize() for word in words] + return "".join(words) + +def to_snake_case(string): + if string is None: + return + string = re.sub('(\.|-)+', '_', string) + words = re.split('([A-Z][^A-Z]*)', string) + words = [word for word in words if len(word)] + string = "_".join(words) + return string.lower() \ No newline at end of file diff --git a/code_generators/code_generators/util/paths.py b/code_generators/code_generators/util/paths.py new file mode 100644 index 000000000..2052c3aab --- /dev/null +++ b/code_generators/code_generators/util/paths.py @@ -0,0 +1,11 @@ +import os,sys +import pathlib + +def GetHermesRoot(): + util_path = pathlib.Path(__file__).parent.resolve() + code_generators_path = os.path.dirname(util_path) + code_generators_path = os.path.dirname(code_generators_path) + hermes_path = os.path.dirname(code_generators_path) + return hermes_path + +HERMES_ROOT=GetHermesRoot() \ No newline at end of file diff --git a/code_generators/hermes_config.py b/code_generators/hermes_config.py new file mode 100644 index 000000000..f6e770ef7 --- /dev/null +++ b/code_generators/hermes_config.py @@ -0,0 +1,26 @@ +""" +USAGE: + cd code_generators/bin + python3 hermes_config.py + +OUTPUT: + ${HERMES}/src/config_client_default.h (if client) + ${HERMES}/src/config_server_default.h (if server) +""" + +from code_generators.hermes_config.generator import create_config +from code_generators.util.paths import HERMES_ROOT + +create_config( + path=f"{HERMES_ROOT}/config/hermes_client_default.yaml", + var_name="kClientDefaultConfigStr", + config_path=f"{HERMES_ROOT}/src/config_client_default.h", + macro_name="CLIENT" +) + +create_config( + path=f"{HERMES_ROOT}/config/hermes_server_default.yaml", + var_name="kServerDefaultConfigStr", + config_path=f"{HERMES_ROOT}/src/config_server_default.h", + macro_name="SERVER" +) \ No newline at end of file diff --git a/code_generators/rpc.py b/code_generators/rpc.py new file mode 100644 index 000000000..109b3fb05 --- /dev/null +++ b/code_generators/rpc.py @@ -0,0 +1,23 @@ + +""" +Automatically generate the RPCs for a series of Local functions + +USAGE: + cd code_generators/bin + python3 rpc.py [whether or not to modify path or make tmpfiles] +""" + +import sys +from code_generators.rpc.generator import RpcGenerator +from code_generators.util.paths import HERMES_ROOT + +rpc_defs_path = f"{HERMES_ROOT}/src/rpc_thallium_defs.cc" +if len(sys.argv) < 2: + gen = RpcGenerator(rpc_defs_path, False) +else: + gen = RpcGenerator(rpc_defs_path, sys.argv[1]) + +gen.set_file(f"{HERMES_ROOT}/src/metadata_manager.h", "MetadataManager", "mdm") +gen.add("LocalGetOrCreateBucket", "0") + +gen.generate() \ No newline at end of file diff --git a/code_generators/singleton.py b/code_generators/singleton.py new file mode 100644 index 000000000..827beee61 --- /dev/null +++ b/code_generators/singleton.py @@ -0,0 +1,16 @@ + +""" +Create the .h and .cc files for defining Singletons +USAGE: + cd code_generators/bin + python3 singleton.py +""" + +import re +from code_generators.singleton.generator import SingletonGenerator +from code_generators.util.paths import HERMES_ROOT + +gen = SingletonGenerator("SRC", "\"singleton.h\"") +gen.add("hermes::api", "Hermes", "hermes.h") +gen.generate(f"{HERMES_ROOT}/src/singleton.cc", + f"{HERMES_ROOT}/src/singleton_macros.h") \ No newline at end of file diff --git a/src/rpc_decorator.h b/src/rpc_decorator.h index 9916e3ddf..0931d8853 100644 --- a/src/rpc_decorator.h +++ b/src/rpc_decorator.h @@ -8,5 +8,7 @@ #define RPC #define RPC_AUTOGEN_START #define RPC_AUTOGEN_END +#define RPC_CLASS_INSTANCE_DEFS_START +#define RPC_CLASS_INSTANCE_DEFS_END #endif // HERMES_SRC_RPC_GENERATOR_DECORATOR_H_ diff --git a/src/rpc_thallium_defs.cc b/src/rpc_thallium_defs.cc index 693fdad47..a6b118b6b 100644 --- a/src/rpc_thallium_defs.cc +++ b/src/rpc_thallium_defs.cc @@ -10,6 +10,10 @@ namespace hermes { using thallium::request; void ThalliumRpc::DefineRpcs() { + RPC_CLASS_INSTANCE_DEFS_START + MetadataManager *mdm = this->mdm_; + RPC_CLASS_INSTANCE_DEFS_END + RPC_AUTOGEN_START auto get_or_create_bucket = [this](const request &req, std::string name) { From 7e8a6224def5041ff5fbc70cf6e40819b178ce82 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 5 Dec 2022 10:58:35 -0600 Subject: [PATCH 054/511] Add & to argtuple type in api.py --- .../code_generators/rpc/generator.py | 20 +- code_generators/code_generators/util/api.py | 5 +- code_generators/code_generators/util/conv.py | 8 + code_generators/rpc.py | 28 +- config/hermes_server_default.yaml | 2 +- src/data_structures.h | 1 + src/hermes_types.h | 1 - src/metadata_manager.cc | 8 +- src/metadata_manager.h | 301 +++++++++++++++++- src/rpc_thallium_defs.cc | 132 +++++++- src/rpc_thallium_serialization.h | 40 +++ 11 files changed, 517 insertions(+), 29 deletions(-) create mode 100644 code_generators/code_generators/util/conv.py diff --git a/code_generators/code_generators/rpc/generator.py b/code_generators/code_generators/rpc/generator.py index 899202aea..2b32fab5d 100644 --- a/code_generators/code_generators/rpc/generator.py +++ b/code_generators/code_generators/rpc/generator.py @@ -1,6 +1,7 @@ import sys, os, re from code_generators.util.api import Api from code_generators.util.naming import to_snake_case +from code_generators.util.conv import str_to_bool rpc_func_text = """ {RET} {GLOBAL_NAME}({PARAMS}) {{ @@ -9,13 +10,22 @@ return {LOCAL_NAME}( {PASS_PARAMS}); }} else {{ - return rpc_->Call( + return rpc_->Call<{RET}>( target_node, "{GLOBAL_NAME}", {PASS_PARAMS}); }} }} """ +rpc_func_text2 = """ +{RET} {GLOBAL_NAME}({PARAMS}) {{ + u32 target_node = {TARGET_NODE}; + return rpc_->Call<{RET}>( + target_node, "{GLOBAL_NAME}", + {PASS_PARAMS}); +}} +""" + # Will add this to rpc_thallium.cc rpc_lambda_text = """ auto {LAMBDA_NAME} = @@ -27,7 +37,7 @@ """ class RpcGenerator: - def __init__(self, rpc_defs_path, modify): + def __init__(self, rpc_defs_path, modify=True): """ Automatically inserts RPC code into class files and builds rpc_thallium_defs.cc. @@ -36,11 +46,7 @@ def __init__(self, rpc_defs_path, modify): store temporary output in the working directory. """ - if modify != "True": - self.modify = False - else: - self.modify = True - + self.modify = str_to_bool(modify) self.path = None self.rpc_defs_path = rpc_defs_path self.macro = None diff --git a/code_generators/code_generators/util/api.py b/code_generators/code_generators/util/api.py index e05634490..2f80d350e 100644 --- a/code_generators/code_generators/util/api.py +++ b/code_generators/code_generators/util/api.py @@ -18,14 +18,17 @@ def _clean(self, toks): return [tok for tok in toks if tok is not None and len(tok) > 0] def get_arg_tuple(self, arg): - arg_toks = self._clean(re.split("[ ]|(\*+)", arg)) + arg_toks = self._clean(re.split("[ ]|(\*+)|(&+)", arg)) if len(arg_toks) == 1: if arg_toks[0] == '...': type = "" name = "..." return (type, name) type = " ".join(arg_toks[:-1]) + type = type.replace(" ", "") + type = type.replace("\n", "") name = arg_toks[-1] + name = name.replace(" ", "") return (type, name) def decompose_prototype(self, api_str): diff --git a/code_generators/code_generators/util/conv.py b/code_generators/code_generators/util/conv.py new file mode 100644 index 000000000..30c61694a --- /dev/null +++ b/code_generators/code_generators/util/conv.py @@ -0,0 +1,8 @@ + +def str_to_bool(text): + text = str(text).lower().strip() + if text == 'false': + return False + elif text == 'true': + return True + raise "Neither true or false (str_too_bool)" \ No newline at end of file diff --git a/code_generators/rpc.py b/code_generators/rpc.py index 109b3fb05..98659b5bb 100644 --- a/code_generators/rpc.py +++ b/code_generators/rpc.py @@ -4,7 +4,9 @@ USAGE: cd code_generators/bin - python3 rpc.py [whether or not to modify path or make tmpfiles] + python3 rpc.py [modify=True] + +modify: whether or not to modify actual source files. """ import sys @@ -13,11 +15,31 @@ rpc_defs_path = f"{HERMES_ROOT}/src/rpc_thallium_defs.cc" if len(sys.argv) < 2: - gen = RpcGenerator(rpc_defs_path, False) + gen = RpcGenerator(rpc_defs_path, True) else: gen = RpcGenerator(rpc_defs_path, sys.argv[1]) gen.set_file(f"{HERMES_ROOT}/src/metadata_manager.h", "MetadataManager", "mdm") -gen.add("LocalGetOrCreateBucket", "0") +gen.add("LocalGetOrCreateBucket", "rpc_->node_id_") +gen.add("LocalGetBucketId", "rpc_->node_id_") +gen.add("LocalBucketContainsBlob", "rpc_->node_id_") +gen.add("LocalRenameBucket", "rpc_->node_id_") +gen.add("LocalDestroyBucket", "rpc_->node_id_") +gen.add("LocalBucketPutBlob", "rpc_->node_id_") +gen.add("LocalGetBlobId", "rpc_->node_id_") +gen.add("LocalSetBlobBuffers", "rpc_->node_id_") +gen.add("LocalGetBlobBuffers", "rpc_->node_id_") +gen.add("LocalRenameBlob", "rpc_->node_id_") +gen.add("LocalDestroyBlob", "rpc_->node_id_") +gen.add("LocalWriteLockBlob", "rpc_->node_id_") +gen.add("LocalWriteUnlockBlob", "rpc_->node_id_") +gen.add("LocalReadLockBlob", "rpc_->node_id_") +gen.add("LocalReadUnlockBlob", "rpc_->node_id_") +gen.add("LocalGetOrCreateVBucket", "rpc_->node_id_") +gen.add("LocalGetVBucketId", "rpc_->node_id_") +gen.add("LocalUnlinkBlobVBucket", "rpc_->node_id_") +gen.add("LocalGetLinksVBucket", "rpc_->node_id_") +gen.add("LocalRenameVBucket", "rpc_->node_id_") +gen.add("LocalDestroyVBucket", "rpc_->node_id_") gen.generate() \ No newline at end of file diff --git a/config/hermes_server_default.yaml b/config/hermes_server_default.yaml index 6ecd2975e..37ec3564c 100644 --- a/config/hermes_server_default.yaml +++ b/config/hermes_server_default.yaml @@ -77,7 +77,7 @@ devices: is_shared_device: 0 borg_capacity_thresh: [ 0.0, 1.0 ] -### Define the network communication protocol +### Define properties of RPCs rpc: # A path to a file containing a list of server names, 1 per line. If your # servers are named according to a pattern (e.g., server-1, server-2, etc.), diff --git a/src/data_structures.h b/src/data_structures.h index edd0a6f48..b1da69fe4 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -9,6 +9,7 @@ #include #include #include +#include namespace lipc = labstor::ipc; namespace lipcl = labstor::ipc::lockless; diff --git a/src/hermes_types.h b/src/hermes_types.h index 702382388..2dbf55544 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -131,7 +131,6 @@ union BlobID { u64 as_int; bool IsNull() const { return as_int == 0; } - bool InSwap() const { return bits.node_id < 0; } i32 GetNodeId() const { return bits.node_id; } }; diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index a180d3aee..de84fd8fa 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -11,14 +11,8 @@ void MetadataManager::Init() { rpc_ = &HERMES->rpc_; } -bool MetadataManager::LocalGetOrCreateBucket(std::string name) { +BucketID MetadataManager::LocalGetOrCreateBucket(std::string name) { std::cout << "In bucket!" << std::endl; - return true; -} - -bool MetadataManager::GetOrCreateBucket(std::string name) { - return rpc_->Call( - rpc_->node_id_, "GetOrCreateBucket", name); } } // namespace hermes \ No newline at end of file diff --git a/src/metadata_manager.h b/src/metadata_manager.h index a010ba217..a3ccc24d9 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -12,22 +12,317 @@ namespace hermes { +using api::Blob; + +struct BufferInfo { + size_t off_; + size_t size_; + TargetID target_; +}; + +struct BlobInfo { + lipcl::charbuf name_; + std::vector buffers_; +}; + +struct BucketInfo { + lipcl::charbuf name_; + std::vector blobs_; +}; + +struct VBucketInfo { + std::vector name_; + std::vector blobs_; +}; + class MetadataManager { private: RPC_TYPE *rpc_; + std::unordered_map blob_id_map_; + std::unordered_map bkt_id_map_; + std::unordered_map vbkt_id_map_; + + std::unordered_map blob_map_; + std::unordered_map bkt_map_; + std::unordered_map vbkt_map_; public: MetadataManager() = default; void Init(); - RPC bool LocalGetOrCreateBucket(std::string bucket_name); + RPC BucketID LocalGetOrCreateBucket(std::string bkt_name); + RPC BucketID LocalGetBucketId(std::string bkt_name); + RPC bool LocalBucketContainsBlob(BucketID bkt_id, BlobID blob_id); + RPC bool LocalRenameBucket(BucketID bkt_id); + RPC bool LocalDestroyBucket(BucketID bkt_id); + + RPC BlobID LocalBucketPutBlob(BucketID bkt_id, + std::string blob_name, + Blob data, + std::vector &buffers); + RPC BlobID LocalGetBlobId(BucketID bkt_id, std::string blob_name); + RPC bool LocalSetBlobBuffers(BlobID blob_id, + std::vector &buffers); + RPC std::vector& + LocalGetBlobBuffers(BlobID blob_id); + RPC bool LocalRenameBlob(BucketID bkt_id, std::string new_blob_name); + RPC bool LocalDestroyBlob(BucketID bkt_id, std::string blob_name); + + RPC bool LocalWriteLockBlob(BlobID blob_id); + RPC bool LocalWriteUnlockBlob(BlobID blob_id); + RPC bool LocalReadLockBlob(BlobID blob_id); + RPC bool LocalReadUnlockBlob(BlobID blob_id); + + RPC VBucketID LocalGetOrCreateVBucket(std::string vbkt_name); + RPC VBucketID LocalGetVBucketId(std::string vbkt_name); + RPC VBucketID LocalLinkBlobVBucket(VBucketID vbkt_id, + BucketID bkt_id, + std::string blob_name); + RPC VBucketID LocalUnlinkBlobVBucket(VBucketID vbkt_id, + BucketID bkt_id, + std::string blob_name); + RPC std::list LocalGetLinksVBucket(VBucketID vbkt_id); + RPC bool LocalRenameVBucket(VBucketID vbkt_id, + std::string new_vbkt_name); + RPC bool LocalDestroyVBucket(VBucketID vbkt_id, + std::string new_vbkt_name); public: RPC_AUTOGEN_START - bool GetOrCreateBucket(std::string bucket_name); + RPC BucketID GetOrCreateBucket(std::string bkt_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetOrCreateBucket( + bkt_name); + } else { + return rpc_->Call( + target_node, "GetOrCreateBucket", + bkt_name); + } + } + RPC BucketID GetBucketId(std::string bkt_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetBucketId( + bkt_name); + } else { + return rpc_->Call( + target_node, "GetBucketId", + bkt_name); + } + } + RPC bool BucketContainsBlob(BucketID bkt_id, BlobID blob_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalBucketContainsBlob( + bkt_id, blob_id); + } else { + return rpc_->Call( + target_node, "BucketContainsBlob", + bkt_id, blob_id); + } + } + RPC bool RenameBucket(BucketID bkt_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalRenameBucket( + bkt_id); + } else { + return rpc_->Call( + target_node, "RenameBucket", + bkt_id); + } + } + RPC bool DestroyBucket(BucketID bkt_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalDestroyBucket( + bkt_id); + } else { + return rpc_->Call( + target_node, "DestroyBucket", + bkt_id); + } + } + RPC BlobID BucketPutBlob(BucketID bkt_id, std::string blob_name, Blob data, std::vector& buffers) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalBucketPutBlob( + bkt_id, blob_name, data, buffers); + } else { + return rpc_->Call( + target_node, "BucketPutBlob", + bkt_id, blob_name, data, buffers); + } + } + RPC BlobID GetBlobId(BucketID bkt_id, std::string blob_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetBlobId( + bkt_id, blob_name); + } else { + return rpc_->Call( + target_node, "GetBlobId", + bkt_id, blob_name); + } + } + RPC bool SetBlobBuffers(BlobID blob_id, std::vector& buffers) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalSetBlobBuffers( + blob_id, buffers); + } else { + return rpc_->Call( + target_node, "SetBlobBuffers", + blob_id, buffers); + } + } + RPC std::vector& GetBlobBuffers(BlobID blob_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetBlobBuffers( + blob_id); + } else { + return rpc_->Call&>( + target_node, "GetBlobBuffers", + blob_id); + } + } + RPC bool RenameBlob(BucketID bkt_id, std::string new_blob_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalRenameBlob( + bkt_id, new_blob_name); + } else { + return rpc_->Call( + target_node, "RenameBlob", + bkt_id, new_blob_name); + } + } + RPC bool DestroyBlob(BucketID bkt_id, std::string blob_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalDestroyBlob( + bkt_id, blob_name); + } else { + return rpc_->Call( + target_node, "DestroyBlob", + bkt_id, blob_name); + } + } + RPC bool WriteLockBlob(BlobID blob_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalWriteLockBlob( + blob_id); + } else { + return rpc_->Call( + target_node, "WriteLockBlob", + blob_id); + } + } + RPC bool WriteUnlockBlob(BlobID blob_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalWriteUnlockBlob( + blob_id); + } else { + return rpc_->Call( + target_node, "WriteUnlockBlob", + blob_id); + } + } + RPC bool ReadLockBlob(BlobID blob_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalReadLockBlob( + blob_id); + } else { + return rpc_->Call( + target_node, "ReadLockBlob", + blob_id); + } + } + RPC bool ReadUnlockBlob(BlobID blob_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalReadUnlockBlob( + blob_id); + } else { + return rpc_->Call( + target_node, "ReadUnlockBlob", + blob_id); + } + } + RPC VBucketID GetOrCreateVBucket(std::string vbkt_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetOrCreateVBucket( + vbkt_name); + } else { + return rpc_->Call( + target_node, "GetOrCreateVBucket", + vbkt_name); + } + } + RPC VBucketID GetVBucketId(std::string vbkt_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetVBucketId( + vbkt_name); + } else { + return rpc_->Call( + target_node, "GetVBucketId", + vbkt_name); + } + } + RPC VBucketID UnlinkBlobVBucket(VBucketID vbkt_id, BucketID bkt_id, std::string blob_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalUnlinkBlobVBucket( + vbkt_id, bkt_id, blob_name); + } else { + return rpc_->Call( + target_node, "UnlinkBlobVBucket", + vbkt_id, bkt_id, blob_name); + } + } + RPC std::list GetLinksVBucket(VBucketID vbkt_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetLinksVBucket( + vbkt_id); + } else { + return rpc_->Call>( + target_node, "GetLinksVBucket", + vbkt_id); + } + } + RPC bool RenameVBucket(VBucketID vbkt_id, std::string new_vbkt_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalRenameVBucket( + vbkt_id, new_vbkt_name); + } else { + return rpc_->Call( + target_node, "RenameVBucket", + vbkt_id, new_vbkt_name); + } + } + RPC bool DestroyVBucket(VBucketID vbkt_id, std::string new_vbkt_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalDestroyVBucket( + vbkt_id, new_vbkt_name); + } else { + return rpc_->Call( + target_node, "DestroyVBucket", + vbkt_id, new_vbkt_name); + } + } RPC_AUTOGEN_END }; } // namespace hermes -#endif // HERMES_SRC_METADATA_MANAGER_H_ +#endif // HERMES_SRC_METADATA_MANAGER_H_ \ No newline at end of file diff --git a/src/rpc_thallium_defs.cc b/src/rpc_thallium_defs.cc index a6b118b6b..3c768d493 100644 --- a/src/rpc_thallium_defs.cc +++ b/src/rpc_thallium_defs.cc @@ -15,12 +15,132 @@ void ThalliumRpc::DefineRpcs() { RPC_CLASS_INSTANCE_DEFS_END RPC_AUTOGEN_START - auto get_or_create_bucket = - [this](const request &req, std::string name) { - this->mdm_->LocalGetOrCreateBucket(name); - req.respond(true); - }; - server_engine_->define("GetOrCreateBucket", get_or_create_bucket); + auto rpc_get_or_create_bucket = + [mdm](const request &req, std::string bkt_name) { + auto result = mdm->LocalGetOrCreateBucket(bkt_name); + req.respond(result); + }; + server_engine_->define("GetOrCreateBucket", rpc_get_or_create_bucket); + auto rpc_get_bucket_id = + [mdm](const request &req, std::string bkt_name) { + auto result = mdm->LocalGetBucketId(bkt_name); + req.respond(result); + }; + server_engine_->define("GetBucketId", rpc_get_bucket_id); + auto rpc_bucket_contains_blob = + [mdm](const request &req, BucketID bkt_id, BlobID blob_id) { + auto result = mdm->LocalBucketContainsBlob(bkt_id, blob_id); + req.respond(result); + }; + server_engine_->define("BucketContainsBlob", rpc_bucket_contains_blob); + auto rpc_rename_bucket = + [mdm](const request &req, BucketID bkt_id) { + auto result = mdm->LocalRenameBucket(bkt_id); + req.respond(result); + }; + server_engine_->define("RenameBucket", rpc_rename_bucket); + auto rpc_destroy_bucket = + [mdm](const request &req, BucketID bkt_id) { + auto result = mdm->LocalDestroyBucket(bkt_id); + req.respond(result); + }; + server_engine_->define("DestroyBucket", rpc_destroy_bucket); + auto rpc_bucket_put_blob = + [mdm](const request &req, BucketID bkt_id, std::string blob_name, Blob data, std::vector& buffers) { + auto result = mdm->LocalBucketPutBlob(bkt_id, blob_name, data, buffers); + req.respond(result); + }; + server_engine_->define("BucketPutBlob", rpc_bucket_put_blob); + auto rpc_get_blob_id = + [mdm](const request &req, BucketID bkt_id, std::string blob_name) { + auto result = mdm->LocalGetBlobId(bkt_id, blob_name); + req.respond(result); + }; + server_engine_->define("GetBlobId", rpc_get_blob_id); + auto rpc_set_blob_buffers = + [mdm](const request &req, BlobID blob_id, std::vector& buffers) { + auto result = mdm->LocalSetBlobBuffers(blob_id, buffers); + req.respond(result); + }; + server_engine_->define("SetBlobBuffers", rpc_set_blob_buffers); + auto rpc_get_blob_buffers = + [mdm](const request &req, BlobID blob_id) { + auto result = mdm->LocalGetBlobBuffers(blob_id); + req.respond(result); + }; + server_engine_->define("GetBlobBuffers", rpc_get_blob_buffers); + auto rpc_rename_blob = + [mdm](const request &req, BucketID bkt_id, std::string new_blob_name) { + auto result = mdm->LocalRenameBlob(bkt_id, new_blob_name); + req.respond(result); + }; + server_engine_->define("RenameBlob", rpc_rename_blob); + auto rpc_destroy_blob = + [mdm](const request &req, BucketID bkt_id, std::string blob_name) { + auto result = mdm->LocalDestroyBlob(bkt_id, blob_name); + req.respond(result); + }; + server_engine_->define("DestroyBlob", rpc_destroy_blob); + auto rpc_write_lock_blob = + [mdm](const request &req, BlobID blob_id) { + auto result = mdm->LocalWriteLockBlob(blob_id); + req.respond(result); + }; + server_engine_->define("WriteLockBlob", rpc_write_lock_blob); + auto rpc_write_unlock_blob = + [mdm](const request &req, BlobID blob_id) { + auto result = mdm->LocalWriteUnlockBlob(blob_id); + req.respond(result); + }; + server_engine_->define("WriteUnlockBlob", rpc_write_unlock_blob); + auto rpc_read_lock_blob = + [mdm](const request &req, BlobID blob_id) { + auto result = mdm->LocalReadLockBlob(blob_id); + req.respond(result); + }; + server_engine_->define("ReadLockBlob", rpc_read_lock_blob); + auto rpc_read_unlock_blob = + [mdm](const request &req, BlobID blob_id) { + auto result = mdm->LocalReadUnlockBlob(blob_id); + req.respond(result); + }; + server_engine_->define("ReadUnlockBlob", rpc_read_unlock_blob); + auto rpc_get_or_create_v_bucket = + [mdm](const request &req, std::string vbkt_name) { + auto result = mdm->LocalGetOrCreateVBucket(vbkt_name); + req.respond(result); + }; + server_engine_->define("GetOrCreateVBucket", rpc_get_or_create_v_bucket); + auto rpc_get_v_bucket_id = + [mdm](const request &req, std::string vbkt_name) { + auto result = mdm->LocalGetVBucketId(vbkt_name); + req.respond(result); + }; + server_engine_->define("GetVBucketId", rpc_get_v_bucket_id); + auto rpc_unlink_blob_v_bucket = + [mdm](const request &req, VBucketID vbkt_id, BucketID bkt_id, std::string blob_name) { + auto result = mdm->LocalUnlinkBlobVBucket(vbkt_id, bkt_id, blob_name); + req.respond(result); + }; + server_engine_->define("UnlinkBlobVBucket", rpc_unlink_blob_v_bucket); + auto rpc_get_links_v_bucket = + [mdm](const request &req, VBucketID vbkt_id) { + auto result = mdm->LocalGetLinksVBucket(vbkt_id); + req.respond(result); + }; + server_engine_->define("GetLinksVBucket", rpc_get_links_v_bucket); + auto rpc_rename_v_bucket = + [mdm](const request &req, VBucketID vbkt_id, std::string new_vbkt_name) { + auto result = mdm->LocalRenameVBucket(vbkt_id, new_vbkt_name); + req.respond(result); + }; + server_engine_->define("RenameVBucket", rpc_rename_v_bucket); + auto rpc_destroy_v_bucket = + [mdm](const request &req, VBucketID vbkt_id, std::string new_vbkt_name) { + auto result = mdm->LocalDestroyVBucket(vbkt_id, new_vbkt_name); + req.respond(result); + }; + server_engine_->define("DestroyVBucket", rpc_destroy_v_bucket); RPC_AUTOGEN_END } diff --git a/src/rpc_thallium_serialization.h b/src/rpc_thallium_serialization.h index dd81c0e8d..0a67340f2 100644 --- a/src/rpc_thallium_serialization.h +++ b/src/rpc_thallium_serialization.h @@ -11,6 +11,46 @@ #include namespace hermes { + +/** + * Lets Thallium know how to serialize a VBucketID. + * + * This function is called implicitly by Thallium. + * + * @param ar An archive provided by Thallium. + * @param vbucket_id The VBucketID to serialize. + */ +template +void serialize(A &ar, VBucketID &vbucket_id) { + ar &vbucket_id.as_int; +} + +/** + * Lets Thallium know how to serialize a BlobID. + * + * This function is called implicitly by Thallium. + * + * @param ar An archive provided by Thallium. + * @param blob_id The BlobID to serialize. + */ +template +void serialize(A &ar, BlobID &blob_id) { + ar &blob_id.as_int; +} + +/** + * Lets Thallium know how to serialize a TargetID. + * + * This function is called implicitly by Thallium. + * + * @param ar An archive provided by Thallium. + * @param target_id The TargetID to serialize. + */ +template +void serialize(A &ar, TargetID &target_id) { + ar &target_id.as_int; +} + } // namespace hermes namespace hermes::api { From eadcceb15b4d477fe15c0dcb946e89dbaaea5c81 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Tue, 6 Dec 2022 04:57:21 -0600 Subject: [PATCH 055/511] Generic API decorator parser --- code_generators/code_generators/util/api.py | 460 ++++++++++++++++++-- src/api/bucket.h | 70 ++- src/data_structures.h | 10 + src/decorator.h | 30 ++ src/metadata_manager.h | 111 ++++- src/rpc.h | 2 +- src/rpc_decorator.h | 14 - 7 files changed, 645 insertions(+), 52 deletions(-) create mode 100644 src/decorator.h delete mode 100644 src/rpc_decorator.h diff --git a/code_generators/code_generators/util/api.py b/code_generators/code_generators/util/api.py index 2f80d350e..fff50e2e6 100644 --- a/code_generators/code_generators/util/api.py +++ b/code_generators/code_generators/util/api.py @@ -1,37 +1,36 @@ import sys, os, re class Api: - def __init__(self, api_str): - self.api_str = api_str + """ + Parses a C++ function prototype to determine: + 1. The arguments to the function + 2. The return value of the function + 3. The function decorators + 4. The function template + """ + + def __init__(self, api_str, template_str=None): + self.api_str = api_str # Original C++ API string + self.template_str = template_str # Original C++ API template string self.name = None # The name of the API self.ret = None # Return value of the API self.var_defs = None # The variables in the API - self.decompose_prototype(api_str) - - def _is_text(self, tok): - first_is_text = re.match("[_a-zA-Z]", tok[0]) is not None - if not first_is_text: - return False - return re.match("[_a-zA-Z0-9]+", tok) is not None + self.decorators = None # The set of function decorators + self._decompose_prototype(api_str) def _clean(self, toks): return [tok for tok in toks if tok is not None and len(tok) > 0] - def get_arg_tuple(self, arg): - arg_toks = self._clean(re.split("[ ]|(\*+)|(&+)", arg)) - if len(arg_toks) == 1: - if arg_toks[0] == '...': - type = "" - name = "..." - return (type, name) - type = " ".join(arg_toks[:-1]) - type = type.replace(" ", "") - type = type.replace("\n", "") - name = arg_toks[-1] - name = name.replace(" ", "") - return (type, name) + def _decompose_prototype(self, api_str): + """ + Parses a C++ api string - def decompose_prototype(self, api_str): + :param api_str: the C++ api to parse + :return: None. But modifies the name, type, parameters, + and decorators of this class + """ + + # Split by parenthesis and semicolon toks = self._clean(re.split("[()]|;", api_str)) proto, args = toks[0], toks[1] @@ -47,12 +46,47 @@ def decompose_prototype(self, api_str): self.var_defs = [] args = args.split(',') for arg in args: - self.var_defs.append(self.get_arg_tuple(arg)) + self.var_defs.append(self._get_arg_tuple(arg)) except: print(f"Failed to decompose proto args: {args}") exit(1) + def _get_arg_tuple(self, arg): + """ + Parse a function argument into a type and name. + E.g., int hi -> (int, hi) + + :param arg: The C++ text representing a function argument + :return: (type, name) + """ + + arg_toks = self._clean(re.split("[ ]|(\*+)|(&+)", arg)) + if len(arg_toks) == 1: + if arg_toks[0] == '...': + type = "" + name = "..." + return (type, name) + type = " ".join(arg_toks[:-1]) + type = type.replace(" ", "") + type = type.replace("\n", "") + name = arg_toks[-1] + name = name.replace(" ", "") + return (type, name) + def get_args(self): + """ + Create string to forward the parameters + passed to this API to another API + + Example: + Hello(int a, int b, int c) { + Hello2(a, b, c); + } + "int a, int b, int c" would be the return value of get_args + + :return: Typed argument list + """ + if len(self.var_defs) == 0: return "" try: @@ -63,7 +97,383 @@ def get_args(self): return ", ".join(args) def pass_args(self): + """ + Create string to forward the parameters + passed to this API to another API + + Example: + Hello(int a, int b, int c) { + Hello2(a, b, c); + } + "a, b, c" is the return value of pass_args + + :return: Untyped argument list + """ + if self.var_defs is None: return "" args = [arg[-1] for arg in self.var_defs if arg[0] != ''] - return ", ".join(args) \ No newline at end of file + return ", ".join(args) + +class ParseDecoratedCppApis: + """ + Parse a C++ header file and get the set of all decorated prototypes + and autogen statements. This parser makes various assumptions about + the C++ style. These are defined in: + _is_class, _is_namespace, _is_api + :return: self.api_map + [namespace+class]['apis'][api_name] -> API() + [namespace+class]['start'] -> autogen macro start + [namespace+class]['end'] -> autogen macro end + [namespace+class]['indent'] -> autogen macro indentation + """ + + def __init__(self, hpp_file, api_dec=None, autogen_dec=None, + ignore_autogen_ns=False): + """ + Load the C++ header file and clean out commented lines + + :param hpp_file: the path to the C++ header file to parse + :param api_dec: the name of the API decorator to search for + :param autogen_dec: the name of the code autogen statement + to search for + :param ignore_autogen_ns: whether or not to consider the + namespace the autogen macros are apart of + """ + self.hpp_file = hpp_file + self.api_dec = api_dec + self.autogen_dec = autogen_dec + self.api_map = {} + + # Load class file lines, but remove excess newlines and comments + with open(self.hpp_file) as fp: + class_lines = fp.read().splitlines() + class_lines = list(enumerate(class_lines)) + self.class_lines = self._clean_lines(class_lines) + self.only_class_lines = list(zip(*self.class_lines))[1] + + def set_decorators(self, api_dec, autogen_dec, ignore_autogen_ns=False): + self.api_dec = api_dec + self.autogen_dec = autogen_dec + self.autogen_dec_start = f"{self.autogen_dec}_START" + self.autogen_dec_end = f"{self.autogen_dec}_END" + self.ignore_autogen_ns = ignore_autogen_ns + + def _clean_lines(self, class_lines): + """ + Removes all lines encapsulated between /* and */. + Removes all excessive newlines + Intended to remove classes which have been commented out. + + :param class_lines: the lines in the class file + :return: a subset of the class_lines + """ + # Remove newlines + class_lines = [(i, line) for i, line in class_lines if len(line)] + + # Remove comments + new_lines = [] + in_comment = False + for i, line in class_lines: + if self._is_comment_start(line): + in_comment = True + if self._is_comment_end(line): + in_comment = False + continue + if self._is_comment_end(line): + in_comment = False + continue + if in_comment: + continue + new_lines.append((i, line)) + return new_lines + + def _is_comment_start(self, line): + """ + Determines if a line begins with /* (excluding whitespace) + + :param line: the line of the C++ file to check + :return: True or False + """ + + return '/*' == line.strip()[0:2] + + def _is_comment_end(self, line): + """ + Determines if a line ends with */ (excluding whitespace) + + :param line: the line of the C++ file to check + :return: True or False + """ + + return '*/' == line.strip()[-2:] + + def parse(self, namespace=None, start=None, end=None): + if start == None: + start = 0 + if end == None: + end = len(self.class_lines) + i = start + while i < end: + if self._is_namespace(i) or self._is_class(i): + i = self._parse_class_or_ns(namespace, i) + continue + elif self._is_api(i): + i = self._parse_api(namespace, i) + continue + elif self._is_autogen(namespace, i): + i = self._parse_autogen(namespace, i) + i += 1 + return i + + def _parse_api(self, namespace, i): + """ + Determines the set of text belonging to a particular API. + ASSUMPTIONS: + 1. If templated, the prior line must end with a ">" + VALID: + template + > + RPC void hello() {} + INVALID: + template RPC void hello(); + 2. The end of the argument list is always on the same line as + either the terminating semicolon or curly brace + VALID: + RPC void hello() { + } + + RPC void hello2(); + INVALID + RPC void hello() + {} + + RP + + :param namespace: the C++ namespace + class the API belongs to + :param i: the line containing part of the API definition + :return: None. Modifies the + """ + + tmpl_str = self._get_template_str(i) + api_str,api_end = self._get_api_str(i) + api = Api(api_str, tmpl_str) + self._induct_namespace(namespace) + self.api_map[namespace][api.name] = api + return api_end + + def _get_template_str(self, i): + """ + Starting at i, parses upwards until the template keyword is reached. + + :param i: The start of the function API + :return: The template text + """ + + if i == 0: + return None + if '>' not in self.only_class_lines[i-1]: + return None + tmpl_i = None + for class_line in reversed(self.only_class_lines[:i-1]): + toks = class_line.split() + if 'template' in toks[0]: + tmpl_i = i + break + i -= 1 + if tmpl_i is None: + return None + tmpl_str = self.only_class_lines[tmpl_i:i] + return tmpl_str + + def _get_api_str(self, i): + """ + Gets the set of text encompassing the entire API string + + :param i: the first line of the API + :return: the API text + """ + + api_end = i + for line in self.only_class_lines[i:]: + if ');' in line: + break + if ':' in line: + break + if ') {' in line: + break + api_end += 1 + api_str = "\n".join(self.only_class_lines[i:api_end+1]) + return api_str, api_end + + def _parse_class_or_ns(self, namespace, i): + """ + Parse all APIs within the boundaries of a class or namespace. + + ASSUMPTIONS: + 1. A class is terminated with the first }; that has equivalent + indentation to the class declaration + VALID: + class hello { + }; // "class" and }; are aligned vertically + INVALID: + class hello { + }; // "class" and }; are misaligned vertically + + :param namespace: the current namespace the class is apart of + :param i: The line to start parsing at + :return: The index of the terminating }; + """ + + # Get the class name + indentation + line = self.class_lines[i][1] + toks = re.split("[ :]", line) + toks = [tok for tok in toks if tok is not None and len(tok)] + class_name = toks[1] + indent = self._indent() + # Find the end of the class (};) + end = i + end_of_class = f"{indent}}};" + for off, line in enumerate(self.class_lines[i+1:]): + if end_of_class == line[0:len(end_of_class)]: + end += off + break + # Parse all lines for prototypes + namespace = self._ns_append(namespace, class_name) + return self.parse(namespace, i+1, end) + + def _parse_autogen(self, namespace, i): + """ + Parse the AUTOGEN keyword statements for a particular namespace + + :param namespace: the current namespace the autogen is apart of + :param i: The line to start parsing at + :return: + """ + + if self.ignore_autogen_ns: + namespace = None + self._induct_namespace(namespace) + line = self.only_class_lines[i].strip() + if line == self.autogen_dec_start: + self.api_map[namespace]['start'] = i + self.api_map[namespace]['indent'] = self._indent(line) + else: + self.api_map[namespace]['end'] = i + return line + + def _is_namespace(self, i): + """ + Determine whether a tokenized line defines a C++ namespace. + + ASSUMPTIONS: + 1. A namespace is defined entirely on a single line + VALID: + namespace hello { + INVALID: + namespace hello + { + + :param i: The line to start parsing at + :return: True or False + """ + line = self.only_class_lines[i] + toks = line.split() + # "namespace hello {" (is 3 tokens) + if len(toks) < 3: + return False + if toks[0] != 'namespace': + return False + if toks[2] != '{': + return False + + def _is_class(self, i): + """ + Determine whether a tokenized line defines a C++ class definition. + Ignores class declarations (e.g., class hello;). + + ASSUMPTIONS: + 1. Class definitions do not contain any ';', which may be possible + in very boundary-case circumstances. + VALID: + class hello { + class hello : public language { + class hello : public language { + class hello : public language { + class hello: + public language + { + INVALID: + class hello : public language { + + :param i: The line to start parsing at + :return: True or False + """ + + line = self.only_class_lines[i] + toks = line.split() + if len(toks) < 2: + return False + if toks[0] != 'class': + return False + for true_i, line in self.class_lines[i:]: + toks = line.split() + if toks[-1] == ';': + return False + if toks[-1] == '{': + return True + raise f"class {toks[1]} definition missing either ; or {{" + + def _is_api(self, i): + """ + Determine whether a line defines a class method or function + ASSUMPTIONS: + 1. The function is marked with an API decorator + + :param i: The line to start parsing at + :return: True or False + """ + + line = self.only_class_lines[i] + toks = line.split() + # Determine if the line has a decorator + for tok in toks: + if tok == self.api_dec: + return True + return False + + def _is_autogen(self, i): + """ + Determine whether a line encompasses the autogen headers + + :param i: The line to start parsing at + :return: True or False + """ + + line = self.only_class_lines[i].strip() + if line == self.autogen_dec_start: + return True + if line == self.autogen_dec_end: + return True + return False + + def _induct_namespace(self, namespace): + if namespace not in self.api_map: + self.api_map[namespace] = { + 'apis': {}, + 'start': None, + 'end': None, + 'indent': None + } + + @staticmethod + def _ns_append(namespace, suffix): + if namespace is None or len(namespace) == 0: + return suffix + return namespace + suffix + + @staticmethod + def _indent(line): + ilen = len(line) - len(line.lstrip()) + return line[0:ilen] \ No newline at end of file diff --git a/src/api/bucket.h b/src/api/bucket.h index cfdc307e1..5d15ad588 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -14,14 +14,78 @@ namespace hermes::api { class Bucket { private: MetadataManager *mdm_; + BucketID id_; + std::string name_; + Context ctx_; + /* Bucket operations */ public: - Bucket(std::string name, + + /** + * Get or create \a bkt_name bucket. + * + * Called from hermes.h in GetBucket(). Should not + * be used directly. + * */ + Bucket(std::string bkt_name, Context &ctx); - /* std::string GetName() const; + /** + * Get the name of this bucket. Name is cached instead of + * making an RPC. Not coherent if Rename is called. + * */ + std::string GetName() const { + return name_; + } + + /** + * Get the identifier of this bucket + * */ + BucketID GetId() const { + return id_; + } + + /** + * Rename this bucket + * */ + void Rename(std::string new_bkt_name); + + /** + * Destroys this bucket along with all its contents. + * */ + void Destroy(std::string blob_name); + + + /* Blob operations */ + public: + + /** + * Put \a blob_name Blob into the bucket + * */ + Status PutBlob(std::string blob_name, Blob &blob, + Context &ctx); + + /** + * Put \a blob_id Blob into the bucket + * */ + Status PutBlob(BlobID blob_id, Blob &blob, + Context &ctx); - u64 GetId() const; */ + /** + * Get \a blob_name Blob from the bucket + * */ + Status GetBlob(std::string blob_name, Blob &blob, + Context &ctx); + + /** + * Get \a blob_id Blob from the bucket + * */ + Status GetBlob(BlobID blob_id, Blob &blob, + Context &ctx); + + public: + CONTEXT_AUTOGEN_START + CONTEXT_AUTOGEN_END public: RPC_AUTOGEN_START diff --git a/src/data_structures.h b/src/data_structures.h index b1da69fe4..af900db71 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -14,4 +14,14 @@ namespace lipc = labstor::ipc; namespace lipcl = labstor::ipc::lockless; +using labstor::RwLock; +using labstor::Mutex; + +#include +#include +#include +#include +#include +#include + #endif // HERMES_SRC_DATA_STRUCTURES_H_ diff --git a/src/decorator.h b/src/decorator.h new file mode 100644 index 000000000..1d6124cf9 --- /dev/null +++ b/src/decorator.h @@ -0,0 +1,30 @@ +// +// Created by lukemartinlogan on 12/1/22. +// + +#ifndef HERMES_SRC_RPC_GENERATOR_DECORATOR_H_ +#define HERMES_SRC_RPC_GENERATOR_DECORATOR_H_ + +/** + * Decorators for RPC code generation + * + * code_generators/rpc.py + * */ +#define RPC +#define RPC_AUTOGEN_START +#define RPC_AUTOGEN_END +#define RPC_CLASS_INSTANCE_DEFS_START +#define RPC_CLASS_INSTANCE_DEFS_END + +/** + * In many cases, we define functions which have a large parameter + * set and then produce wrapper functions which set those parameters + * differently. These decorators automate generating those wrapper + * functions + * */ + +#define WRAP(...) +#define WRAP_AUTOGEN_START +#define WRAP_AUTOGEN_END + +#endif // HERMES_SRC_RPC_GENERATOR_DECORATOR_H_ diff --git a/src/metadata_manager.h b/src/metadata_manager.h index a3ccc24d9..1dd1e9ea9 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -5,7 +5,7 @@ #ifndef HERMES_SRC_METADATA_MANAGER_H_ #define HERMES_SRC_METADATA_MANAGER_H_ -#include "rpc_decorator.h" +#include "decorator.h" #include "hermes_types.h" #include "hermes_status.h" #include "rpc.h" @@ -23,6 +23,7 @@ struct BufferInfo { struct BlobInfo { lipcl::charbuf name_; std::vector buffers_; + RwLock rwlock_; }; struct BucketInfo { @@ -32,7 +33,7 @@ struct BucketInfo { struct VBucketInfo { std::vector name_; - std::vector blobs_; + std::unordered_set blobs_; }; class MetadataManager { @@ -50,42 +51,134 @@ class MetadataManager { MetadataManager() = default; void Init(); + /** + * Get or create a bucket with \a bkt_name bucket name + * */ RPC BucketID LocalGetOrCreateBucket(std::string bkt_name); + + /** + * Get the BucketID with \a bkt_name bucket name + * */ RPC BucketID LocalGetBucketId(std::string bkt_name); + + /** + * Check whether or not \a bkt_id bucket contains + * \a blob_id blob + * */ RPC bool LocalBucketContainsBlob(BucketID bkt_id, BlobID blob_id); - RPC bool LocalRenameBucket(BucketID bkt_id); + + /** + * Rename \a bkt_id bucket to \a new_bkt_name new name + * */ + RPC bool LocalRenameBucket(BucketID bkt_id, std::string new_bkt_name); + + /** + * Destroy \a bkt_id bucket + * */ RPC bool LocalDestroyBucket(BucketID bkt_id); + /** + * Put a blob in a bucket + * + * @param bkt_id id of the bucket + * @param blob_name semantic blob name + * @param data the data being placed + * @param buffers the buffers to place data in + * */ RPC BlobID LocalBucketPutBlob(BucketID bkt_id, std::string blob_name, Blob data, std::vector &buffers); + + /** + * Get \a blob_name blob from \a bkt_id bucket + * */ RPC BlobID LocalGetBlobId(BucketID bkt_id, std::string blob_name); + + /** + * Change \a blob_id blob's buffers to \the buffers + * */ RPC bool LocalSetBlobBuffers(BlobID blob_id, std::vector &buffers); + + /** + * Get \a blob_id blob's buffers + * */ RPC std::vector& LocalGetBlobBuffers(BlobID blob_id); - RPC bool LocalRenameBlob(BucketID bkt_id, std::string new_blob_name); + + /** + * Rename \a blob_id blob to \a new_blob_name new blob name + * in \a bkt_id bucket. + * */ + RPC bool LocalRenameBlob(BucketID bkt_id, + BlobID blob_id, std::string new_blob_name); + + /** + * Destroy \a blob_id blob in \a bkt_id bucket + * */ RPC bool LocalDestroyBlob(BucketID bkt_id, std::string blob_name); + /** + * Acquire \a blob_id blob's write lock + * */ RPC bool LocalWriteLockBlob(BlobID blob_id); + + /** + * Release \a blob_id blob's write lock + * */ RPC bool LocalWriteUnlockBlob(BlobID blob_id); + + /** + * Acquire \a blob_id blob's read lock + * */ RPC bool LocalReadLockBlob(BlobID blob_id); + + /** + * Release \a blob_id blob's read lock + * */ RPC bool LocalReadUnlockBlob(BlobID blob_id); + /** + * Get or create \a vbkt_name VBucket + * */ RPC VBucketID LocalGetOrCreateVBucket(std::string vbkt_name); + + /** + * Get the VBucketID of \a vbkt_name VBucket + * */ RPC VBucketID LocalGetVBucketId(std::string vbkt_name); - RPC VBucketID LocalLinkBlobVBucket(VBucketID vbkt_id, + + /** + * Link \a vbkt_id VBucketID + * */ + RPC VBucketID LocalVBucketLinkBlob(VBucketID vbkt_id, BucketID bkt_id, std::string blob_name); - RPC VBucketID LocalUnlinkBlobVBucket(VBucketID vbkt_id, + + /** + * Unlink \a blob_name Blob of \a bkt_id Bucket + * from \a vbkt_id VBucket + * */ + RPC VBucketID LocalVBucketUnlinkBlob(VBucketID vbkt_id, BucketID bkt_id, std::string blob_name); - RPC std::list LocalGetLinksVBucket(VBucketID vbkt_id); + + /** + * Get the linked blobs from \a vbkt_id VBucket + * */ + RPC std::list LocalVBucketGetLinks(VBucketID vbkt_id); + + /** + * Rename \a vbkt_id VBucket to \a new_vbkt_name name + * */ RPC bool LocalRenameVBucket(VBucketID vbkt_id, std::string new_vbkt_name); - RPC bool LocalDestroyVBucket(VBucketID vbkt_id, - std::string new_vbkt_name); + + /** + * Destroy \a vbkt_id VBucket + * */ + RPC bool LocalDestroyVBucket(VBucketID vbkt_id); public: RPC_AUTOGEN_START diff --git a/src/rpc.h b/src/rpc.h index 1b0d382ec..dc29e910f 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -23,7 +23,7 @@ #include "hermes_types.h" #include "communication.h" -#include "rpc_decorator.h" +#include "decorator.h" #include "config.h" #include "utils.h" diff --git a/src/rpc_decorator.h b/src/rpc_decorator.h deleted file mode 100644 index 0931d8853..000000000 --- a/src/rpc_decorator.h +++ /dev/null @@ -1,14 +0,0 @@ -// -// Created by lukemartinlogan on 12/1/22. -// - -#ifndef HERMES_SRC_RPC_GENERATOR_DECORATOR_H_ -#define HERMES_SRC_RPC_GENERATOR_DECORATOR_H_ - -#define RPC -#define RPC_AUTOGEN_START -#define RPC_AUTOGEN_END -#define RPC_CLASS_INSTANCE_DEFS_START -#define RPC_CLASS_INSTANCE_DEFS_END - -#endif // HERMES_SRC_RPC_GENERATOR_DECORATOR_H_ From 69618486302fd8a995c91f6b9b7a1cf03ef51ed7 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Tue, 6 Dec 2022 05:20:44 -0600 Subject: [PATCH 056/511] Use generic generator in RPC generator --- .../code_generators/rpc/generator.py | 129 +++++++----------- code_generators/code_generators/util/api.py | 11 +- 2 files changed, 52 insertions(+), 88 deletions(-) diff --git a/code_generators/code_generators/rpc/generator.py b/code_generators/code_generators/rpc/generator.py index 2b32fab5d..209120a33 100644 --- a/code_generators/code_generators/rpc/generator.py +++ b/code_generators/code_generators/rpc/generator.py @@ -1,5 +1,5 @@ import sys, os, re -from code_generators.util.api import Api +from code_generators.util.api import Api, ParseDecoratedCppApis from code_generators.util.naming import to_snake_case from code_generators.util.conv import str_to_bool @@ -62,7 +62,7 @@ def set_file(self, path, class_name, class_instance): :param path: the path to the class containing RPC prototypes (e.g., metadata_manager.h) :param class_name: the name of the class to scan prototypes from - (e.g., MetadataManager) + (e.g., hermes::MetadataManager). Namespace is required. :param class_instance: The name of the C++ class instance to input into the RPC lambda in rpc_thallium_defs.cc (e.g., mdm). These are encapsulated in RPC_CLASS_INSTANCE_DEFS in rpc_thallium_defs.cc. @@ -104,7 +104,7 @@ def generate(self): def generate_class_file(self, path, class_rpcs, rpc_lambdas): """ - Generates the RPCs for a particular class file + Generates the RPCs (GlobalRPC + lambda) for a particular class file (e.g., metadata_manager.h) :param path: the path to the C++ class file (e.g., metadata_manager.h) @@ -112,33 +112,43 @@ def generate_class_file(self, path, class_rpcs, rpc_lambdas): :param rpc_lambdas: (output) :return: Modifies rpc_lambdas and the C++ class file. """ - - with open(path) as fp: - class_lines = fp.read().splitlines() - rpc_map = self.get_rpcs_from_class(class_lines) + + # Parse class file (e.g., metadata_manager.h) + gen = ParseDecoratedCppApis(path, + api_dec='RPC', + autogen_dec='RPC_AUTOGEN') + gen.parse() + rpc_map = gen.api_map + class_lines = gen.orig_class_lines + + # Autogen RPCs for each class for class_name, rpcs in class_rpcs.items(): - # Find RPC_AUTOGEN_START and RPC_AUTOGEN_END - gen_start = rpc_map[class_name]['gen_start'] - gen_end = rpc_map[class_name]['gen_end'] - # Get the amount of space in front of RPC_AUTOGEN_START - space = self.get_macro_space(class_lines[gen_start]) - # + # Get the autogen start + gen_start = rpc_map[class_name]['start'] + gen_end = rpc_map[class_name]['end'] + indent = rpc_map[class_name]['indent'] global_rpc_funcs = [] + + # Create lambda + global RPC for rpc in rpcs: local_rpc_name = rpc[0] target_node = rpc[1] class_instance = rpc[2] local_rpc_api = rpc_map[class_name]['apis'][local_rpc_name] self.create_global_rpc_func(local_rpc_api, target_node, - space, global_rpc_funcs) + indent, global_rpc_funcs) self.create_rpc_lambda(local_rpc_api, class_instance, - space, rpc_lambdas) + indent, rpc_lambdas) + # Remove previous autogen data class_lines = class_lines[:gen_start+1] + class_lines[gen_end:] + + # Insert new autogen data class_lines = class_lines[:gen_start + 1] + \ global_rpc_funcs + \ class_lines[gen_start + 1:] + # Persist if self.modify: with open(path, 'w') as fp: fp.write("\n".join(class_lines)) @@ -155,15 +165,28 @@ def generate_rpc_file(self, rpc_lambdas): :return: """ + # Parse rpc_thallium_defs.cc path = self.rpc_defs_path - with open(path) as fp: - rpc_lines = fp.read().splitlines() - gen_start = self.find_macro("RPC_AUTOGEN_START", rpc_lines) - gen_end = self.find_macro("RPC_AUTOGEN_END", rpc_lines) + gen = ParseDecoratedCppApis(path, + api_dec='RPC', + autogen_dec='RPC_AUTOGEN', + ignore_autogen_ns=True) + gen.parse() + + # Get the autogen start and end + rpc_lines = gen.orig_class_lines + gen_start = gen.api_map[None]['start'] + gen_end = gen.api_map[None]['end'] + + # Remove previous autogen data rpc_lines = rpc_lines[:gen_start+1] + rpc_lines[gen_end:] + + # Insert new autogen data rpc_lines = rpc_lines[:gen_start+1] + \ rpc_lambdas + \ rpc_lines[gen_start+1:] + + # Persist if self.modify: with open(path, 'w') as fp: fp.write("\n".join(rpc_lines)) @@ -172,73 +195,13 @@ def generate_rpc_file(self, rpc_lambdas): with open(tmp_path, 'w') as fp: fp.write("\n".join(rpc_lines)) - def get_rpcs_from_class(self, class_lines): - """ - Loads the prototypes of all RPCs in a particular class file - - :param class_lines: The parsed lines of the class file - (e.g., metadata_manager.h) - :return: rpc_map. Stores the set of RPC Apis of a particular class. - [class_name]['apis'][local_rpc_name] -> Api - """ - - cur_class = None - rpc_map = {} - for i, line in enumerate(class_lines): - toks = line.split() - first_tok = "" - if len(toks) > 0: - first_tok = toks[0].strip() - - if "class" == first_tok: - cur_class = self.get_class_name(line) - rpc_map[cur_class] = {'apis': {}, - 'gen_start': None, - 'gen_end': None} - elif "RPC_AUTOGEN_START" in line: - rpc_map[cur_class]['gen_start'] = i - elif "RPC_AUTOGEN_END" in line: - rpc_map[cur_class]['gen_end'] = i - elif "RPC" == first_tok: - text_proto = self.get_rpc_prototype(class_lines[i:]) - api = Api(text_proto) - api.global_name = api.name.replace("Local", "") - api.lambda_name = to_snake_case(f"Rpc{api.global_name}") - local_rpc_name = api.name - rpc_map[cur_class]['apis'][local_rpc_name] = api - return rpc_map - - def get_class_name(self, line): - toks = re.split("[\:\*+ ]", line) - toks = [tok.strip() for tok in toks if tok is not None and len(tok)] - class_name = toks[1] - return class_name - - def get_rpc_prototype(self, lines): - proto_toks = [] - for line in lines: - proto_toks.append(line.strip()) - if ';' in line: - break - proto = " ".join(proto_toks) - return proto - - def find_macro(self, macro, lines): - for i, line in enumerate(lines): - if macro in line: - return i - - def get_macro_space(self, line): - space_len = len(line) - len(line.lstrip()) - return " " * space_len - def add_space(self, space, text): lines = text.splitlines() for j, line in enumerate(lines): lines[j] = f"{space}{line}" return "\n".join(lines) - def create_global_rpc_func(self, rpc, target_node, space, lines): + def create_global_rpc_func(self, rpc, target_node, indent, lines): lines.append(rpc_func_text.format( RET=rpc.ret, LOCAL_NAME=rpc.name, @@ -247,9 +210,9 @@ def create_global_rpc_func(self, rpc, target_node, space, lines): PASS_PARAMS=rpc.pass_args(), TARGET_NODE=target_node ).strip()) - lines[-1] = self.add_space(space, lines[-1]) + lines[-1] = self.add_space(indent, lines[-1]) - def create_rpc_lambda(self, rpc, class_instance, space, lines): + def create_rpc_lambda(self, rpc, class_instance, indent, lines): lines.append(rpc_lambda_text.format( GLOBAL_NAME=rpc.global_name, LAMBDA_NAME=rpc.lambda_name, @@ -258,5 +221,5 @@ def create_rpc_lambda(self, rpc, class_instance, space, lines): PASS_PARAMS=rpc.pass_args(), LOCAL_NAME=rpc.name ).strip()) - lines[-1] = self.add_space(space, lines[-1]) + lines[-1] = self.add_space(indent, lines[-1]) diff --git a/code_generators/code_generators/util/api.py b/code_generators/code_generators/util/api.py index fff50e2e6..8c86d2af7 100644 --- a/code_generators/code_generators/util/api.py +++ b/code_generators/code_generators/util/api.py @@ -147,8 +147,8 @@ def __init__(self, hpp_file, api_dec=None, autogen_dec=None, # Load class file lines, but remove excess newlines and comments with open(self.hpp_file) as fp: - class_lines = fp.read().splitlines() - class_lines = list(enumerate(class_lines)) + self.orig_class_lines = fp.read().splitlines() + class_lines = list(enumerate(self.orig_class_lines)) self.class_lines = self._clean_lines(class_lines) self.only_class_lines = list(zip(*self.class_lines))[1] @@ -355,12 +355,13 @@ def _parse_autogen(self, namespace, i): if self.ignore_autogen_ns: namespace = None self._induct_namespace(namespace) - line = self.only_class_lines[i].strip() + true_i, line = self.class_lines[i] + line = line.strip() if line == self.autogen_dec_start: - self.api_map[namespace]['start'] = i + self.api_map[namespace]['start'] = true_i self.api_map[namespace]['indent'] = self._indent(line) else: - self.api_map[namespace]['end'] = i + self.api_map[namespace]['end'] = true_i return line def _is_namespace(self, i): From b09bf86877c05d17bc93fc365386b211295c8a87 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Tue, 6 Dec 2022 16:11:16 -0600 Subject: [PATCH 057/511] Prototype parsing works more generally --- .../code_generators/decorator/api.py | 326 ++++++++++++++++++ .../code_generators/decorator/decorator.py | 26 ++ .../{util/api.py => decorator/parse_cpp.py} | 242 ++++--------- .../code_generators/rpc/generator.py | 202 +++++------ code_generators/decorate.py | 45 +++ code_generators/rpc.py | 45 --- code_generators/unit/api/apis.h | 53 +++ code_generators/unit/api/rpcs.cc | 4 + code_generators/unit/api/test.py | 39 +++ code_generators/unit/cpp_toks/test.py | 18 + 10 files changed, 663 insertions(+), 337 deletions(-) create mode 100644 code_generators/code_generators/decorator/api.py create mode 100644 code_generators/code_generators/decorator/decorator.py rename code_generators/code_generators/{util/api.py => decorator/parse_cpp.py} (60%) create mode 100644 code_generators/decorate.py delete mode 100644 code_generators/rpc.py create mode 100644 code_generators/unit/api/apis.h create mode 100644 code_generators/unit/api/rpcs.cc create mode 100644 code_generators/unit/api/test.py create mode 100644 code_generators/unit/cpp_toks/test.py diff --git a/code_generators/code_generators/decorator/api.py b/code_generators/code_generators/decorator/api.py new file mode 100644 index 000000000..53f2baa3e --- /dev/null +++ b/code_generators/code_generators/decorator/api.py @@ -0,0 +1,326 @@ +import sys, os, re +from enum import Enum + + +class Api: + """ + Parses a C++ function prototype to determine: + 1. The arguments to the function + 2. The return value of the function + 3. The function decorators + 4. The function template + """ + + def __init__(self, api_str, api_decs, template_str=None): + self.api_str = api_str # Original C++ API string + self.api_decs = api_decs + self.template_str = template_str # Original C++ API template string + self.name = None # The name of the API + self.ret = None # Return value of the API + self.params = [] # The variables in the API + self.decorators = [] # The set of function decorators + self._decompose_prototype(api_str) + + def _decompose_prototype(self, api_str): + """ + Parses a C++ api string + + [DEC1] [DEC2] ... [RETURN_TYPE] [API_NAME]( + T1 param1, + T2 param2 = R2(T3, T4), + T3 param3 = R3() + ); + + :param api_str: the C++ api to parse + :return: None. But modifies the name, type, parameters, + and decorators of this class + """ + + # Remove all spaces around operators + toks = self.split_cpp_toks(api_str) + + # Remove all strings and comments + toks = self._remove_strings_and_comments(toks) + + # Parse the API + self._parse(0, toks) + + # Check the special + + def get_args(self): + """ + Create string to forward the parameters + passed to this API to another API + + Example: + Hello(int a, int b, int c) { + Hello2(a, b, c); + } + "int a, int b, int c" would be the return value of get_args + + :return: Typed argument list + """ + + if len(self.params) == 0: + return "" + args = [f"{arg[0]} {arg[1]}" for arg in self.params] + return ", ".join(args) + + def pass_args(self): + """ + Create string to forward the parameters + passed to this API to another API + + Example: + Hello(int a, int b, int c) { + Hello2(a, b, c); + } + "a, b, c" is the return value of pass_args + + :return: Untyped argument list + """ + + if self.params is None: + return "" + args = [arg[1] for arg in self.params if arg[0] != ''] + return ", ".join(args) + + """ + TOKENIZATION + """ + + @staticmethod + def _remove_strings_and_comments(toks): + i = 0 + new_toks = [] + while i < len(toks): + if Api._is_ml_comment_start(i, toks): + i = Api._end_of_ml_comment(i + 1, toks) + continue + elif Api._is_sl_comment_start(i, toks): + i = Api._end_of_sl_comment(i + 1, toks) + continue + elif Api._is_string(i, toks): + i = Api._end_of_string(i + 1, toks) + new_toks.append("PLACE") + continue + elif Api._is_whitespace(i, toks): + i += 1 + continue + new_toks.append(toks[i]) + i += 1 + return new_toks + + @staticmethod + def _end_of_string(i, toks): + while i < len(toks): + if Api._is_string(i, toks): + return i + 1 + i += 1 + + @staticmethod + def _end_of_ml_comment(i, toks): + while i < len(toks): + if Api._is_ml_comment_end(i, toks): + return i + 2 + i += 1 + + @staticmethod + def _end_of_sl_comment(i, toks): + while i < len(toks): + if Api._is_sl_comment_end(i, toks): + return i + 1 + i += 1 + + @staticmethod + def _is_ml_comment_start(i, toks): + if i + 1 >= len(toks): + return False + return toks[i] == '/' and toks[i + 1] == '*' + + @staticmethod + def _is_ml_comment_end(i, toks): + if i + 1 >= len(toks): + return False + return toks[i] == '/' and toks[i + 1] == '*' + + @staticmethod + def _is_sl_comment_start(i, toks): + if i + 1 >= len(toks): + return False + return toks[i] == '/' and toks[i + 1] == '/' + + @staticmethod + def _is_sl_comment_end(i, toks): + return '\n' in toks[i] + + @staticmethod + def _is_string(i, toks): + is_str = toks[i] == '\"' + if i == 0: + return is_str + if toks[i - 1] == '\\': + return False + return is_str + + @staticmethod + def _is_whitespace(i, toks): + return re.match("\s+", toks[i]) + + @staticmethod + def split_cpp_toks(text): + chars = ['\\\'', '\\\"', '\(', '\)', '<', '>', '\[', '\]', '\{', '\}', + '\+', '\-', '=', '\*', '/', '\|', '\*', '&', ',', '\:', ';'] + chars = "".join(chars) + chars = f"[{chars}]" + text = " ".join(text.split()) + toks = re.split(f"({chars}|\s+)", text) + toks = Api._clean(toks) + return toks + + @staticmethod + def _clean(toks): + toks = [tok for tok in toks if tok is not None and len(tok) > 0] + return toks + + @staticmethod + def _is_valid_name(tok): + return re.match('[a-zA-z0-9_]+', tok) + + + """ + PARSING + """ + + def _parse(self, i, toks): + fn_name_i = self._find_function_name(i, toks) + self.name = toks[fn_name_i] + self._parse_decorators_and_type(i, fn_name_i, toks) + self.params = self._parse_params(fn_name_i + 2, toks) + + def _find_function_name(self, i, toks): + while i < len(toks): + if toks[i] == '(': + return i-1 + if toks[i] == '<': + i = self._parse_brackets('<', '>', i, toks) + continue + if toks[i] == '(': + i = self._parse_brackets('(', ')', i, toks) + continue + if toks[i] == '[': + i = self._parse_brackets('[', ']', i, toks) + continue + if toks[i] == '{': + i = self._parse_brackets('{', '}', i, toks) + continue + i += 1 + return i + + def _parse_decorators_and_type(self, i, fn_name_i, toks): + type_toks = [] + while i < fn_name_i: + if self._is_decorator(i, toks): + self.decorators.append(toks[i]) + else: + type_toks.append(toks[i]) + i += 1 + self.ret = self._merge_type_tuple(type_toks) + + def _parse_params(self, i, toks): + params = [] + do_parse_param = True + while do_parse_param: + i, param_info, do_parse_param = self._parse_param(i, toks) + if param_info == None: + continue + params.append(param_info) + return params + + def _parse_param(self, i, toks): + param_start = i + while i < len(toks): + tok = toks[i] + if tok == ',': + param_name = toks[i - 1] + param_type = self._merge_type_tuple(toks[param_start:i - 1]) + param_val = None + return i + 1, (param_type, param_name, param_val), True + if tok == ')': + param_name = toks[i - 1] + param_type = self._merge_type_tuple(toks[param_start:i - 1]) + param_val = None + return i + 1, (param_type, param_name, param_val), False + if tok == '=': + param_name = toks[i - 1] + param_type = self._merge_type_tuple(toks[param_start:i - 1]) + i, param_val = self._parse_param_val(i + 1, toks) + param_val = self._merge_type_tuple(param_val) + return i, (param_type, param_name, param_val), True + if self._is_bracket(i, toks): + i = self._parse_all_brackets(i, toks) + continue + i += 1 + return i + 1, None, False + + def _parse_param_val(self, i, toks): + param_val_start = i + while i < len(toks): + tok = toks[i] + if tok == ',': + return i + 1, toks[param_val_start:i] + if tok == ')': + return i + 1, toks[param_val_start:i] + if self._is_bracket(i, toks): + i = self._parse_all_brackets(i, toks) + continue + i += 1 + return i + + def _is_bracket(self, i, toks): + brackets = ['<', '(', '[', '{'] + return toks[i] in brackets + + def _parse_all_brackets(self, i, toks): + tok = toks[i] + if tok == '<': + return self._parse_brackets('<', '>', i, toks) + if tok == '(': + return self._parse_brackets('(', ')', i, toks) + if tok == '[': + return self._parse_brackets('[', ']', i, toks) + if tok == '{': + return self._parse_brackets('{', '}', i, toks) + + def _parse_brackets(self, left, right, i, toks): + depth = 0 + while i < len(toks): + tok = toks[i] + if tok == left: + depth += 1 + if tok == right: + depth -= 1 + if depth == 0: + return i+1 + i += 1 + return i + + def _is_decorator(self, i, toks): + for api_dec in self.api_decs: + if toks[i] == api_dec.api_dec: + return True + return False + + def _merge_type_tuple(self, type_tuple): + new_toks = [] + i = 0 + while i < len(type_tuple): + tok = type_tuple[i] + new_toks.append(tok) + if i + 1 < len(type_tuple): + this_valid = self._is_valid_name(type_tuple[i]) + next_valid = self._is_valid_name(type_tuple[i + 1]) + if this_valid and next_valid: + new_toks.append(' ') + i += 1 + return "".join(new_toks) diff --git a/code_generators/code_generators/decorator/decorator.py b/code_generators/code_generators/decorator/decorator.py new file mode 100644 index 000000000..1f2f47a7d --- /dev/null +++ b/code_generators/code_generators/decorator/decorator.py @@ -0,0 +1,26 @@ +from abc import ABC, abstractmethod + + +class ApiDecorator(ABC): + def __init__(self, api_dec): + self.api_dec = api_dec + self.autogen_dec_start = f"{self.api_dec}_AUTOGEN_START" + self.autogen_dec_end = f"{self.api_dec}_AUTOGEN_END" + + @abstractmethod + def modify(self, api_map): + """ + Generate RPCs in the files + + :param api_map: [file][namespace] -> { + 'apis': [api_name] -> API + 'start': start of autogen region + 'end': end of autogen region + } + """ + pass + + +class NullDecorator(ApiDecorator): + def modify(self, api_map): + pass \ No newline at end of file diff --git a/code_generators/code_generators/util/api.py b/code_generators/code_generators/decorator/parse_cpp.py similarity index 60% rename from code_generators/code_generators/util/api.py rename to code_generators/code_generators/decorator/parse_cpp.py index 8c86d2af7..b7ec96cb5 100644 --- a/code_generators/code_generators/util/api.py +++ b/code_generators/code_generators/decorator/parse_cpp.py @@ -1,119 +1,6 @@ import sys, os, re +from .api import Api -class Api: - """ - Parses a C++ function prototype to determine: - 1. The arguments to the function - 2. The return value of the function - 3. The function decorators - 4. The function template - """ - - def __init__(self, api_str, template_str=None): - self.api_str = api_str # Original C++ API string - self.template_str = template_str # Original C++ API template string - self.name = None # The name of the API - self.ret = None # Return value of the API - self.var_defs = None # The variables in the API - self.decorators = None # The set of function decorators - self._decompose_prototype(api_str) - - def _clean(self, toks): - return [tok for tok in toks if tok is not None and len(tok) > 0] - - def _decompose_prototype(self, api_str): - """ - Parses a C++ api string - - :param api_str: the C++ api to parse - :return: None. But modifies the name, type, parameters, - and decorators of this class - """ - - # Split by parenthesis and semicolon - toks = self._clean(re.split("[()]|;", api_str)) - proto, args = toks[0], toks[1] - - try: - proto = self._clean(re.split("[ ]|(\*+)", proto)) - self.name = proto[-1] - self.ret = " ".join(proto[:-1]) - except: - print(f"Failed to decompose proto name: {proto}") - exit() - - try: - self.var_defs = [] - args = args.split(',') - for arg in args: - self.var_defs.append(self._get_arg_tuple(arg)) - except: - print(f"Failed to decompose proto args: {args}") - exit(1) - - def _get_arg_tuple(self, arg): - """ - Parse a function argument into a type and name. - E.g., int hi -> (int, hi) - - :param arg: The C++ text representing a function argument - :return: (type, name) - """ - - arg_toks = self._clean(re.split("[ ]|(\*+)|(&+)", arg)) - if len(arg_toks) == 1: - if arg_toks[0] == '...': - type = "" - name = "..." - return (type, name) - type = " ".join(arg_toks[:-1]) - type = type.replace(" ", "") - type = type.replace("\n", "") - name = arg_toks[-1] - name = name.replace(" ", "") - return (type, name) - - def get_args(self): - """ - Create string to forward the parameters - passed to this API to another API - - Example: - Hello(int a, int b, int c) { - Hello2(a, b, c); - } - "int a, int b, int c" would be the return value of get_args - - :return: Typed argument list - """ - - if len(self.var_defs) == 0: - return "" - try: - args = [" ".join(arg_tuple) for arg_tuple in self.var_defs] - except: - print(f"Failed to get arg list: {self.var_defs}") - exit(1) - return ", ".join(args) - - def pass_args(self): - """ - Create string to forward the parameters - passed to this API to another API - - Example: - Hello(int a, int b, int c) { - Hello2(a, b, c); - } - "a, b, c" is the return value of pass_args - - :return: Untyped argument list - """ - - if self.var_defs is None: - return "" - args = [arg[-1] for arg in self.var_defs if arg[0] != ''] - return ", ".join(args) class ParseDecoratedCppApis: """ @@ -122,43 +9,23 @@ class ParseDecoratedCppApis: the C++ style. These are defined in: _is_class, _is_namespace, _is_api :return: self.api_map - [namespace+class]['apis'][api_name] -> API() - [namespace+class]['start'] -> autogen macro start - [namespace+class]['end'] -> autogen macro end - [namespace+class]['indent'] -> autogen macro indentation + [path][namespace+class]['apis'][api_name] -> API() + [path][namespace+class]['start'] -> autogen macro start + [path][namespace+class]['end'] -> autogen macro end + [path][namespace+class]['indent'] -> autogen macro indentation """ - def __init__(self, hpp_file, api_dec=None, autogen_dec=None, - ignore_autogen_ns=False): + def __init__(self, files, api_decs): """ Load the C++ header file and clean out commented lines - :param hpp_file: the path to the C++ header file to parse - :param api_dec: the name of the API decorator to search for - :param autogen_dec: the name of the code autogen statement - to search for - :param ignore_autogen_ns: whether or not to consider the - namespace the autogen macros are apart of + :param files: the files to augment + :param api_decs: the API decorators to process """ - self.hpp_file = hpp_file - self.api_dec = api_dec - self.autogen_dec = autogen_dec + self.files = files + self.api_decs = api_decs self.api_map = {} - # Load class file lines, but remove excess newlines and comments - with open(self.hpp_file) as fp: - self.orig_class_lines = fp.read().splitlines() - class_lines = list(enumerate(self.orig_class_lines)) - self.class_lines = self._clean_lines(class_lines) - self.only_class_lines = list(zip(*self.class_lines))[1] - - def set_decorators(self, api_dec, autogen_dec, ignore_autogen_ns=False): - self.api_dec = api_dec - self.autogen_dec = autogen_dec - self.autogen_dec_start = f"{self.autogen_dec}_START" - self.autogen_dec_end = f"{self.autogen_dec}_END" - self.ignore_autogen_ns = ignore_autogen_ns - def _clean_lines(self, class_lines): """ Removes all lines encapsulated between /* and */. @@ -208,7 +75,42 @@ def _is_comment_end(self, line): return '*/' == line.strip()[-2:] - def parse(self, namespace=None, start=None, end=None): + def parse(self): + self._parse_files() + self._apply_decorators() + + def _parse_files(self): + for path in self.files: + self.hpp_file = path + with open(self.hpp_file) as fp: + self.orig_class_lines = fp.read().splitlines() + class_lines = list(enumerate(self.orig_class_lines)) + self.class_lines = self._clean_lines(class_lines) + self.only_class_lines = list(zip(*self.class_lines))[1] + self._parse() + + def _apply_decorators(self): + while self._has_unmodified_apis(): + for api_dec in self.api_decs: + api_dec.modify(self.api_map) + self._strip_decorator(api_dec) + + def _strip_decorator(self, api_dec): + for path, namespace_dict in self.api_map.items(): + for namespace, api_dict in namespace_dict.items(): + for api in api_dict['apis'].values(): + api.decorators.remove(api_dec.dec) + if len(api.decorators) == 0: + del api_dict['apis'][api.name] + + def _has_unmodified_apis(self): + for path, namespace_dict in self.api_map.items(): + for namespace, api_dict in namespace_dict.items(): + if len(api_dict['apis']): + return True + return False + + def _parse(self, namespace=None, start=None, end=None): if start == None: start = 0 if end == None: @@ -221,8 +123,9 @@ def parse(self, namespace=None, start=None, end=None): elif self._is_api(i): i = self._parse_api(namespace, i) continue - elif self._is_autogen(namespace, i): + elif self._is_autogen(i): i = self._parse_autogen(namespace, i) + continue i += 1 return i @@ -260,8 +163,8 @@ class Hash = std::hash api_str,api_end = self._get_api_str(i) api = Api(api_str, tmpl_str) self._induct_namespace(namespace) - self.api_map[namespace][api.name] = api - return api_end + self.api_map[self.hpp_file][namespace]['apis'][api.name] = api + return api_end + 1 def _get_template_str(self, i): """ @@ -329,9 +232,9 @@ class hello { # Get the class name + indentation line = self.class_lines[i][1] toks = re.split("[ :]", line) - toks = [tok for tok in toks if tok is not None and len(tok)] + toks = [tok .strip() for tok in toks if tok is not None and len(tok)] class_name = toks[1] - indent = self._indent() + indent = self._indent(line) # Find the end of the class (};) end = i end_of_class = f"{indent}}};" @@ -341,7 +244,7 @@ class hello { break # Parse all lines for prototypes namespace = self._ns_append(namespace, class_name) - return self.parse(namespace, i+1, end) + return self._parse(namespace, i+1, end) def _parse_autogen(self, namespace, i): """ @@ -352,17 +255,16 @@ def _parse_autogen(self, namespace, i): :return: """ - if self.ignore_autogen_ns: - namespace = None self._induct_namespace(namespace) true_i, line = self.class_lines[i] line = line.strip() if line == self.autogen_dec_start: - self.api_map[namespace]['start'] = true_i - self.api_map[namespace]['indent'] = self._indent(line) + self.api_map[self.hpp_file][namespace]['start'] = true_i + self.api_map[self.hpp_file][namespace]['indent'] = \ + self._indent(line) else: - self.api_map[namespace]['end'] = true_i - return line + self.api_map[self.hpp_file][namespace]['end'] = true_i + return i + 1 def _is_namespace(self, i): """ @@ -391,8 +293,8 @@ def _is_namespace(self, i): def _is_class(self, i): """ - Determine whether a tokenized line defines a C++ class definition. - Ignores class declarations (e.g., class hello;). + Determine whether a tokenized line defines a C++ class, struct, + or union definition. Ignores class declarations (e.g., class hello;). ASSUMPTIONS: 1. Class definitions do not contain any ';', which may be possible @@ -416,7 +318,7 @@ class hello : public language { toks = line.split() if len(toks) < 2: return False - if toks[0] != 'class': + if toks[0] != 'class' and toks[0] != 'struct' and toks[0] != 'union': return False for true_i, line in self.class_lines[i:]: toks = line.split() @@ -439,9 +341,10 @@ def _is_api(self, i): line = self.only_class_lines[i] toks = line.split() # Determine if the line has a decorator - for tok in toks: - if tok == self.api_dec: - return True + for api_dec in self.api_decs: + for tok in toks: + if tok == api_dec.api_dec: + return True return False def _is_autogen(self, i): @@ -453,15 +356,18 @@ def _is_autogen(self, i): """ line = self.only_class_lines[i].strip() - if line == self.autogen_dec_start: - return True - if line == self.autogen_dec_end: - return True + for api_dec in self.api_decs: + if line == api_dec.autogen_dec_start: + return True + if line == api_dec.autogen_dec_end: + return True return False def _induct_namespace(self, namespace): - if namespace not in self.api_map: - self.api_map[namespace] = { + if self.hpp_file not in self.api_map: + self.api_map[self.hpp_file] = {} + if namespace not in self.api_map[self.hpp_file]: + self.api_map[self.hpp_file][namespace] = { 'apis': {}, 'start': None, 'end': None, diff --git a/code_generators/code_generators/rpc/generator.py b/code_generators/code_generators/rpc/generator.py index 209120a33..6fbecbbe7 100644 --- a/code_generators/code_generators/rpc/generator.py +++ b/code_generators/code_generators/rpc/generator.py @@ -1,9 +1,10 @@ -import sys, os, re -from code_generators.util.api import Api, ParseDecoratedCppApis -from code_generators.util.naming import to_snake_case +import os +from code_generators.decorator.decorator import ApiDecorator +from code_generators.decorator.api import Api from code_generators.util.conv import str_to_bool rpc_func_text = """ +{DEC} {RET} {GLOBAL_NAME}({PARAMS}) {{ u32 target_node = {TARGET_NODE}; if (target_node == rpc_->node_id_) {{ @@ -18,6 +19,7 @@ """ rpc_func_text2 = """ +{DEC} {RET} {GLOBAL_NAME}({PARAMS}) {{ u32 target_node = {TARGET_NODE}; return rpc_->Call<{RET}>( @@ -35,32 +37,48 @@ }}; server_engine_->define("{GLOBAL_NAME}", {LAMBDA_NAME}); """ +rpc_lambda_text_void = """ +auto {LAMBDA_NAME} = + [](const request &req, {PARAMS}) {{ + auto result = {LOCAL_NAME}({PASS_PARAMS}); + req.respond(result); + }}; +server_engine_->define("{GLOBAL_NAME}", {LAMBDA_NAME}); +""" -class RpcGenerator: - def __init__(self, rpc_defs_path, modify=True): + +class RpcGenerator(ApiDecorator): + def __init__(self): """ Automatically inserts RPC code into class files and builds rpc_thallium_defs.cc. - - :param modify: Whether or not to modify class files directly or - store temporary output in the working directory. """ - self.modify = str_to_bool(modify) + super().__init__("RPC") self.path = None - self.rpc_defs_path = rpc_defs_path self.macro = None self.class_instance = None - self.rpcs = {} # [class_path][class_name] -> + self.rpcs = {} # [class_path][class_name][api_name] -> # tuple(local_rpc_name, target_node, # class_instance) - def set_file(self, path, class_name, class_instance): + def set_rpc_lambda_file(self, rpc_defs_path): + self.rpc_defs_path = rpc_defs_path + + def set_file(self, path): """ Sets information used in subsequent calls to "add". - - :param path: the path to the class containing RPC prototypes - (e.g., metadata_manager.h) + + :param path: the path to the class containing RPC prototypes + (e.g., metadata_manager.h) + """ + + self.path = path + + def set_class(self, class_name, class_instance): + """ + Sets information used in subsequent calls to "add". + :param class_name: the name of the class to scan prototypes from (e.g., hermes::MetadataManager). Namespace is required. :param class_instance: The name of the C++ class instance to input @@ -68,8 +86,6 @@ def set_file(self, path, class_name, class_instance): encapsulated in RPC_CLASS_INSTANCE_DEFS in rpc_thallium_defs.cc. :return: None """ - - self.path = path self.class_name = class_name self.class_instance = class_instance @@ -86,114 +102,46 @@ def add(self, local_rpc_name, target_node): if self.path not in self.rpcs: self.rpcs[self.path] = {} if self.class_name not in self.rpcs[self.path]: - self.rpcs[self.path][self.class_name] = [] - self.rpcs[self.path][self.class_name].append( - (local_rpc_name, target_node, self.class_instance)) - - def generate(self): - """ - Generate the RPCs based on the local function prototypes. - - :return: None. - """ - - rpc_lambdas = [] - for path, class_rpcs in self.rpcs.items(): - self.generate_class_file(path, class_rpcs, rpc_lambdas) - self.generate_rpc_file(rpc_lambdas) + self.rpcs[self.path][self.class_name] = {} + self.rpcs[self.path][self.class_name][local_rpc_name] = ( + (target_node, self.class_instance)) - def generate_class_file(self, path, class_rpcs, rpc_lambdas): + def modify(self, api_map): """ Generates the RPCs (GlobalRPC + lambda) for a particular class file (e.g., metadata_manager.h) - + :param path: the path to the C++ class file (e.g., metadata_manager.h) :param class_rpcs: the set of RPCs names belonging to the class :param rpc_lambdas: (output) :return: Modifies rpc_lambdas and the C++ class file. """ - - # Parse class file (e.g., metadata_manager.h) - gen = ParseDecoratedCppApis(path, - api_dec='RPC', - autogen_dec='RPC_AUTOGEN') - gen.parse() - rpc_map = gen.api_map - class_lines = gen.orig_class_lines + # Get the autogen dict for rpc_thallium_defs.cc + autogen_api_dict = api_map[self.rpc_defs_path][None] # Autogen RPCs for each class - for class_name, rpcs in class_rpcs.items(): - # Get the autogen start - gen_start = rpc_map[class_name]['start'] - gen_end = rpc_map[class_name]['end'] - indent = rpc_map[class_name]['indent'] - global_rpc_funcs = [] - - # Create lambda + global RPC - for rpc in rpcs: - local_rpc_name = rpc[0] - target_node = rpc[1] - class_instance = rpc[2] - local_rpc_api = rpc_map[class_name]['apis'][local_rpc_name] - self.create_global_rpc_func(local_rpc_api, target_node, - indent, global_rpc_funcs) - self.create_rpc_lambda(local_rpc_api, class_instance, - indent, rpc_lambdas) - - # Remove previous autogen data - class_lines = class_lines[:gen_start+1] + class_lines[gen_end:] - - # Insert new autogen data - class_lines = class_lines[:gen_start + 1] + \ - global_rpc_funcs + \ - class_lines[gen_start + 1:] - - # Persist - if self.modify: - with open(path, 'w') as fp: - fp.write("\n".join(class_lines)) - else: - tmp_path = os.path.basename(path) - with open(f"tmp_{tmp_path}", 'w') as fp: - fp.write("\n".join(class_lines)) - - def generate_rpc_file(self, rpc_lambdas): - """ - Generate rpc_thallium_defs.cc - - :param rpc_lambdas: - :return: - """ - - # Parse rpc_thallium_defs.cc - path = self.rpc_defs_path - gen = ParseDecoratedCppApis(path, - api_dec='RPC', - autogen_dec='RPC_AUTOGEN', - ignore_autogen_ns=True) - gen.parse() - - # Get the autogen start and end - rpc_lines = gen.orig_class_lines - gen_start = gen.api_map[None]['start'] - gen_end = gen.api_map[None]['end'] - - # Remove previous autogen data - rpc_lines = rpc_lines[:gen_start+1] + rpc_lines[gen_end:] - - # Insert new autogen data - rpc_lines = rpc_lines[:gen_start+1] + \ - rpc_lambdas + \ - rpc_lines[gen_start+1:] - - # Persist - if self.modify: - with open(path, 'w') as fp: - fp.write("\n".join(rpc_lines)) - else: - tmp_path = os.path.basename(path) - with open(tmp_path, 'w') as fp: - fp.write("\n".join(rpc_lines)) + for path, namespace_dict in api_map.items(): + for namespace, api_dict in namespace_dict.items(): + indent = api_dict['indent'] + for local_rpc_api in api_dict['apis']: + if "RPC" not in local_rpc_api.decorators: + continue + rpc_info = self.rpcs[path][namespace][local_rpc_api.name] + target_node = rpc_info[0] + class_instance = rpc_info[1] + + # Generate RPC code + rpc_api = self.create_global_rpc_func(local_rpc_api, + target_node, indent) + rpc_lambda = self.create_rpc_lambda(local_rpc_api, + class_instance, indent) + + # Add the generated code to the API map + if len(rpc_api.decorators): + api_dict['apis'][rpc_api.name] = rpc_api + else: + api_dict['gen'].append(rpc_api.api_str) + autogen_api_dict['gen'].append(rpc_lambda) def add_space(self, space, text): lines = text.splitlines() @@ -201,25 +149,31 @@ def add_space(self, space, text): lines[j] = f"{space}{line}" return "\n".join(lines) - def create_global_rpc_func(self, rpc, target_node, indent, lines): - lines.append(rpc_func_text.format( + def create_global_rpc_func(self, rpc, target_node, indent): + func = rpc_func_text.format( + DEC=rpc.get_decorators("RPC"), RET=rpc.ret, LOCAL_NAME=rpc.name, GLOBAL_NAME=rpc.global_name, PARAMS=rpc.get_args(), PASS_PARAMS=rpc.pass_args(), TARGET_NODE=target_node - ).strip()) - lines[-1] = self.add_space(indent, lines[-1]) - - def create_rpc_lambda(self, rpc, class_instance, indent, lines): - lines.append(rpc_lambda_text.format( + ).strip() + func = self.add_space(indent, func) + return Api(func) + + def create_rpc_lambda(self, rpc, class_instance, indent): + lambda_text = rpc_lambda_text + if class_instance is None: + lambda_text = rpc_lambda_text_void + func = lambda_text.format( + DEC=rpc.get_decorators("RPC"), GLOBAL_NAME=rpc.global_name, LAMBDA_NAME=rpc.lambda_name, class_instance=class_instance, PARAMS=rpc.get_args(), PASS_PARAMS=rpc.pass_args(), LOCAL_NAME=rpc.name - ).strip()) - lines[-1] = self.add_space(indent, lines[-1]) - + ).strip() + func = self.add_space(indent, func) + return func diff --git a/code_generators/decorate.py b/code_generators/decorate.py new file mode 100644 index 000000000..e1ae03968 --- /dev/null +++ b/code_generators/decorate.py @@ -0,0 +1,45 @@ +from code_generators.decorator.parse_cpp import ParseDecoratedCppApis +from code_generators.rpc.generator import RpcGenerator +from code_generators.util.paths import HERMES_ROOT + +def create_rpc_generator(): + gen = RpcGenerator() + rpc_defs_path = f"{HERMES_ROOT}/src/rpc_thallium_defs.cc" + gen.set_rpc_lambda_file(rpc_defs_path) + + # metadata_manager.h + gen.set_file(f"{HERMES_ROOT}/src/metadata_manager.h") + gen.set_class("MetadataManager", "mdm") + gen.add("LocalGetOrCreateBucket", "rpc_->node_id_") + gen.add("LocalGetBucketId", "rpc_->node_id_") + gen.add("LocalBucketContainsBlob", "rpc_->node_id_") + gen.add("LocalRenameBucket", "rpc_->node_id_") + gen.add("LocalDestroyBucket", "rpc_->node_id_") + gen.add("LocalBucketPutBlob", "rpc_->node_id_") + gen.add("LocalGetBlobId", "rpc_->node_id_") + gen.add("LocalSetBlobBuffers", "rpc_->node_id_") + gen.add("LocalGetBlobBuffers", "rpc_->node_id_") + gen.add("LocalRenameBlob", "rpc_->node_id_") + gen.add("LocalDestroyBlob", "rpc_->node_id_") + gen.add("LocalWriteLockBlob", "rpc_->node_id_") + gen.add("LocalWriteUnlockBlob", "rpc_->node_id_") + gen.add("LocalReadLockBlob", "rpc_->node_id_") + gen.add("LocalReadUnlockBlob", "rpc_->node_id_") + gen.add("LocalGetOrCreateVBucket", "rpc_->node_id_") + gen.add("LocalGetVBucketId", "rpc_->node_id_") + gen.add("LocalUnlinkBlobVBucket", "rpc_->node_id_") + gen.add("LocalGetLinksVBucket", "rpc_->node_id_") + gen.add("LocalRenameVBucket", "rpc_->node_id_") + gen.add("LocalDestroyVBucket", "rpc_->node_id_") + + return gen + +files = [ + f"{HERMES_ROOT}/src/metadata_manager.h" +] + +decs = [ + create_rpc_generator() +] + +gen = ParseDecoratedCppApis(files, decs) diff --git a/code_generators/rpc.py b/code_generators/rpc.py deleted file mode 100644 index 98659b5bb..000000000 --- a/code_generators/rpc.py +++ /dev/null @@ -1,45 +0,0 @@ - -""" -Automatically generate the RPCs for a series of Local functions - -USAGE: - cd code_generators/bin - python3 rpc.py [modify=True] - -modify: whether or not to modify actual source files. -""" - -import sys -from code_generators.rpc.generator import RpcGenerator -from code_generators.util.paths import HERMES_ROOT - -rpc_defs_path = f"{HERMES_ROOT}/src/rpc_thallium_defs.cc" -if len(sys.argv) < 2: - gen = RpcGenerator(rpc_defs_path, True) -else: - gen = RpcGenerator(rpc_defs_path, sys.argv[1]) - -gen.set_file(f"{HERMES_ROOT}/src/metadata_manager.h", "MetadataManager", "mdm") -gen.add("LocalGetOrCreateBucket", "rpc_->node_id_") -gen.add("LocalGetBucketId", "rpc_->node_id_") -gen.add("LocalBucketContainsBlob", "rpc_->node_id_") -gen.add("LocalRenameBucket", "rpc_->node_id_") -gen.add("LocalDestroyBucket", "rpc_->node_id_") -gen.add("LocalBucketPutBlob", "rpc_->node_id_") -gen.add("LocalGetBlobId", "rpc_->node_id_") -gen.add("LocalSetBlobBuffers", "rpc_->node_id_") -gen.add("LocalGetBlobBuffers", "rpc_->node_id_") -gen.add("LocalRenameBlob", "rpc_->node_id_") -gen.add("LocalDestroyBlob", "rpc_->node_id_") -gen.add("LocalWriteLockBlob", "rpc_->node_id_") -gen.add("LocalWriteUnlockBlob", "rpc_->node_id_") -gen.add("LocalReadLockBlob", "rpc_->node_id_") -gen.add("LocalReadUnlockBlob", "rpc_->node_id_") -gen.add("LocalGetOrCreateVBucket", "rpc_->node_id_") -gen.add("LocalGetVBucketId", "rpc_->node_id_") -gen.add("LocalUnlinkBlobVBucket", "rpc_->node_id_") -gen.add("LocalGetLinksVBucket", "rpc_->node_id_") -gen.add("LocalRenameVBucket", "rpc_->node_id_") -gen.add("LocalDestroyVBucket", "rpc_->node_id_") - -gen.generate() \ No newline at end of file diff --git a/code_generators/unit/api/apis.h b/code_generators/unit/api/apis.h new file mode 100644 index 000000000..143b7d29d --- /dev/null +++ b/code_generators/unit/api/apis.h @@ -0,0 +1,53 @@ +// +// Created by lukemartinlogan on 12/6/22. +// + +#ifndef HERMES_CODE_GENERATORS_CODE_GENERATORS_UNIT_PROTOS_H_ +#define HERMES_CODE_GENERATORS_CODE_GENERATORS_UNIT_PROTOS_H_ + +#include + +#define RPC +#define RPC_AUTOGEN_START +#define RPC_AUTOGEN_END + +#define WRAP +#define WRAP_AUTOGEN_START +#define WRAP_AUTOGEN_END + +struct Ctx {}; + +int f1(); + +RPC int Localf2(); + +RPC int Localf3(int a, int b); + +template +RPC std::vector& Localf4(int a, + std::vector b, + Ctx = Ctx()); + +template> +WRAP RPC std::vector& Localf5(int a, + std::vector b, + Ctx = Ctx()); + +WRAP RPC +std::vector& Localf6(int a, std::vector b, Ctx = Ctx()); + +namespace nstest { + +RPC int Localf99(); + +template +class Hi { + RPC int Localf100(); +}; + +RPC int Localf101(); +} + +#endif // HERMES_CODE_GENERATORS_CODE_GENERATORS_UNIT_PROTOS_H_ diff --git a/code_generators/unit/api/rpcs.cc b/code_generators/unit/api/rpcs.cc new file mode 100644 index 000000000..f0a6cb829 --- /dev/null +++ b/code_generators/unit/api/rpcs.cc @@ -0,0 +1,4 @@ +int main() { + RPC_AUTOGEN_START + RPC_AUTOGEN_END +} \ No newline at end of file diff --git a/code_generators/unit/api/test.py b/code_generators/unit/api/test.py new file mode 100644 index 000000000..8d354b1b5 --- /dev/null +++ b/code_generators/unit/api/test.py @@ -0,0 +1,39 @@ +from code_generators.decorator.parse_cpp import ParseDecoratedCppApis +from code_generators.decorator.decorator import NullDecorator +from code_generators.rpc.generator import RpcGenerator +from code_generators.util.paths import HERMES_ROOT + + +def create_rpc_generator(): + gen = RpcGenerator() + rpc_defs_path = f"{HERMES_ROOT}/code_generators/unit/rpcs.cc" + gen.set_rpc_lambda_file(rpc_defs_path) + + gen.set_file(f"{HERMES_ROOT}/code_generators/unit/api/apis.h") + gen.set_class(None, None) + gen.add("Localf2", "0") + gen.add("Localf3", "1") + gen.add("Localf4", "2") + gen.add("Localf5", "3") + gen.add("Localf6", "4") + + gen.set_class("nstest", None) + gen.add("Localf99", "5") + gen.add("Localf101", "6") + + gen.set_class("nstest::Hi", "hi") + gen.add("Localf100", "7") + + return gen + +files = [ + f"{HERMES_ROOT}/code_generators/unit/api/apis.h" +] + +decs = [ + create_rpc_generator(), + NullDecorator("WRAP") +] + +gen = ParseDecoratedCppApis(files, decs) +gen.parse() \ No newline at end of file diff --git a/code_generators/unit/cpp_toks/test.py b/code_generators/unit/cpp_toks/test.py new file mode 100644 index 000000000..c6f4c6397 --- /dev/null +++ b/code_generators/unit/cpp_toks/test.py @@ -0,0 +1,18 @@ +from code_generators.decorator.api import Api +from code_generators.rpc.generator import RpcGenerator + +text = """ +WRAP RPC std::vector& Localf5(int a, + std::vector b, + std::string x = "/*>*/", + Ctx ctx = Ctx()); +""" + +gen = RpcGenerator() +api = Api(text, [gen]) + +print(api.name) +print(api.ret) +print(api.params) +print(api.get_args()) +print(api.pass_args()) \ No newline at end of file From da1c7b4480a758d2a3a5cfe8f25b6512c4de63c1 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 7 Dec 2022 02:11:31 -0600 Subject: [PATCH 058/511] Code generator nearly works --- .../code_generators/decorator/api.py | 7 +- .../code_generators/decorator/decorator.py | 8 +++ .../code_generators/decorator/parse_cpp.py | 72 ++++++++++++++----- .../code_generators/rpc/generator.py | 7 +- code_generators/unit/api/apis.h | 3 + code_generators/unit/api/test.py | 5 +- code_generators/unit/cpp_toks/test.py | 4 ++ 7 files changed, 84 insertions(+), 22 deletions(-) diff --git a/code_generators/code_generators/decorator/api.py b/code_generators/code_generators/decorator/api.py index 53f2baa3e..833ea9172 100644 --- a/code_generators/code_generators/decorator/api.py +++ b/code_generators/code_generators/decorator/api.py @@ -11,10 +11,13 @@ class Api: 4. The function template """ - def __init__(self, api_str, api_decs, template_str=None): + def __init__(self, api_str, api_decs, template_str=None, doc_str=None): self.api_str = api_str # Original C++ API string self.api_decs = api_decs + if self.api_decs is None: + self.api_decs = [] self.template_str = template_str # Original C++ API template string + self.doc_str = doc_str self.name = None # The name of the API self.ret = None # Return value of the API self.params = [] # The variables in the API @@ -239,6 +242,8 @@ def _parse_params(self, i, toks): def _parse_param(self, i, toks): param_start = i + if i >= len(toks) or toks[i] == ')': + return i + 1, None, False while i < len(toks): tok = toks[i] if tok == ',': diff --git a/code_generators/code_generators/decorator/decorator.py b/code_generators/code_generators/decorator/decorator.py index 1f2f47a7d..cb486df59 100644 --- a/code_generators/code_generators/decorator/decorator.py +++ b/code_generators/code_generators/decorator/decorator.py @@ -7,6 +7,14 @@ def __init__(self, api_dec): self.autogen_dec_start = f"{self.api_dec}_AUTOGEN_START" self.autogen_dec_end = f"{self.api_dec}_AUTOGEN_END" + @abstractmethod + def init_api(self, api): + """ + Add additional information to the Api object when it's registered + for processing + """ + pass + @abstractmethod def modify(self, api_map): """ diff --git a/code_generators/code_generators/decorator/parse_cpp.py b/code_generators/code_generators/decorator/parse_cpp.py index b7ec96cb5..784cb04e5 100644 --- a/code_generators/code_generators/decorator/parse_cpp.py +++ b/code_generators/code_generators/decorator/parse_cpp.py @@ -117,6 +117,7 @@ def _parse(self, namespace=None, start=None, end=None): end = len(self.class_lines) i = start while i < end: + line = self.class_lines[i] if self._is_namespace(i) or self._is_class(i): i = self._parse_class_or_ns(namespace, i) continue @@ -159,13 +160,40 @@ class Hash = std::hash :return: None. Modifies the """ - tmpl_str = self._get_template_str(i) + tmpl_i, tmpl_str = self._get_template_str(i) + doc_str = self._get_doc_str(i) api_str,api_end = self._get_api_str(i) - api = Api(api_str, tmpl_str) + api = Api(api_str, self.api_decs, tmpl_str, doc_str) self._induct_namespace(namespace) self.api_map[self.hpp_file][namespace]['apis'][api.name] = api return api_end + 1 + def _get_doc_str(self, i): + """ + Starting at i, parses upwards until the docstring comment has started + """ + + in_comment = False + docstr_i = i + for class_line in reversed(self.orig_class_lines[:i - 1]): + strip_class_line = class_line.strip() + if len(strip_class_line) == 0: + docstr_i -= 1 + continue + if strip_class_line[-2:] == '*/': + in_comment = True + docstr_i -= 1 + continue + if strip_class_line[0:2] == '/*': + in_comment = False + return "\n".join(self.orig_class_lines[docstr_i:i]) + if strip_class_line[0:2] == '//': + return i + if in_comment: + docstr_i -= 1 + continue + return None + def _get_template_str(self, i): """ Starting at i, parses upwards until the template keyword is reached. @@ -175,9 +203,9 @@ def _get_template_str(self, i): """ if i == 0: - return None + return i, None if '>' not in self.only_class_lines[i-1]: - return None + return i, None tmpl_i = None for class_line in reversed(self.only_class_lines[:i-1]): toks = class_line.split() @@ -186,9 +214,9 @@ def _get_template_str(self, i): break i -= 1 if tmpl_i is None: - return None + return i, None tmpl_str = self.only_class_lines[tmpl_i:i] - return tmpl_str + return tmpl_i, tmpl_str def _get_api_str(self, i): """ @@ -230,16 +258,20 @@ class hello { """ # Get the class name + indentation - line = self.class_lines[i][1] - toks = re.split("[ :]", line) + line = self.only_class_lines[i] + toks = re.split("[ \{]", line) toks = [tok .strip() for tok in toks if tok is not None and len(tok)] + is_ns = toks[0] == 'namespace' class_name = toks[1] indent = self._indent(line) # Find the end of the class (};) end = i - end_of_class = f"{indent}}};" - for off, line in enumerate(self.class_lines[i+1:]): - if end_of_class == line[0:len(end_of_class)]: + if is_ns: + end_of_scope = f"{indent}}}" + else: + end_of_scope = f"{indent}}};" + for off, line in enumerate(self.only_class_lines[i+1:]): + if end_of_scope == line[0:len(end_of_scope)]: end += off break # Parse all lines for prototypes @@ -258,12 +290,13 @@ def _parse_autogen(self, namespace, i): self._induct_namespace(namespace) true_i, line = self.class_lines[i] line = line.strip() - if line == self.autogen_dec_start: - self.api_map[self.hpp_file][namespace]['start'] = true_i - self.api_map[self.hpp_file][namespace]['indent'] = \ - self._indent(line) - else: - self.api_map[self.hpp_file][namespace]['end'] = true_i + for api_dec in self.api_decs: + if line == api_dec.autogen_dec_start: + self.api_map[self.hpp_file][namespace]['start'] = true_i + self.api_map[self.hpp_file][namespace]['indent'] = \ + self._indent(line) + elif line == api_dec.autogen_dec_end: + self.api_map[self.hpp_file][namespace]['end'] = true_i return i + 1 def _is_namespace(self, i): @@ -290,6 +323,7 @@ def _is_namespace(self, i): return False if toks[2] != '{': return False + return True def _is_class(self, i): """ @@ -343,6 +377,8 @@ def _is_api(self, i): # Determine if the line has a decorator for api_dec in self.api_decs: for tok in toks: + if '#' in tok: + return False if tok == api_dec.api_dec: return True return False @@ -378,7 +414,7 @@ def _induct_namespace(self, namespace): def _ns_append(namespace, suffix): if namespace is None or len(namespace) == 0: return suffix - return namespace + suffix + return f"{namespace}::{suffix}" @staticmethod def _indent(line): diff --git a/code_generators/code_generators/rpc/generator.py b/code_generators/code_generators/rpc/generator.py index 6fbecbbe7..566cc9532 100644 --- a/code_generators/code_generators/rpc/generator.py +++ b/code_generators/code_generators/rpc/generator.py @@ -106,6 +106,9 @@ def add(self, local_rpc_name, target_node): self.rpcs[self.path][self.class_name][local_rpc_name] = ( (target_node, self.class_instance)) + def init_api(self, api): + pass + def modify(self, api_map): """ Generates the RPCs (GlobalRPC + lambda) for a particular class file @@ -123,9 +126,11 @@ def modify(self, api_map): for path, namespace_dict in api_map.items(): for namespace, api_dict in namespace_dict.items(): indent = api_dict['indent'] - for local_rpc_api in api_dict['apis']: + for local_rpc_api in api_dict['apis'].values(): if "RPC" not in local_rpc_api.decorators: continue + if local_rpc_api.name in rpc_info: + pass rpc_info = self.rpcs[path][namespace][local_rpc_api.name] target_node = rpc_info[0] class_instance = rpc_info[1] diff --git a/code_generators/unit/api/apis.h b/code_generators/unit/api/apis.h index 143b7d29d..e0a0069c5 100644 --- a/code_generators/unit/api/apis.h +++ b/code_generators/unit/api/apis.h @@ -2,6 +2,9 @@ // Created by lukemartinlogan on 12/6/22. // +namespace hello::hi { +} + #ifndef HERMES_CODE_GENERATORS_CODE_GENERATORS_UNIT_PROTOS_H_ #define HERMES_CODE_GENERATORS_CODE_GENERATORS_UNIT_PROTOS_H_ diff --git a/code_generators/unit/api/test.py b/code_generators/unit/api/test.py index 8d354b1b5..269134647 100644 --- a/code_generators/unit/api/test.py +++ b/code_generators/unit/api/test.py @@ -6,7 +6,7 @@ def create_rpc_generator(): gen = RpcGenerator() - rpc_defs_path = f"{HERMES_ROOT}/code_generators/unit/rpcs.cc" + rpc_defs_path = f"{HERMES_ROOT}/code_generators/unit/api/rpcs.cc" gen.set_rpc_lambda_file(rpc_defs_path) gen.set_file(f"{HERMES_ROOT}/code_generators/unit/api/apis.h") @@ -27,7 +27,8 @@ def create_rpc_generator(): return gen files = [ - f"{HERMES_ROOT}/code_generators/unit/api/apis.h" + f"{HERMES_ROOT}/code_generators/unit/api/apis.h", + f"{HERMES_ROOT}/code_generators/unit/api/rpcs.cc", ] decs = [ diff --git a/code_generators/unit/cpp_toks/test.py b/code_generators/unit/cpp_toks/test.py index c6f4c6397..4fbff78bd 100644 --- a/code_generators/unit/cpp_toks/test.py +++ b/code_generators/unit/cpp_toks/test.py @@ -8,6 +8,10 @@ Ctx ctx = Ctx()); """ +text = """ +RPC int f2(); +""" + gen = RpcGenerator() api = Api(text, [gen]) From 6a93917a2c81cca88e55cac4fa65c03df51b1850 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 7 Dec 2022 04:40:40 -0600 Subject: [PATCH 059/511] RPC generator passes basic unit tests --- .../code_generators/decorator/api.py | 60 ++++++-- .../code_generators/decorator/decorator.py | 19 +-- .../code_generators/decorator/parse_cpp.py | 139 ++++++++++++------ .../code_generators/rpc/generator.py | 44 +++--- code_generators/code_generators/util/conv.py | 2 +- code_generators/unit/api/apis.h | 32 +++- code_generators/unit/api/test.py | 11 +- code_generators/unit/cpp_toks/test.py | 10 +- 8 files changed, 218 insertions(+), 99 deletions(-) diff --git a/code_generators/code_generators/decorator/api.py b/code_generators/code_generators/decorator/api.py index 833ea9172..89d39005d 100644 --- a/code_generators/code_generators/decorator/api.py +++ b/code_generators/code_generators/decorator/api.py @@ -11,17 +11,20 @@ class Api: 4. The function template """ - def __init__(self, api_str, api_decs, template_str=None, doc_str=None): - self.api_str = api_str # Original C++ API string - self.api_decs = api_decs - if self.api_decs is None: - self.api_decs = [] - self.template_str = template_str # Original C++ API template string + def __init__(self, path, namespace, api_str, all_decorators, + template_str=None, doc_str=None): + self.path = path # The file containing the API + self.namespace = namespace # The namespace of the API + self.api_str = api_str # Original C++ API string + self.all_decorators = all_decorators + if self.all_decorators is None: + self.all_decorators = [] + self.template_str = template_str # Original C++ API template string self.doc_str = doc_str self.name = None # The name of the API self.ret = None # Return value of the API self.params = [] # The variables in the API - self.decorators = [] # The set of function decorators + self.decorators = [] # The set of function decorators self._decompose_prototype(api_str) def _decompose_prototype(self, api_str): @@ -88,6 +91,19 @@ def pass_args(self): args = [arg[1] for arg in self.params if arg[0] != ''] return ", ".join(args) + def get_decorator_macros(self, exclude=None): + if exclude is None: + exclude = [] + return [macro for macro in self.decorators + if macro not in exclude] + + def get_decorator_macro_str(self, exclude=None): + return " ".join(self.get_decorator_macros(exclude)) + + def rm_decorator_by_macro(self, exclude_macro): + self.decorators = [macro for macro in self.decorators + if macro != exclude_macro] + """ TOKENIZATION """ @@ -311,8 +327,8 @@ def _parse_brackets(self, left, right, i, toks): return i def _is_decorator(self, i, toks): - for api_dec in self.api_decs: - if toks[i] == api_dec.api_dec: + for api_dec in self.all_decorators: + if toks[i] == api_dec.macro: return True return False @@ -329,3 +345,29 @@ def _merge_type_tuple(self, type_tuple): new_toks.append(' ') i += 1 return "".join(new_toks) + + """ + HELPERS + """ + + def __str__(self): + strs = [ + f"PATH: {self.path}", + f"NAMESPACE: {self.namespace}", + f"DECORATORS: {self.get_decorator_macros()}", + f"RETURN: {self.ret}", + f"NAME: {self.name}", + f"PARAMS: {self.params}", + ] + return "\n".join(strs) + + def __repr__(self): + strs = [ + f"PATH: {self.path}", + f"NAMESPACE: {self.namespace}", + f"DECORATORS: {self.get_decorator_macros()}", + f"RETURN: {self.ret}", + f"NAME: {self.name}", + f"PARAMS: {self.params}", + ] + return "\n".join(strs) \ No newline at end of file diff --git a/code_generators/code_generators/decorator/decorator.py b/code_generators/code_generators/decorator/decorator.py index cb486df59..bbf24b5b3 100644 --- a/code_generators/code_generators/decorator/decorator.py +++ b/code_generators/code_generators/decorator/decorator.py @@ -2,18 +2,15 @@ class ApiDecorator(ABC): - def __init__(self, api_dec): - self.api_dec = api_dec - self.autogen_dec_start = f"{self.api_dec}_AUTOGEN_START" - self.autogen_dec_end = f"{self.api_dec}_AUTOGEN_END" - - @abstractmethod - def init_api(self, api): + def __init__(self, macro): """ - Add additional information to the Api object when it's registered - for processing + :param api_dec: the string representing the decorator macro to + search for in the CPP files """ - pass + + self.macro = macro + self.autogen_dec_start = f"{self.macro}_AUTOGEN_START" + self.autogen_dec_end = f"{self.macro}_AUTOGEN_END" @abstractmethod def modify(self, api_map): @@ -31,4 +28,4 @@ def modify(self, api_map): class NullDecorator(ApiDecorator): def modify(self, api_map): - pass \ No newline at end of file + pass diff --git a/code_generators/code_generators/decorator/parse_cpp.py b/code_generators/code_generators/decorator/parse_cpp.py index 784cb04e5..e7fdd4e15 100644 --- a/code_generators/code_generators/decorator/parse_cpp.py +++ b/code_generators/code_generators/decorator/parse_cpp.py @@ -15,7 +15,7 @@ class ParseDecoratedCppApis: [path][namespace+class]['indent'] -> autogen macro indentation """ - def __init__(self, files, api_decs): + def __init__(self, files, api_decs, modify=True): """ Load the C++ header file and clean out commented lines @@ -25,6 +25,20 @@ def __init__(self, files, api_decs): self.files = files self.api_decs = api_decs self.api_map = {} + self.text_map = {} + self.modify = modify + + def parse(self): + self._parse_files() + self._apply_decorators() + self._autogen_lines() + if self.modify: + self._generate_files() + return self.text_map + + """ + TEXT CLEANING + """ def _clean_lines(self, class_lines): """ @@ -75,9 +89,9 @@ def _is_comment_end(self, line): return '*/' == line.strip()[-2:] - def parse(self): - self._parse_files() - self._apply_decorators() + """ + PARSE ALL FILES FOR DECORATED FUNCTIONS + """ def _parse_files(self): for path in self.files: @@ -89,27 +103,6 @@ def _parse_files(self): self.only_class_lines = list(zip(*self.class_lines))[1] self._parse() - def _apply_decorators(self): - while self._has_unmodified_apis(): - for api_dec in self.api_decs: - api_dec.modify(self.api_map) - self._strip_decorator(api_dec) - - def _strip_decorator(self, api_dec): - for path, namespace_dict in self.api_map.items(): - for namespace, api_dict in namespace_dict.items(): - for api in api_dict['apis'].values(): - api.decorators.remove(api_dec.dec) - if len(api.decorators) == 0: - del api_dict['apis'][api.name] - - def _has_unmodified_apis(self): - for path, namespace_dict in self.api_map.items(): - for namespace, api_dict in namespace_dict.items(): - if len(api_dict['apis']): - return True - return False - def _parse(self, namespace=None, start=None, end=None): if start == None: start = 0 @@ -163,9 +156,9 @@ class Hash = std::hash tmpl_i, tmpl_str = self._get_template_str(i) doc_str = self._get_doc_str(i) api_str,api_end = self._get_api_str(i) - api = Api(api_str, self.api_decs, tmpl_str, doc_str) + api = Api(self.hpp_file, namespace, api_str, self.api_decs, tmpl_str, doc_str) self._induct_namespace(namespace) - self.api_map[self.hpp_file][namespace]['apis'][api.name] = api + self.api_map[api.path][api.namespace]['apis'][api.name] = api return api_end + 1 def _get_doc_str(self, i): @@ -264,18 +257,20 @@ class hello { is_ns = toks[0] == 'namespace' class_name = toks[1] indent = self._indent(line) + namespace = self._ns_append(namespace, class_name) # Find the end of the class (};) - end = i + end = None if is_ns: - end_of_scope = f"{indent}}}" + end_of_scope = f"}} // namespace {namespace}" else: end_of_scope = f"{indent}}};" for off, line in enumerate(self.only_class_lines[i+1:]): if end_of_scope == line[0:len(end_of_scope)]: - end += off + end = i + 1 + off break + if end is None: + raise Exception(f"Could not find the end of {namespace}") # Parse all lines for prototypes - namespace = self._ns_append(namespace, class_name) return self._parse(namespace, i+1, end) def _parse_autogen(self, namespace, i): @@ -289,13 +284,13 @@ def _parse_autogen(self, namespace, i): self._induct_namespace(namespace) true_i, line = self.class_lines[i] - line = line.strip() + strip_line = line.strip() for api_dec in self.api_decs: - if line == api_dec.autogen_dec_start: + if strip_line == api_dec.autogen_dec_start: self.api_map[self.hpp_file][namespace]['start'] = true_i self.api_map[self.hpp_file][namespace]['indent'] = \ self._indent(line) - elif line == api_dec.autogen_dec_end: + elif strip_line == api_dec.autogen_dec_end: self.api_map[self.hpp_file][namespace]['end'] = true_i return i + 1 @@ -350,17 +345,13 @@ class hello : public language { line = self.only_class_lines[i] toks = line.split() - if len(toks) < 2: + if len(toks) < 3: return False if toks[0] != 'class' and toks[0] != 'struct' and toks[0] != 'union': return False - for true_i, line in self.class_lines[i:]: - toks = line.split() - if toks[-1] == ';': - return False - if toks[-1] == '{': - return True - raise f"class {toks[1]} definition missing either ; or {{" + if toks[2] != '{' and toks[2] != ':': + return False + return True def _is_api(self, i): """ @@ -379,7 +370,7 @@ def _is_api(self, i): for tok in toks: if '#' in tok: return False - if tok == api_dec.api_dec: + if tok == api_dec.macro: return True return False @@ -407,7 +398,8 @@ def _induct_namespace(self, namespace): 'apis': {}, 'start': None, 'end': None, - 'indent': None + 'indent': '', + 'gen': [] } @staticmethod @@ -419,4 +411,61 @@ def _ns_append(namespace, suffix): @staticmethod def _indent(line): ilen = len(line) - len(line.lstrip()) - return line[0:ilen] \ No newline at end of file + return line[0:ilen] + + """ + APPLY DECORATORS AFTER PARSING + """ + + def _apply_decorators(self): + while self._has_unmodified_apis(): + for api_dec in self.api_decs: + api_dec.modify(self.api_map) + self._strip_decorator(api_dec) + + def _strip_decorator(self, api_dec): + for path, namespace_dict in self.api_map.items(): + for namespace, api_dict in namespace_dict.items(): + cur_apis = list(api_dict['apis'].values()) + for api in cur_apis: + if api_dec.macro in api.get_decorator_macros(): + api.rm_decorator_by_macro(api_dec.macro) + if len(api.decorators) == 0: + del api_dict['apis'][api.name] + + def _has_unmodified_apis(self): + for path, namespace_dict in self.api_map.items(): + for namespace, api_dict in namespace_dict.items(): + if len(api_dict['apis']): + return True + return False + + """ + GENERATE THE FINAL OUTPUT + """ + + def _autogen_lines(self): + self.text_map = {} + for path, namespace_dict in self.api_map.items(): + with open(path) as fp: + lines = fp.read().splitlines() + autogens = list(namespace_dict.values()) + autogens.sort(reverse=True, key=lambda x : x['start']) + for api_dict in autogens: + autogen = api_dict['gen'] + start = api_dict['start'] + end = api_dict['end'] + + # Remove (start, end) + # I.e, include everything up to start + # and include everything after end + lines = lines[0:start+1] + lines[end:] + + # Add new autogen APIs + lines = lines[0:start+1] + autogen + lines[end:] + self.text_map[path] = "\n".join(lines) + + def _generate_files(self): + for path, text in self.text_map.items(): + with open(path, 'w') as fp: + fp.write(text) diff --git a/code_generators/code_generators/rpc/generator.py b/code_generators/code_generators/rpc/generator.py index 566cc9532..9c992c300 100644 --- a/code_generators/code_generators/rpc/generator.py +++ b/code_generators/code_generators/rpc/generator.py @@ -1,6 +1,7 @@ import os from code_generators.decorator.decorator import ApiDecorator from code_generators.decorator.api import Api +from code_generators.util.naming import to_snake_case from code_generators.util.conv import str_to_bool rpc_func_text = """ @@ -56,7 +57,6 @@ def __init__(self): super().__init__("RPC") self.path = None - self.macro = None self.class_instance = None self.rpcs = {} # [class_path][class_name][api_name] -> # tuple(local_rpc_name, target_node, @@ -106,9 +106,6 @@ def add(self, local_rpc_name, target_node): self.rpcs[self.path][self.class_name][local_rpc_name] = ( (target_node, self.class_instance)) - def init_api(self, api): - pass - def modify(self, api_map): """ Generates the RPCs (GlobalRPC + lambda) for a particular class file @@ -124,25 +121,32 @@ def modify(self, api_map): # Autogen RPCs for each class for path, namespace_dict in api_map.items(): + if path not in self.rpcs: + continue for namespace, api_dict in namespace_dict.items(): indent = api_dict['indent'] + if namespace not in self.rpcs[path]: + continue for local_rpc_api in api_dict['apis'].values(): if "RPC" not in local_rpc_api.decorators: continue - if local_rpc_api.name in rpc_info: - pass + if local_rpc_api.name not in self.rpcs[path][namespace]: + continue rpc_info = self.rpcs[path][namespace][local_rpc_api.name] target_node = rpc_info[0] class_instance = rpc_info[1] # Generate RPC code - rpc_api = self.create_global_rpc_func(local_rpc_api, - target_node, indent) - rpc_lambda = self.create_rpc_lambda(local_rpc_api, - class_instance, indent) + global_name = local_rpc_api.name.replace("Local", "") + lambda_name = f"remote_{to_snake_case(global_name)}" + rpc_api = self.create_global_rpc_func( + global_name, local_rpc_api, target_node, indent) + rpc_lambda = self.create_rpc_lambda( + global_name, lambda_name, + local_rpc_api, class_instance, indent) # Add the generated code to the API map - if len(rpc_api.decorators): + if len(rpc_api.decorators) == 1: api_dict['apis'][rpc_api.name] = rpc_api else: api_dict['gen'].append(rpc_api.api_str) @@ -154,27 +158,29 @@ def add_space(self, space, text): lines[j] = f"{space}{line}" return "\n".join(lines) - def create_global_rpc_func(self, rpc, target_node, indent): + def create_global_rpc_func(self, global_name, rpc, target_node, indent): func = rpc_func_text.format( - DEC=rpc.get_decorators("RPC"), + DEC=rpc.get_decorator_macro_str("RPC"), RET=rpc.ret, LOCAL_NAME=rpc.name, - GLOBAL_NAME=rpc.global_name, + GLOBAL_NAME=global_name, PARAMS=rpc.get_args(), PASS_PARAMS=rpc.pass_args(), TARGET_NODE=target_node ).strip() func = self.add_space(indent, func) - return Api(func) + return Api(rpc.path, rpc.namespace, func, + rpc.all_decorators) - def create_rpc_lambda(self, rpc, class_instance, indent): + def create_rpc_lambda(self, global_name, lambda_name, + rpc, class_instance, indent): lambda_text = rpc_lambda_text if class_instance is None: lambda_text = rpc_lambda_text_void func = lambda_text.format( - DEC=rpc.get_decorators("RPC"), - GLOBAL_NAME=rpc.global_name, - LAMBDA_NAME=rpc.lambda_name, + DEC=rpc.get_decorator_macro_str("RPC"), + GLOBAL_NAME=global_name, + LAMBDA_NAME=lambda_name, class_instance=class_instance, PARAMS=rpc.get_args(), PASS_PARAMS=rpc.pass_args(), diff --git a/code_generators/code_generators/util/conv.py b/code_generators/code_generators/util/conv.py index 30c61694a..40274922a 100644 --- a/code_generators/code_generators/util/conv.py +++ b/code_generators/code_generators/util/conv.py @@ -5,4 +5,4 @@ def str_to_bool(text): return False elif text == 'true': return True - raise "Neither true or false (str_too_bool)" \ No newline at end of file + raise Exception("Neither true or false (str_too_bool)") \ No newline at end of file diff --git a/code_generators/unit/api/apis.h b/code_generators/unit/api/apis.h index e0a0069c5..fb32f0347 100644 --- a/code_generators/unit/api/apis.h +++ b/code_generators/unit/api/apis.h @@ -3,7 +3,7 @@ // namespace hello::hi { -} +} // namespace hello::hi #ifndef HERMES_CODE_GENERATORS_CODE_GENERATORS_UNIT_PROTOS_H_ #define HERMES_CODE_GENERATORS_CODE_GENERATORS_UNIT_PROTOS_H_ @@ -18,7 +18,8 @@ namespace hello::hi { #define WRAP_AUTOGEN_START #define WRAP_AUTOGEN_END -struct Ctx {}; +struct Ctx { +}; int f1(); @@ -38,19 +39,42 @@ WRAP RPC std::vector& Localf5(int a, std::vector b, Ctx = Ctx()); +/** +* This is considered a docstring +*/ WRAP RPC std::vector& Localf6(int a, std::vector b, Ctx = Ctx()); namespace nstest { +/** +* This is considered a docstring +*/ RPC int Localf99(); template class Hi { RPC int Localf100(); + + RPC_AUTOGEN_START + RPC_AUTOGEN_END }; -RPC int Localf101(); -} +template +class BigHi { + RPC int Localf101(); + + RPC_AUTOGEN_START + RPC_AUTOGEN_END +}; + +RPC int Localf102(); + +RPC_AUTOGEN_START +RPC_AUTOGEN_END +} // namespace nstest + +RPC_AUTOGEN_START +RPC_AUTOGEN_END #endif // HERMES_CODE_GENERATORS_CODE_GENERATORS_UNIT_PROTOS_H_ diff --git a/code_generators/unit/api/test.py b/code_generators/unit/api/test.py index 269134647..c014712ee 100644 --- a/code_generators/unit/api/test.py +++ b/code_generators/unit/api/test.py @@ -19,11 +19,14 @@ def create_rpc_generator(): gen.set_class("nstest", None) gen.add("Localf99", "5") - gen.add("Localf101", "6") + gen.add("Localf102", "6") gen.set_class("nstest::Hi", "hi") gen.add("Localf100", "7") + gen.set_class("nstest::BigHi", "hi2") + gen.add("Localf101", "8") + return gen files = [ @@ -36,5 +39,7 @@ def create_rpc_generator(): NullDecorator("WRAP") ] -gen = ParseDecoratedCppApis(files, decs) -gen.parse() \ No newline at end of file +gen = ParseDecoratedCppApis(files, decs, modify=False) +gen.parse() +print(gen.text_map[files[0]]) +print(gen.text_map[files[1]]) diff --git a/code_generators/unit/cpp_toks/test.py b/code_generators/unit/cpp_toks/test.py index 4fbff78bd..9e81fd19e 100644 --- a/code_generators/unit/cpp_toks/test.py +++ b/code_generators/unit/cpp_toks/test.py @@ -8,15 +8,11 @@ Ctx ctx = Ctx()); """ -text = """ +text2 = """ RPC int f2(); """ gen = RpcGenerator() -api = Api(text, [gen]) +api = Api(None, None, text, [gen]) -print(api.name) -print(api.ret) -print(api.params) -print(api.get_args()) -print(api.pass_args()) \ No newline at end of file +print(api) \ No newline at end of file From e62370205894263a8f17f23690d30e69e0d65fd4 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 7 Dec 2022 05:06:20 -0600 Subject: [PATCH 060/511] API map shows that docstrings can be parsed --- .../code_generators/decorator/parse_cpp.py | 22 +++++++++++-------- code_generators/unit/api/apis.h | 7 ++++++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/code_generators/code_generators/decorator/parse_cpp.py b/code_generators/code_generators/decorator/parse_cpp.py index e7fdd4e15..9d29ee3d6 100644 --- a/code_generators/code_generators/decorator/parse_cpp.py +++ b/code_generators/code_generators/decorator/parse_cpp.py @@ -154,8 +154,8 @@ class Hash = std::hash """ tmpl_i, tmpl_str = self._get_template_str(i) - doc_str = self._get_doc_str(i) api_str,api_end = self._get_api_str(i) + doc_str = self._get_doc_str(i) api = Api(self.hpp_file, namespace, api_str, self.api_decs, tmpl_str, doc_str) self._induct_namespace(namespace) self.api_map[api.path][api.namespace]['apis'][api.name] = api @@ -167,8 +167,10 @@ def _get_doc_str(self, i): """ in_comment = False - docstr_i = i - for class_line in reversed(self.orig_class_lines[:i - 1]): + true_i = self.class_lines[i][0] + docstr_i = true_i + cur_line = self.orig_class_lines[true_i] + for class_line in reversed(self.orig_class_lines[:true_i]): strip_class_line = class_line.strip() if len(strip_class_line) == 0: docstr_i -= 1 @@ -179,7 +181,7 @@ def _get_doc_str(self, i): continue if strip_class_line[0:2] == '/*': in_comment = False - return "\n".join(self.orig_class_lines[docstr_i:i]) + return "\n".join(self.orig_class_lines[docstr_i:true_i]) if strip_class_line[0:2] == '//': return i if in_comment: @@ -197,18 +199,20 @@ def _get_template_str(self, i): if i == 0: return i, None - if '>' not in self.only_class_lines[i-1]: + prior_line = self.only_class_lines[i-1] + if '>' not in prior_line: return i, None tmpl_i = None - for class_line in reversed(self.only_class_lines[:i-1]): + off = 1 + for class_line in reversed(self.only_class_lines[:i]): toks = class_line.split() if 'template' in toks[0]: - tmpl_i = i + tmpl_i = i - off break - i -= 1 + off += 1 if tmpl_i is None: return i, None - tmpl_str = self.only_class_lines[tmpl_i:i] + tmpl_str = "".join(self.only_class_lines[tmpl_i:i]) return tmpl_i, tmpl_str def _get_api_str(self, i): diff --git a/code_generators/unit/api/apis.h b/code_generators/unit/api/apis.h index fb32f0347..4859ac9ec 100644 --- a/code_generators/unit/api/apis.h +++ b/code_generators/unit/api/apis.h @@ -25,6 +25,10 @@ int f1(); RPC int Localf2(); +/** +* This is considered a docstring +*/ + RPC int Localf3(int a, int b); template @@ -32,6 +36,9 @@ RPC std::vector& Localf4(int a, std::vector b, Ctx = Ctx()); +/** +* This is considered a docstring +*/ template> From 596e71f2cefaaf404cc717d073f03d6838931635 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 7 Dec 2022 05:35:42 -0600 Subject: [PATCH 061/511] Docstring parser --- .../code_generators/decorator/api.py | 5 ++ .../decorator/parse_docstring.py | 26 ++++++++ .../code_generators/rpc/generator.py | 63 +++---------------- .../code_generators/rpc/parse_docstring.py | 12 ++++ code_generators/unit/api/test.py | 22 +------ src/api/bucket.h | 5 +- src/metadata_manager.h | 44 +++++++++++++ 7 files changed, 96 insertions(+), 81 deletions(-) create mode 100644 code_generators/code_generators/decorator/parse_docstring.py create mode 100644 code_generators/code_generators/rpc/parse_docstring.py diff --git a/code_generators/code_generators/decorator/api.py b/code_generators/code_generators/decorator/api.py index 89d39005d..943d63443 100644 --- a/code_generators/code_generators/decorator/api.py +++ b/code_generators/code_generators/decorator/api.py @@ -91,6 +91,11 @@ def pass_args(self): args = [arg[1] for arg in self.params if arg[0] != ''] return ", ".join(args) + def get_scoped_name(self): + if self.namespace is None or len(self.namespace) == 0: + return self.name + return f"{self.namespace}::{self.name}" + def get_decorator_macros(self, exclude=None): if exclude is None: exclude = [] diff --git a/code_generators/code_generators/decorator/parse_docstring.py b/code_generators/code_generators/decorator/parse_docstring.py new file mode 100644 index 000000000..f97f2fdeb --- /dev/null +++ b/code_generators/code_generators/decorator/parse_docstring.py @@ -0,0 +1,26 @@ +from abc import ABC, abstractmethod +import re + + +class ParseDocstring(ABC): + def __init__(self, api): + self.api = api + self.doc_str = self.api.doc_str + if self.doc_str is None: + self.doc_str = "" + self.lines = self.doc_str.splitlines() + + def get_param(self, param_name, required=True): + param_name = f"@{param_name}" + for line in self.lines: + if param_name in line: + line = line[line.find(param_name) + len(param_name):] + param_val = line.strip() + return param_val + if required: + raise Exception(f"The parameter {param_name} was not found " + f"in {self.api.get_scoped_name()} for RPC") + + @abstractmethod + def parse(self): + pass \ No newline at end of file diff --git a/code_generators/code_generators/rpc/generator.py b/code_generators/code_generators/rpc/generator.py index 9c992c300..44b6d5426 100644 --- a/code_generators/code_generators/rpc/generator.py +++ b/code_generators/code_generators/rpc/generator.py @@ -3,6 +3,8 @@ from code_generators.decorator.api import Api from code_generators.util.naming import to_snake_case from code_generators.util.conv import str_to_bool +from .parse_docstring import RpcDocstring + rpc_func_text = """ {DEC} @@ -49,7 +51,7 @@ class RpcGenerator(ApiDecorator): - def __init__(self): + def __init__(self, rpc_defs_path): """ Automatically inserts RPC code into class files and builds rpc_thallium_defs.cc. @@ -58,54 +60,8 @@ def __init__(self): super().__init__("RPC") self.path = None self.class_instance = None - self.rpcs = {} # [class_path][class_name][api_name] -> - # tuple(local_rpc_name, target_node, - # class_instance) - - def set_rpc_lambda_file(self, rpc_defs_path): self.rpc_defs_path = rpc_defs_path - def set_file(self, path): - """ - Sets information used in subsequent calls to "add". - - :param path: the path to the class containing RPC prototypes - (e.g., metadata_manager.h) - """ - - self.path = path - - def set_class(self, class_name, class_instance): - """ - Sets information used in subsequent calls to "add". - - :param class_name: the name of the class to scan prototypes from - (e.g., hermes::MetadataManager). Namespace is required. - :param class_instance: The name of the C++ class instance to input - into the RPC lambda in rpc_thallium_defs.cc (e.g., mdm). These are - encapsulated in RPC_CLASS_INSTANCE_DEFS in rpc_thallium_defs.cc. - :return: None - """ - self.class_name = class_name - self.class_instance = class_instance - - def add(self, local_rpc_name, target_node): - """ - Register an RPC to scan for. - - :param local_rpc_name: The local name of the RPC in a C++ class - (e.g., LocalGetOrCreateBucket) - :param target_node: The C++ code to determine the node to execute an RPC - :return: None - """ - - if self.path not in self.rpcs: - self.rpcs[self.path] = {} - if self.class_name not in self.rpcs[self.path]: - self.rpcs[self.path][self.class_name] = {} - self.rpcs[self.path][self.class_name][local_rpc_name] = ( - (target_node, self.class_instance)) - def modify(self, api_map): """ Generates the RPCs (GlobalRPC + lambda) for a particular class file @@ -121,20 +77,15 @@ def modify(self, api_map): # Autogen RPCs for each class for path, namespace_dict in api_map.items(): - if path not in self.rpcs: - continue for namespace, api_dict in namespace_dict.items(): indent = api_dict['indent'] - if namespace not in self.rpcs[path]: - continue for local_rpc_api in api_dict['apis'].values(): if "RPC" not in local_rpc_api.decorators: continue - if local_rpc_api.name not in self.rpcs[path][namespace]: - continue - rpc_info = self.rpcs[path][namespace][local_rpc_api.name] - target_node = rpc_info[0] - class_instance = rpc_info[1] + doc = RpcDocstring(local_rpc_api) + doc.parse() + target_node = doc.target_node + class_instance = doc.class_instance # Generate RPC code global_name = local_rpc_api.name.replace("Local", "") diff --git a/code_generators/code_generators/rpc/parse_docstring.py b/code_generators/code_generators/rpc/parse_docstring.py new file mode 100644 index 000000000..4cd7f165f --- /dev/null +++ b/code_generators/code_generators/rpc/parse_docstring.py @@ -0,0 +1,12 @@ +from code_generators.decorator.parse_docstring import ParseDocstring + + +class RpcDocstring(ParseDocstring): + def __init__(self, api): + super().__init__(api) + self.target_node = None + self.class_instance = None + + def parse(self): + self.target_node = self.get_param("RPC_HASH") + self.class_instance = self.get_param("RPC_CLASS") diff --git a/code_generators/unit/api/test.py b/code_generators/unit/api/test.py index c014712ee..6aa521ca0 100644 --- a/code_generators/unit/api/test.py +++ b/code_generators/unit/api/test.py @@ -5,28 +5,8 @@ def create_rpc_generator(): - gen = RpcGenerator() rpc_defs_path = f"{HERMES_ROOT}/code_generators/unit/api/rpcs.cc" - gen.set_rpc_lambda_file(rpc_defs_path) - - gen.set_file(f"{HERMES_ROOT}/code_generators/unit/api/apis.h") - gen.set_class(None, None) - gen.add("Localf2", "0") - gen.add("Localf3", "1") - gen.add("Localf4", "2") - gen.add("Localf5", "3") - gen.add("Localf6", "4") - - gen.set_class("nstest", None) - gen.add("Localf99", "5") - gen.add("Localf102", "6") - - gen.set_class("nstest::Hi", "hi") - gen.add("Localf100", "7") - - gen.set_class("nstest::BigHi", "hi2") - gen.add("Localf101", "8") - + gen = RpcGenerator(rpc_defs_path) return gen files = [ diff --git a/src/api/bucket.h b/src/api/bucket.h index 5d15ad588..37e370fc4 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -79,14 +79,11 @@ class Bucket { /** * Get \a blob_id Blob from the bucket + * :WRAP-param: ctx -> ctx_ * */ Status GetBlob(BlobID blob_id, Blob &blob, Context &ctx); - public: - CONTEXT_AUTOGEN_START - CONTEXT_AUTOGEN_END - public: RPC_AUTOGEN_START RPC_AUTOGEN_END diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 1dd1e9ea9..e117f575b 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -53,27 +53,37 @@ class MetadataManager { /** * Get or create a bucket with \a bkt_name bucket name + * + * @RPC_HASH 0 * */ RPC BucketID LocalGetOrCreateBucket(std::string bkt_name); /** * Get the BucketID with \a bkt_name bucket name + * + * @RPC_HASH 0 * */ RPC BucketID LocalGetBucketId(std::string bkt_name); /** * Check whether or not \a bkt_id bucket contains * \a blob_id blob + * + * @RPC_HASH 0 * */ RPC bool LocalBucketContainsBlob(BucketID bkt_id, BlobID blob_id); /** * Rename \a bkt_id bucket to \a new_bkt_name new name + * + * @RPC_HASH 0 * */ RPC bool LocalRenameBucket(BucketID bkt_id, std::string new_bkt_name); /** * Destroy \a bkt_id bucket + * + * @RPC_HASH 0 * */ RPC bool LocalDestroyBucket(BucketID bkt_id); @@ -84,6 +94,8 @@ class MetadataManager { * @param blob_name semantic blob name * @param data the data being placed * @param buffers the buffers to place data in + * + * @RPC_HASH 0 * */ RPC BlobID LocalBucketPutBlob(BucketID bkt_id, std::string blob_name, @@ -92,17 +104,23 @@ class MetadataManager { /** * Get \a blob_name blob from \a bkt_id bucket + * + * @RPC_HASH 0 * */ RPC BlobID LocalGetBlobId(BucketID bkt_id, std::string blob_name); /** * Change \a blob_id blob's buffers to \the buffers + * + * @RPC_HASH 0 * */ RPC bool LocalSetBlobBuffers(BlobID blob_id, std::vector &buffers); /** * Get \a blob_id blob's buffers + * + * @RPC_HASH 0 * */ RPC std::vector& LocalGetBlobBuffers(BlobID blob_id); @@ -110,47 +128,65 @@ class MetadataManager { /** * Rename \a blob_id blob to \a new_blob_name new blob name * in \a bkt_id bucket. + * + * @RPC_HASH 0 * */ RPC bool LocalRenameBlob(BucketID bkt_id, BlobID blob_id, std::string new_blob_name); /** * Destroy \a blob_id blob in \a bkt_id bucket + * + * @RPC_HASH 0 * */ RPC bool LocalDestroyBlob(BucketID bkt_id, std::string blob_name); /** * Acquire \a blob_id blob's write lock + * + * @RPC_HASH 0 * */ RPC bool LocalWriteLockBlob(BlobID blob_id); /** * Release \a blob_id blob's write lock + * + * @RPC_HASH 0 * */ RPC bool LocalWriteUnlockBlob(BlobID blob_id); /** * Acquire \a blob_id blob's read lock + * + * @RPC_HASH 0 * */ RPC bool LocalReadLockBlob(BlobID blob_id); /** * Release \a blob_id blob's read lock + * + * @RPC_HASH 0 * */ RPC bool LocalReadUnlockBlob(BlobID blob_id); /** * Get or create \a vbkt_name VBucket + * + * @RPC_HASH 0 * */ RPC VBucketID LocalGetOrCreateVBucket(std::string vbkt_name); /** * Get the VBucketID of \a vbkt_name VBucket + * + * @RPC_HASH 0 * */ RPC VBucketID LocalGetVBucketId(std::string vbkt_name); /** * Link \a vbkt_id VBucketID + * + * @RPC_HASH 0 * */ RPC VBucketID LocalVBucketLinkBlob(VBucketID vbkt_id, BucketID bkt_id, @@ -159,6 +195,8 @@ class MetadataManager { /** * Unlink \a blob_name Blob of \a bkt_id Bucket * from \a vbkt_id VBucket + * + * @RPC_HASH 0 * */ RPC VBucketID LocalVBucketUnlinkBlob(VBucketID vbkt_id, BucketID bkt_id, @@ -166,17 +204,23 @@ class MetadataManager { /** * Get the linked blobs from \a vbkt_id VBucket + * + * @RPC_HASH 0 * */ RPC std::list LocalVBucketGetLinks(VBucketID vbkt_id); /** * Rename \a vbkt_id VBucket to \a new_vbkt_name name + * + * @RPC_HASH 0 * */ RPC bool LocalRenameVBucket(VBucketID vbkt_id, std::string new_vbkt_name); /** * Destroy \a vbkt_id VBucket + * + * @RPC_HASH 0 * */ RPC bool LocalDestroyVBucket(VBucketID vbkt_id); From 2001981f4bf3f86f18704efd564f0581df36050d Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 7 Dec 2022 05:55:22 -0600 Subject: [PATCH 062/511] Pass parameters to decorator using docstring --- .../code_generators/decorator/parse_cpp.py | 2 +- .../code_generators/rpc/parse_docstring.py | 4 +- code_generators/unit/api/apis.h | 58 +++++++++++++--- src/metadata_manager.h | 66 ++++++++++++------- 4 files changed, 97 insertions(+), 33 deletions(-) diff --git a/code_generators/code_generators/decorator/parse_cpp.py b/code_generators/code_generators/decorator/parse_cpp.py index 9d29ee3d6..60290c87a 100644 --- a/code_generators/code_generators/decorator/parse_cpp.py +++ b/code_generators/code_generators/decorator/parse_cpp.py @@ -155,7 +155,7 @@ class Hash = std::hash tmpl_i, tmpl_str = self._get_template_str(i) api_str,api_end = self._get_api_str(i) - doc_str = self._get_doc_str(i) + doc_str = self._get_doc_str(tmpl_i) api = Api(self.hpp_file, namespace, api_str, self.api_decs, tmpl_str, doc_str) self._induct_namespace(namespace) self.api_map[api.path][api.namespace]['apis'][api.name] = api diff --git a/code_generators/code_generators/rpc/parse_docstring.py b/code_generators/code_generators/rpc/parse_docstring.py index 4cd7f165f..c51bf29d5 100644 --- a/code_generators/code_generators/rpc/parse_docstring.py +++ b/code_generators/code_generators/rpc/parse_docstring.py @@ -8,5 +8,5 @@ def __init__(self, api): self.class_instance = None def parse(self): - self.target_node = self.get_param("RPC_HASH") - self.class_instance = self.get_param("RPC_CLASS") + self.target_node = self.get_param("RPC_TARGET_NODE") + self.class_instance = self.get_param("RPC_CLASS_INSTANCE") diff --git a/code_generators/unit/api/apis.h b/code_generators/unit/api/apis.h index 4859ac9ec..a235efe52 100644 --- a/code_generators/unit/api/apis.h +++ b/code_generators/unit/api/apis.h @@ -23,22 +23,40 @@ struct Ctx { int f1(); +/** + * Get or create a bucket with \a bkt_name bucket name + * + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm + * */ RPC int Localf2(); /** -* This is considered a docstring -*/ + * Get or create a bucket with \a bkt_name bucket name + * + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm + * */ RPC int Localf3(int a, int b); +/** + * Get or create a bucket with \a bkt_name bucket name + * + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm + * */ template RPC std::vector& Localf4(int a, std::vector b, Ctx = Ctx()); /** -* This is considered a docstring -*/ + * Get or create a bucket with \a bkt_name bucket name + * + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm + * */ template> @@ -47,20 +65,32 @@ WRAP RPC std::vector& Localf5(int a, Ctx = Ctx()); /** -* This is considered a docstring -*/ + * Get or create a bucket with \a bkt_name bucket name + * + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm + * */ WRAP RPC std::vector& Localf6(int a, std::vector b, Ctx = Ctx()); namespace nstest { /** -* This is considered a docstring -*/ + * Get or create a bucket with \a bkt_name bucket name + * + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm + * */ RPC int Localf99(); template class Hi { + /** + * Get or create a bucket with \a bkt_name bucket name + * + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm + * */ RPC int Localf100(); RPC_AUTOGEN_START @@ -69,12 +99,24 @@ class Hi { template class BigHi { + /** + * Get or create a bucket with \a bkt_name bucket name + * + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm + * */ RPC int Localf101(); RPC_AUTOGEN_START RPC_AUTOGEN_END }; +/** + * Get or create a bucket with \a bkt_name bucket name + * + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm + * */ RPC int Localf102(); RPC_AUTOGEN_START diff --git a/src/metadata_manager.h b/src/metadata_manager.h index e117f575b..cc06ccafb 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -54,14 +54,16 @@ class MetadataManager { /** * Get or create a bucket with \a bkt_name bucket name * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC BucketID LocalGetOrCreateBucket(std::string bkt_name); /** * Get the BucketID with \a bkt_name bucket name * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC BucketID LocalGetBucketId(std::string bkt_name); @@ -69,21 +71,24 @@ class MetadataManager { * Check whether or not \a bkt_id bucket contains * \a blob_id blob * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalBucketContainsBlob(BucketID bkt_id, BlobID blob_id); /** * Rename \a bkt_id bucket to \a new_bkt_name new name * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalRenameBucket(BucketID bkt_id, std::string new_bkt_name); /** * Destroy \a bkt_id bucket * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalDestroyBucket(BucketID bkt_id); @@ -95,7 +100,8 @@ class MetadataManager { * @param data the data being placed * @param buffers the buffers to place data in * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC BlobID LocalBucketPutBlob(BucketID bkt_id, std::string blob_name, @@ -105,14 +111,16 @@ class MetadataManager { /** * Get \a blob_name blob from \a bkt_id bucket * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC BlobID LocalGetBlobId(BucketID bkt_id, std::string blob_name); /** * Change \a blob_id blob's buffers to \the buffers * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalSetBlobBuffers(BlobID blob_id, std::vector &buffers); @@ -120,7 +128,8 @@ class MetadataManager { /** * Get \a blob_id blob's buffers * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC std::vector& LocalGetBlobBuffers(BlobID blob_id); @@ -129,7 +138,8 @@ class MetadataManager { * Rename \a blob_id blob to \a new_blob_name new blob name * in \a bkt_id bucket. * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalRenameBlob(BucketID bkt_id, BlobID blob_id, std::string new_blob_name); @@ -137,56 +147,64 @@ class MetadataManager { /** * Destroy \a blob_id blob in \a bkt_id bucket * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalDestroyBlob(BucketID bkt_id, std::string blob_name); /** * Acquire \a blob_id blob's write lock * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalWriteLockBlob(BlobID blob_id); /** * Release \a blob_id blob's write lock * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalWriteUnlockBlob(BlobID blob_id); /** * Acquire \a blob_id blob's read lock * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalReadLockBlob(BlobID blob_id); /** * Release \a blob_id blob's read lock * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalReadUnlockBlob(BlobID blob_id); /** * Get or create \a vbkt_name VBucket * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC VBucketID LocalGetOrCreateVBucket(std::string vbkt_name); /** * Get the VBucketID of \a vbkt_name VBucket * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC VBucketID LocalGetVBucketId(std::string vbkt_name); /** * Link \a vbkt_id VBucketID * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC VBucketID LocalVBucketLinkBlob(VBucketID vbkt_id, BucketID bkt_id, @@ -196,7 +214,8 @@ class MetadataManager { * Unlink \a blob_name Blob of \a bkt_id Bucket * from \a vbkt_id VBucket * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC VBucketID LocalVBucketUnlinkBlob(VBucketID vbkt_id, BucketID bkt_id, @@ -205,14 +224,16 @@ class MetadataManager { /** * Get the linked blobs from \a vbkt_id VBucket * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC std::list LocalVBucketGetLinks(VBucketID vbkt_id); /** * Rename \a vbkt_id VBucket to \a new_vbkt_name name * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalRenameVBucket(VBucketID vbkt_id, std::string new_vbkt_name); @@ -220,7 +241,8 @@ class MetadataManager { /** * Destroy \a vbkt_id VBucket * - * @RPC_HASH 0 + * @RPC_TARGET_NODE 0 + * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalDestroyVBucket(VBucketID vbkt_id); From 6a5bbf5fe6fd2aec573c48d4cf0fa5da9d8ab36a Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 7 Dec 2022 06:07:38 -0600 Subject: [PATCH 063/511] Make docstring parsing more reliable --- .../code_generators/decorator/parse_cpp.py | 99 ++++++++++--------- code_generators/unit/api/apis.h | 4 + 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/code_generators/code_generators/decorator/parse_cpp.py b/code_generators/code_generators/decorator/parse_cpp.py index 60290c87a..f51612830 100644 --- a/code_generators/code_generators/decorator/parse_cpp.py +++ b/code_generators/code_generators/decorator/parse_cpp.py @@ -7,12 +7,12 @@ class ParseDecoratedCppApis: Parse a C++ header file and get the set of all decorated prototypes and autogen statements. This parser makes various assumptions about the C++ style. These are defined in: - _is_class, _is_namespace, _is_api + _is_class, _is_full_namespace, _is_api :return: self.api_map - [path][namespace+class]['apis'][api_name] -> API() - [path][namespace+class]['start'] -> autogen macro start - [path][namespace+class]['end'] -> autogen macro end - [path][namespace+class]['indent'] -> autogen macro indentation + [path][full_namespace+class]['apis'][api_name] -> API() + [path][full_namespace+class]['start'] -> autogen macro start + [path][full_namespace+class]['end'] -> autogen macro end + [path][full_namespace+class]['indent'] -> autogen macro indentation """ def __init__(self, files, api_decs, modify=True): @@ -103,7 +103,7 @@ def _parse_files(self): self.only_class_lines = list(zip(*self.class_lines))[1] self._parse() - def _parse(self, namespace=None, start=None, end=None): + def _parse(self, full_namespace=None, start=None, end=None): if start == None: start = 0 if end == None: @@ -111,19 +111,19 @@ def _parse(self, namespace=None, start=None, end=None): i = start while i < end: line = self.class_lines[i] - if self._is_namespace(i) or self._is_class(i): - i = self._parse_class_or_ns(namespace, i) + if self._is_full_namespace(i) or self._is_class(i): + i = self._parse_class_or_ns(full_namespace, i) continue elif self._is_api(i): - i = self._parse_api(namespace, i) + i = self._parse_api(full_namespace, i) continue elif self._is_autogen(i): - i = self._parse_autogen(namespace, i) + i = self._parse_autogen(full_namespace, i) continue i += 1 return i - def _parse_api(self, namespace, i): + def _parse_api(self, full_namespace, i): """ Determines the set of text belonging to a particular API. ASSUMPTIONS: @@ -148,7 +148,7 @@ class Hash = std::hash RP - :param namespace: the C++ namespace + class the API belongs to + :param full_namespace: the C++ full_namespace + class the API belongs to :param i: the line containing part of the API definition :return: None. Modifies the """ @@ -156,8 +156,8 @@ class Hash = std::hash tmpl_i, tmpl_str = self._get_template_str(i) api_str,api_end = self._get_api_str(i) doc_str = self._get_doc_str(tmpl_i) - api = Api(self.hpp_file, namespace, api_str, self.api_decs, tmpl_str, doc_str) - self._induct_namespace(namespace) + api = Api(self.hpp_file, full_namespace, api_str, self.api_decs, tmpl_str, doc_str) + self._induct_full_namespace(full_namespace) self.api_map[api.path][api.namespace]['apis'][api.name] = api return api_end + 1 @@ -183,11 +183,12 @@ def _get_doc_str(self, i): in_comment = False return "\n".join(self.orig_class_lines[docstr_i:true_i]) if strip_class_line[0:2] == '//': - return i + docstr_i -= 1 + continue if in_comment: docstr_i -= 1 continue - return None + return "\n".join(self.orig_class_lines[docstr_i:true_i]) def _get_template_str(self, i): """ @@ -235,9 +236,9 @@ def _get_api_str(self, i): api_str = "\n".join(self.only_class_lines[i:api_end+1]) return api_str, api_end - def _parse_class_or_ns(self, namespace, i): + def _parse_class_or_ns(self, full_namespace, i): """ - Parse all APIs within the boundaries of a class or namespace. + Parse all APIs within the boundaries of a class or full_namespace. ASSUMPTIONS: 1. A class is terminated with the first }; that has equivalent @@ -249,7 +250,7 @@ class hello { class hello { }; // "class" and }; are misaligned vertically - :param namespace: the current namespace the class is apart of + :param full_namespace: the current full_namespace the class is apart of :param i: The line to start parsing at :return: The index of the terminating }; """ @@ -259,9 +260,9 @@ class hello { toks = re.split("[ \{]", line) toks = [tok .strip() for tok in toks if tok is not None and len(tok)] is_ns = toks[0] == 'namespace' - class_name = toks[1] + namespace = toks[1] indent = self._indent(line) - namespace = self._ns_append(namespace, class_name) + full_namespace = self._ns_append(full_namespace, namespace) # Find the end of the class (};) end = None if is_ns: @@ -273,41 +274,41 @@ class hello { end = i + 1 + off break if end is None: - raise Exception(f"Could not find the end of {namespace}") + raise Exception(f"Could not find the end of {full_namespace}") # Parse all lines for prototypes - return self._parse(namespace, i+1, end) + return self._parse(full_namespace, i+1, end) - def _parse_autogen(self, namespace, i): + def _parse_autogen(self, full_namespace, i): """ - Parse the AUTOGEN keyword statements for a particular namespace + Parse the AUTOGEN keyword statements for a particular full_namespace - :param namespace: the current namespace the autogen is apart of + :param full_namespace: the current full_namespace the autogen is apart of :param i: The line to start parsing at :return: """ - self._induct_namespace(namespace) + self._induct_full_namespace(full_namespace) true_i, line = self.class_lines[i] strip_line = line.strip() for api_dec in self.api_decs: if strip_line == api_dec.autogen_dec_start: - self.api_map[self.hpp_file][namespace]['start'] = true_i - self.api_map[self.hpp_file][namespace]['indent'] = \ + self.api_map[self.hpp_file][full_namespace]['start'] = true_i + self.api_map[self.hpp_file][full_namespace]['indent'] = \ self._indent(line) elif strip_line == api_dec.autogen_dec_end: - self.api_map[self.hpp_file][namespace]['end'] = true_i + self.api_map[self.hpp_file][full_namespace]['end'] = true_i return i + 1 - def _is_namespace(self, i): + def _is_full_namespace(self, i): """ - Determine whether a tokenized line defines a C++ namespace. + Determine whether a tokenized line defines a C++ full_namespace. ASSUMPTIONS: - 1. A namespace is defined entirely on a single line + 1. A full_namespace is defined entirely on a single line VALID: - namespace hello { + full_namespace hello { INVALID: - namespace hello + full_namespace hello { :param i: The line to start parsing at @@ -315,10 +316,10 @@ def _is_namespace(self, i): """ line = self.only_class_lines[i] toks = line.split() - # "namespace hello {" (is 3 tokens) + # "full_namespace hello {" (is 3 tokens) if len(toks) < 3: return False - if toks[0] != 'namespace': + if toks[0] != 'full_namespace': return False if toks[2] != '{': return False @@ -394,11 +395,11 @@ def _is_autogen(self, i): return True return False - def _induct_namespace(self, namespace): + def _induct_full_namespace(self, full_namespace): if self.hpp_file not in self.api_map: self.api_map[self.hpp_file] = {} - if namespace not in self.api_map[self.hpp_file]: - self.api_map[self.hpp_file][namespace] = { + if full_namespace not in self.api_map[self.hpp_file]: + self.api_map[self.hpp_file][full_namespace] = { 'apis': {}, 'start': None, 'end': None, @@ -407,10 +408,10 @@ def _induct_namespace(self, namespace): } @staticmethod - def _ns_append(namespace, suffix): - if namespace is None or len(namespace) == 0: + def _ns_append(full_namespace, suffix): + if full_namespace is None or len(full_namespace) == 0: return suffix - return f"{namespace}::{suffix}" + return f"{full_namespace}::{suffix}" @staticmethod def _indent(line): @@ -428,8 +429,8 @@ def _apply_decorators(self): self._strip_decorator(api_dec) def _strip_decorator(self, api_dec): - for path, namespace_dict in self.api_map.items(): - for namespace, api_dict in namespace_dict.items(): + for path, full_namespace_dict in self.api_map.items(): + for full_namespace, api_dict in full_namespace_dict.items(): cur_apis = list(api_dict['apis'].values()) for api in cur_apis: if api_dec.macro in api.get_decorator_macros(): @@ -438,8 +439,8 @@ def _strip_decorator(self, api_dec): del api_dict['apis'][api.name] def _has_unmodified_apis(self): - for path, namespace_dict in self.api_map.items(): - for namespace, api_dict in namespace_dict.items(): + for path, full_namespace_dict in self.api_map.items(): + for full_namespace, api_dict in full_namespace_dict.items(): if len(api_dict['apis']): return True return False @@ -450,10 +451,10 @@ def _has_unmodified_apis(self): def _autogen_lines(self): self.text_map = {} - for path, namespace_dict in self.api_map.items(): + for path, full_namespace_dict in self.api_map.items(): with open(path) as fp: lines = fp.read().splitlines() - autogens = list(namespace_dict.values()) + autogens = list(full_namespace_dict.values()) autogens.sort(reverse=True, key=lambda x : x['start']) for api_dict in autogens: autogen = api_dict['gen'] diff --git a/code_generators/unit/api/apis.h b/code_generators/unit/api/apis.h index a235efe52..6b8614ae9 100644 --- a/code_generators/unit/api/apis.h +++ b/code_generators/unit/api/apis.h @@ -29,6 +29,7 @@ int f1(); * @RPC_TARGET_NODE 0 * @RPC_CLASS_INSTANCE mdm * */ +// RPC int Localf2(); /** @@ -83,6 +84,8 @@ namespace nstest { * */ RPC int Localf99(); + +namespace nstest2 { template class Hi { /** @@ -96,6 +99,7 @@ class Hi { RPC_AUTOGEN_START RPC_AUTOGEN_END }; +} // namespace nstest2 template class BigHi { From 6c38884ee13485d97bf70b605397c7a800e23d66 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 7 Dec 2022 06:15:01 -0600 Subject: [PATCH 064/511] Note that the check for loading an API string makes assumptions that can be relaxed later --- code_generators/code_generators/decorator/parse_cpp.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/code_generators/code_generators/decorator/parse_cpp.py b/code_generators/code_generators/decorator/parse_cpp.py index f51612830..4201331ca 100644 --- a/code_generators/code_generators/decorator/parse_cpp.py +++ b/code_generators/code_generators/decorator/parse_cpp.py @@ -222,13 +222,15 @@ def _get_api_str(self, i): :param i: the first line of the API :return: the API text + + TODO(llogan): Keep track of the offset of a line in the file + and pass everything after decorator directly to API(), which + is much less error-prone """ api_end = i for line in self.only_class_lines[i:]: - if ');' in line: - break - if ':' in line: + if ';' in line: break if ') {' in line: break From 778e97e30dfe8e896ff94a7efb11ffefc9cf205f Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 7 Dec 2022 06:50:18 -0600 Subject: [PATCH 065/511] Strengthen check for class + namespace termination --- .../code_generators/decorator/parse_cpp.py | 101 +++++++++--------- code_generators/unit/api/apis.h | 101 +++++++++++++++++- code_generators/unit/api/rpcs.cc | 56 +++++++++- code_generators/unit/api/test.py | 70 ++++++++---- 4 files changed, 257 insertions(+), 71 deletions(-) diff --git a/code_generators/code_generators/decorator/parse_cpp.py b/code_generators/code_generators/decorator/parse_cpp.py index 4201331ca..f78beaaee 100644 --- a/code_generators/code_generators/decorator/parse_cpp.py +++ b/code_generators/code_generators/decorator/parse_cpp.py @@ -7,12 +7,12 @@ class ParseDecoratedCppApis: Parse a C++ header file and get the set of all decorated prototypes and autogen statements. This parser makes various assumptions about the C++ style. These are defined in: - _is_class, _is_full_namespace, _is_api + _is_class, _is_namespace, _is_api :return: self.api_map - [path][full_namespace+class]['apis'][api_name] -> API() - [path][full_namespace+class]['start'] -> autogen macro start - [path][full_namespace+class]['end'] -> autogen macro end - [path][full_namespace+class]['indent'] -> autogen macro indentation + [path][namespace+class]['apis'][api_name] -> API() + [path][namespace+class]['start'] -> autogen macro start + [path][namespace+class]['end'] -> autogen macro end + [path][namespace+class]['indent'] -> autogen macro indentation """ def __init__(self, files, api_decs, modify=True): @@ -28,6 +28,9 @@ def __init__(self, files, api_decs, modify=True): self.text_map = {} self.modify = modify + def build_api_map(self): + self._parse_files() + def parse(self): self._parse_files() self._apply_decorators() @@ -103,7 +106,7 @@ def _parse_files(self): self.only_class_lines = list(zip(*self.class_lines))[1] self._parse() - def _parse(self, full_namespace=None, start=None, end=None): + def _parse(self, namespace=None, start=None, end=None): if start == None: start = 0 if end == None: @@ -111,19 +114,19 @@ def _parse(self, full_namespace=None, start=None, end=None): i = start while i < end: line = self.class_lines[i] - if self._is_full_namespace(i) or self._is_class(i): - i = self._parse_class_or_ns(full_namespace, i) + if self._is_namespace(i) or self._is_class(i): + i = self._parse_class_or_ns(namespace, i) continue elif self._is_api(i): - i = self._parse_api(full_namespace, i) + i = self._parse_api(namespace, i) continue elif self._is_autogen(i): - i = self._parse_autogen(full_namespace, i) + i = self._parse_autogen(namespace, i) continue i += 1 return i - def _parse_api(self, full_namespace, i): + def _parse_api(self, namespace, i): """ Determines the set of text belonging to a particular API. ASSUMPTIONS: @@ -148,7 +151,7 @@ class Hash = std::hash RP - :param full_namespace: the C++ full_namespace + class the API belongs to + :param namespace: the C++ namespace + class the API belongs to :param i: the line containing part of the API definition :return: None. Modifies the """ @@ -156,8 +159,8 @@ class Hash = std::hash tmpl_i, tmpl_str = self._get_template_str(i) api_str,api_end = self._get_api_str(i) doc_str = self._get_doc_str(tmpl_i) - api = Api(self.hpp_file, full_namespace, api_str, self.api_decs, tmpl_str, doc_str) - self._induct_full_namespace(full_namespace) + api = Api(self.hpp_file, namespace, api_str, self.api_decs, tmpl_str, doc_str) + self._induct_namespace(namespace) self.api_map[api.path][api.namespace]['apis'][api.name] = api return api_end + 1 @@ -238,9 +241,9 @@ def _get_api_str(self, i): api_str = "\n".join(self.only_class_lines[i:api_end+1]) return api_str, api_end - def _parse_class_or_ns(self, full_namespace, i): + def _parse_class_or_ns(self, namespace, i): """ - Parse all APIs within the boundaries of a class or full_namespace. + Parse all APIs within the boundaries of a class or namespace. ASSUMPTIONS: 1. A class is terminated with the first }; that has equivalent @@ -252,7 +255,7 @@ class hello { class hello { }; // "class" and }; are misaligned vertically - :param full_namespace: the current full_namespace the class is apart of + :param namespace: the current namespace the class is apart of :param i: The line to start parsing at :return: The index of the terminating }; """ @@ -262,55 +265,55 @@ class hello { toks = re.split("[ \{]", line) toks = [tok .strip() for tok in toks if tok is not None and len(tok)] is_ns = toks[0] == 'namespace' - namespace = toks[1] + scoped_namespace = toks[1] indent = self._indent(line) - full_namespace = self._ns_append(full_namespace, namespace) + namespace = self._ns_append(namespace, scoped_namespace) # Find the end of the class (};) end = None if is_ns: - end_of_scope = f"}} // namespace {namespace}" + end_of_scope = f"}} // namespace {scoped_namespace}" else: end_of_scope = f"{indent}}};" for off, line in enumerate(self.only_class_lines[i+1:]): - if end_of_scope == line[0:len(end_of_scope)]: + if end_of_scope == line: end = i + 1 + off break if end is None: - raise Exception(f"Could not find the end of {full_namespace}") + raise Exception(f"Could not find the end of {namespace}") # Parse all lines for prototypes - return self._parse(full_namespace, i+1, end) + return self._parse(namespace, i+1, end) - def _parse_autogen(self, full_namespace, i): + def _parse_autogen(self, namespace, i): """ - Parse the AUTOGEN keyword statements for a particular full_namespace + Parse the AUTOGEN keyword statements for a particular namespace - :param full_namespace: the current full_namespace the autogen is apart of + :param namespace: the current namespace the autogen is apart of :param i: The line to start parsing at :return: """ - self._induct_full_namespace(full_namespace) + self._induct_namespace(namespace) true_i, line = self.class_lines[i] strip_line = line.strip() for api_dec in self.api_decs: if strip_line == api_dec.autogen_dec_start: - self.api_map[self.hpp_file][full_namespace]['start'] = true_i - self.api_map[self.hpp_file][full_namespace]['indent'] = \ + self.api_map[self.hpp_file][namespace]['start'] = true_i + self.api_map[self.hpp_file][namespace]['indent'] = \ self._indent(line) elif strip_line == api_dec.autogen_dec_end: - self.api_map[self.hpp_file][full_namespace]['end'] = true_i + self.api_map[self.hpp_file][namespace]['end'] = true_i return i + 1 - def _is_full_namespace(self, i): + def _is_namespace(self, i): """ - Determine whether a tokenized line defines a C++ full_namespace. + Determine whether a tokenized line defines a C++ namespace. ASSUMPTIONS: - 1. A full_namespace is defined entirely on a single line + 1. A namespace is defined entirely on a single line VALID: - full_namespace hello { + namespace hello { INVALID: - full_namespace hello + namespace hello { :param i: The line to start parsing at @@ -318,10 +321,10 @@ def _is_full_namespace(self, i): """ line = self.only_class_lines[i] toks = line.split() - # "full_namespace hello {" (is 3 tokens) + # "namespace hello {" (is 3 tokens) if len(toks) < 3: return False - if toks[0] != 'full_namespace': + if toks[0] != 'namespace': return False if toks[2] != '{': return False @@ -397,11 +400,11 @@ def _is_autogen(self, i): return True return False - def _induct_full_namespace(self, full_namespace): + def _induct_namespace(self, namespace): if self.hpp_file not in self.api_map: self.api_map[self.hpp_file] = {} - if full_namespace not in self.api_map[self.hpp_file]: - self.api_map[self.hpp_file][full_namespace] = { + if namespace not in self.api_map[self.hpp_file]: + self.api_map[self.hpp_file][namespace] = { 'apis': {}, 'start': None, 'end': None, @@ -410,10 +413,10 @@ def _induct_full_namespace(self, full_namespace): } @staticmethod - def _ns_append(full_namespace, suffix): - if full_namespace is None or len(full_namespace) == 0: + def _ns_append(namespace, suffix): + if namespace is None or len(namespace) == 0: return suffix - return f"{full_namespace}::{suffix}" + return f"{namespace}::{suffix}" @staticmethod def _indent(line): @@ -431,8 +434,8 @@ def _apply_decorators(self): self._strip_decorator(api_dec) def _strip_decorator(self, api_dec): - for path, full_namespace_dict in self.api_map.items(): - for full_namespace, api_dict in full_namespace_dict.items(): + for path, namespace_dict in self.api_map.items(): + for namespace, api_dict in namespace_dict.items(): cur_apis = list(api_dict['apis'].values()) for api in cur_apis: if api_dec.macro in api.get_decorator_macros(): @@ -441,8 +444,8 @@ def _strip_decorator(self, api_dec): del api_dict['apis'][api.name] def _has_unmodified_apis(self): - for path, full_namespace_dict in self.api_map.items(): - for full_namespace, api_dict in full_namespace_dict.items(): + for path, namespace_dict in self.api_map.items(): + for namespace, api_dict in namespace_dict.items(): if len(api_dict['apis']): return True return False @@ -453,10 +456,10 @@ def _has_unmodified_apis(self): def _autogen_lines(self): self.text_map = {} - for path, full_namespace_dict in self.api_map.items(): + for path, namespace_dict in self.api_map.items(): with open(path) as fp: lines = fp.read().splitlines() - autogens = list(full_namespace_dict.values()) + autogens = list(namespace_dict.values()) autogens.sort(reverse=True, key=lambda x : x['start']) for api_dict in autogens: autogen = api_dict['gen'] diff --git a/code_generators/unit/api/apis.h b/code_generators/unit/api/apis.h index 6b8614ae9..28e9b29bc 100644 --- a/code_generators/unit/api/apis.h +++ b/code_generators/unit/api/apis.h @@ -97,6 +97,17 @@ class Hi { RPC int Localf100(); RPC_AUTOGEN_START + int f100() { + u32 target_node = 0; + if (target_node == rpc_->node_id_) { + return Localf100( + ); + } else { + return rpc_->Call( + target_node, "f100", + ); + } + } RPC_AUTOGEN_END }; } // namespace nstest2 @@ -112,6 +123,17 @@ class BigHi { RPC int Localf101(); RPC_AUTOGEN_START + int f101() { + u32 target_node = 0; + if (target_node == rpc_->node_id_) { + return Localf101( + ); + } else { + return rpc_->Call( + target_node, "f101", + ); + } + } RPC_AUTOGEN_END }; @@ -124,10 +146,87 @@ class BigHi { RPC int Localf102(); RPC_AUTOGEN_START +int f99() { + u32 target_node = 0; + if (target_node == rpc_->node_id_) { + return Localf99( + ); + } else { + return rpc_->Call( + target_node, "f99", + ); + } +} +int f102() { + u32 target_node = 0; + if (target_node == rpc_->node_id_) { + return Localf102( + ); + } else { + return rpc_->Call( + target_node, "f102", + ); + } +} RPC_AUTOGEN_END } // namespace nstest RPC_AUTOGEN_START +int f2() { + u32 target_node = 0; + if (target_node == rpc_->node_id_) { + return Localf2( + ); + } else { + return rpc_->Call( + target_node, "f2", + ); + } +} +int f3(int a, int b) { + u32 target_node = 0; + if (target_node == rpc_->node_id_) { + return Localf3( + a, b); + } else { + return rpc_->Call( + target_node, "f3", + a, b); + } +} +std::vector& f4(int a, std::vector b, Ctx) { + u32 target_node = 0; + if (target_node == rpc_->node_id_) { + return Localf4( + a, b); + } else { + return rpc_->Call&>( + target_node, "f4", + a, b); + } +} +WRAP std::vector& f5(int a, std::vector b, Ctx) { + u32 target_node = 0; + if (target_node == rpc_->node_id_) { + return Localf5( + a, b); + } else { + return rpc_->Call&>( + target_node, "f5", + a, b); + } +} +WRAP std::vector& f6(int a, std::vector b, Ctx) { + u32 target_node = 0; + if (target_node == rpc_->node_id_) { + return Localf6( + a, b); + } else { + return rpc_->Call&>( + target_node, "f6", + a, b); + } +} RPC_AUTOGEN_END -#endif // HERMES_CODE_GENERATORS_CODE_GENERATORS_UNIT_PROTOS_H_ +#endif // HERMES_CODE_GENERATORS_CODE_GENERATORS_UNIT_PROTOS_H_ \ No newline at end of file diff --git a/code_generators/unit/api/rpcs.cc b/code_generators/unit/api/rpcs.cc index f0a6cb829..5f7acbb43 100644 --- a/code_generators/unit/api/rpcs.cc +++ b/code_generators/unit/api/rpcs.cc @@ -1,4 +1,56 @@ int main() { RPC_AUTOGEN_START - RPC_AUTOGEN_END -} \ No newline at end of file +auto remote_f2 = + [mdm](const request &req, ) { + auto result = mdm->Localf2(); + req.respond(result); + }; +server_engine_->define("f2", remote_f2); +auto remote_f3 = + [mdm](const request &req, int a, int b) { + auto result = mdm->Localf3(a, b); + req.respond(result); + }; +server_engine_->define("f3", remote_f3); +auto remote_f4 = + [mdm](const request &req, int a, std::vector b, Ctx) { + auto result = mdm->Localf4(a, b); + req.respond(result); + }; +server_engine_->define("f4", remote_f4); +auto remote_f5 = + [mdm](const request &req, int a, std::vector b, Ctx) { + auto result = mdm->Localf5(a, b); + req.respond(result); + }; +server_engine_->define("f5", remote_f5); +auto remote_f6 = + [mdm](const request &req, int a, std::vector b, Ctx) { + auto result = mdm->Localf6(a, b); + req.respond(result); + }; +server_engine_->define("f6", remote_f6); +auto remote_f99 = + [mdm](const request &req, ) { + auto result = mdm->Localf99(); + req.respond(result); + }; +server_engine_->define("f99", remote_f99); +auto remote_f102 = + [mdm](const request &req, ) { + auto result = mdm->Localf102(); + req.respond(result); + }; +server_engine_->define("f102", remote_f102); + auto remote_f100 = + [mdm](const request &req, ) { + auto result = mdm->Localf100(); + req.respond(result); + }; + server_engine_->define("f100", remote_f100); + auto remote_f101 = + [mdm](const request &req, ) { + auto result = mdm->Localf101(); + req.respond(result); + }; + server_engine_->define("f101", remote_f101); \ No newline at end of file diff --git a/code_generators/unit/api/test.py b/code_generators/unit/api/test.py index 6aa521ca0..c55bfad4e 100644 --- a/code_generators/unit/api/test.py +++ b/code_generators/unit/api/test.py @@ -4,22 +4,54 @@ from code_generators.util.paths import HERMES_ROOT -def create_rpc_generator(): - rpc_defs_path = f"{HERMES_ROOT}/code_generators/unit/api/rpcs.cc" - gen = RpcGenerator(rpc_defs_path) - return gen - -files = [ - f"{HERMES_ROOT}/code_generators/unit/api/apis.h", - f"{HERMES_ROOT}/code_generators/unit/api/rpcs.cc", -] - -decs = [ - create_rpc_generator(), - NullDecorator("WRAP") -] - -gen = ParseDecoratedCppApis(files, decs, modify=False) -gen.parse() -print(gen.text_map[files[0]]) -print(gen.text_map[files[1]]) +class ParseCppUnitTest: + def __init__(self): + self.files = [ + f"{HERMES_ROOT}/code_generators/unit/api/apis.h", + f"{HERMES_ROOT}/code_generators/unit/api/rpcs.cc", + ] + self.decs = [ + self.create_rpc_generator(), + NullDecorator("WRAP") + ] + self.gen = ParseDecoratedCppApis(self.files, self.decs, modify=True) + self.gen.build_api_map() + self.verify_namespaces() + self.verify_apis() + self.gen.parse() + print(self.gen.text_map[self.files[0]]) + print(self.gen.text_map[self.files[1]]) + + def create_rpc_generator(self): + rpc_defs_path = f"{HERMES_ROOT}/code_generators/unit/api/rpcs.cc" + gen = RpcGenerator(rpc_defs_path) + return gen + + def verify_namespaces(self): + namespaces = [ + None, "nstest", "nstest", + "nstest::nstest2::Hi", "nstest::BigHi", + ] + + for namespace in namespaces: + if namespace not in self.gen.api_map[self.files[0]]: + raise Exception(f"Could not find {namespace} in api_map") + + def verify_apis(self): + ignore_apis = { + None: ['Localf1'] + } + parse_apis = { + None: ['Localf2', 'Localf2', 'Localf4', 'Localf5', 'Localf6'], + 'nstest': ['Localf99', 'Localf102'], + 'nstest::nstest2::Hi': ['Localf100'], + 'nstest::BigHi': ['Localf101'] + } + + for namespace, api_list in parse_apis.items(): + for api in api_list: + if api not in self.gen.api_map[self.files[0]][namespace]['apis']: + raise Exception(f"Could not find {api} in api_map") + + +ParseCppUnitTest() From 58f9b74bde23496532d04a6125526ab87718f11e Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 7 Dec 2022 07:08:13 -0600 Subject: [PATCH 066/511] Fix bug with autogen_lines, which was removing content that should still exist --- .../code_generators/decorator/parse_cpp.py | 5 +- .../code_generators/rpc/generator.py | 2 +- code_generators/decorate.py | 61 ++-- src/data_structures.h | 2 +- src/metadata_manager.h | 306 ++---------------- src/rpc_thallium_defs.cc | 110 ++++--- src/rpc_thallium_serialization.h | 1 + 7 files changed, 118 insertions(+), 369 deletions(-) diff --git a/code_generators/code_generators/decorator/parse_cpp.py b/code_generators/code_generators/decorator/parse_cpp.py index f78beaaee..be7ffb846 100644 --- a/code_generators/code_generators/decorator/parse_cpp.py +++ b/code_generators/code_generators/decorator/parse_cpp.py @@ -466,12 +466,9 @@ def _autogen_lines(self): start = api_dict['start'] end = api_dict['end'] - # Remove (start, end) + # Inject autogen APIs (start, end) # I.e, include everything up to start # and include everything after end - lines = lines[0:start+1] + lines[end:] - - # Add new autogen APIs lines = lines[0:start+1] + autogen + lines[end:] self.text_map[path] = "\n".join(lines) diff --git a/code_generators/code_generators/rpc/generator.py b/code_generators/code_generators/rpc/generator.py index 44b6d5426..166806b00 100644 --- a/code_generators/code_generators/rpc/generator.py +++ b/code_generators/code_generators/rpc/generator.py @@ -73,7 +73,7 @@ def modify(self, api_map): :return: Modifies rpc_lambdas and the C++ class file. """ # Get the autogen dict for rpc_thallium_defs.cc - autogen_api_dict = api_map[self.rpc_defs_path][None] + autogen_api_dict = api_map[self.rpc_defs_path]['hermes'] # Autogen RPCs for each class for path, namespace_dict in api_map.items(): diff --git a/code_generators/decorate.py b/code_generators/decorate.py index e1ae03968..d7aae29f4 100644 --- a/code_generators/decorate.py +++ b/code_generators/decorate.py @@ -1,45 +1,28 @@ +""" +USAGE: + cd /path/to/code_generators + python3 decorate.py +""" + from code_generators.decorator.parse_cpp import ParseDecoratedCppApis from code_generators.rpc.generator import RpcGenerator from code_generators.util.paths import HERMES_ROOT -def create_rpc_generator(): - gen = RpcGenerator() - rpc_defs_path = f"{HERMES_ROOT}/src/rpc_thallium_defs.cc" - gen.set_rpc_lambda_file(rpc_defs_path) - - # metadata_manager.h - gen.set_file(f"{HERMES_ROOT}/src/metadata_manager.h") - gen.set_class("MetadataManager", "mdm") - gen.add("LocalGetOrCreateBucket", "rpc_->node_id_") - gen.add("LocalGetBucketId", "rpc_->node_id_") - gen.add("LocalBucketContainsBlob", "rpc_->node_id_") - gen.add("LocalRenameBucket", "rpc_->node_id_") - gen.add("LocalDestroyBucket", "rpc_->node_id_") - gen.add("LocalBucketPutBlob", "rpc_->node_id_") - gen.add("LocalGetBlobId", "rpc_->node_id_") - gen.add("LocalSetBlobBuffers", "rpc_->node_id_") - gen.add("LocalGetBlobBuffers", "rpc_->node_id_") - gen.add("LocalRenameBlob", "rpc_->node_id_") - gen.add("LocalDestroyBlob", "rpc_->node_id_") - gen.add("LocalWriteLockBlob", "rpc_->node_id_") - gen.add("LocalWriteUnlockBlob", "rpc_->node_id_") - gen.add("LocalReadLockBlob", "rpc_->node_id_") - gen.add("LocalReadUnlockBlob", "rpc_->node_id_") - gen.add("LocalGetOrCreateVBucket", "rpc_->node_id_") - gen.add("LocalGetVBucketId", "rpc_->node_id_") - gen.add("LocalUnlinkBlobVBucket", "rpc_->node_id_") - gen.add("LocalGetLinksVBucket", "rpc_->node_id_") - gen.add("LocalRenameVBucket", "rpc_->node_id_") - gen.add("LocalDestroyVBucket", "rpc_->node_id_") - - return gen - -files = [ - f"{HERMES_ROOT}/src/metadata_manager.h" -] +class HermesDecorator: + def __init__(self): + files = [ + f"{HERMES_ROOT}/src/metadata_manager.h", + f"{HERMES_ROOT}/src/rpc_thallium_defs.cc" + ] + decs = [ + self.create_rpc_generator() + ] + gen = ParseDecoratedCppApis(files, decs, modify=True) + gen.parse() -decs = [ - create_rpc_generator() -] + @staticmethod + def create_rpc_generator(): + rpc_defs_path = f"{HERMES_ROOT}/src/rpc_thallium_defs.cc" + return RpcGenerator(rpc_defs_path) -gen = ParseDecoratedCppApis(files, decs) +HermesDecorator() \ No newline at end of file diff --git a/src/data_structures.h b/src/data_structures.h index af900db71..ee37006d7 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -9,7 +9,7 @@ #include #include #include -#include +// #include namespace lipc = labstor::ipc; namespace lipcl = labstor::ipc::lockless; diff --git a/src/metadata_manager.h b/src/metadata_manager.h index cc06ccafb..3dce78f6e 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -21,13 +21,13 @@ struct BufferInfo { }; struct BlobInfo { - lipcl::charbuf name_; + std::string name_; std::vector buffers_; RwLock rwlock_; }; struct BucketInfo { - lipcl::charbuf name_; + std::string name_; std::vector blobs_; }; @@ -38,7 +38,7 @@ struct VBucketInfo { class MetadataManager { private: - RPC_TYPE *rpc_; + RPC_TYPE* rpc_; std::unordered_map blob_id_map_; std::unordered_map bkt_id_map_; std::unordered_map vbkt_id_map_; @@ -54,7 +54,7 @@ class MetadataManager { /** * Get or create a bucket with \a bkt_name bucket name * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC BucketID LocalGetOrCreateBucket(std::string bkt_name); @@ -62,7 +62,7 @@ class MetadataManager { /** * Get the BucketID with \a bkt_name bucket name * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC BucketID LocalGetBucketId(std::string bkt_name); @@ -71,7 +71,7 @@ class MetadataManager { * Check whether or not \a bkt_id bucket contains * \a blob_id blob * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalBucketContainsBlob(BucketID bkt_id, BlobID blob_id); @@ -79,7 +79,7 @@ class MetadataManager { /** * Rename \a bkt_id bucket to \a new_bkt_name new name * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalRenameBucket(BucketID bkt_id, std::string new_bkt_name); @@ -87,7 +87,7 @@ class MetadataManager { /** * Destroy \a bkt_id bucket * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalDestroyBucket(BucketID bkt_id); @@ -100,18 +100,16 @@ class MetadataManager { * @param data the data being placed * @param buffers the buffers to place data in * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BlobID LocalBucketPutBlob(BucketID bkt_id, - std::string blob_name, - Blob data, - std::vector &buffers); + RPC BlobID LocalBucketPutBlob(BucketID bkt_id, std::string blob_name, + Blob data, std::vector buffers); /** * Get \a blob_name blob from \a bkt_id bucket * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC BlobID LocalGetBlobId(BucketID bkt_id, std::string blob_name); @@ -119,35 +117,33 @@ class MetadataManager { /** * Change \a blob_id blob's buffers to \the buffers * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalSetBlobBuffers(BlobID blob_id, - std::vector &buffers); + RPC bool LocalSetBlobBuffers(BlobID blob_id, std::vector buffers); /** * Get \a blob_id blob's buffers * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC std::vector& - LocalGetBlobBuffers(BlobID blob_id); + RPC std::vector& LocalGetBlobBuffers(BlobID blob_id); /** * Rename \a blob_id blob to \a new_blob_name new blob name * in \a bkt_id bucket. * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalRenameBlob(BucketID bkt_id, - BlobID blob_id, std::string new_blob_name); + RPC bool LocalRenameBlob(BucketID bkt_id, BlobID blob_id, + std::string new_blob_name); /** * Destroy \a blob_id blob in \a bkt_id bucket * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalDestroyBlob(BucketID bkt_id, std::string blob_name); @@ -155,7 +151,7 @@ class MetadataManager { /** * Acquire \a blob_id blob's write lock * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalWriteLockBlob(BlobID blob_id); @@ -163,7 +159,7 @@ class MetadataManager { /** * Release \a blob_id blob's write lock * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalWriteUnlockBlob(BlobID blob_id); @@ -171,7 +167,7 @@ class MetadataManager { /** * Acquire \a blob_id blob's read lock * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalReadLockBlob(BlobID blob_id); @@ -179,7 +175,7 @@ class MetadataManager { /** * Release \a blob_id blob's read lock * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalReadUnlockBlob(BlobID blob_id); @@ -187,7 +183,7 @@ class MetadataManager { /** * Get or create \a vbkt_name VBucket * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC VBucketID LocalGetOrCreateVBucket(std::string vbkt_name); @@ -195,7 +191,7 @@ class MetadataManager { /** * Get the VBucketID of \a vbkt_name VBucket * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC VBucketID LocalGetVBucketId(std::string vbkt_name); @@ -203,28 +199,26 @@ class MetadataManager { /** * Link \a vbkt_id VBucketID * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC VBucketID LocalVBucketLinkBlob(VBucketID vbkt_id, - BucketID bkt_id, + RPC VBucketID LocalVBucketLinkBlob(VBucketID vbkt_id, BucketID bkt_id, std::string blob_name); /** * Unlink \a blob_name Blob of \a bkt_id Bucket * from \a vbkt_id VBucket * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC VBucketID LocalVBucketUnlinkBlob(VBucketID vbkt_id, - BucketID bkt_id, + RPC VBucketID LocalVBucketUnlinkBlob(VBucketID vbkt_id, BucketID bkt_id, std::string blob_name); /** * Get the linked blobs from \a vbkt_id VBucket * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC std::list LocalVBucketGetLinks(VBucketID vbkt_id); @@ -232,253 +226,21 @@ class MetadataManager { /** * Rename \a vbkt_id VBucket to \a new_vbkt_name name * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalRenameVBucket(VBucketID vbkt_id, - std::string new_vbkt_name); + RPC bool LocalRenameVBucket(VBucketID vbkt_id, std::string new_vbkt_name); /** * Destroy \a vbkt_id VBucket * - * @RPC_TARGET_NODE 0 + * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalDestroyVBucket(VBucketID vbkt_id); public: RPC_AUTOGEN_START - RPC BucketID GetOrCreateBucket(std::string bkt_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetOrCreateBucket( - bkt_name); - } else { - return rpc_->Call( - target_node, "GetOrCreateBucket", - bkt_name); - } - } - RPC BucketID GetBucketId(std::string bkt_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetBucketId( - bkt_name); - } else { - return rpc_->Call( - target_node, "GetBucketId", - bkt_name); - } - } - RPC bool BucketContainsBlob(BucketID bkt_id, BlobID blob_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalBucketContainsBlob( - bkt_id, blob_id); - } else { - return rpc_->Call( - target_node, "BucketContainsBlob", - bkt_id, blob_id); - } - } - RPC bool RenameBucket(BucketID bkt_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalRenameBucket( - bkt_id); - } else { - return rpc_->Call( - target_node, "RenameBucket", - bkt_id); - } - } - RPC bool DestroyBucket(BucketID bkt_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalDestroyBucket( - bkt_id); - } else { - return rpc_->Call( - target_node, "DestroyBucket", - bkt_id); - } - } - RPC BlobID BucketPutBlob(BucketID bkt_id, std::string blob_name, Blob data, std::vector& buffers) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalBucketPutBlob( - bkt_id, blob_name, data, buffers); - } else { - return rpc_->Call( - target_node, "BucketPutBlob", - bkt_id, blob_name, data, buffers); - } - } - RPC BlobID GetBlobId(BucketID bkt_id, std::string blob_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetBlobId( - bkt_id, blob_name); - } else { - return rpc_->Call( - target_node, "GetBlobId", - bkt_id, blob_name); - } - } - RPC bool SetBlobBuffers(BlobID blob_id, std::vector& buffers) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalSetBlobBuffers( - blob_id, buffers); - } else { - return rpc_->Call( - target_node, "SetBlobBuffers", - blob_id, buffers); - } - } - RPC std::vector& GetBlobBuffers(BlobID blob_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetBlobBuffers( - blob_id); - } else { - return rpc_->Call&>( - target_node, "GetBlobBuffers", - blob_id); - } - } - RPC bool RenameBlob(BucketID bkt_id, std::string new_blob_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalRenameBlob( - bkt_id, new_blob_name); - } else { - return rpc_->Call( - target_node, "RenameBlob", - bkt_id, new_blob_name); - } - } - RPC bool DestroyBlob(BucketID bkt_id, std::string blob_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalDestroyBlob( - bkt_id, blob_name); - } else { - return rpc_->Call( - target_node, "DestroyBlob", - bkt_id, blob_name); - } - } - RPC bool WriteLockBlob(BlobID blob_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalWriteLockBlob( - blob_id); - } else { - return rpc_->Call( - target_node, "WriteLockBlob", - blob_id); - } - } - RPC bool WriteUnlockBlob(BlobID blob_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalWriteUnlockBlob( - blob_id); - } else { - return rpc_->Call( - target_node, "WriteUnlockBlob", - blob_id); - } - } - RPC bool ReadLockBlob(BlobID blob_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalReadLockBlob( - blob_id); - } else { - return rpc_->Call( - target_node, "ReadLockBlob", - blob_id); - } - } - RPC bool ReadUnlockBlob(BlobID blob_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalReadUnlockBlob( - blob_id); - } else { - return rpc_->Call( - target_node, "ReadUnlockBlob", - blob_id); - } - } - RPC VBucketID GetOrCreateVBucket(std::string vbkt_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetOrCreateVBucket( - vbkt_name); - } else { - return rpc_->Call( - target_node, "GetOrCreateVBucket", - vbkt_name); - } - } - RPC VBucketID GetVBucketId(std::string vbkt_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetVBucketId( - vbkt_name); - } else { - return rpc_->Call( - target_node, "GetVBucketId", - vbkt_name); - } - } - RPC VBucketID UnlinkBlobVBucket(VBucketID vbkt_id, BucketID bkt_id, std::string blob_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalUnlinkBlobVBucket( - vbkt_id, bkt_id, blob_name); - } else { - return rpc_->Call( - target_node, "UnlinkBlobVBucket", - vbkt_id, bkt_id, blob_name); - } - } - RPC std::list GetLinksVBucket(VBucketID vbkt_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetLinksVBucket( - vbkt_id); - } else { - return rpc_->Call>( - target_node, "GetLinksVBucket", - vbkt_id); - } - } - RPC bool RenameVBucket(VBucketID vbkt_id, std::string new_vbkt_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalRenameVBucket( - vbkt_id, new_vbkt_name); - } else { - return rpc_->Call( - target_node, "RenameVBucket", - vbkt_id, new_vbkt_name); - } - } - RPC bool DestroyVBucket(VBucketID vbkt_id, std::string new_vbkt_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalDestroyVBucket( - vbkt_id, new_vbkt_name); - } else { - return rpc_->Call( - target_node, "DestroyVBucket", - vbkt_id, new_vbkt_name); - } - } RPC_AUTOGEN_END }; diff --git a/src/rpc_thallium_defs.cc b/src/rpc_thallium_defs.cc index 3c768d493..06069d917 100644 --- a/src/rpc_thallium_defs.cc +++ b/src/rpc_thallium_defs.cc @@ -15,132 +15,138 @@ void ThalliumRpc::DefineRpcs() { RPC_CLASS_INSTANCE_DEFS_END RPC_AUTOGEN_START - auto rpc_get_or_create_bucket = + auto remote_get_or_create_bucket = [mdm](const request &req, std::string bkt_name) { auto result = mdm->LocalGetOrCreateBucket(bkt_name); req.respond(result); }; - server_engine_->define("GetOrCreateBucket", rpc_get_or_create_bucket); - auto rpc_get_bucket_id = + server_engine_->define("GetOrCreateBucket", remote_get_or_create_bucket); + auto remote_get_bucket_id = [mdm](const request &req, std::string bkt_name) { auto result = mdm->LocalGetBucketId(bkt_name); req.respond(result); }; - server_engine_->define("GetBucketId", rpc_get_bucket_id); - auto rpc_bucket_contains_blob = + server_engine_->define("GetBucketId", remote_get_bucket_id); + auto remote_bucket_contains_blob = [mdm](const request &req, BucketID bkt_id, BlobID blob_id) { auto result = mdm->LocalBucketContainsBlob(bkt_id, blob_id); req.respond(result); }; - server_engine_->define("BucketContainsBlob", rpc_bucket_contains_blob); - auto rpc_rename_bucket = - [mdm](const request &req, BucketID bkt_id) { - auto result = mdm->LocalRenameBucket(bkt_id); + server_engine_->define("BucketContainsBlob", remote_bucket_contains_blob); + auto remote_rename_bucket = + [mdm](const request &req, BucketID bkt_id, std::string new_bkt_name) { + auto result = mdm->LocalRenameBucket(bkt_id, new_bkt_name); req.respond(result); }; - server_engine_->define("RenameBucket", rpc_rename_bucket); - auto rpc_destroy_bucket = + server_engine_->define("RenameBucket", remote_rename_bucket); + auto remote_destroy_bucket = [mdm](const request &req, BucketID bkt_id) { auto result = mdm->LocalDestroyBucket(bkt_id); req.respond(result); }; - server_engine_->define("DestroyBucket", rpc_destroy_bucket); - auto rpc_bucket_put_blob = - [mdm](const request &req, BucketID bkt_id, std::string blob_name, Blob data, std::vector& buffers) { + server_engine_->define("DestroyBucket", remote_destroy_bucket); + auto remote_bucket_put_blob = + [mdm](const request &req, BucketID bkt_id, std::string blob_name, Blob data, std::vector buffers) { auto result = mdm->LocalBucketPutBlob(bkt_id, blob_name, data, buffers); req.respond(result); }; - server_engine_->define("BucketPutBlob", rpc_bucket_put_blob); - auto rpc_get_blob_id = + server_engine_->define("BucketPutBlob", remote_bucket_put_blob); + auto remote_get_blob_id = [mdm](const request &req, BucketID bkt_id, std::string blob_name) { auto result = mdm->LocalGetBlobId(bkt_id, blob_name); req.respond(result); }; - server_engine_->define("GetBlobId", rpc_get_blob_id); - auto rpc_set_blob_buffers = - [mdm](const request &req, BlobID blob_id, std::vector& buffers) { + server_engine_->define("GetBlobId", remote_get_blob_id); + auto remote_set_blob_buffers = + [mdm](const request &req, BlobID blob_id, std::vector buffers) { auto result = mdm->LocalSetBlobBuffers(blob_id, buffers); req.respond(result); }; - server_engine_->define("SetBlobBuffers", rpc_set_blob_buffers); - auto rpc_get_blob_buffers = + server_engine_->define("SetBlobBuffers", remote_set_blob_buffers); + auto remote_get_blob_buffers = [mdm](const request &req, BlobID blob_id) { auto result = mdm->LocalGetBlobBuffers(blob_id); req.respond(result); }; - server_engine_->define("GetBlobBuffers", rpc_get_blob_buffers); - auto rpc_rename_blob = - [mdm](const request &req, BucketID bkt_id, std::string new_blob_name) { - auto result = mdm->LocalRenameBlob(bkt_id, new_blob_name); + server_engine_->define("GetBlobBuffers", remote_get_blob_buffers); + auto remote_rename_blob = + [mdm](const request &req, BucketID bkt_id, BlobID blob_id, std::string new_blob_name) { + auto result = mdm->LocalRenameBlob(bkt_id, blob_id, new_blob_name); req.respond(result); }; - server_engine_->define("RenameBlob", rpc_rename_blob); - auto rpc_destroy_blob = + server_engine_->define("RenameBlob", remote_rename_blob); + auto remote_destroy_blob = [mdm](const request &req, BucketID bkt_id, std::string blob_name) { auto result = mdm->LocalDestroyBlob(bkt_id, blob_name); req.respond(result); }; - server_engine_->define("DestroyBlob", rpc_destroy_blob); - auto rpc_write_lock_blob = + server_engine_->define("DestroyBlob", remote_destroy_blob); + auto remote_write_lock_blob = [mdm](const request &req, BlobID blob_id) { auto result = mdm->LocalWriteLockBlob(blob_id); req.respond(result); }; - server_engine_->define("WriteLockBlob", rpc_write_lock_blob); - auto rpc_write_unlock_blob = + server_engine_->define("WriteLockBlob", remote_write_lock_blob); + auto remote_write_unlock_blob = [mdm](const request &req, BlobID blob_id) { auto result = mdm->LocalWriteUnlockBlob(blob_id); req.respond(result); }; - server_engine_->define("WriteUnlockBlob", rpc_write_unlock_blob); - auto rpc_read_lock_blob = + server_engine_->define("WriteUnlockBlob", remote_write_unlock_blob); + auto remote_read_lock_blob = [mdm](const request &req, BlobID blob_id) { auto result = mdm->LocalReadLockBlob(blob_id); req.respond(result); }; - server_engine_->define("ReadLockBlob", rpc_read_lock_blob); - auto rpc_read_unlock_blob = + server_engine_->define("ReadLockBlob", remote_read_lock_blob); + auto remote_read_unlock_blob = [mdm](const request &req, BlobID blob_id) { auto result = mdm->LocalReadUnlockBlob(blob_id); req.respond(result); }; - server_engine_->define("ReadUnlockBlob", rpc_read_unlock_blob); - auto rpc_get_or_create_v_bucket = + server_engine_->define("ReadUnlockBlob", remote_read_unlock_blob); + auto remote_get_or_create_v_bucket = [mdm](const request &req, std::string vbkt_name) { auto result = mdm->LocalGetOrCreateVBucket(vbkt_name); req.respond(result); }; - server_engine_->define("GetOrCreateVBucket", rpc_get_or_create_v_bucket); - auto rpc_get_v_bucket_id = + server_engine_->define("GetOrCreateVBucket", remote_get_or_create_v_bucket); + auto remote_get_v_bucket_id = [mdm](const request &req, std::string vbkt_name) { auto result = mdm->LocalGetVBucketId(vbkt_name); req.respond(result); }; - server_engine_->define("GetVBucketId", rpc_get_v_bucket_id); - auto rpc_unlink_blob_v_bucket = + server_engine_->define("GetVBucketId", remote_get_v_bucket_id); + auto remote_v_bucket_link_blob = + [mdm](const request &req, VBucketID vbkt_id, BucketID bkt_id, std::string blob_name) { + auto result = mdm->LocalVBucketLinkBlob(vbkt_id, bkt_id, blob_name); + req.respond(result); + }; + server_engine_->define("VBucketLinkBlob", remote_v_bucket_link_blob); + auto remote_v_bucket_unlink_blob = [mdm](const request &req, VBucketID vbkt_id, BucketID bkt_id, std::string blob_name) { - auto result = mdm->LocalUnlinkBlobVBucket(vbkt_id, bkt_id, blob_name); + auto result = mdm->LocalVBucketUnlinkBlob(vbkt_id, bkt_id, blob_name); req.respond(result); }; - server_engine_->define("UnlinkBlobVBucket", rpc_unlink_blob_v_bucket); - auto rpc_get_links_v_bucket = + server_engine_->define("VBucketUnlinkBlob", remote_v_bucket_unlink_blob); + auto remote_v_bucket_get_links = [mdm](const request &req, VBucketID vbkt_id) { - auto result = mdm->LocalGetLinksVBucket(vbkt_id); + auto result = mdm->LocalVBucketGetLinks(vbkt_id); req.respond(result); }; - server_engine_->define("GetLinksVBucket", rpc_get_links_v_bucket); - auto rpc_rename_v_bucket = + server_engine_->define("VBucketGetLinks", remote_v_bucket_get_links); + auto remote_rename_v_bucket = [mdm](const request &req, VBucketID vbkt_id, std::string new_vbkt_name) { auto result = mdm->LocalRenameVBucket(vbkt_id, new_vbkt_name); req.respond(result); }; - server_engine_->define("RenameVBucket", rpc_rename_v_bucket); - auto rpc_destroy_v_bucket = - [mdm](const request &req, VBucketID vbkt_id, std::string new_vbkt_name) { - auto result = mdm->LocalDestroyVBucket(vbkt_id, new_vbkt_name); + server_engine_->define("RenameVBucket", remote_rename_v_bucket); + auto remote_destroy_v_bucket = + [mdm](const request &req, VBucketID vbkt_id) { + auto result = mdm->LocalDestroyVBucket(vbkt_id); req.respond(result); }; - server_engine_->define("DestroyVBucket", rpc_destroy_v_bucket); + server_engine_->define("DestroyVBucket", remote_destroy_v_bucket); RPC_AUTOGEN_END } diff --git a/src/rpc_thallium_serialization.h b/src/rpc_thallium_serialization.h index 0a67340f2..6b412a58d 100644 --- a/src/rpc_thallium_serialization.h +++ b/src/rpc_thallium_serialization.h @@ -9,6 +9,7 @@ #include #include #include +#include "hermes_types.h" namespace hermes { From be69043b42739995d65a3c7da5c22d6e3f021ef1 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 7 Dec 2022 07:25:42 -0600 Subject: [PATCH 067/511] Passing compiler checks again --- src/metadata_manager.h | 269 ++++++++++++++++++++++++++++--- src/metadata_types.h | 38 +++++ src/rpc_thallium_serialization.h | 30 ++++ 3 files changed, 312 insertions(+), 25 deletions(-) create mode 100644 src/metadata_types.h diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 3dce78f6e..15ed4e9ff 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -9,33 +9,10 @@ #include "hermes_types.h" #include "hermes_status.h" #include "rpc.h" +#include "metadata_types.h" namespace hermes { -using api::Blob; - -struct BufferInfo { - size_t off_; - size_t size_; - TargetID target_; -}; - -struct BlobInfo { - std::string name_; - std::vector buffers_; - RwLock rwlock_; -}; - -struct BucketInfo { - std::string name_; - std::vector blobs_; -}; - -struct VBucketInfo { - std::vector name_; - std::unordered_set blobs_; -}; - class MetadataManager { private: RPC_TYPE* rpc_; @@ -128,7 +105,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC std::vector& LocalGetBlobBuffers(BlobID blob_id); + RPC std::vector LocalGetBlobBuffers(BlobID blob_id); /** * Rename \a blob_id blob to \a new_blob_name new blob name @@ -241,6 +218,248 @@ class MetadataManager { public: RPC_AUTOGEN_START + BucketID GetOrCreateBucket(std::string bkt_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetOrCreateBucket( + bkt_name); + } else { + return rpc_->Call( + target_node, "GetOrCreateBucket", + bkt_name); + } + } + BucketID GetBucketId(std::string bkt_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetBucketId( + bkt_name); + } else { + return rpc_->Call( + target_node, "GetBucketId", + bkt_name); + } + } + bool BucketContainsBlob(BucketID bkt_id, BlobID blob_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalBucketContainsBlob( + bkt_id, blob_id); + } else { + return rpc_->Call( + target_node, "BucketContainsBlob", + bkt_id, blob_id); + } + } + bool RenameBucket(BucketID bkt_id, std::string new_bkt_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalRenameBucket( + bkt_id, new_bkt_name); + } else { + return rpc_->Call( + target_node, "RenameBucket", + bkt_id, new_bkt_name); + } + } + bool DestroyBucket(BucketID bkt_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalDestroyBucket( + bkt_id); + } else { + return rpc_->Call( + target_node, "DestroyBucket", + bkt_id); + } + } + BlobID BucketPutBlob(BucketID bkt_id, std::string blob_name, Blob data, std::vector buffers) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalBucketPutBlob( + bkt_id, blob_name, data, buffers); + } else { + return rpc_->Call( + target_node, "BucketPutBlob", + bkt_id, blob_name, data, buffers); + } + } + BlobID GetBlobId(BucketID bkt_id, std::string blob_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetBlobId( + bkt_id, blob_name); + } else { + return rpc_->Call( + target_node, "GetBlobId", + bkt_id, blob_name); + } + } + bool SetBlobBuffers(BlobID blob_id, std::vector buffers) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalSetBlobBuffers( + blob_id, buffers); + } else { + return rpc_->Call( + target_node, "SetBlobBuffers", + blob_id, buffers); + } + } + std::vector GetBlobBuffers(BlobID blob_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetBlobBuffers( + blob_id); + } else { + return rpc_->Call>( + target_node, "GetBlobBuffers", + blob_id); + } + } + bool RenameBlob(BucketID bkt_id, BlobID blob_id, std::string new_blob_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalRenameBlob( + bkt_id, blob_id, new_blob_name); + } else { + return rpc_->Call( + target_node, "RenameBlob", + bkt_id, blob_id, new_blob_name); + } + } + bool DestroyBlob(BucketID bkt_id, std::string blob_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalDestroyBlob( + bkt_id, blob_name); + } else { + return rpc_->Call( + target_node, "DestroyBlob", + bkt_id, blob_name); + } + } + bool WriteLockBlob(BlobID blob_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalWriteLockBlob( + blob_id); + } else { + return rpc_->Call( + target_node, "WriteLockBlob", + blob_id); + } + } + bool WriteUnlockBlob(BlobID blob_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalWriteUnlockBlob( + blob_id); + } else { + return rpc_->Call( + target_node, "WriteUnlockBlob", + blob_id); + } + } + bool ReadLockBlob(BlobID blob_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalReadLockBlob( + blob_id); + } else { + return rpc_->Call( + target_node, "ReadLockBlob", + blob_id); + } + } + bool ReadUnlockBlob(BlobID blob_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalReadUnlockBlob( + blob_id); + } else { + return rpc_->Call( + target_node, "ReadUnlockBlob", + blob_id); + } + } + VBucketID GetOrCreateVBucket(std::string vbkt_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetOrCreateVBucket( + vbkt_name); + } else { + return rpc_->Call( + target_node, "GetOrCreateVBucket", + vbkt_name); + } + } + VBucketID GetVBucketId(std::string vbkt_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalGetVBucketId( + vbkt_name); + } else { + return rpc_->Call( + target_node, "GetVBucketId", + vbkt_name); + } + } + VBucketID VBucketLinkBlob(VBucketID vbkt_id, BucketID bkt_id, std::string blob_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalVBucketLinkBlob( + vbkt_id, bkt_id, blob_name); + } else { + return rpc_->Call( + target_node, "VBucketLinkBlob", + vbkt_id, bkt_id, blob_name); + } + } + VBucketID VBucketUnlinkBlob(VBucketID vbkt_id, BucketID bkt_id, std::string blob_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalVBucketUnlinkBlob( + vbkt_id, bkt_id, blob_name); + } else { + return rpc_->Call( + target_node, "VBucketUnlinkBlob", + vbkt_id, bkt_id, blob_name); + } + } + std::list VBucketGetLinks(VBucketID vbkt_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalVBucketGetLinks( + vbkt_id); + } else { + return rpc_->Call>( + target_node, "VBucketGetLinks", + vbkt_id); + } + } + bool RenameVBucket(VBucketID vbkt_id, std::string new_vbkt_name) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalRenameVBucket( + vbkt_id, new_vbkt_name); + } else { + return rpc_->Call( + target_node, "RenameVBucket", + vbkt_id, new_vbkt_name); + } + } + bool DestroyVBucket(VBucketID vbkt_id) { + u32 target_node = rpc_->node_id_; + if (target_node == rpc_->node_id_) { + return LocalDestroyVBucket( + vbkt_id); + } else { + return rpc_->Call( + target_node, "DestroyVBucket", + vbkt_id); + } + } RPC_AUTOGEN_END }; diff --git a/src/metadata_types.h b/src/metadata_types.h new file mode 100644 index 000000000..be84f085c --- /dev/null +++ b/src/metadata_types.h @@ -0,0 +1,38 @@ +// +// Created by lukemartinlogan on 12/7/22. +// + +#ifndef HERMES_SRC_METADATA_TYPES_H_ +#define HERMES_SRC_METADATA_TYPES_H_ + +#include "hermes_types.h" + +namespace hermes { + +using api::Blob; + +struct BufferInfo { + size_t off_; + size_t size_; + TargetID target_; +}; + +struct BlobInfo { + std::string name_; + std::vector buffers_; + RwLock rwlock_; +}; + +struct BucketInfo { + std::string name_; + std::vector blobs_; +}; + +struct VBucketInfo { + std::vector name_; + std::unordered_set blobs_; +}; + +} // namespace hermes + +#endif // HERMES_SRC_METADATA_TYPES_H_ diff --git a/src/rpc_thallium_serialization.h b/src/rpc_thallium_serialization.h index 6b412a58d..088bbf43f 100644 --- a/src/rpc_thallium_serialization.h +++ b/src/rpc_thallium_serialization.h @@ -9,7 +9,9 @@ #include #include #include +#include #include "hermes_types.h" +#include "metadata_types.h" namespace hermes { @@ -26,6 +28,19 @@ void serialize(A &ar, VBucketID &vbucket_id) { ar &vbucket_id.as_int; } +/** + * Lets Thallium know how to serialize a BucketID. + * + * This function is called implicitly by Thallium. + * + * @param ar An archive provided by Thallium. + * @param bucket_id The BucketID to serialize. + */ +template +void serialize(A &ar, BucketID &bucket_id) { + ar &bucket_id.as_int; +} + /** * Lets Thallium know how to serialize a BlobID. * @@ -52,6 +67,21 @@ void serialize(A &ar, TargetID &target_id) { ar &target_id.as_int; } +/** + * Lets Thallium know how to serialize a TargetID. + * + * This function is called implicitly by Thallium. + * + * @param ar An archive provided by Thallium. + * @param target_id The TargetID to serialize. + */ +template +void serialize(A &ar, BufferInfo &info) { + ar &info.off_; + ar &info.size_; + ar &info.target_; +} + } // namespace hermes namespace hermes::api { From 24c7e6d742d2ffd8ef7dbeec141ca1a0265aa2e8 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 19 Dec 2022 01:28:42 -0600 Subject: [PATCH 068/511] MDM compiles again --- src/api/bucket.cc | 2 +- src/api/hermes.cc | 12 +- src/api/hermes.h | 12 ++ src/data_structures.h | 11 +- src/hermes_types.h | 98 +++++------ src/metadata_manager.cc | 290 ++++++++++++++++++++++++++++++- src/metadata_manager.h | 138 +++++++++++---- src/metadata_types.h | 12 +- src/rpc.h | 8 +- src/rpc_thallium.h | 10 +- src/rpc_thallium_defs.cc | 30 ++-- src/rpc_thallium_serialization.h | 13 +- 12 files changed, 494 insertions(+), 142 deletions(-) diff --git a/src/api/bucket.cc b/src/api/bucket.cc index e4e2a6fcf..0c1847d45 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -8,7 +8,7 @@ namespace hermes::api { Bucket::Bucket(std::string name, Context &ctx) : mdm_(&HERMES->mdm_) { - mdm_->GetOrCreateBucket(name); + // mdm_->GetOrCreateBucket(name); } } // namespace hermes::api \ No newline at end of file diff --git a/src/api/hermes.cc b/src/api/hermes.cc index afa8bef3d..76d911b79 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -58,7 +58,7 @@ void Hermes::StopDaemon() { void Hermes::InitServer(std::string server_config_path) { LoadServerConfig(server_config_path); InitSharedMemory(); - mdm_.Init(); + mdm_.shm_init(&header_->mdm_); rpc_.InitServer(); rpc_.InitClient(); } @@ -68,7 +68,7 @@ void Hermes::InitClient(std::string server_config_path, LoadServerConfig(server_config_path); LoadClientConfig(client_config_path); LoadSharedMemory(); - mdm_.Init(); + mdm_.shm_deserialize(&header_->mdm_); rpc_.InitClient(); } @@ -77,7 +77,7 @@ void Hermes::InitColocated(std::string server_config_path, LoadServerConfig(server_config_path); LoadClientConfig(client_config_path); InitSharedMemory(); - mdm_.Init(); + mdm_.shm_init(&header_->mdm_); rpc_.InitColocated(); } @@ -102,7 +102,10 @@ void Hermes::InitSharedMemory() { server_config_.shmem_name_); main_alloc_ = mem_mngr->CreateAllocator(lipc::AllocatorType::kPageAllocator, - server_config_.shmem_name_, main_alloc_id); + server_config_.shmem_name_, main_alloc_id, + sizeof(HermesShmHeader), + lipc::MemoryManager::kDefaultSlotSize); + header_ = main_alloc_->GetCustomHeader(); } void Hermes::LoadSharedMemory() { @@ -111,6 +114,7 @@ void Hermes::LoadSharedMemory() { mem_mngr->AttachBackend(lipc::MemoryBackendType::kPosixShmMmap, server_config_.shmem_name_); main_alloc_ = mem_mngr->GetAllocator(main_alloc_id); + header_ = main_alloc_->GetCustomHeader(); } void Hermes::FinalizeServer() { diff --git a/src/api/hermes.h b/src/api/hermes.h index 8aa003aa8..680f1cc5e 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -18,9 +18,21 @@ namespace hermes::api { class Bucket; class VBucket; + +/** + * The Hermes shared-memory header + * */ +struct HermesShmHeader { + MetadataManagerShmHeader mdm_; +}; + +/** + * An index into all Hermes-related data structures. + * */ class Hermes { public: HermesType mode_; + HermesShmHeader *header_; ServerConfig server_config_; ClientConfig client_config_; MetadataManager mdm_; diff --git a/src/data_structures.h b/src/data_structures.h index ee37006d7..dc989f579 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -5,14 +5,13 @@ #ifndef HERMES_SRC_DATA_STRUCTURES_H_ #define HERMES_SRC_DATA_STRUCTURES_H_ -#include -#include -#include -#include -// #include +#include +#include +#include +#include +#include namespace lipc = labstor::ipc; -namespace lipcl = labstor::ipc::lockless; using labstor::RwLock; using labstor::Mutex; diff --git a/src/hermes_types.h b/src/hermes_types.h index 2dbf55544..e6431e106 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -75,20 +75,17 @@ enum class IoType { typedef u16 DeviceID; /**< device id in unsigned 16-bit integer */ -union BucketID { - /** The Bucket ID as bitfield */ - struct { - /** The index into the Target array starting at BufferPool::targets_offset - * (on the node with ID node_id). */ - u32 index; - /** The ID of the node in charge of this bucket. */ - u32 node_id; - } bits; +struct BucketID { + u64 unique_; /**< A unique id for the blob */ + i32 node_id_; /**< The node the blob is on */ - /** The BucketID as a unsigned 64-bit integer */ - u64 as_int; + bool IsNull() const { return unique_ == 0; } - bool IsNull() const { return as_int == 0; } + static BucketID GetNull() { + BucketID id; + id.unique_ = 0; + return id; + } }; // NOTE(chogan): We reserve sizeof(BucketID) * 2 bytes in order to embed the @@ -100,38 +97,19 @@ constexpr int kBucketIdStringSize = sizeof(BucketID) * 2; */ constexpr int kMaxBlobNameSize = 64 - kBucketIdStringSize; -union VBucketID { - /** The VBucket ID as bitfield */ - struct { - /** The index into the Target array starting at BufferPool::targets_offset - * (on the node with ID node_id). */ - u32 index; - /** The ID of the node in charge of this vbucket. */ - u32 node_id; - } bits; - - /** The VBucketID as a unsigned 64-bit integer */ - u64 as_int; +struct VBucketID { + u64 unique_; /**< A unique id for the blob */ + i32 node_id_; /**< The node the blob is on */ - bool IsNull() const { return as_int == 0; } + bool IsNull() const { return unique_ == 0; } }; -union BlobID { - /** The Blob ID as bitfield */ - struct { - /** The index into the Target array starting at BufferPool::targets_offset - * (on the node with ID node_id). */ - u32 buffer_ids_offset; - /** The ID of the node in charge of this bucket. (Negative when in swap - space.) */ - i32 node_id; - } bits; - - /** The BlobID as an unsigned 64-bit integer */ - u64 as_int; - - bool IsNull() const { return as_int == 0; } - i32 GetNodeId() const { return bits.node_id; } +struct BlobID { + u64 unique_; /**< A unique id for the blob */ + i32 node_id_; /**< The node the blob is on */ + + bool IsNull() const { return unique_ == 0; } + i32 GetNodeId() const { return node_id_; } }; /** A definition for logging something that is not yet implemented */ @@ -146,20 +124,18 @@ union TargetID { /** The Target ID as bitfield */ struct { /** The ID of the node in charge of this target. */ - u32 node_id; + u32 node_id_; /** The ID of the virtual device that backs this target. It is an index into - * the Device array starting at BufferPool::devices_offset (on the node with - * ID node_id). */ - u16 device_id; - /** The index into the Target array starting at BufferPool::targets_offset - * (on the node with ID node_id). */ - u16 index; - } bits; + * the Device array. */ + u16 device_id_; + /** The index into the Target array. */ + u16 index_; + } bits_; /** The TargetID as a unsigned 64-bit integer */ - u64 as_int; + u64 as_int_; - bool IsNull() const { return as_int == 0; } + bool IsNull() const { return as_int_ == 0; } }; /** @@ -173,12 +149,14 @@ using PlacementSchema = std::vector>; * A structure to represent thesholds with mimimum and maximum values */ struct Thresholds { - float min; /**< minimum threshold value */ - float max; /**< maximum threshold value */ + float min_; /**< minimum threshold value */ + float max_; /**< maximum threshold value */ }; /** Trait ID type */ -typedef u64 TraitID; +struct TraitID { + u64 type_; +}; } // namespace hermes @@ -315,21 +293,27 @@ namespace std { template <> struct hash { std::size_t operator()(const hermes::BlobID &key) const { - return std::hash{}(key.as_int); + return + std::hash{}(key.unique_) + + std::hash{}(key.node_id_); } }; template <> struct hash { std::size_t operator()(const hermes::BucketID &key) const { - return std::hash{}(key.as_int); + return + std::hash{}(key.unique_) + + std::hash{}(key.node_id_); } }; template <> struct hash { std::size_t operator()(const hermes::VBucketID &key) const { - return std::hash{}(key.as_int); + return + std::hash{}(key.unique_) + + std::hash{}(key.node_id_); } }; } // namespace std diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index de84fd8fa..43f17bc49 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -7,12 +7,296 @@ namespace hermes { -void MetadataManager::Init() { +/** + * Explicitly initialize the MetadataManager + * */ +void MetadataManager::shm_init(MetadataManagerShmHeader *header) { + header_ = header; rpc_ = &HERMES->rpc_; + header_->id_alloc_ = 1; + + blob_id_map_owner_ = + lipc::make_uptr>(nullptr); + bkt_id_map_owner_ = + lipc::make_uptr>(nullptr); + vbkt_id_map_owner_ = + lipc::make_uptr>(nullptr); + blob_map_owner_ = + lipc::make_uptr>(nullptr); + bkt_map_owner_ = + lipc::make_uptr>(nullptr); + vbkt_map_owner_ = + lipc::make_uptr>(nullptr); +} + +/** + * Store the MetadataManager in shared memory. + * */ +void MetadataManager::shm_serialize() { + blob_id_map_owner_ >> header_->blob_id_map_ar_; + bkt_id_map_owner_ >> header_->bkt_id_map_ar_; + vbkt_id_map_owner_ >> header_->vbkt_id_map_ar_; + blob_map_owner_ >> header_->blob_map_ar_; + bkt_map_owner_ >> header_->bkt_map_ar_; + vbkt_map_owner_ >> header_->vbkt_map_ar_; +} + +/** + * Store the MetadataManager in shared memory. + * */ +void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { + header_ = header; + rpc_ = &HERMES->rpc_; + blob_id_map_ << header_->blob_id_map_ar_; + bkt_id_map_ << header_->bkt_id_map_ar_; + vbkt_id_map_ << header_->vbkt_id_map_ar_; + blob_map_ << header_->blob_map_ar_; + bkt_map_ << header_->bkt_map_ar_; + vbkt_map_ << header_->vbkt_map_ar_; +} + +/** + * Get or create a bucket with \a bkt_name bucket name + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +BucketID MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { + // Create unique ID for the Bucket + BucketID bkt_id; + bkt_id.unique_ = header_->id_alloc_.fetch_add(1); + bkt_id.node_id_ = rpc_->node_id_; + + // Emplace bucket if it does not already exist + if (bkt_id_map_->try_emplace(bkt_name, bkt_id)) { + } else { + auto iter = bkt_id_map_->find(bkt_name); + if (iter == bkt_id_map_->end()) { + return BucketID::GetNull(); + } + bkt_id = (*iter).val_; + } + + return bkt_id; +} + +/** + * Get the BucketID with \a bkt_name bucket name + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +BucketID MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { + BucketID bkt_id; + auto iter = bkt_id_map_->find(bkt_name); + if (iter == bkt_id_map_->end()) { + return BucketID::GetNull(); + } + bkt_id = (*iter).val_; + return bkt_id; +} + +/** + * Check whether or not \a bkt_id bucket contains + * \a blob_id blob + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalBucketContainsBlob(BucketID bkt_id, BlobID blob_id) { +} + +/** + * Rename \a bkt_id bucket to \a new_bkt_name new name + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalRenameBucket(BucketID bkt_id, + lipc::charbuf &new_bkt_name) { +} + + +/** + * Destroy \a bkt_id bucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalDestroyBucket(BucketID bkt_id) { +} + + +/** + * Put a blob in a bucket + * + * @param bkt_id id of the bucket + * @param blob_name semantic blob name + * @param data the data being placed + * @param buffers the buffers to place data in + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +BlobID MetadataManager::LocalBucketPutBlob(BucketID bkt_id, + lipc::charbuf &blob_name, + Blob &data, + lipc::vector &buffers) { +} + +/** + * Get \a blob_name blob from \a bkt_id bucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +BlobID MetadataManager::LocalGetBlobId(BucketID bkt_id, + lipc::charbuf &blob_name) { +} + +/** + * Change \a blob_id blob's buffers to \the buffers + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalSetBlobBuffers(BlobID blob_id, + lipc::vector &buffers) { +} + +/** + * Get \a blob_id blob's buffers + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +lipc::vector MetadataManager::LocalGetBlobBuffers(BlobID blob_id) { +} + +/** + * Rename \a blob_id blob to \a new_blob_name new blob name + * in \a bkt_id bucket. + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalRenameBlob(BucketID bkt_id, BlobID blob_id, + lipc::charbuf &new_blob_name) { +} + +/** + * Destroy \a blob_id blob in \a bkt_id bucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalDestroyBlob(BucketID bkt_id, + lipc::charbuf &blob_name) { +} + +/** + * Acquire \a blob_id blob's write lock + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalWriteLockBlob(BlobID blob_id) { +} + +/** + * Release \a blob_id blob's write lock + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalWriteUnlockBlob(BlobID blob_id) { +} + +/** + * Acquire \a blob_id blob's read lock + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalReadLockBlob(BlobID blob_id) { +} + +/** + * Release \a blob_id blob's read lock + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalReadUnlockBlob(BlobID blob_id) { +} + +/** + * Get or create \a vbkt_name VBucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +VBucketID MetadataManager::LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name) { +} + +/** + * Get the VBucketID of \a vbkt_name VBucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +VBucketID MetadataManager::LocalGetVBucketId(lipc::charbuf &vbkt_name) { +} + +/** + * Link \a vbkt_id VBucketID + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +VBucketID MetadataManager::LocalVBucketLinkBlob(VBucketID vbkt_id, + BucketID bkt_id, + lipc::charbuf &blob_name) { +} + +/** + * Unlink \a blob_name Blob of \a bkt_id Bucket + * from \a vbkt_id VBucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +VBucketID MetadataManager::LocalVBucketUnlinkBlob(VBucketID vbkt_id, + BucketID bkt_id, + lipc::charbuf &blob_name) { +} + +/** + * Get the linked blobs from \a vbkt_id VBucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +std::list MetadataManager::LocalVBucketGetLinks(VBucketID vbkt_id) { +} + +/** + * Rename \a vbkt_id VBucket to \a new_vbkt_name name + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalRenameVBucket(VBucketID vbkt_id, + lipc::charbuf &new_vbkt_name) { } -BucketID MetadataManager::LocalGetOrCreateBucket(std::string name) { - std::cout << "In bucket!" << std::endl; +/** + * Destroy \a vbkt_id VBucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalDestroyVBucket(VBucketID vbkt_id) { } } // namespace hermes \ No newline at end of file diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 15ed4e9ff..9e6d16420 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -10,23 +10,86 @@ #include "hermes_status.h" #include "rpc.h" #include "metadata_types.h" +#include "rpc_thallium_serialization.h" namespace hermes { +/** + * The SHM representation of the MetadataManager + * */ +struct MetadataManagerShmHeader { + /// SHM representation of blob id map + lipc::ShmArchive>> + blob_id_map_ar_; + /// SHM representation of bucket id map + lipc::ShmArchive>> + bkt_id_map_ar_; + /// SHM representation of vbucket id map + lipc::ShmArchive>> + vbkt_id_map_ar_; + /// SHM representation of blob map + lipc::ShmArchive>> + blob_map_ar_; + /// SHM representation of bucket map + lipc::ShmArchive>> + bkt_map_ar_; + /// SHM representation of vbucket map + lipc::ShmArchive>> + vbkt_map_ar_; + /// Used to create unique ids. Starts at 1. + std::atomic id_alloc_; +}; + +/** + * Manages the metadata for blobs, buckets, and vbuckets. + * */ class MetadataManager { private: RPC_TYPE* rpc_; - std::unordered_map blob_id_map_; - std::unordered_map bkt_id_map_; - std::unordered_map vbkt_id_map_; + MetadataManagerShmHeader *header_; - std::unordered_map blob_map_; - std::unordered_map bkt_map_; - std::unordered_map vbkt_map_; + /** + * The unique pointers representing the different map types. + * They are created in shm_init. They are destroyed automatically when the + * MetadataManager (on the Hermes core) is destroyed. This avoids having + * to manually "delete" the MetadataManager. + * */ + lipc::uptr> blob_id_map_owner_; + lipc::uptr> bkt_id_map_owner_; + lipc::uptr> vbkt_id_map_owner_; + lipc::uptr> blob_map_owner_; + lipc::uptr> bkt_map_owner_; + lipc::uptr> vbkt_map_owner_; + + /** + * The manual pointers representing the different map types. + * These are references to the objects stored in lipc::uptr + * objects above. + * */ + lipc::mptr> blob_id_map_; + lipc::mptr> bkt_id_map_; + lipc::mptr> vbkt_id_map_; + lipc::mptr> blob_map_; + lipc::mptr> bkt_map_; + lipc::mptr> vbkt_map_; public: MetadataManager() = default; - void Init(); + + /** + * Explicitly initialize the MetadataManager + * */ + void shm_init(MetadataManagerShmHeader *header); + + /** + * Store the MetadataManager in shared memory. + * */ + void shm_serialize(); + + /** + * Unload the MetadtaManager from shared memory + * */ + void shm_deserialize(MetadataManagerShmHeader *header); /** * Get or create a bucket with \a bkt_name bucket name @@ -34,7 +97,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BucketID LocalGetOrCreateBucket(std::string bkt_name); + RPC BucketID LocalGetOrCreateBucket(lipc::charbuf &bkt_name); /** * Get the BucketID with \a bkt_name bucket name @@ -42,7 +105,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BucketID LocalGetBucketId(std::string bkt_name); + RPC BucketID LocalGetBucketId(lipc::charbuf &bkt_name); /** * Check whether or not \a bkt_id bucket contains @@ -59,7 +122,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalRenameBucket(BucketID bkt_id, std::string new_bkt_name); + RPC bool LocalRenameBucket(BucketID bkt_id, lipc::charbuf &new_bkt_name); /** * Destroy \a bkt_id bucket @@ -80,8 +143,8 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BlobID LocalBucketPutBlob(BucketID bkt_id, std::string blob_name, - Blob data, std::vector buffers); + RPC BlobID LocalBucketPutBlob(BucketID bkt_id, lipc::charbuf &blob_name, + Blob &data, lipc::vector &buffers); /** * Get \a blob_name blob from \a bkt_id bucket @@ -89,7 +152,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BlobID LocalGetBlobId(BucketID bkt_id, std::string blob_name); + RPC BlobID LocalGetBlobId(BucketID bkt_id, lipc::charbuf &blob_name); /** * Change \a blob_id blob's buffers to \the buffers @@ -97,7 +160,8 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalSetBlobBuffers(BlobID blob_id, std::vector buffers); + RPC bool LocalSetBlobBuffers(BlobID blob_id, + lipc::vector &buffers); /** * Get \a blob_id blob's buffers @@ -105,7 +169,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC std::vector LocalGetBlobBuffers(BlobID blob_id); + RPC lipc::vector LocalGetBlobBuffers(BlobID blob_id); /** * Rename \a blob_id blob to \a new_blob_name new blob name @@ -115,7 +179,7 @@ class MetadataManager { * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalRenameBlob(BucketID bkt_id, BlobID blob_id, - std::string new_blob_name); + lipc::charbuf &new_blob_name); /** * Destroy \a blob_id blob in \a bkt_id bucket @@ -123,7 +187,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalDestroyBlob(BucketID bkt_id, std::string blob_name); + RPC bool LocalDestroyBlob(BucketID bkt_id, lipc::charbuf &blob_name); /** * Acquire \a blob_id blob's write lock @@ -163,7 +227,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC VBucketID LocalGetOrCreateVBucket(std::string vbkt_name); + RPC VBucketID LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name); /** * Get the VBucketID of \a vbkt_name VBucket @@ -171,7 +235,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC VBucketID LocalGetVBucketId(std::string vbkt_name); + RPC VBucketID LocalGetVBucketId(lipc::charbuf &vbkt_name); /** * Link \a vbkt_id VBucketID @@ -180,7 +244,7 @@ class MetadataManager { * @RPC_CLASS_INSTANCE mdm * */ RPC VBucketID LocalVBucketLinkBlob(VBucketID vbkt_id, BucketID bkt_id, - std::string blob_name); + lipc::charbuf &blob_name); /** * Unlink \a blob_name Blob of \a bkt_id Bucket @@ -190,7 +254,7 @@ class MetadataManager { * @RPC_CLASS_INSTANCE mdm * */ RPC VBucketID LocalVBucketUnlinkBlob(VBucketID vbkt_id, BucketID bkt_id, - std::string blob_name); + lipc::charbuf &blob_name); /** * Get the linked blobs from \a vbkt_id VBucket @@ -206,7 +270,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalRenameVBucket(VBucketID vbkt_id, std::string new_vbkt_name); + RPC bool LocalRenameVBucket(VBucketID vbkt_id, lipc::charbuf &new_vbkt_name); /** * Destroy \a vbkt_id VBucket @@ -218,7 +282,7 @@ class MetadataManager { public: RPC_AUTOGEN_START - BucketID GetOrCreateBucket(std::string bkt_name) { + BucketID GetOrCreateBucket(lipc::charbuf& bkt_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalGetOrCreateBucket( @@ -229,7 +293,7 @@ class MetadataManager { bkt_name); } } - BucketID GetBucketId(std::string bkt_name) { + BucketID GetBucketId(lipc::charbuf& bkt_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalGetBucketId( @@ -251,7 +315,7 @@ class MetadataManager { bkt_id, blob_id); } } - bool RenameBucket(BucketID bkt_id, std::string new_bkt_name) { + bool RenameBucket(BucketID bkt_id, lipc::charbuf& new_bkt_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalRenameBucket( @@ -273,7 +337,7 @@ class MetadataManager { bkt_id); } } - BlobID BucketPutBlob(BucketID bkt_id, std::string blob_name, Blob data, std::vector buffers) { + BlobID BucketPutBlob(BucketID bkt_id, lipc::charbuf& blob_name, Blob& data, lipc::vector& buffers) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalBucketPutBlob( @@ -284,7 +348,7 @@ class MetadataManager { bkt_id, blob_name, data, buffers); } } - BlobID GetBlobId(BucketID bkt_id, std::string blob_name) { + BlobID GetBlobId(BucketID bkt_id, lipc::charbuf& blob_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalGetBlobId( @@ -295,7 +359,7 @@ class MetadataManager { bkt_id, blob_name); } } - bool SetBlobBuffers(BlobID blob_id, std::vector buffers) { + bool SetBlobBuffers(BlobID blob_id, lipc::vector& buffers) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalSetBlobBuffers( @@ -306,18 +370,18 @@ class MetadataManager { blob_id, buffers); } } - std::vector GetBlobBuffers(BlobID blob_id) { + lipc::vector GetBlobBuffers(BlobID blob_id) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalGetBlobBuffers( blob_id); } else { - return rpc_->Call>( + return rpc_->Call>( target_node, "GetBlobBuffers", blob_id); } } - bool RenameBlob(BucketID bkt_id, BlobID blob_id, std::string new_blob_name) { + bool RenameBlob(BucketID bkt_id, BlobID blob_id, lipc::charbuf& new_blob_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalRenameBlob( @@ -328,7 +392,7 @@ class MetadataManager { bkt_id, blob_id, new_blob_name); } } - bool DestroyBlob(BucketID bkt_id, std::string blob_name) { + bool DestroyBlob(BucketID bkt_id, lipc::charbuf& blob_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalDestroyBlob( @@ -383,7 +447,7 @@ class MetadataManager { blob_id); } } - VBucketID GetOrCreateVBucket(std::string vbkt_name) { + VBucketID GetOrCreateVBucket(lipc::charbuf& vbkt_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalGetOrCreateVBucket( @@ -394,7 +458,7 @@ class MetadataManager { vbkt_name); } } - VBucketID GetVBucketId(std::string vbkt_name) { + VBucketID GetVBucketId(lipc::charbuf& vbkt_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalGetVBucketId( @@ -405,7 +469,7 @@ class MetadataManager { vbkt_name); } } - VBucketID VBucketLinkBlob(VBucketID vbkt_id, BucketID bkt_id, std::string blob_name) { + VBucketID VBucketLinkBlob(VBucketID vbkt_id, BucketID bkt_id, lipc::charbuf& blob_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalVBucketLinkBlob( @@ -416,7 +480,7 @@ class MetadataManager { vbkt_id, bkt_id, blob_name); } } - VBucketID VBucketUnlinkBlob(VBucketID vbkt_id, BucketID bkt_id, std::string blob_name) { + VBucketID VBucketUnlinkBlob(VBucketID vbkt_id, BucketID bkt_id, lipc::charbuf& blob_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalVBucketUnlinkBlob( @@ -438,7 +502,7 @@ class MetadataManager { vbkt_id); } } - bool RenameVBucket(VBucketID vbkt_id, std::string new_vbkt_name) { + bool RenameVBucket(VBucketID vbkt_id, lipc::charbuf& new_vbkt_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalRenameVBucket( diff --git a/src/metadata_types.h b/src/metadata_types.h index be84f085c..8c3877ca8 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -18,19 +18,19 @@ struct BufferInfo { }; struct BlobInfo { - std::string name_; - std::vector buffers_; + BucketID bkt_id_; /**< The bucket containing the blob */ + lipc::ShmArchive> name_; + lipc::ShmArchive>> buffers_; RwLock rwlock_; }; struct BucketInfo { - std::string name_; - std::vector blobs_; + lipc::ShmArchive> name_; }; struct VBucketInfo { - std::vector name_; - std::unordered_set blobs_; + lipc::ShmArchive>> name_; + lipc::ShmArchive>> blobs_; }; } // namespace hermes diff --git a/src/rpc.h b/src/rpc.h index dc29e910f..29dc8c951 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -27,9 +27,6 @@ #include "config.h" #include "utils.h" -#include -#include - namespace hermes::api { class Hermes; } // namespace hermes::api @@ -44,6 +41,7 @@ enum class RpcType { kThallium }; +/** Uniquely identify a host machine */ struct HostInfo { int node_id_; std::string hostname_; @@ -54,9 +52,7 @@ struct HostInfo { : hostname_(hostname), ip_addr_(ip_addr) {} }; -/** - A structure to represent RPC context. - */ +/** A structure to represent RPC context. */ class RpcContext { public: COMM_TYPE *comm_; diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index 4f7de3594..0190eeab7 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -49,8 +49,8 @@ class ThalliumRpc : public RpcContext { std::string GetServerName(u32 node_id); /** RPC call */ - template - ReturnType Call(u32 node_id, const char *func_name, Ts... args) { + template + ReturnType Call(u32 node_id, const char *func_name, Args&&... args) { VLOG(1) << "Calling " << func_name << " on node " << node_id << " from node " << node_id << std::endl; std::string server_name = GetServerName(node_id); @@ -58,9 +58,9 @@ class ThalliumRpc : public RpcContext { tl::endpoint server = client_engine_->lookup(server_name); if constexpr (std::is_same::value) { remote_proc.disable_response(); - remote_proc.on(server)(std::forward(args)...); + remote_proc.on(server)(std::forward(args)...); } else { - ReturnType result = remote_proc.on(server)(std::forward(args)...); + ReturnType result = remote_proc.on(server)(std::forward(args)...); return result; } } @@ -76,10 +76,12 @@ class ThalliumRpc : public RpcContext { case IoType::kRead: { func_name = "BulkRead"; flag = tl::bulk_mode::read_only; + break; } case IoType::kWrite: { func_name = "BulkWrite"; flag = tl::bulk_mode::write_only; + break; } } diff --git a/src/rpc_thallium_defs.cc b/src/rpc_thallium_defs.cc index 06069d917..a4e695851 100644 --- a/src/rpc_thallium_defs.cc +++ b/src/rpc_thallium_defs.cc @@ -4,6 +4,8 @@ #include "rpc_thallium.h" #include "metadata_manager.h" +#include "rpc_thallium_serialization.h" +#include "data_structures.h" namespace hermes { @@ -16,13 +18,13 @@ void ThalliumRpc::DefineRpcs() { RPC_AUTOGEN_START auto remote_get_or_create_bucket = - [mdm](const request &req, std::string bkt_name) { + [mdm](const request &req, lipc::charbuf& bkt_name) { auto result = mdm->LocalGetOrCreateBucket(bkt_name); req.respond(result); }; server_engine_->define("GetOrCreateBucket", remote_get_or_create_bucket); auto remote_get_bucket_id = - [mdm](const request &req, std::string bkt_name) { + [mdm](const request &req, lipc::charbuf& bkt_name) { auto result = mdm->LocalGetBucketId(bkt_name); req.respond(result); }; @@ -34,7 +36,7 @@ void ThalliumRpc::DefineRpcs() { }; server_engine_->define("BucketContainsBlob", remote_bucket_contains_blob); auto remote_rename_bucket = - [mdm](const request &req, BucketID bkt_id, std::string new_bkt_name) { + [mdm](const request &req, BucketID bkt_id, lipc::charbuf& new_bkt_name) { auto result = mdm->LocalRenameBucket(bkt_id, new_bkt_name); req.respond(result); }; @@ -46,19 +48,19 @@ void ThalliumRpc::DefineRpcs() { }; server_engine_->define("DestroyBucket", remote_destroy_bucket); auto remote_bucket_put_blob = - [mdm](const request &req, BucketID bkt_id, std::string blob_name, Blob data, std::vector buffers) { + [mdm](const request &req, BucketID bkt_id, lipc::charbuf& blob_name, Blob& data, lipc::vector& buffers) { auto result = mdm->LocalBucketPutBlob(bkt_id, blob_name, data, buffers); req.respond(result); }; server_engine_->define("BucketPutBlob", remote_bucket_put_blob); auto remote_get_blob_id = - [mdm](const request &req, BucketID bkt_id, std::string blob_name) { + [mdm](const request &req, BucketID bkt_id, lipc::charbuf& blob_name) { auto result = mdm->LocalGetBlobId(bkt_id, blob_name); req.respond(result); }; server_engine_->define("GetBlobId", remote_get_blob_id); auto remote_set_blob_buffers = - [mdm](const request &req, BlobID blob_id, std::vector buffers) { + [mdm](const request &req, BlobID blob_id, lipc::vector& buffers) { auto result = mdm->LocalSetBlobBuffers(blob_id, buffers); req.respond(result); }; @@ -66,17 +68,17 @@ void ThalliumRpc::DefineRpcs() { auto remote_get_blob_buffers = [mdm](const request &req, BlobID blob_id) { auto result = mdm->LocalGetBlobBuffers(blob_id); - req.respond(result); + req.respond(std::ref(result)); }; server_engine_->define("GetBlobBuffers", remote_get_blob_buffers); auto remote_rename_blob = - [mdm](const request &req, BucketID bkt_id, BlobID blob_id, std::string new_blob_name) { + [mdm](const request &req, BucketID bkt_id, BlobID blob_id, lipc::charbuf& new_blob_name) { auto result = mdm->LocalRenameBlob(bkt_id, blob_id, new_blob_name); req.respond(result); }; server_engine_->define("RenameBlob", remote_rename_blob); auto remote_destroy_blob = - [mdm](const request &req, BucketID bkt_id, std::string blob_name) { + [mdm](const request &req, BucketID bkt_id, lipc::charbuf& blob_name) { auto result = mdm->LocalDestroyBlob(bkt_id, blob_name); req.respond(result); }; @@ -106,25 +108,25 @@ void ThalliumRpc::DefineRpcs() { }; server_engine_->define("ReadUnlockBlob", remote_read_unlock_blob); auto remote_get_or_create_v_bucket = - [mdm](const request &req, std::string vbkt_name) { + [mdm](const request &req, lipc::charbuf& vbkt_name) { auto result = mdm->LocalGetOrCreateVBucket(vbkt_name); req.respond(result); }; server_engine_->define("GetOrCreateVBucket", remote_get_or_create_v_bucket); auto remote_get_v_bucket_id = - [mdm](const request &req, std::string vbkt_name) { + [mdm](const request &req, lipc::charbuf& vbkt_name) { auto result = mdm->LocalGetVBucketId(vbkt_name); req.respond(result); }; server_engine_->define("GetVBucketId", remote_get_v_bucket_id); auto remote_v_bucket_link_blob = - [mdm](const request &req, VBucketID vbkt_id, BucketID bkt_id, std::string blob_name) { + [mdm](const request &req, VBucketID vbkt_id, BucketID bkt_id, lipc::charbuf& blob_name) { auto result = mdm->LocalVBucketLinkBlob(vbkt_id, bkt_id, blob_name); req.respond(result); }; server_engine_->define("VBucketLinkBlob", remote_v_bucket_link_blob); auto remote_v_bucket_unlink_blob = - [mdm](const request &req, VBucketID vbkt_id, BucketID bkt_id, std::string blob_name) { + [mdm](const request &req, VBucketID vbkt_id, BucketID bkt_id, lipc::charbuf& blob_name) { auto result = mdm->LocalVBucketUnlinkBlob(vbkt_id, bkt_id, blob_name); req.respond(result); }; @@ -136,7 +138,7 @@ void ThalliumRpc::DefineRpcs() { }; server_engine_->define("VBucketGetLinks", remote_v_bucket_get_links); auto remote_rename_v_bucket = - [mdm](const request &req, VBucketID vbkt_id, std::string new_vbkt_name) { + [mdm](const request &req, VBucketID vbkt_id, lipc::charbuf& new_vbkt_name) { auto result = mdm->LocalRenameVBucket(vbkt_id, new_vbkt_name); req.respond(result); }; diff --git a/src/rpc_thallium_serialization.h b/src/rpc_thallium_serialization.h index 088bbf43f..98717a042 100644 --- a/src/rpc_thallium_serialization.h +++ b/src/rpc_thallium_serialization.h @@ -12,6 +12,8 @@ #include #include "hermes_types.h" #include "metadata_types.h" +#include "data_structures.h" +#include namespace hermes { @@ -25,7 +27,8 @@ namespace hermes { */ template void serialize(A &ar, VBucketID &vbucket_id) { - ar &vbucket_id.as_int; + ar &vbucket_id.unique_; + ar &vbucket_id.node_id_; } /** @@ -38,7 +41,8 @@ void serialize(A &ar, VBucketID &vbucket_id) { */ template void serialize(A &ar, BucketID &bucket_id) { - ar &bucket_id.as_int; + ar &bucket_id.unique_; + ar &bucket_id.node_id_; } /** @@ -51,7 +55,8 @@ void serialize(A &ar, BucketID &bucket_id) { */ template void serialize(A &ar, BlobID &blob_id) { - ar &blob_id.as_int; + ar &blob_id.unique_; + ar &blob_id.node_id_; } /** @@ -64,7 +69,7 @@ void serialize(A &ar, BlobID &blob_id) { */ template void serialize(A &ar, TargetID &target_id) { - ar &target_id.as_int; + ar &target_id.as_int_; } /** From 16191ed6b87ae157c5072b173f4e1b995d9e1ccd Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 19 Dec 2022 08:14:52 -0600 Subject: [PATCH 069/511] MDM map compiling again --- src/hermes_types.h | 61 +++++++++++------------------------- src/metadata_manager.cc | 54 ++++++++++++++++++++++++-------- src/metadata_manager.h | 68 +++++++++++++++++++++++++---------------- src/metadata_types.h | 45 +++++++++++++++++++++++---- 4 files changed, 139 insertions(+), 89 deletions(-) diff --git a/src/hermes_types.h b/src/hermes_types.h index e6431e106..539d538ea 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -75,42 +75,33 @@ enum class IoType { typedef u16 DeviceID; /**< device id in unsigned 16-bit integer */ -struct BucketID { +template +struct UniqueID { u64 unique_; /**< A unique id for the blob */ - i32 node_id_; /**< The node the blob is on */ + i32 node_id_; /**< The node the content is on */ bool IsNull() const { return unique_ == 0; } - static BucketID GetNull() { - BucketID id; + static UniqueID GetNull() { + UniqueID id; id.unique_ = 0; return id; } -}; -// NOTE(chogan): We reserve sizeof(BucketID) * 2 bytes in order to embed the -// BucketID into the Blob name. See MakeInternalBlobName() for a description of -// why we need double the bytes of a BucketID. -constexpr int kBucketIdStringSize = sizeof(BucketID) * 2; -/** - * The maximum size in bytes allowed for Blob names. - */ -constexpr int kMaxBlobNameSize = 64 - kBucketIdStringSize; + i32 GetNodeId() const { return node_id_; } -struct VBucketID { - u64 unique_; /**< A unique id for the blob */ - i32 node_id_; /**< The node the blob is on */ + bool operator==(const UniqueID &other) const { + return unique_ == other.unique_ && node_id_ == other.node_id_; + } - bool IsNull() const { return unique_ == 0; } + bool operator!=(const UniqueID &other) const { + return unique_ != other.unique_ || node_id_ != other.node_id_; + } }; -struct BlobID { - u64 unique_; /**< A unique id for the blob */ - i32 node_id_; /**< The node the blob is on */ - - bool IsNull() const { return unique_ == 0; } - i32 GetNodeId() const { return node_id_; } -}; +typedef UniqueID<0> BucketID; +typedef UniqueID<1> VBucketID; +typedef UniqueID<2> BlobID; /** A definition for logging something that is not yet implemented */ #define HERMES_NOT_IMPLEMENTED_YET \ @@ -290,31 +281,13 @@ enum class TraitType : u8 { * */ namespace std { -template <> -struct hash { +template +struct hash> { std::size_t operator()(const hermes::BlobID &key) const { return std::hash{}(key.unique_) + std::hash{}(key.node_id_); } }; - -template <> -struct hash { - std::size_t operator()(const hermes::BucketID &key) const { - return - std::hash{}(key.unique_) + - std::hash{}(key.node_id_); - } -}; - -template <> -struct hash { - std::size_t operator()(const hermes::VBucketID &key) const { - return - std::hash{}(key.unique_) + - std::hash{}(key.node_id_); - } -}; } // namespace std #endif // HERMES_TYPES_H_ diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 43f17bc49..c70840c36 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -14,19 +14,12 @@ void MetadataManager::shm_init(MetadataManagerShmHeader *header) { header_ = header; rpc_ = &HERMES->rpc_; header_->id_alloc_ = 1; - - blob_id_map_owner_ = - lipc::make_uptr>(nullptr); - bkt_id_map_owner_ = - lipc::make_uptr>(nullptr); - vbkt_id_map_owner_ = - lipc::make_uptr>(nullptr); - blob_map_owner_ = - lipc::make_uptr>(nullptr); - bkt_map_owner_ = - lipc::make_uptr>(nullptr); - vbkt_map_owner_ = - lipc::make_uptr>(nullptr); + blob_id_map_owner_ = lipc::make_uptr(nullptr); + bkt_id_map_owner_ = lipc::make_uptr(nullptr); + vbkt_id_map_owner_ = lipc::make_uptr(nullptr); + blob_map_owner_ = lipc::make_uptr(nullptr); + bkt_map_owner_ = lipc::make_uptr(nullptr); + vbkt_map_owner_ = lipc::make_uptr(nullptr); } /** @@ -104,6 +97,14 @@ BucketID MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { * @RPC_CLASS_INSTANCE mdm * */ bool MetadataManager::LocalBucketContainsBlob(BucketID bkt_id, BlobID blob_id) { + auto iter = blob_map_->find(blob_id); + if (iter == blob_map_->end()) { + return false; + } + // Get the blob info + BlobInfoShmHeader &hdr = (*iter).val_.get_ref(); + BlobInfo info(hdr); + return info.bkt_id_ == bkt_id; } /** @@ -114,6 +115,7 @@ bool MetadataManager::LocalBucketContainsBlob(BucketID bkt_id, BlobID blob_id) { * */ bool MetadataManager::LocalRenameBucket(BucketID bkt_id, lipc::charbuf &new_bkt_name) { + return true; } @@ -142,6 +144,32 @@ BlobID MetadataManager::LocalBucketPutBlob(BucketID bkt_id, lipc::charbuf &blob_name, Blob &data, lipc::vector &buffers) { + /*lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); + + // Create unique ID for the Blob + BlobID blob_id; + blob_id.unique_ = header_->id_alloc_.fetch_add(1); + blob_id.node_id_ = rpc_->node_id_; + if (blob_id_map_->try_emplace(blob_name, blob_id)) { + BlobInfo info; + info.name_ = lipc::make_mptr( + CreateBlobName(bkt_id, blob_name)); + info.buffers_ = lipc::make_mptr>( + std::move(buffers)); + + BlobInfoShmHeader hdr; + info.shm_serialize(hdr); + // blob_map_->emplace(blob_id, hdr); + } else { + auto iter = blob_map_->find(blob_id); + BlobInfoShmHeader &hdr = (*iter).val_.get_ref(); + BlobInfo info(hdr); + *(info.buffers_) = std::move(buffers); + info.shm_serialize(hdr); + (*iter).val_ = hdr; + } + + return blob_id;*/ } /** diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 9e6d16420..5f8a60186 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -14,28 +14,32 @@ namespace hermes { +/** + * Type name simplification for the various map types + * */ +typedef lipc::unordered_map BLOB_ID_MAP_T; +typedef lipc::unordered_map BKT_ID_MAP_T; +typedef lipc::unordered_map VBKT_ID_MAP_T; +typedef lipc::unordered_map BLOB_MAP_T; +typedef lipc::unordered_map BKT_MAP_T; +typedef lipc::unordered_map VBKT_MAP_T; + /** * The SHM representation of the MetadataManager * */ struct MetadataManagerShmHeader { /// SHM representation of blob id map - lipc::ShmArchive>> - blob_id_map_ar_; + lipc::ShmArchive> blob_id_map_ar_; /// SHM representation of bucket id map - lipc::ShmArchive>> - bkt_id_map_ar_; + lipc::ShmArchive> bkt_id_map_ar_; /// SHM representation of vbucket id map - lipc::ShmArchive>> - vbkt_id_map_ar_; + lipc::ShmArchive> vbkt_id_map_ar_; /// SHM representation of blob map - lipc::ShmArchive>> - blob_map_ar_; + lipc::ShmArchive> blob_map_ar_; /// SHM representation of bucket map - lipc::ShmArchive>> - bkt_map_ar_; + lipc::ShmArchive> bkt_map_ar_; /// SHM representation of vbucket map - lipc::ShmArchive>> - vbkt_map_ar_; + lipc::ShmArchive> vbkt_map_ar_; /// Used to create unique ids. Starts at 1. std::atomic id_alloc_; }; @@ -54,24 +58,24 @@ class MetadataManager { * MetadataManager (on the Hermes core) is destroyed. This avoids having * to manually "delete" the MetadataManager. * */ - lipc::uptr> blob_id_map_owner_; - lipc::uptr> bkt_id_map_owner_; - lipc::uptr> vbkt_id_map_owner_; - lipc::uptr> blob_map_owner_; - lipc::uptr> bkt_map_owner_; - lipc::uptr> vbkt_map_owner_; + lipc::uptr blob_id_map_owner_; + lipc::uptr bkt_id_map_owner_; + lipc::uptr vbkt_id_map_owner_; + lipc::uptr blob_map_owner_; + lipc::uptr bkt_map_owner_; + lipc::uptr vbkt_map_owner_; /** * The manual pointers representing the different map types. * These are references to the objects stored in lipc::uptr * objects above. * */ - lipc::mptr> blob_id_map_; - lipc::mptr> bkt_id_map_; - lipc::mptr> vbkt_id_map_; - lipc::mptr> blob_map_; - lipc::mptr> bkt_map_; - lipc::mptr> vbkt_map_; + lipc::mptr blob_id_map_; + lipc::mptr bkt_id_map_; + lipc::mptr vbkt_id_map_; + lipc::mptr blob_map_; + lipc::mptr bkt_map_; + lipc::mptr vbkt_map_; public: MetadataManager() = default; @@ -84,12 +88,24 @@ class MetadataManager { /** * Store the MetadataManager in shared memory. * */ - void shm_serialize(); + void shm_serialize(); /** * Unload the MetadtaManager from shared memory * */ - void shm_deserialize(MetadataManagerShmHeader *header); + void shm_deserialize(MetadataManagerShmHeader *header); + + /** + * Create a unique blob name using BucketID + * */ + lipc::charbuf CreateBlobName(BucketID bkt_id, lipc::charbuf &blob_name) { + lipc::charbuf new_name(sizeof(bkt_id) + blob_name.size()); + size_t off = 0; + memcpy(new_name.data_mutable() + off, &bkt_id, sizeof(BucketID)); + off += sizeof(BucketID); + memcpy(blob_name.data_mutable() + off, blob_name.data(), blob_name.size()); + return new_name; + } /** * Get or create a bucket with \a bkt_name bucket name diff --git a/src/metadata_types.h b/src/metadata_types.h index 8c3877ca8..8346591ca 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -17,20 +17,53 @@ struct BufferInfo { TargetID target_; }; -struct BlobInfo { +struct BlobInfoShmHeader { BucketID bkt_id_; /**< The bucket containing the blob */ - lipc::ShmArchive> name_; - lipc::ShmArchive>> buffers_; + lipc::ShmArchive> name_ar_; + lipc::ShmArchive>> buffers_ar_; RwLock rwlock_; + + BlobInfoShmHeader() = default; +}; + +struct BlobInfo { + BucketID bkt_id_; /**< The bucket containing the blob */ + lipc::mptr name_; + lipc::mptr> buffers_; + + BlobInfo() = default; + + BlobInfo(BlobInfoShmHeader &ar) { + shm_deserialize(ar); + } + + void shm_serialize(BlobInfoShmHeader &ar) { + name_ >> ar.name_ar_; + buffers_ >> ar.buffers_ar_; + } + + void shm_deserialize(BlobInfoShmHeader &ar) { + name_ << ar.name_ar_; + buffers_ << ar.buffers_ar_; + } +}; + +struct BucketInfoShmHeader { + lipc::ShmArchive> name_ar_; }; struct BucketInfo { - lipc::ShmArchive> name_; + lipc::mptr name_; +}; + +struct VBucketInfoShmHeader { + lipc::ShmArchive>> name_; + lipc::ShmArchive>> blobs_; }; struct VBucketInfo { - lipc::ShmArchive>> name_; - lipc::ShmArchive>> blobs_; + lipc::mptr> name_; + lipc::mptr> blobs_; }; } // namespace hermes From 5be6ce24585e28c0a0230f4511883ab3d2560f44 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 19 Dec 2022 17:21:10 -0600 Subject: [PATCH 070/511] Split into configclient and configserver --- src/api/hermes.h | 3 +- src/buffer_organizer.cc | 5 ++ src/buffer_organizer.h | 13 ++++ src/buffer_pool.cc | 11 ++++ src/buffer_pool.h | 52 ++++++++++++++++ src/config.h | 128 ---------------------------------------- src/config_client.cc | 2 +- src/config_client.h | 29 +++++++++ src/config_server.cc | 2 +- src/config_server.h | 126 +++++++++++++++++++++++++++++++++++++++ src/rpc.h | 2 +- 11 files changed, 241 insertions(+), 132 deletions(-) create mode 100644 src/buffer_organizer.cc create mode 100644 src/buffer_organizer.h create mode 100644 src/buffer_pool.cc create mode 100644 src/buffer_pool.h create mode 100644 src/config_client.h create mode 100644 src/config_server.h diff --git a/src/api/hermes.h b/src/api/hermes.h index 680f1cc5e..1c27790f2 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -5,7 +5,8 @@ #ifndef HERMES_SRC_API_HERMES_H_ #define HERMES_SRC_API_HERMES_H_ -#include "config.h" +#include "config_client.h" +#include "config_server.h" #include "constants.h" #include "hermes_types.h" diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc new file mode 100644 index 000000000..323c15a1d --- /dev/null +++ b/src/buffer_organizer.cc @@ -0,0 +1,5 @@ +// +// Created by lukemartinlogan on 12/19/22. +// + +#include "buffer_organizer.h" diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h new file mode 100644 index 000000000..f4ea48547 --- /dev/null +++ b/src/buffer_organizer.h @@ -0,0 +1,13 @@ +// +// Created by lukemartinlogan on 12/19/22. +// + +#ifndef HERMES_SRC_BUFFER_ORGANIZER_H_ +#define HERMES_SRC_BUFFER_ORGANIZER_H_ + +class BufferOrganizer { + public: + BufferOrganizer() = default; +}; + +#endif // HERMES_SRC_BUFFER_ORGANIZER_H_ diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc new file mode 100644 index 000000000..8a01c7e5b --- /dev/null +++ b/src/buffer_pool.cc @@ -0,0 +1,11 @@ +// +// Created by lukemartinlogan on 12/19/22. +// + +#include "buffer_pool.h" + +namespace hermes { + +bool LocalPlaceBlob(PlacementSchema &schema, Blob &blob) {} + +} // namespace hermes \ No newline at end of file diff --git a/src/buffer_pool.h b/src/buffer_pool.h new file mode 100644 index 000000000..823640774 --- /dev/null +++ b/src/buffer_pool.h @@ -0,0 +1,52 @@ +// +// Created by lukemartinlogan on 12/19/22. +// + +#ifndef HERMES_SRC_BUFFER_POOL_H_ +#define HERMES_SRC_BUFFER_POOL_H_ + +#include "hermes_types.h" +#include "rpc.h" + +class MetadataManager; + +namespace hermes { + +/** + * The shared-memory representation of the BufferPool + * */ +struct BufferPoolManagerShmHeader { + lipc::vector targets_; +}; + +/** + * Responsible for managing the buffering space of all node-local targets. + * */ +class BufferPoolManager { + private: + MetadataManager *mdm_; + + public: + BufferPoolManager() = default; + + void shm_init(); + + void shm_serialize(); + + void shm_deserialize(); + + /** + * Allocate buffers from the targets according to the schema + * */ + RPC lipc::vector + LocalAllocateBuffers(PlacementSchema &schema, Blob &blob); + + /** + * Free buffers from the BufferPool + * */ + RPC bool LocalReleaseBuffers(lipc::vector &buffers); +}; + +} // namespace hermes + +#endif // HERMES_SRC_BUFFER_POOL_H_ diff --git a/src/config.h b/src/config.h index 81003e3a2..ac079ea1c 100644 --- a/src/config.h +++ b/src/config.h @@ -60,134 +60,6 @@ class BaseConfig { virtual void ParseYAML(YAML::Node &yaml_conf) = 0; }; -/** - * Configuration used to intialize client - * */ -class ClientConfig : public BaseConfig { - public: - bool stop_daemon_; - - public: - ClientConfig() = default; - void LoadDefault() override; - - private: - void ParseYAML(YAML::Node &yaml_conf) override; -}; - - -/** - * Device information defined in server config - * */ -struct DeviceInfo { - /** The minimum transfer size of each device */ - size_t block_size_; - /** The unit of each slab, a multiple of the Device's block size */ - std::vector slab_sizes_; - /** The mount point of a device */ - std::string mount_point_; - /** Device capacity (bytes) */ - size_t capacity_; - /** Bandwidth of a device (MBps) */ - f32 bandwidth_; - /** Latency of the device (us)*/ - f32 latency_; - /** Whether or not the device is shared among all nodes */ - bool is_shared_; - /** BORG's minimum and maximum capacity threshold for device */ - f32 borg_min_thresh_, borg_max_thresh_; -}; - -/** - * RPC information defined in server config - * */ -struct RpcInfo { - /** The name of a file that contains host names, 1 per line */ - std::string host_file_; - /** The parsed hostnames from the hermes conf */ - std::vector host_names_; - /** The RPC protocol to be used. */ - std::string protocol_; - /** The RPC domain name for verbs transport. */ - std::string domain_; - /** The RPC port number. */ - int port_; - /** The number of handler threads per RPC server. */ - int num_threads_; -}; - -/** - * DPE information defined in server config - * */ -struct DpeInfo { - /** The default blob placement policy. */ - api::PlacementPolicy default_policy_; - - /** Whether blob splitting is enabled for Round-Robin blob placement. */ - bool default_rr_split_; -}; - -/** - * Buffer organizer information defined in server config - * */ -struct BorgInfo { - /** The RPC port number for the buffer organizer. */ - int port_; - /** The number of buffer organizer threads. */ - int num_threads_; -}; - -/** - * System configuration for Hermes - */ -class ServerConfig : public BaseConfig { - public: - /** The device information */ - std::vector devices_; - - /** The RPC information */ - RpcInfo rpc_; - - /** The DPE information */ - DpeInfo dpe_; - - /** Buffer organizer (BORG) information */ - BorgInfo borg_; - - /** The length of a view state epoch */ - u32 system_view_state_update_interval_ms; - - /** A base name for the BufferPool shared memory segement. Hermes appends the - * value of the USER environment variable to this string. - */ - std::string shmem_name_; - - /** - * Paths prefixed with the following directories are not tracked in Hermes - * Exclusion list used by darshan at - * darshan/darshan-runtime/lib/darshan-core.c - */ - std::vector path_exclusions; - - /** - * Paths prefixed with the following directories are tracked by Hermes even if - * they share a root with a path listed in path_exclusions - */ - std::vector path_inclusions; - - public: - ServerConfig() = default; - void LoadDefault(); - - private: - void ParseYAML(YAML::Node &yaml_conf); - void CheckConstraints(); - void ParseRpcInfo(YAML::Node yaml_conf); - void ParseDeviceInfo(YAML::Node yaml_conf); - void ParseDpeInfo(YAML::Node yaml_conf); - void ParseBorgInfo(YAML::Node yaml_conf); -}; - /** print \a expected value and fail when an error occurs */ static void PrintExpectedAndFail(const std::string &expected, u32 line_number = 0) { std::ostringstream msg; diff --git a/src/config_client.cc b/src/config_client.cc index d2352447b..544d8c521 100644 --- a/src/config_client.cc +++ b/src/config_client.cc @@ -2,7 +2,7 @@ // Created by lukemartinlogan on 12/2/22. // -#include "config.h" +#include "config_client.h" #include "config_client_default.h" namespace hermes { diff --git a/src/config_client.h b/src/config_client.h new file mode 100644 index 000000000..0f268a52d --- /dev/null +++ b/src/config_client.h @@ -0,0 +1,29 @@ +// +// Created by lukemartinlogan on 12/19/22. +// + +#ifndef HERMES_SRC_CONFIG_CLIENT_H_ +#define HERMES_SRC_CONFIG_CLIENT_H_ + +#include "config.h" + +namespace hermes { + +/** + * Configuration used to intialize client + * */ +class ClientConfig : public BaseConfig { + public: + bool stop_daemon_; + + public: + ClientConfig() = default; + void LoadDefault() override; + + private: + void ParseYAML(YAML::Node &yaml_conf) override; +}; + +} // namespace hermes + +#endif // HERMES_SRC_CONFIG_CLIENT_H_ diff --git a/src/config_server.cc b/src/config_server.cc index 3db7b117b..7ba130d86 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -14,7 +14,7 @@ #include "config.h" #include -#include "config.h" +#include "config_server.h" #include "config_server_default.h" namespace hermes { diff --git a/src/config_server.h b/src/config_server.h new file mode 100644 index 000000000..88aed46ff --- /dev/null +++ b/src/config_server.h @@ -0,0 +1,126 @@ +// +// Created by lukemartinlogan on 12/19/22. +// + +#ifndef HERMES_SRC_CONFIG_SERVER_H_ +#define HERMES_SRC_CONFIG_SERVER_H_ + +#include "config.h" + +namespace hermes { + +/** + * Device information defined in server config + * */ +struct DeviceInfo { + /** The minimum transfer size of each device */ + size_t block_size_; + /** The unit of each slab, a multiple of the Device's block size */ + std::vector slab_sizes_; + /** The mount point of a device */ + std::string mount_point_; + /** Device capacity (bytes) */ + size_t capacity_; + /** Bandwidth of a device (MBps) */ + f32 bandwidth_; + /** Latency of the device (us)*/ + f32 latency_; + /** Whether or not the device is shared among all nodes */ + bool is_shared_; + /** BORG's minimum and maximum capacity threshold for device */ + f32 borg_min_thresh_, borg_max_thresh_; +}; + +/** + * RPC information defined in server config + * */ +struct RpcInfo { + /** The name of a file that contains host names, 1 per line */ + std::string host_file_; + /** The parsed hostnames from the hermes conf */ + std::vector host_names_; + /** The RPC protocol to be used. */ + std::string protocol_; + /** The RPC domain name for verbs transport. */ + std::string domain_; + /** The RPC port number. */ + int port_; + /** The number of handler threads per RPC server. */ + int num_threads_; +}; + +/** + * DPE information defined in server config + * */ +struct DpeInfo { + /** The default blob placement policy. */ + api::PlacementPolicy default_policy_; + + /** Whether blob splitting is enabled for Round-Robin blob placement. */ + bool default_rr_split_; +}; + +/** + * Buffer organizer information defined in server config + * */ +struct BorgInfo { + /** The RPC port number for the buffer organizer. */ + int port_; + /** The number of buffer organizer threads. */ + int num_threads_; +}; + +/** + * System configuration for Hermes + */ +class ServerConfig : public BaseConfig { + public: + /** The device information */ + std::vector devices_; + + /** The RPC information */ + RpcInfo rpc_; + + /** The DPE information */ + DpeInfo dpe_; + + /** Buffer organizer (BORG) information */ + BorgInfo borg_; + + /** The length of a view state epoch */ + u32 system_view_state_update_interval_ms; + + /** A base name for the BufferPool shared memory segement. Hermes appends the + * value of the USER environment variable to this string. + */ + std::string shmem_name_; + + /** + * Paths prefixed with the following directories are not tracked in Hermes + * Exclusion list used by darshan at + * darshan/darshan-runtime/lib/darshan-core.c + */ + std::vector path_exclusions; + + /** + * Paths prefixed with the following directories are tracked by Hermes even if + * they share a root with a path listed in path_exclusions + */ + std::vector path_inclusions; + + public: + ServerConfig() = default; + void LoadDefault(); + + private: + void ParseYAML(YAML::Node &yaml_conf); + void CheckConstraints(); + void ParseRpcInfo(YAML::Node yaml_conf); + void ParseDeviceInfo(YAML::Node yaml_conf); + void ParseDpeInfo(YAML::Node yaml_conf); + void ParseBorgInfo(YAML::Node yaml_conf); +}; + +} // namespace hermes + +#endif // HERMES_SRC_CONFIG_SERVER_H_ diff --git a/src/rpc.h b/src/rpc.h index 29dc8c951..f49da7e5c 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -24,7 +24,7 @@ #include "hermes_types.h" #include "communication.h" #include "decorator.h" -#include "config.h" +#include "config_server.h" #include "utils.h" namespace hermes::api { From 4c15c57181ecfe225baa3fbf96615f1321053c5d Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 21 Dec 2022 02:09:43 -0600 Subject: [PATCH 071/511] Add dpes back --- adapter/filesystem/filesystem.cc | 8 +- benchmarks/mdm_bench.cc | 2 +- src/CMakeLists.txt | 1 + src/api/bucket.cc | 44 ++++++- src/api/bucket.h | 28 ++--- src/api/vbucket.h | 2 +- src/buffer_pool.h | 2 +- src/config.h | 4 +- src/config_client.cc | 4 +- src/config_client.h | 6 +- src/config_server.cc | 4 +- src/config_server.h | 6 +- src/data_placement_engine.cc | 79 ++++++++++++ src/data_placement_engine.h | 64 ++++++++++ src/data_placement_engine_factory.h | 60 ++++++++++ src/dpe/linprog.h | 163 +++++++++++++++++++++++++ src/dpe/minimize_io_time.cc | 178 ++++++++++++++++++++++++++++ src/dpe/minimize_io_time.h | 48 ++++++++ src/dpe/random.cc | 95 +++++++++++++++ src/dpe/random.h | 46 +++++++ src/dpe/round_robin.cc | 41 +++++++ src/dpe/round_robin.h | 46 +++++++ src/hermes_types.h | 51 ++++++-- src/metadata_manager.cc | 64 +++++----- src/metadata_manager.h | 134 ++++++++++----------- src/metadata_types.h | 30 ++++- src/rpc_thallium_defs.cc | 36 +++--- src/rpc_thallium_serialization.h | 18 +-- src/status.cc | 11 ++ src/{hermes_status.h => status.h} | 26 +++- src/statuses.h | 19 +++ wrapper/CMakeLists.txt | 71 ----------- wrapper/hermes_wrapper.cpp | 132 --------------------- wrapper/hermes_wrapper.h | 58 --------- 34 files changed, 1143 insertions(+), 438 deletions(-) create mode 100644 src/data_placement_engine.cc create mode 100644 src/data_placement_engine.h create mode 100644 src/data_placement_engine_factory.h create mode 100644 src/dpe/linprog.h create mode 100644 src/dpe/minimize_io_time.cc create mode 100644 src/dpe/minimize_io_time.h create mode 100644 src/dpe/random.cc create mode 100644 src/dpe/random.h create mode 100644 src/dpe/round_robin.cc create mode 100644 src/dpe/round_robin.h create mode 100644 src/status.cc rename src/{hermes_status.h => status.h} (72%) create mode 100644 src/statuses.h delete mode 100644 wrapper/CMakeLists.txt delete mode 100644 wrapper/hermes_wrapper.cpp delete mode 100644 wrapper/hermes_wrapper.h diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index e79ba0737..e93b7bca9 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -186,8 +186,8 @@ bool Lock(const std::string &bucket, const std::string &blob_name) { auto &hermes = mdm->GetHermes(); SharedMemoryContext *context = &hermes->context_; RpcContext *rpc = &hermes->rpc_; - BucketID bucket_id = GetBucketId(context, rpc, bucket.c_str()); - BlobID lock_id = GetBlobId(context, rpc, blob_name, bucket_id, true); + BucketId bucket_id = GetBucketId(context, rpc, bucket.c_str()); + BlobId lock_id = GetBlobId(context, rpc, blob_name, bucket_id, true); bool ret = LockBlob(context, rpc, lock_id); return ret; } @@ -197,8 +197,8 @@ void Unlock(const std::string &bucket, const std::string &blob_name) { auto &hermes = mdm->GetHermes(); SharedMemoryContext *context = &hermes->context_; RpcContext *rpc = &hermes->rpc_; - BucketID bucket_id = GetBucketId(context, rpc, bucket.c_str()); - BlobID lock_id = GetBlobId(context, rpc, blob_name, bucket_id, true); + BucketId bucket_id = GetBucketId(context, rpc, bucket.c_str()); + BlobId lock_id = GetBlobId(context, rpc, blob_name, bucket_id, true); UnlockBlob(context, rpc, lock_id); } diff --git a/benchmarks/mdm_bench.cc b/benchmarks/mdm_bench.cc index 629560595..6c9ab49f3 100644 --- a/benchmarks/mdm_bench.cc +++ b/benchmarks/mdm_bench.cc @@ -66,7 +66,7 @@ void Run(int target_node, int rank, int comm_size, int num_requests, MPI_Barrier(comm); - hermes::BlobID blob_id = {}; + hermes::BlobId blob_id = {}; blob_id.bits.node_id = target_node; blob_id.bits.buffer_ids_offset = id_list_offset; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 39215a34e..10354758d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -43,6 +43,7 @@ set(HERMES_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/config_client.cc ${CMAKE_CURRENT_SOURCE_DIR}/config_server.cc ${CMAKE_CURRENT_SOURCE_DIR}/hermes_types.cc + ${CMAKE_CURRENT_SOURCE_DIR}/status.cc ${CMAKE_CURRENT_SOURCE_DIR}/utils.cc ${CMAKE_CURRENT_SOURCE_DIR}/rpc.cc ${CMAKE_CURRENT_SOURCE_DIR}/rpc_thallium.cc diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 0c1847d45..a54fdbd24 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -3,12 +3,50 @@ // #include "bucket.h" +// #include "data_placement_engine_factory.h" namespace hermes::api { -Bucket::Bucket(std::string name, - Context &ctx) : mdm_(&HERMES->mdm_) { - // mdm_->GetOrCreateBucket(name); +/** + * Either initialize or fetch the bucket. + * */ +Bucket::Bucket(std::string name, Context &ctx) : mdm_(&HERMES->mdm_) { + lipc::string lname(name); + mdm_->GetOrCreateBucket(lname); +} + +/** + * Rename this bucket + * */ +void Bucket::Rename(std::string new_bkt_name) { +} + +/** + * Destroys this bucket along with all its contents. + * */ +void Bucket::Destroy(std::string blob_name) { +} + +/** + * Put \a blob_id Blob into the bucket + * */ +Status Bucket::Put(std::string blob_name, Blob blob, + BlobId &blob_id, Context &ctx) { + // Calculate placement + /*auto dpe = DPEFactory::Get(ctx.policy); + std::vector blob_sizes(1, blob.size()); + std::vector schema; + dpe->CalculatePlacement(blob_sizes, schema, ctx);*/ + + // Allocate buffers for the blob + +} + +/** + * Get \a blob_id Blob from the bucket + * :WRAP-param: ctx -> ctx_ + * */ +Status Bucket::Get(BlobId blob_id, Blob &blob, Context &ctx) { } } // namespace hermes::api \ No newline at end of file diff --git a/src/api/bucket.h b/src/api/bucket.h index 37e370fc4..69f6c6524 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -6,7 +6,7 @@ #define HERMES_SRC_API_BUCKET_H_ #include "hermes_types.h" -#include "hermes_status.h" +#include "status.h" #include "hermes.h" namespace hermes::api { @@ -14,7 +14,7 @@ namespace hermes::api { class Bucket { private: MetadataManager *mdm_; - BucketID id_; + BucketId id_; std::string name_; Context ctx_; @@ -41,7 +41,7 @@ class Bucket { /** * Get the identifier of this bucket * */ - BucketID GetId() const { + BucketId GetId() const { return id_; } @@ -60,29 +60,23 @@ class Bucket { public: /** - * Put \a blob_name Blob into the bucket + * Get the id of a blob from the blob name * */ - Status PutBlob(std::string blob_name, Blob &blob, - Context &ctx); + Status GetBlobId(std::string blob_name, BlobId &blob_id, Context &ctx); /** * Put \a blob_id Blob into the bucket * */ - Status PutBlob(BlobID blob_id, Blob &blob, - Context &ctx); - - /** - * Get \a blob_name Blob from the bucket - * */ - Status GetBlob(std::string blob_name, Blob &blob, - Context &ctx); + Status Put(std::string blob_name, Blob blob, + BlobId &blob_id, Context &ctx); /** * Get \a blob_id Blob from the bucket - * :WRAP-param: ctx -> ctx_ + * @WRAP_DEFAULT: ctx -> ctx_ + * @WRAP_PROTO: blob_id -> std::string blob_name + * @WRAP_DEFAULT: blob_id -> GetBlobId(blob_name) * */ - Status GetBlob(BlobID blob_id, Blob &blob, - Context &ctx); + Status Get(BlobId blob_id, Blob &blob, Context &ctx); public: RPC_AUTOGEN_START diff --git a/src/api/vbucket.h b/src/api/vbucket.h index f93e26c29..7023af0cb 100644 --- a/src/api/vbucket.h +++ b/src/api/vbucket.h @@ -6,7 +6,7 @@ #define HERMES_SRC_API_VBUCKET_H_ #include "hermes_types.h" -#include "hermes_status.h" +#include "status.h" #include "hermes.h" namespace hermes::api { diff --git a/src/buffer_pool.h b/src/buffer_pool.h index 823640774..56df5f44a 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -16,7 +16,7 @@ namespace hermes { * The shared-memory representation of the BufferPool * */ struct BufferPoolManagerShmHeader { - lipc::vector targets_; + lipc::vector targets_; }; /** diff --git a/src/config.h b/src/config.h index ac079ea1c..43d179cae 100644 --- a/src/config.h +++ b/src/config.h @@ -24,7 +24,7 @@ #include "hermes_types.h" #include "constants.h" -namespace hermes { +namespace hermes::config { /** * Base class for configuration files @@ -177,5 +177,5 @@ static size_t ParseLatency(const std::string &latency_text) { LOG(FATAL) << "Could not parse the latency: " << latency_text << std::endl; } -} // namespace hermes +} // namespace hermes::config #endif // HERMES_CONFIG_PARSER_H_ diff --git a/src/config_client.cc b/src/config_client.cc index 544d8c521..6e15b44ff 100644 --- a/src/config_client.cc +++ b/src/config_client.cc @@ -5,7 +5,7 @@ #include "config_client.h" #include "config_client_default.h" -namespace hermes { +namespace hermes::config { /** parse the YAML node */ void ClientConfig::ParseYAML(YAML::Node &yaml_conf) { @@ -19,4 +19,4 @@ void ClientConfig::LoadDefault() { LoadText(kClientDefaultConfigStr, false); } -} // namespace hermes \ No newline at end of file +} // namespace hermes::config \ No newline at end of file diff --git a/src/config_client.h b/src/config_client.h index 0f268a52d..ef7288bbc 100644 --- a/src/config_client.h +++ b/src/config_client.h @@ -7,7 +7,7 @@ #include "config.h" -namespace hermes { +namespace hermes::config { /** * Configuration used to intialize client @@ -24,6 +24,10 @@ class ClientConfig : public BaseConfig { void ParseYAML(YAML::Node &yaml_conf) override; }; +} // hermes::config + +namespace hermes { +using config::ClientConfig; } // namespace hermes #endif // HERMES_SRC_CONFIG_CLIENT_H_ diff --git a/src/config_server.cc b/src/config_server.cc index 7ba130d86..17de5deec 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -17,7 +17,7 @@ #include "config_server.h" #include "config_server_default.h" -namespace hermes { +namespace hermes::config { /** parse device information from YAML config */ void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { @@ -141,4 +141,4 @@ void ServerConfig::LoadDefault() { LoadText(kServerDefaultConfigStr, false); } -} // namespace hermes +} // hermes::config diff --git a/src/config_server.h b/src/config_server.h index 88aed46ff..6b8f5de7b 100644 --- a/src/config_server.h +++ b/src/config_server.h @@ -7,7 +7,7 @@ #include "config.h" -namespace hermes { +namespace hermes::config { /** * Device information defined in server config @@ -121,6 +121,10 @@ class ServerConfig : public BaseConfig { void ParseBorgInfo(YAML::Node yaml_conf); }; +} // namespace hermes::config + +namespace hermes { +using config::ServerConfig; } // namespace hermes #endif // HERMES_SRC_CONFIG_SERVER_H_ diff --git a/src/data_placement_engine.cc b/src/data_placement_engine.cc new file mode 100644 index 000000000..f957c39a0 --- /dev/null +++ b/src/data_placement_engine.cc @@ -0,0 +1,79 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "data_placement_engine_factory.h" + +#include +#include + +#include +#include +#include + +#include "hermes.h" +#include "hermes_types.h" +#include "buffer_pool.h" + +namespace hermes { + +/** topology */ +enum Topology { + Topology_Local, + Topology_Neighborhood, + Topology_Global, + + Topology_Count +}; + +/** calculate data placement */ +Status DPE::CalculatePlacement(const std::vector &blob_sizes, + std::vector &output, + const api::Context &ctx) { + Status result; + + // NOTE(chogan): Start with local targets and gradually expand the target + // list until the placement succeeds. + for (int i = 0; i < Topology_Count; ++i) { + // Reset the output schema + output.clear(); + // Get the capacity/bandwidth of targets + std::vector targets; + switch (static_cast(i)) { + case TopologyType::Local: { + // TODO(chogan): @optimization We can avoid the copy here when getting + // local targets by just getting a pointer and length. + targets = mdm_->LocalGetNodeTargetInfo(); + break; + } + case TopologyType::Neighborhood: { + targets = mdm_->GetNeighborhoodTargets(); + break; + } + case TopologyType::Global: { + targets = mdm_->GetGlobalTargets(); + break; + } + } + if (targets.size() == 0) { + result = DPE_PLACEMENT_SCHEMA_EMPTY; + continue; + } + // Calculate a placement schema + result = Placement(blob_sizes, targets, ctx, output); + if (!result.Failed()) { + break; + } + } + return result; +} + +} // namespace hermes diff --git a/src/data_placement_engine.h b/src/data_placement_engine.h new file mode 100644 index 000000000..09c99ac81 --- /dev/null +++ b/src/data_placement_engine.h @@ -0,0 +1,64 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_DATA_PLACEMENT_ENGINE_H_ +#define HERMES_DATA_PLACEMENT_ENGINE_H_ + +#include + +#include "hermes.h" +#include "status.h" +#include "hermes_types.h" +#include "metadata_manager.h" + +namespace hermes { + +using api::Status; +using hermes::api::PlacementPolicy; + +/** + A class to represent data placement engine +*/ +class DPE { + protected: + PlacementPolicy policy_; /**< data placement policy */ + MetadataManager *mdm_; /**< A pointer to the MDM */ + + public: + std::vector bandwidths; /**< a vector of bandwidths */ + + /** Constructor. */ + explicit DPE(PlacementPolicy policy) : policy_(policy) {} + + /** Destructor. */ + virtual ~DPE() = default; + + /** + * Calculate the placement of a set of blobs using a particular + * algorithm given a context. + * */ + virtual Status Placement(const std::vector &blob_sizes, + const std::vector &targets, + const api::Context &ctx, + std::vector &output) = 0; + + /** + * Calculate the total placement for all blobs and output a schema for + * each blob. + * */ + Status CalculatePlacement(const std::vector &blob_sizes, + std::vector &output, + const api::Context &api_context); +}; + +} // namespace hermes +#endif // HERMES_DATA_PLACEMENT_ENGINE_H_ diff --git a/src/data_placement_engine_factory.h b/src/data_placement_engine_factory.h new file mode 100644 index 000000000..5ad5b01d6 --- /dev/null +++ b/src/data_placement_engine_factory.h @@ -0,0 +1,60 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SRC_DPE_DATA_PLACEMENT_ENGINE_FACTORY_H_ +#define HERMES_SRC_DPE_DATA_PLACEMENT_ENGINE_FACTORY_H_ + +#include "dpe/minimize_io_time.h" +#include "dpe/random.h" +#include "dpe/round_robin.h" + +namespace hermes { + +using hermes::api::PlacementPolicy; + +/** + A class to represent Data Placement Engine Factory +*/ +class DPEFactory { + public: + /** + * return a pointer to data placement engine given a policy type. + * This uses factory pattern. + * + * @param[in] type a placement policy type to be used by the + * data placement engine factory. + * @return pointer to DataPlacementEngine given \a type PlacementPolicy. + */ + static std::unique_ptr Get(const PlacementPolicy &type) { + switch (type) { + case PlacementPolicy::kRandom: { + return std::make_unique(); + } + case PlacementPolicy::kRoundRobin: { + return std::make_unique(); + } + case PlacementPolicy::kMinimizeIoTime: { + return std::make_unique(); + } + case PlacementPolicy::kNone: + default: { + // TODO(luke): @errorhandling not implemented + LOG(FATAL) << "PlacementPolicy not implemented" << std::endl; + return NULL; + } + } + } +}; + +} // namespace hermes + +#endif // HERMES_SRC_DPE_DATA_PLACEMENT_ENGINE_FACTORY_H_ diff --git a/src/dpe/linprog.h b/src/dpe/linprog.h new file mode 100644 index 000000000..bb53bc968 --- /dev/null +++ b/src/dpe/linprog.h @@ -0,0 +1,163 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SRC_DPE_LINPROG_H_ +#define HERMES_SRC_DPE_LINPROG_H_ + +#include +#include + +#include +#include + +namespace hermes { + +/** + A structure to represent 2D array index +*/ +struct Array2DIdx { + int nrow_; /**< number of rows */ + int ncol_; /**< number of columns */ + + /** Initialize structure with \a nrow and \a ncol. */ + Array2DIdx(int nrow, int ncol) : nrow_(nrow), ncol_(ncol) {} + + /** Get the index of row \a i and column \a j. */ + int Get(int i, int j) { return i * nrow_ + j; } + + /** Get the beginning index of row \a i. */ + int Begin(int i) { return Get(i, 0); } + + /** Get the last index of row \a i. */ + int End(int i) { return Get(i, ncol_); } +}; + +/** + * GLPK documentation: http://most.ccib.rutgers.edu/glpk.pdf + * */ + +const size_t kDefaultCoeffs = 1000 + 1; + +/** + A structure to represent linear program +*/ +class LinearProgram { + private: + int num_vars_; /**< number of variables */ + int num_constraints_; /**< number of constraints */ + glp_prob *lp_; /**< pointer to GLPK problem solver */ + std::vector ia_; /**< The "i" in A[i][j] */ + std::vector ja_; /**< The "j" in A[i][j] */ + std::vector ar_; /**< values for A[i][j] */ + size_t cur_constraint_; /**< current constraint */ + size_t result_; /**< result of solver */ + + public: + /** Initialize linear program solver with \a name. */ + explicit LinearProgram(const char *name) { + lp_ = glp_create_prob(); + glp_set_prob_name(lp_, name); + cur_constraint_ = 0; + } + + /** Clean up resources used by the GLPK solver. */ + ~LinearProgram() { + glp_delete_prob(lp_); + glp_free_env(); + } + + /** Define the problem size using \a num_vars and \a num_constraints. */ + void DefineDimension(int num_vars, int num_constraints) { + // NOTE(llogan): GLPK requires arrays start from "1" instead of "0" + glp_add_rows(lp_, num_constraints); + glp_add_cols(lp_, num_vars); + ia_.reserve(kDefaultCoeffs); + ia_.emplace_back(0); + ja_.reserve(kDefaultCoeffs); + ja_.emplace_back(0); + ar_.reserve(kDefaultCoeffs); + ar_.emplace_back(0.0); + num_vars_ = num_vars; + num_constraints_ = num_constraints; + } + + /** Add a constraint to the GLPK solver. */ + void AddConstraint(const std::string &base_name, int op_type, double lb, + double ub) { + cur_constraint_ += 1; + std::string name = base_name + std::to_string(cur_constraint_); + glp_set_row_name(lp_, cur_constraint_, name.c_str()); + glp_set_row_bnds(lp_, cur_constraint_, op_type, lb, ub); + } + + /** Set coefficient value as \a val for the \a var variable. */ + void SetConstraintCoeff(int var, double val) { + var += 1; + ia_.emplace_back(cur_constraint_); + ja_.emplace_back(var); + ar_.emplace_back(val); + } + + /** Set the upper and lower bound for \a var variable. */ + void SetVariableBounds(const std::string &base_name, int var, int op_type, + double lb, double ub) { + var += 1; + std::string name = base_name + std::to_string(var); + glp_set_col_name(lp_, var, name.c_str()); + glp_set_col_bnds(lp_, var, op_type, lb, ub); + } + + /** Set the objective function to optimize. */ + void SetObjective(int objective) { glp_set_obj_dir(lp_, objective); } + + /** Set the coefficients of objective function. */ + void SetObjectiveCoeff(int var, double val) { + var += 1; + glp_set_obj_coef(lp_, var, val); + } + + /** Solve the problem. */ + void Solve() { + glp_load_matrix(lp_, ia_.size() - 1, ia_.data(), ja_.data(), ar_.data()); + glp_smcp parm; + glp_init_smcp(&parm); + parm.msg_lev = GLP_MSG_OFF; + glp_simplex(lp_, &parm); + result_ = glp_get_status(lp_); + } + + /** Check if optimal solution exists. */ + bool IsOptimal() { return result_ == GLP_OPT; } + + /** Get solution.*/ + double GetSolution() { return glp_get_obj_val(lp_); } + + /** Get the values for optimal solution.*/ + double GetVariable(int var) { + var += 1; + return glp_get_col_prim(lp_, var); + } + + /** Collect the values as a vector.*/ + std::vector ToVector() { + std::vector v; + v.reserve(num_vars_); + for (int var = 0; var < num_vars_; ++var) { + v.emplace_back(GetVariable(var)); + } + return v; + } +}; + +} // namespace hermes + +#endif // HERMES_SRC_DPE_LINPROG_H_ diff --git a/src/dpe/minimize_io_time.cc b/src/dpe/minimize_io_time.cc new file mode 100644 index 000000000..72848faa1 --- /dev/null +++ b/src/dpe/minimize_io_time.cc @@ -0,0 +1,178 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "minimize_io_time.h" +#include "linprog.h" +#include +#include +#include + +namespace hermes { + +Status MinimizeIoTime::Placement(const std::vector &blob_sizes, + const std::vector &node_state, + const std::vector &targets, + const api::Context &ctx, + std::vector &output) { + Status result; + const size_t num_targets = targets.size(); + const size_t num_blobs = blob_sizes.size(); + + const double minimum_remaining_capacity = + ctx.minimize_io_time_options.minimum_remaining_capacity; + const double capacity_change_threshold = + ctx.minimize_io_time_options.capacity_change_threshold; + GetPlacementRatios(node_state, ctx); + + size_t constraints_per_target = 2; + VLOG(1) << "MinimizeIoTimePlacement()::minimum_remaining_capacity=" << + minimum_remaining_capacity; + VLOG(1) << "MinimizeIoTimePlacement()::constraints_per_target=" << + constraints_per_target; + const size_t total_constraints = + num_blobs + (num_targets * constraints_per_target); + Array2DIdx var(num_blobs, num_targets); + hermes::LinearProgram lp("min_io"); + lp.DefineDimension(num_blobs * num_targets, total_constraints); + + // Constraint #1: Sum of fraction of each blob is 1. + for (size_t i = 0; i < num_blobs; ++i) { + // Ensure the entire row sums up to 1 + lp.AddConstraint("blob_row_", GLP_FX, 1.0, 1.0); + + // TODO(KIMMY): consider remote nodes? + for (size_t j = 0; j < num_targets; ++j) { + lp.SetConstraintCoeff(var.Get(i, j), 1); + if (placement_ratios_[j] > 0) { + lp.SetVariableBounds("blob_dst_", var.Get(i, j), GLP_DB, 0, + placement_ratios_[j]); + } else { + lp.SetVariableBounds("blob_dst_", var.Get(i, j), GLP_FX, 0, 0); + } + } + } + + // Constraint #2: Capacity constraints + for (size_t j = 0; j < num_targets; ++j) { + double rem_cap_thresh = + static_cast(node_state[j]) * (1 - minimum_remaining_capacity); + double est_rem_cap = capacity_change_threshold * node_state[j]; + double max_capacity = std::max({rem_cap_thresh, est_rem_cap}); + if (max_capacity > 0) { + lp.AddConstraint("rem_cap_", GLP_DB, 0.0, max_capacity); + } else { + lp.AddConstraint("rem_gap_", GLP_FX, 0.0, 0.0); + } + for (size_t i = 0; i < num_blobs; ++i) { + lp.SetConstraintCoeff(var.Get(i, j), + static_cast(blob_sizes[i])); + } + } + + // Objective to minimize IO time + lp.SetObjective(GLP_MIN); + for (size_t i = 0; i < num_blobs; ++i) { + for (size_t j = 0; j < num_targets; ++j) { + lp.SetObjectiveCoeff(var.Get(i, j), + static_cast(blob_sizes[i])/bandwidths[j]); + } + } + + // Solve the problem + lp.Solve(); + if (!lp.IsOptimal()) { + result = DPE_ORTOOLS_NO_SOLUTION; + LOG(ERROR) << result.Msg(); + return result; + } + std::vector vars = lp.ToVector(); + + // Create the placement schema + for (size_t i = 0; i < num_blobs; ++i) { + PlacementSchema schema; + int row_start = var.Begin(i); + int row_end = var.End(i); + + // Convert solution from blob fractions to bytes + std::transform(vars.begin() + row_start, + vars.begin() + row_end, + vars.begin() + row_start, + std::bind(std::multiplies(), + std::placeholders::_1, blob_sizes[i])); + std::vector vars_bytes(vars.begin(), vars.end()); + + // Account for rounding errors + size_t est_io_size_u = std::accumulate(vars_bytes.begin(), + vars_bytes.end(), + 0ul); + ssize_t est_io_size = static_cast(est_io_size_u); + ssize_t true_io_size = static_cast(blob_sizes[i]); + ssize_t io_diff = true_io_size - est_io_size; + PlaceBytes(0, io_diff, vars_bytes, node_state); + + // Push all non-zero schemas to target + for (size_t j = 0; j < num_targets; ++j) { + size_t io_to_target = vars_bytes[j]; + if (io_to_target != 0) { + schema.push_back(std::make_pair(io_to_target, targets[j])); + } + } + output.push_back(schema); + } + return result; +} + +void MinimizeIoTime::PlaceBytes(size_t j, ssize_t bytes, + std::vector &vars_bytes, + const std::vector &node_state) { + if (vars_bytes[j] == 0) { + PlaceBytes(j+1, bytes, vars_bytes, node_state); + return; + } + ssize_t node_cap = static_cast(node_state[j]); + ssize_t req_bytes = static_cast(vars_bytes[j]); + req_bytes += bytes; + ssize_t io_diff = req_bytes - node_cap; + if (io_diff <= 0) { + vars_bytes[j] = static_cast(req_bytes); + return; + } + if (j == node_state.size() - 1) { + LOG(FATAL) << "No capacity left to buffer blob" << std::endl; + return; + } + req_bytes -= io_diff; + vars_bytes[j] = static_cast(req_bytes); + PlaceBytes(j+1, io_diff, vars_bytes, node_state); +} + +void MinimizeIoTime::GetPlacementRatios(const std::vector &node_state, + const api::Context &ctx) { + placement_ratios_.reserve(node_state.size()); + if (ctx.minimize_io_time_options.use_placement_ratio) { + size_t total_bytes = std::accumulate( + node_state.begin(), node_state.end(), (size_t)0); + double total = static_cast(total_bytes); + for (size_t j = 0; j < node_state.size() - 1; ++j) { + double target_cap = static_cast(node_state[j]); + double placement_ratio = target_cap / total; + placement_ratios_.emplace_back(placement_ratio); + } + placement_ratios_.emplace_back(1.0); + } else { + for (size_t j = 0; j < node_state.size(); ++j) { + placement_ratios_.emplace_back(1.0); + } + } +} + +} // namespace hermes diff --git a/src/dpe/minimize_io_time.h b/src/dpe/minimize_io_time.h new file mode 100644 index 000000000..fcec7403c --- /dev/null +++ b/src/dpe/minimize_io_time.h @@ -0,0 +1,48 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SRC_DPE_MINIMIZE_IO_TIME_H_ +#define HERMES_SRC_DPE_MINIMIZE_IO_TIME_H_ + +#include "data_placement_engine.h" + +namespace hermes { +/** + A class to represent data placement engine that minimizes I/O time. +*/ +class MinimizeIoTime : public DPE { + private: + std::vector placement_ratios_; /**< a vector of placement ratios */ + + public: + MinimizeIoTime() : DPE(PlacementPolicy::kMinimizeIoTime) {} + ~MinimizeIoTime() = default; + Status Placement(const std::vector &blob_sizes, + const std::vector &node_state, + const std::vector &targets, + const api::Context &ctx, + std::vector &output); + + private: + /** get the absolute difference value from \a x size and \a y size */ + size_t AbsDiff(size_t x, size_t y, bool &y_gt_x); + /** place bytes */ + void PlaceBytes(size_t j, ssize_t bytes, std::vector &vars_bytes, + const std::vector &node_state); + /** get placement ratios from node states in \a ctx context */ + void GetPlacementRatios(const std::vector &node_state, + const api::Context &ctx); +}; + +} // namespace hermes + +#endif // HERMES_SRC_DPE_MINIMIZE_IO_TIME_H_ diff --git a/src/dpe/random.cc b/src/dpe/random.cc new file mode 100644 index 000000000..528f416a3 --- /dev/null +++ b/src/dpe/random.cc @@ -0,0 +1,95 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "random.h" + +#include +#include +#include + +namespace hermes { + +Status Random::AddSchema(std::multimap &ordered_cap, + size_t blob_size, PlacementSchema &schema) { + std::random_device rd; + std::mt19937 gen(rd()); + Status result; + + auto itlow = ordered_cap.lower_bound(blob_size); + if (itlow == ordered_cap.end()) { + result = DPE_RANDOM_FOUND_NO_TGT; + LOG(ERROR) << result.Msg(); + } else { + // distance from lower bound to the end + std::uniform_int_distribution<> + dst_dist(1, std::distance(itlow, ordered_cap.end())); + size_t dst_relative = dst_dist(gen); + std::advance(itlow, dst_relative-1); + ordered_cap.insert(std::pair((*itlow).first-blob_size, + (*itlow).second)); + + schema.push_back(std::make_pair(blob_size, (*itlow).second)); + ordered_cap.erase(itlow); + } + + return result; +} + +void Random::GetOrderedCapacities(const std::vector &node_state, + const std::vector &targets, + std::multimap &ordered_cap) { + for (size_t i = 0; i < node_state.size(); ++i) { + ordered_cap.insert(std::pair(node_state[i], targets[i])); + } +} + +Status Random::Placement(const std::vector &blob_sizes, + const std::vector &node_state, + const std::vector &targets, + const api::Context &ctx, + std::vector &output) { + Status result; + std::multimap ordered_cap; + VERIFY_DPE_POLICY(ctx) + + GetOrderedCapacities(node_state, targets, ordered_cap); + + for (size_t i {0}; i < blob_sizes.size(); ++i) { + PlacementSchema schema; + + // Split the blob + if (SplitBlob(blob_sizes[i])) { + // Construct the vector for the splitted blob + std::vector new_blob_size; + GetSplitSizes(blob_sizes[i], new_blob_size); + + for (size_t k {0}; k < new_blob_size.size(); ++k) { + result = AddSchema(ordered_cap, new_blob_size[k], schema); + + if (!result.Succeeded()) { + break; + } + } + } else { + // Blob size is less than 64KB or do not split + result = AddSchema(ordered_cap, blob_sizes[i], schema); + if (!result.Succeeded()) { + return result; + } + } + output.push_back(schema); + } + + return result; +} + +} // namespace hermes diff --git a/src/dpe/random.h b/src/dpe/random.h new file mode 100644 index 000000000..383b656d3 --- /dev/null +++ b/src/dpe/random.h @@ -0,0 +1,46 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SRC_DPE_RANDOM_H_ +#define HERMES_SRC_DPE_RANDOM_H_ + +#include "data_placement_engine.h" + +namespace hermes { +/** + A class to represent data placement engine that places data randomly. +*/ +class Random : public DPE { + public: + Random() : DPE(PlacementPolicy::kRandom) {} + ~Random() = default; + Status Placement(const std::vector &blob_sizes, + const std::vector &node_state, + const std::vector &targets, + const api::Context &ctx, + std::vector &output); + + private: + /** + get the capacities of each \a node_state and \a targets and store them + into \a ordered_cap.*/ + void GetOrderedCapacities(const std::vector &node_state, + const std::vector &targets, + std::multimap &ordered_cap); + /** add placement schema */ + Status AddSchema(std::multimap &ordered_cap, size_t blob_size, + PlacementSchema &schema); +}; + +} // namespace hermes + +#endif // HERMES_SRC_DPE_RANDOM_H_ diff --git a/src/dpe/round_robin.cc b/src/dpe/round_robin.cc new file mode 100644 index 000000000..0df127675 --- /dev/null +++ b/src/dpe/round_robin.cc @@ -0,0 +1,41 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "round_robin.h" +#include + +namespace hermes { + +// Initialize RoundRobin devices +std::vector RoundRobin::devices_; + +Status RoundRobin::Placement(const std::vector &blob_sizes, + const std::vector &node_state, + const std::vector &targets, + const api::Context &ctx, + std::vector &output) { + Status result; + std::vector ns_local(node_state.begin(), node_state.end()); + bool split = ctx.rr_split; + VERIFY_DPE_POLICY(ctx) + + for (auto &blob_size : blob_sizes) { + for (auto &target : targets) { + + } + } + + return result; +} + + +} // namespace hermes diff --git a/src/dpe/round_robin.h b/src/dpe/round_robin.h new file mode 100644 index 000000000..d7f8dc9c1 --- /dev/null +++ b/src/dpe/round_robin.h @@ -0,0 +1,46 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SRC_DPE_ROUND_ROBIN_H_ +#define HERMES_SRC_DPE_ROUND_ROBIN_H_ + +#include + +#include "data_placement_engine.h" + +namespace hermes { + +using api::Status; + +/** Represents the state of a Round-Robin data placement strategy */ +class RoundRobin : public DPE { + private: + static inline int current_device_index_{}; /**< The current device index */ + static std::vector devices_; /**< A list of device targets */ + std::mutex device_index_mutex_; /**< Protect index updates */ + + public: + RoundRobin() : DPE(PlacementPolicy::kRoundRobin) { + device_index_mutex_.lock(); + } + ~RoundRobin() { device_index_mutex_.unlock(); } + + Status Placement(const std::vector &blob_sizes, + const std::vector &node_state, + const std::vector &targets, + const api::Context &ctx, + std::vector &output); +}; + +} // namespace hermes + +#endif // HERMES_SRC_DPE_ROUND_ROBIN_H_ diff --git a/src/hermes_types.h b/src/hermes_types.h index 539d538ea..ecda2ec7c 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -25,6 +25,7 @@ #include "data_structures.h" #include "constants.h" #include "singleton_macros.h" +#include "statuses.h" /** * \file hermes_types.h @@ -75,6 +76,14 @@ enum class IoType { typedef u16 DeviceID; /**< device id in unsigned 16-bit integer */ +/** The types of topologies */ +enum class TopologyType { + Local, + Neighborhood, + Global +}; + +/** Represents unique ID for BlobId, BucketId, and VBucketId */ template struct UniqueID { u64 unique_; /**< A unique id for the blob */ @@ -98,10 +107,9 @@ struct UniqueID { return unique_ != other.unique_ || node_id_ != other.node_id_; } }; - -typedef UniqueID<0> BucketID; -typedef UniqueID<1> VBucketID; -typedef UniqueID<2> BlobID; +typedef UniqueID<0> BucketId; +typedef UniqueID<1> VBucketId; +typedef UniqueID<2> BlobId; /** A definition for logging something that is not yet implemented */ #define HERMES_NOT_IMPLEMENTED_YET \ @@ -130,11 +138,32 @@ union TargetID { }; /** - * A PlacementSchema is a vector of (size, target) pairs where size is the - * number of bytes to buffer and target is the TargetID where to buffer those - * bytes. + * Represents the fraction of a blob to place + * on a particular target during data placement + * */ +struct SubPlacement { + size_t size_; /**> Size (bytes) */ + TargetID tid_; /**> Target destination of data */ + + SubPlacement(size_t size, TargetID tid) + : size_(size), tid_(tid) {} +}; + +/** + * The organization of a particular blob in the storage + * hierarchy during data placement. */ -using PlacementSchema = std::vector>; +struct PlacementSchema { + std::vector plcmnt_; + + void AddSubPlacement(size_t size, TargetID tid) { + plcmnt_.emplace_back(size, tid); + } + + void Clear() { + plcmnt_.clear(); + } +}; /** * A structure to represent thesholds with mimimum and maximum values @@ -157,7 +186,7 @@ namespace hermes::api { /** * A Blob is simply an uninterpreted vector of bytes. */ -typedef std::vector Blob; +typedef lipc::charbuf Blob; /** Supported data placement policies */ @@ -258,7 +287,7 @@ struct Context { bool disable_swap; /** Prefetching hints */ - VBucketID vbkt_id_; + VBucketId vbkt_id_; PrefetchContext pctx_; Context(); @@ -283,7 +312,7 @@ enum class TraitType : u8 { namespace std { template struct hash> { - std::size_t operator()(const hermes::BlobID &key) const { + std::size_t operator()(const hermes::BlobId &key) const { return std::hash{}(key.unique_) + std::hash{}(key.node_id_); diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index c70840c36..e8317b349 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -54,9 +54,9 @@ void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -BucketID MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { +BucketId MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { // Create unique ID for the Bucket - BucketID bkt_id; + BucketId bkt_id; bkt_id.unique_ = header_->id_alloc_.fetch_add(1); bkt_id.node_id_ = rpc_->node_id_; @@ -65,7 +65,7 @@ BucketID MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { } else { auto iter = bkt_id_map_->find(bkt_name); if (iter == bkt_id_map_->end()) { - return BucketID::GetNull(); + return BucketId::GetNull(); } bkt_id = (*iter).val_; } @@ -74,16 +74,16 @@ BucketID MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { } /** - * Get the BucketID with \a bkt_name bucket name + * Get the BucketId with \a bkt_name bucket name * * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -BucketID MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { - BucketID bkt_id; +BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { + BucketId bkt_id; auto iter = bkt_id_map_->find(bkt_name); if (iter == bkt_id_map_->end()) { - return BucketID::GetNull(); + return BucketId::GetNull(); } bkt_id = (*iter).val_; return bkt_id; @@ -96,7 +96,7 @@ BucketID MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalBucketContainsBlob(BucketID bkt_id, BlobID blob_id) { +bool MetadataManager::LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id) { auto iter = blob_map_->find(blob_id); if (iter == blob_map_->end()) { return false; @@ -113,7 +113,7 @@ bool MetadataManager::LocalBucketContainsBlob(BucketID bkt_id, BlobID blob_id) { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalRenameBucket(BucketID bkt_id, +bool MetadataManager::LocalRenameBucket(BucketId bkt_id, lipc::charbuf &new_bkt_name) { return true; } @@ -125,7 +125,7 @@ bool MetadataManager::LocalRenameBucket(BucketID bkt_id, * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalDestroyBucket(BucketID bkt_id) { +bool MetadataManager::LocalDestroyBucket(BucketId bkt_id) { } @@ -140,14 +140,14 @@ bool MetadataManager::LocalDestroyBucket(BucketID bkt_id) { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -BlobID MetadataManager::LocalBucketPutBlob(BucketID bkt_id, +BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, lipc::charbuf &blob_name, Blob &data, lipc::vector &buffers) { /*lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); // Create unique ID for the Blob - BlobID blob_id; + BlobId blob_id; blob_id.unique_ = header_->id_alloc_.fetch_add(1); blob_id.node_id_ = rpc_->node_id_; if (blob_id_map_->try_emplace(blob_name, blob_id)) { @@ -178,7 +178,7 @@ BlobID MetadataManager::LocalBucketPutBlob(BucketID bkt_id, * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -BlobID MetadataManager::LocalGetBlobId(BucketID bkt_id, +BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, lipc::charbuf &blob_name) { } @@ -188,7 +188,7 @@ BlobID MetadataManager::LocalGetBlobId(BucketID bkt_id, * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalSetBlobBuffers(BlobID blob_id, +bool MetadataManager::LocalSetBlobBuffers(BlobId blob_id, lipc::vector &buffers) { } @@ -198,7 +198,7 @@ bool MetadataManager::LocalSetBlobBuffers(BlobID blob_id, * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -lipc::vector MetadataManager::LocalGetBlobBuffers(BlobID blob_id) { +lipc::vector MetadataManager::LocalGetBlobBuffers(BlobId blob_id) { } /** @@ -208,7 +208,7 @@ lipc::vector MetadataManager::LocalGetBlobBuffers(BlobID blob_id) { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalRenameBlob(BucketID bkt_id, BlobID blob_id, +bool MetadataManager::LocalRenameBlob(BucketId bkt_id, BlobId blob_id, lipc::charbuf &new_blob_name) { } @@ -218,7 +218,7 @@ bool MetadataManager::LocalRenameBlob(BucketID bkt_id, BlobID blob_id, * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalDestroyBlob(BucketID bkt_id, +bool MetadataManager::LocalDestroyBlob(BucketId bkt_id, lipc::charbuf &blob_name) { } @@ -228,7 +228,7 @@ bool MetadataManager::LocalDestroyBlob(BucketID bkt_id, * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalWriteLockBlob(BlobID blob_id) { +bool MetadataManager::LocalWriteLockBlob(BlobId blob_id) { } /** @@ -237,7 +237,7 @@ bool MetadataManager::LocalWriteLockBlob(BlobID blob_id) { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalWriteUnlockBlob(BlobID blob_id) { +bool MetadataManager::LocalWriteUnlockBlob(BlobId blob_id) { } /** @@ -246,7 +246,7 @@ bool MetadataManager::LocalWriteUnlockBlob(BlobID blob_id) { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalReadLockBlob(BlobID blob_id) { +bool MetadataManager::LocalReadLockBlob(BlobId blob_id) { } /** @@ -255,7 +255,7 @@ bool MetadataManager::LocalReadLockBlob(BlobID blob_id) { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalReadUnlockBlob(BlobID blob_id) { +bool MetadataManager::LocalReadUnlockBlob(BlobId blob_id) { } /** @@ -264,26 +264,26 @@ bool MetadataManager::LocalReadUnlockBlob(BlobID blob_id) { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -VBucketID MetadataManager::LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name) { +VBucketId MetadataManager::LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name) { } /** - * Get the VBucketID of \a vbkt_name VBucket + * Get the VBucketId of \a vbkt_name VBucket * * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -VBucketID MetadataManager::LocalGetVBucketId(lipc::charbuf &vbkt_name) { +VBucketId MetadataManager::LocalGetVBucketId(lipc::charbuf &vbkt_name) { } /** - * Link \a vbkt_id VBucketID + * Link \a vbkt_id VBucketId * * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -VBucketID MetadataManager::LocalVBucketLinkBlob(VBucketID vbkt_id, - BucketID bkt_id, +VBucketId MetadataManager::LocalVBucketLinkBlob(VBucketId vbkt_id, + BucketId bkt_id, lipc::charbuf &blob_name) { } @@ -294,8 +294,8 @@ VBucketID MetadataManager::LocalVBucketLinkBlob(VBucketID vbkt_id, * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -VBucketID MetadataManager::LocalVBucketUnlinkBlob(VBucketID vbkt_id, - BucketID bkt_id, +VBucketId MetadataManager::LocalVBucketUnlinkBlob(VBucketId vbkt_id, + BucketId bkt_id, lipc::charbuf &blob_name) { } @@ -305,7 +305,7 @@ VBucketID MetadataManager::LocalVBucketUnlinkBlob(VBucketID vbkt_id, * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -std::list MetadataManager::LocalVBucketGetLinks(VBucketID vbkt_id) { +std::list MetadataManager::LocalVBucketGetLinks(VBucketId vbkt_id) { } /** @@ -314,7 +314,7 @@ std::list MetadataManager::LocalVBucketGetLinks(VBucketID vbkt_id) { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalRenameVBucket(VBucketID vbkt_id, +bool MetadataManager::LocalRenameVBucket(VBucketId vbkt_id, lipc::charbuf &new_vbkt_name) { } @@ -324,7 +324,7 @@ bool MetadataManager::LocalRenameVBucket(VBucketID vbkt_id, * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalDestroyVBucket(VBucketID vbkt_id) { +bool MetadataManager::LocalDestroyVBucket(VBucketId vbkt_id) { } } // namespace hermes \ No newline at end of file diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 5f8a60186..37dc9c269 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -7,7 +7,7 @@ #include "decorator.h" #include "hermes_types.h" -#include "hermes_status.h" +#include "status.h" #include "rpc.h" #include "metadata_types.h" #include "rpc_thallium_serialization.h" @@ -17,12 +17,12 @@ namespace hermes { /** * Type name simplification for the various map types * */ -typedef lipc::unordered_map BLOB_ID_MAP_T; -typedef lipc::unordered_map BKT_ID_MAP_T; -typedef lipc::unordered_map VBKT_ID_MAP_T; -typedef lipc::unordered_map BLOB_MAP_T; -typedef lipc::unordered_map BKT_MAP_T; -typedef lipc::unordered_map VBKT_MAP_T; +typedef lipc::unordered_map BLOB_ID_MAP_T; +typedef lipc::unordered_map BKT_ID_MAP_T; +typedef lipc::unordered_map VBKT_ID_MAP_T; +typedef lipc::unordered_map BLOB_MAP_T; +typedef lipc::unordered_map BKT_MAP_T; +typedef lipc::unordered_map VBKT_MAP_T; /** * The SHM representation of the MetadataManager @@ -96,13 +96,13 @@ class MetadataManager { void shm_deserialize(MetadataManagerShmHeader *header); /** - * Create a unique blob name using BucketID + * Create a unique blob name using BucketId * */ - lipc::charbuf CreateBlobName(BucketID bkt_id, lipc::charbuf &blob_name) { + lipc::charbuf CreateBlobName(BucketId bkt_id, lipc::charbuf &blob_name) { lipc::charbuf new_name(sizeof(bkt_id) + blob_name.size()); size_t off = 0; - memcpy(new_name.data_mutable() + off, &bkt_id, sizeof(BucketID)); - off += sizeof(BucketID); + memcpy(new_name.data_mutable() + off, &bkt_id, sizeof(BucketId)); + off += sizeof(BucketId); memcpy(blob_name.data_mutable() + off, blob_name.data(), blob_name.size()); return new_name; } @@ -113,15 +113,15 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BucketID LocalGetOrCreateBucket(lipc::charbuf &bkt_name); + RPC BucketId LocalGetOrCreateBucket(lipc::charbuf &bkt_name); /** - * Get the BucketID with \a bkt_name bucket name + * Get the BucketId with \a bkt_name bucket name * * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BucketID LocalGetBucketId(lipc::charbuf &bkt_name); + RPC BucketId LocalGetBucketId(lipc::charbuf &bkt_name); /** * Check whether or not \a bkt_id bucket contains @@ -130,7 +130,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalBucketContainsBlob(BucketID bkt_id, BlobID blob_id); + RPC bool LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id); /** * Rename \a bkt_id bucket to \a new_bkt_name new name @@ -138,7 +138,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalRenameBucket(BucketID bkt_id, lipc::charbuf &new_bkt_name); + RPC bool LocalRenameBucket(BucketId bkt_id, lipc::charbuf &new_bkt_name); /** * Destroy \a bkt_id bucket @@ -146,7 +146,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalDestroyBucket(BucketID bkt_id); + RPC bool LocalDestroyBucket(BucketId bkt_id); /** * Put a blob in a bucket @@ -159,7 +159,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BlobID LocalBucketPutBlob(BucketID bkt_id, lipc::charbuf &blob_name, + RPC BlobId LocalBucketPutBlob(BucketId bkt_id, lipc::charbuf &blob_name, Blob &data, lipc::vector &buffers); /** @@ -168,7 +168,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BlobID LocalGetBlobId(BucketID bkt_id, lipc::charbuf &blob_name); + RPC BlobId LocalGetBlobId(BucketId bkt_id, lipc::charbuf &blob_name); /** * Change \a blob_id blob's buffers to \the buffers @@ -176,7 +176,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalSetBlobBuffers(BlobID blob_id, + RPC bool LocalSetBlobBuffers(BlobId blob_id, lipc::vector &buffers); /** @@ -185,7 +185,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC lipc::vector LocalGetBlobBuffers(BlobID blob_id); + RPC lipc::vector LocalGetBlobBuffers(BlobId blob_id); /** * Rename \a blob_id blob to \a new_blob_name new blob name @@ -194,7 +194,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalRenameBlob(BucketID bkt_id, BlobID blob_id, + RPC bool LocalRenameBlob(BucketId bkt_id, BlobId blob_id, lipc::charbuf &new_blob_name); /** @@ -203,7 +203,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalDestroyBlob(BucketID bkt_id, lipc::charbuf &blob_name); + RPC bool LocalDestroyBlob(BucketId bkt_id, lipc::charbuf &blob_name); /** * Acquire \a blob_id blob's write lock @@ -211,7 +211,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalWriteLockBlob(BlobID blob_id); + RPC bool LocalWriteLockBlob(BlobId blob_id); /** * Release \a blob_id blob's write lock @@ -219,7 +219,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalWriteUnlockBlob(BlobID blob_id); + RPC bool LocalWriteUnlockBlob(BlobId blob_id); /** * Acquire \a blob_id blob's read lock @@ -227,7 +227,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalReadLockBlob(BlobID blob_id); + RPC bool LocalReadLockBlob(BlobId blob_id); /** * Release \a blob_id blob's read lock @@ -235,7 +235,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalReadUnlockBlob(BlobID blob_id); + RPC bool LocalReadUnlockBlob(BlobId blob_id); /** * Get or create \a vbkt_name VBucket @@ -243,23 +243,23 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC VBucketID LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name); + RPC VBucketId LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name); /** - * Get the VBucketID of \a vbkt_name VBucket + * Get the VBucketId of \a vbkt_name VBucket * * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC VBucketID LocalGetVBucketId(lipc::charbuf &vbkt_name); + RPC VBucketId LocalGetVBucketId(lipc::charbuf &vbkt_name); /** - * Link \a vbkt_id VBucketID + * Link \a vbkt_id VBucketId * * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC VBucketID LocalVBucketLinkBlob(VBucketID vbkt_id, BucketID bkt_id, + RPC VBucketId LocalVBucketLinkBlob(VBucketId vbkt_id, BucketId bkt_id, lipc::charbuf &blob_name); /** @@ -269,7 +269,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC VBucketID LocalVBucketUnlinkBlob(VBucketID vbkt_id, BucketID bkt_id, + RPC VBucketId LocalVBucketUnlinkBlob(VBucketId vbkt_id, BucketId bkt_id, lipc::charbuf &blob_name); /** @@ -278,7 +278,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC std::list LocalVBucketGetLinks(VBucketID vbkt_id); + RPC std::list LocalVBucketGetLinks(VBucketId vbkt_id); /** * Rename \a vbkt_id VBucket to \a new_vbkt_name name @@ -286,7 +286,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalRenameVBucket(VBucketID vbkt_id, lipc::charbuf &new_vbkt_name); + RPC bool LocalRenameVBucket(VBucketId vbkt_id, lipc::charbuf &new_vbkt_name); /** * Destroy \a vbkt_id VBucket @@ -294,33 +294,33 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalDestroyVBucket(VBucketID vbkt_id); + RPC bool LocalDestroyVBucket(VBucketId vbkt_id); public: RPC_AUTOGEN_START - BucketID GetOrCreateBucket(lipc::charbuf& bkt_name) { + BucketId GetOrCreateBucket(lipc::charbuf& bkt_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalGetOrCreateBucket( bkt_name); } else { - return rpc_->Call( + return rpc_->Call( target_node, "GetOrCreateBucket", bkt_name); } } - BucketID GetBucketId(lipc::charbuf& bkt_name) { + BucketId GetBucketId(lipc::charbuf& bkt_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalGetBucketId( bkt_name); } else { - return rpc_->Call( + return rpc_->Call( target_node, "GetBucketId", bkt_name); } } - bool BucketContainsBlob(BucketID bkt_id, BlobID blob_id) { + bool BucketContainsBlob(BucketId bkt_id, BlobId blob_id) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalBucketContainsBlob( @@ -331,7 +331,7 @@ class MetadataManager { bkt_id, blob_id); } } - bool RenameBucket(BucketID bkt_id, lipc::charbuf& new_bkt_name) { + bool RenameBucket(BucketId bkt_id, lipc::charbuf& new_bkt_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalRenameBucket( @@ -342,7 +342,7 @@ class MetadataManager { bkt_id, new_bkt_name); } } - bool DestroyBucket(BucketID bkt_id) { + bool DestroyBucket(BucketId bkt_id) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalDestroyBucket( @@ -353,29 +353,29 @@ class MetadataManager { bkt_id); } } - BlobID BucketPutBlob(BucketID bkt_id, lipc::charbuf& blob_name, Blob& data, lipc::vector& buffers) { + BlobId BucketPutBlob(BucketId bkt_id, lipc::charbuf& blob_name, Blob& data, lipc::vector& buffers) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalBucketPutBlob( bkt_id, blob_name, data, buffers); } else { - return rpc_->Call( + return rpc_->Call( target_node, "BucketPutBlob", bkt_id, blob_name, data, buffers); } } - BlobID GetBlobId(BucketID bkt_id, lipc::charbuf& blob_name) { + BlobId GetBlobId(BucketId bkt_id, lipc::charbuf& blob_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalGetBlobId( bkt_id, blob_name); } else { - return rpc_->Call( + return rpc_->Call( target_node, "GetBlobId", bkt_id, blob_name); } } - bool SetBlobBuffers(BlobID blob_id, lipc::vector& buffers) { + bool SetBlobBuffers(BlobId blob_id, lipc::vector& buffers) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalSetBlobBuffers( @@ -386,7 +386,7 @@ class MetadataManager { blob_id, buffers); } } - lipc::vector GetBlobBuffers(BlobID blob_id) { + lipc::vector GetBlobBuffers(BlobId blob_id) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalGetBlobBuffers( @@ -397,7 +397,7 @@ class MetadataManager { blob_id); } } - bool RenameBlob(BucketID bkt_id, BlobID blob_id, lipc::charbuf& new_blob_name) { + bool RenameBlob(BucketId bkt_id, BlobId blob_id, lipc::charbuf& new_blob_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalRenameBlob( @@ -408,7 +408,7 @@ class MetadataManager { bkt_id, blob_id, new_blob_name); } } - bool DestroyBlob(BucketID bkt_id, lipc::charbuf& blob_name) { + bool DestroyBlob(BucketId bkt_id, lipc::charbuf& blob_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalDestroyBlob( @@ -419,7 +419,7 @@ class MetadataManager { bkt_id, blob_name); } } - bool WriteLockBlob(BlobID blob_id) { + bool WriteLockBlob(BlobId blob_id) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalWriteLockBlob( @@ -430,7 +430,7 @@ class MetadataManager { blob_id); } } - bool WriteUnlockBlob(BlobID blob_id) { + bool WriteUnlockBlob(BlobId blob_id) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalWriteUnlockBlob( @@ -441,7 +441,7 @@ class MetadataManager { blob_id); } } - bool ReadLockBlob(BlobID blob_id) { + bool ReadLockBlob(BlobId blob_id) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalReadLockBlob( @@ -452,7 +452,7 @@ class MetadataManager { blob_id); } } - bool ReadUnlockBlob(BlobID blob_id) { + bool ReadUnlockBlob(BlobId blob_id) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalReadUnlockBlob( @@ -463,62 +463,62 @@ class MetadataManager { blob_id); } } - VBucketID GetOrCreateVBucket(lipc::charbuf& vbkt_name) { + VBucketId GetOrCreateVBucket(lipc::charbuf& vbkt_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalGetOrCreateVBucket( vbkt_name); } else { - return rpc_->Call( + return rpc_->Call( target_node, "GetOrCreateVBucket", vbkt_name); } } - VBucketID GetVBucketId(lipc::charbuf& vbkt_name) { + VBucketId GetVBucketId(lipc::charbuf& vbkt_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalGetVBucketId( vbkt_name); } else { - return rpc_->Call( + return rpc_->Call( target_node, "GetVBucketId", vbkt_name); } } - VBucketID VBucketLinkBlob(VBucketID vbkt_id, BucketID bkt_id, lipc::charbuf& blob_name) { + VBucketId VBucketLinkBlob(VBucketId vbkt_id, BucketId bkt_id, lipc::charbuf& blob_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalVBucketLinkBlob( vbkt_id, bkt_id, blob_name); } else { - return rpc_->Call( + return rpc_->Call( target_node, "VBucketLinkBlob", vbkt_id, bkt_id, blob_name); } } - VBucketID VBucketUnlinkBlob(VBucketID vbkt_id, BucketID bkt_id, lipc::charbuf& blob_name) { + VBucketId VBucketUnlinkBlob(VBucketId vbkt_id, BucketId bkt_id, lipc::charbuf& blob_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalVBucketUnlinkBlob( vbkt_id, bkt_id, blob_name); } else { - return rpc_->Call( + return rpc_->Call( target_node, "VBucketUnlinkBlob", vbkt_id, bkt_id, blob_name); } } - std::list VBucketGetLinks(VBucketID vbkt_id) { + std::list VBucketGetLinks(VBucketId vbkt_id) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalVBucketGetLinks( vbkt_id); } else { - return rpc_->Call>( + return rpc_->Call>( target_node, "VBucketGetLinks", vbkt_id); } } - bool RenameVBucket(VBucketID vbkt_id, lipc::charbuf& new_vbkt_name) { + bool RenameVBucket(VBucketId vbkt_id, lipc::charbuf& new_vbkt_name) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalRenameVBucket( @@ -529,7 +529,7 @@ class MetadataManager { vbkt_id, new_vbkt_name); } } - bool DestroyVBucket(VBucketID vbkt_id) { + bool DestroyVBucket(VBucketId vbkt_id) { u32 target_node = rpc_->node_id_; if (target_node == rpc_->node_id_) { return LocalDestroyVBucket( diff --git a/src/metadata_types.h b/src/metadata_types.h index 8346591ca..e3467d2ae 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -11,14 +11,28 @@ namespace hermes { using api::Blob; +/** */ +struct DeviceInfo { + +}; + +/** Represents the current status of a target */ +struct TargetInfo { + TargetID tid_; /**< unique Target ID */ + size_t max_cap_; /**< maximum capacity of the target */ + size_t rem_cap_; /**< remaining capacity of the target */ +}; + +/** Represents an allocated fraction of a target */ struct BufferInfo { size_t off_; size_t size_; TargetID target_; }; +/** Represents BlobInfo in shared memory */ struct BlobInfoShmHeader { - BucketID bkt_id_; /**< The bucket containing the blob */ + BucketId bkt_id_; /**< The bucket containing the blob */ lipc::ShmArchive> name_ar_; lipc::ShmArchive>> buffers_ar_; RwLock rwlock_; @@ -26,9 +40,13 @@ struct BlobInfoShmHeader { BlobInfoShmHeader() = default; }; +/** Blob metadata */ struct BlobInfo { - BucketID bkt_id_; /**< The bucket containing the blob */ + /// The bucket containing the blob + BucketId bkt_id_; + /// The name of the blob lipc::mptr name_; + /// The BufferInfo vector lipc::mptr> buffers_; BlobInfo() = default; @@ -48,22 +66,26 @@ struct BlobInfo { } }; +/** Represents BucketInfo in shared memory */ struct BucketInfoShmHeader { lipc::ShmArchive> name_ar_; }; +/** Metadata for a Bucket */ struct BucketInfo { lipc::mptr name_; }; +/** Represents a VBucket in shared memory */ struct VBucketInfoShmHeader { lipc::ShmArchive>> name_; - lipc::ShmArchive>> blobs_; + lipc::ShmArchive>> blobs_; }; +/** Metadata for a VBucket */ struct VBucketInfo { lipc::mptr> name_; - lipc::mptr> blobs_; + lipc::mptr> blobs_; }; } // namespace hermes diff --git a/src/rpc_thallium_defs.cc b/src/rpc_thallium_defs.cc index a4e695851..5594c4d7a 100644 --- a/src/rpc_thallium_defs.cc +++ b/src/rpc_thallium_defs.cc @@ -30,79 +30,79 @@ void ThalliumRpc::DefineRpcs() { }; server_engine_->define("GetBucketId", remote_get_bucket_id); auto remote_bucket_contains_blob = - [mdm](const request &req, BucketID bkt_id, BlobID blob_id) { + [mdm](const request &req, BucketId bkt_id, BlobId blob_id) { auto result = mdm->LocalBucketContainsBlob(bkt_id, blob_id); req.respond(result); }; server_engine_->define("BucketContainsBlob", remote_bucket_contains_blob); auto remote_rename_bucket = - [mdm](const request &req, BucketID bkt_id, lipc::charbuf& new_bkt_name) { + [mdm](const request &req, BucketId bkt_id, lipc::charbuf& new_bkt_name) { auto result = mdm->LocalRenameBucket(bkt_id, new_bkt_name); req.respond(result); }; server_engine_->define("RenameBucket", remote_rename_bucket); auto remote_destroy_bucket = - [mdm](const request &req, BucketID bkt_id) { + [mdm](const request &req, BucketId bkt_id) { auto result = mdm->LocalDestroyBucket(bkt_id); req.respond(result); }; server_engine_->define("DestroyBucket", remote_destroy_bucket); auto remote_bucket_put_blob = - [mdm](const request &req, BucketID bkt_id, lipc::charbuf& blob_name, Blob& data, lipc::vector& buffers) { + [mdm](const request &req, BucketId bkt_id, lipc::charbuf& blob_name, Blob& data, lipc::vector& buffers) { auto result = mdm->LocalBucketPutBlob(bkt_id, blob_name, data, buffers); req.respond(result); }; server_engine_->define("BucketPutBlob", remote_bucket_put_blob); auto remote_get_blob_id = - [mdm](const request &req, BucketID bkt_id, lipc::charbuf& blob_name) { + [mdm](const request &req, BucketId bkt_id, lipc::charbuf& blob_name) { auto result = mdm->LocalGetBlobId(bkt_id, blob_name); req.respond(result); }; server_engine_->define("GetBlobId", remote_get_blob_id); auto remote_set_blob_buffers = - [mdm](const request &req, BlobID blob_id, lipc::vector& buffers) { + [mdm](const request &req, BlobId blob_id, lipc::vector& buffers) { auto result = mdm->LocalSetBlobBuffers(blob_id, buffers); req.respond(result); }; server_engine_->define("SetBlobBuffers", remote_set_blob_buffers); auto remote_get_blob_buffers = - [mdm](const request &req, BlobID blob_id) { + [mdm](const request &req, BlobId blob_id) { auto result = mdm->LocalGetBlobBuffers(blob_id); req.respond(std::ref(result)); }; server_engine_->define("GetBlobBuffers", remote_get_blob_buffers); auto remote_rename_blob = - [mdm](const request &req, BucketID bkt_id, BlobID blob_id, lipc::charbuf& new_blob_name) { + [mdm](const request &req, BucketId bkt_id, BlobId blob_id, lipc::charbuf& new_blob_name) { auto result = mdm->LocalRenameBlob(bkt_id, blob_id, new_blob_name); req.respond(result); }; server_engine_->define("RenameBlob", remote_rename_blob); auto remote_destroy_blob = - [mdm](const request &req, BucketID bkt_id, lipc::charbuf& blob_name) { + [mdm](const request &req, BucketId bkt_id, lipc::charbuf& blob_name) { auto result = mdm->LocalDestroyBlob(bkt_id, blob_name); req.respond(result); }; server_engine_->define("DestroyBlob", remote_destroy_blob); auto remote_write_lock_blob = - [mdm](const request &req, BlobID blob_id) { + [mdm](const request &req, BlobId blob_id) { auto result = mdm->LocalWriteLockBlob(blob_id); req.respond(result); }; server_engine_->define("WriteLockBlob", remote_write_lock_blob); auto remote_write_unlock_blob = - [mdm](const request &req, BlobID blob_id) { + [mdm](const request &req, BlobId blob_id) { auto result = mdm->LocalWriteUnlockBlob(blob_id); req.respond(result); }; server_engine_->define("WriteUnlockBlob", remote_write_unlock_blob); auto remote_read_lock_blob = - [mdm](const request &req, BlobID blob_id) { + [mdm](const request &req, BlobId blob_id) { auto result = mdm->LocalReadLockBlob(blob_id); req.respond(result); }; server_engine_->define("ReadLockBlob", remote_read_lock_blob); auto remote_read_unlock_blob = - [mdm](const request &req, BlobID blob_id) { + [mdm](const request &req, BlobId blob_id) { auto result = mdm->LocalReadUnlockBlob(blob_id); req.respond(result); }; @@ -120,31 +120,31 @@ void ThalliumRpc::DefineRpcs() { }; server_engine_->define("GetVBucketId", remote_get_v_bucket_id); auto remote_v_bucket_link_blob = - [mdm](const request &req, VBucketID vbkt_id, BucketID bkt_id, lipc::charbuf& blob_name) { + [mdm](const request &req, VBucketId vbkt_id, BucketId bkt_id, lipc::charbuf& blob_name) { auto result = mdm->LocalVBucketLinkBlob(vbkt_id, bkt_id, blob_name); req.respond(result); }; server_engine_->define("VBucketLinkBlob", remote_v_bucket_link_blob); auto remote_v_bucket_unlink_blob = - [mdm](const request &req, VBucketID vbkt_id, BucketID bkt_id, lipc::charbuf& blob_name) { + [mdm](const request &req, VBucketId vbkt_id, BucketId bkt_id, lipc::charbuf& blob_name) { auto result = mdm->LocalVBucketUnlinkBlob(vbkt_id, bkt_id, blob_name); req.respond(result); }; server_engine_->define("VBucketUnlinkBlob", remote_v_bucket_unlink_blob); auto remote_v_bucket_get_links = - [mdm](const request &req, VBucketID vbkt_id) { + [mdm](const request &req, VBucketId vbkt_id) { auto result = mdm->LocalVBucketGetLinks(vbkt_id); req.respond(result); }; server_engine_->define("VBucketGetLinks", remote_v_bucket_get_links); auto remote_rename_v_bucket = - [mdm](const request &req, VBucketID vbkt_id, lipc::charbuf& new_vbkt_name) { + [mdm](const request &req, VBucketId vbkt_id, lipc::charbuf& new_vbkt_name) { auto result = mdm->LocalRenameVBucket(vbkt_id, new_vbkt_name); req.respond(result); }; server_engine_->define("RenameVBucket", remote_rename_v_bucket); auto remote_destroy_v_bucket = - [mdm](const request &req, VBucketID vbkt_id) { + [mdm](const request &req, VBucketId vbkt_id) { auto result = mdm->LocalDestroyVBucket(vbkt_id); req.respond(result); }; diff --git a/src/rpc_thallium_serialization.h b/src/rpc_thallium_serialization.h index 98717a042..d1c36506a 100644 --- a/src/rpc_thallium_serialization.h +++ b/src/rpc_thallium_serialization.h @@ -18,43 +18,43 @@ namespace hermes { /** - * Lets Thallium know how to serialize a VBucketID. + * Lets Thallium know how to serialize a VBucketId. * * This function is called implicitly by Thallium. * * @param ar An archive provided by Thallium. - * @param vbucket_id The VBucketID to serialize. + * @param vbucket_id The VBucketId to serialize. */ template -void serialize(A &ar, VBucketID &vbucket_id) { +void serialize(A &ar, VBucketId &vbucket_id) { ar &vbucket_id.unique_; ar &vbucket_id.node_id_; } /** - * Lets Thallium know how to serialize a BucketID. + * Lets Thallium know how to serialize a BucketId. * * This function is called implicitly by Thallium. * * @param ar An archive provided by Thallium. - * @param bucket_id The BucketID to serialize. + * @param bucket_id The BucketId to serialize. */ template -void serialize(A &ar, BucketID &bucket_id) { +void serialize(A &ar, BucketId &bucket_id) { ar &bucket_id.unique_; ar &bucket_id.node_id_; } /** - * Lets Thallium know how to serialize a BlobID. + * Lets Thallium know how to serialize a BlobId. * * This function is called implicitly by Thallium. * * @param ar An archive provided by Thallium. - * @param blob_id The BlobID to serialize. + * @param blob_id The BlobId to serialize. */ template -void serialize(A &ar, BlobID &blob_id) { +void serialize(A &ar, BlobId &blob_id) { ar &blob_id.unique_; ar &blob_id.node_id_; } diff --git a/src/status.cc b/src/status.cc new file mode 100644 index 000000000..d0d54c652 --- /dev/null +++ b/src/status.cc @@ -0,0 +1,11 @@ +// +// Created by lukemartinlogan on 12/21/22. +// + +#include "status.h" + +namespace hermes::api { + +int Status::code_counter_ = 0; + +} // namespace hermes::api \ No newline at end of file diff --git a/src/hermes_status.h b/src/status.h similarity index 72% rename from src/hermes_status.h rename to src/status.h index 7a8c8e876..40edb7a68 100644 --- a/src/hermes_status.h +++ b/src/status.h @@ -17,10 +17,34 @@ /** \file hermes_status.h */ -namespace hermes { +namespace hermes::api { class Status { + private: + static int code_counter_; + int code_; + const char *msg_; + public: + Status() = default; + + explicit Status(const char *msg) : msg_(msg) { + code_ = code_counter_; + code_counter_ += 1; + } + + Status(const Status &other) { + code_ = other.code_; + msg_ = other.msg_; + } + + bool Success() { + return code_ == 0; + } + + bool Failed() { + return code_ != 0; + } }; } // hermes diff --git a/src/statuses.h b/src/statuses.h new file mode 100644 index 000000000..343a5b3f6 --- /dev/null +++ b/src/statuses.h @@ -0,0 +1,19 @@ +// +// Created by lukemartinlogan on 12/21/22. +// + +#ifndef HERMES_SRC_STATUSES_H_ +#define HERMES_SRC_STATUSES_H_ + +#include "status.h" + +namespace hermes { + +using api::Status; + +const Status DPE_PLACEMENT_SCHEMA_EMPTY("Placement failed. Non-fatal."); +const Status DPE_NO_SPACE("DPE has no remaining space."); + +} + +#endif // HERMES_SRC_STATUSES_H_ diff --git a/wrapper/CMakeLists.txt b/wrapper/CMakeLists.txt deleted file mode 100644 index ccd2df186..000000000 --- a/wrapper/CMakeLists.txt +++ /dev/null @@ -1,71 +0,0 @@ -#------------------------------------------------------------------------------ -# Include source and build directories -#------------------------------------------------------------------------------ -include_directories( - ${PROJECT_SOURCE_DIR}/src/api - ${CMAKE_CURRENT_SOURCE_DIR} - ${HERMES_INCLUDES_BUILD_TIME} -) - -#------------------------------------------------------------------------------ -# Hermes Wrapper -#------------------------------------------------------------------------------ -add_library(hermes_wrapper hermes_wrapper.cpp) -target_link_libraries(hermes_wrapper ${LIBRT} hermes) - -set(HERMES_EXPORTED_LIBS hermes_wrapper ${HERMES_EXPORTED_LIBS}) - -#----------------------------------------------------------------------------- -# Add file(s) to CMake Install -#----------------------------------------------------------------------------- -install( - FILES - hermes_wrapper.h - DESTINATION - ${HERMES_INSTALL_INCLUDE_DIR} - COMPONENT - headers -) - -#----------------------------------------------------------------------------- -# Add Target(s) to CMake Install -#----------------------------------------------------------------------------- -install( - TARGETS - hermes_wrapper - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) - -#----------------------------------------------------------------------------- -# Export all exported targets to the build tree for use by parent project -#----------------------------------------------------------------------------- -if(NOT HERMES_EXTERNALLY_CONFIGURED) -EXPORT ( - TARGETS - ${HERMES_EXPORTED_LIBS} - FILE - ${HERMES_EXPORTED_TARGETS}.cmake -) -endif() - -#------------------------------------------------------------------------------ -# Set variables for parent scope -#------------------------------------------------------------------------------ -# Used by config.cmake.build.in and Testing -set(HERMES_INCLUDES_BUILD_TIME - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${HERMES_EXT_INCLUDE_DEPENDENCIES} - PARENT_SCOPE -) - -# Used by config.cmake.install.in -set(HERMES_INCLUDES_INSTALL_TIME - ${HERMES_INSTALL_INCLUDE_DIR} - ${HERMES_EXT_INCLUDE_DEPENDENCIES} - PARENT_SCOPE -) diff --git a/wrapper/hermes_wrapper.cpp b/wrapper/hermes_wrapper.cpp deleted file mode 100644 index 9a3dc7bca..000000000 --- a/wrapper/hermes_wrapper.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "hermes_wrapper.h" - -#include "hermes.h" -#include "bucket.h" -#include "vbucket.h" - -extern "C" { - -std::shared_ptr hermes_ptr; - -int HermesInitHermes(char *hermes_config) { - int result = 0; - - VLOG(1) << "Hermes Wrapper: Initializing Hermes\n"; - - hermes_ptr = hermes::InitHermesDaemon(hermes_config); - - return result; -} - -void HermesFinalize() { - hermes_ptr->Finalize(true); -} - -void HermesVBucketLink(VBucketClass *vbkt, char *blob_name) { - hermes::api::VBucket *vbucket = (hermes::api::VBucket *)vbkt; - - VLOG(1) << "Hermes Wrapper: Linking Blob " << blob_name << "to VBucket " - << vbucket->GetName() << '\n'; - - hermes::api::Status status = - vbucket->Link(std::string(blob_name), vbucket->GetName()); - - if (status.Failed()) - LOG(ERROR) << "Hermes Wrapper: HermesVBucketLink failed\n"; -} - -bool HermesVBucketIsValid(VBucketClass *vbkt) { - hermes::api::VBucket *vbucket = (hermes::api::VBucket *)vbkt; - - VLOG(1) << "Hermes Wrapper: Checking if VBucket is valid\n"; - - return vbucket->IsValid(); -} - -BucketClass *HermesBucketCreate(const char *name) { - VLOG(1) << "Hermes Wrapper: Creating Bucket " << name << '\n'; - - try { - hermes::api::Bucket *new_bucket = - new hermes::api::Bucket(std::string(name), hermes_ptr); - - return (BucketClass *)new_bucket; - } - catch (const std::runtime_error& e) { - LOG(ERROR) << "Blob runtime error\n"; - return NULL; - } - catch (const std::length_error& e) { - LOG(ERROR) << "Blob length error\n"; - return NULL; - } -} - -void HermesBucketClose(BucketClass *bkt) { - hermes::api::Bucket *my_bkt = (hermes::api::Bucket *)bkt; - - VLOG(1) << "Hermes Wrapper: Closing Bucket " << my_bkt->GetName() << '\n'; - - my_bkt->Release(); - delete my_bkt; -} - -void HermesBucketDestroy(BucketClass *bkt) { - hermes::api::Bucket *my_bkt = (hermes::api::Bucket *)bkt; - - VLOG(1) << "Hermes Wrapper: Destroying Bucket\n"; - - my_bkt->Destroy(); - delete my_bkt; -} - -bool HermesBucketContainsBlob(BucketClass *bkt, char *name) { - hermes::api::Bucket *bucket = (hermes::api::Bucket *)bkt; - - VLOG(1) << "Hermes Wrapper: Checking if Bucket " - << bucket->GetName() - << " contains Blob " << name << '\n'; - - return bucket->ContainsBlob(name); -} - -void HermesBucketPut(BucketClass *bkt, char *name, - const unsigned char *put_data, size_t size) { - hermes::api::Bucket *bucket = (hermes::api::Bucket *)bkt; - - VLOG(1) << "Hermes Wrapper: Putting Blob " << name << " to bucket " - << bucket->GetName() << '\n'; - - hermes::api::Status status = bucket->Put(name, put_data, size); - - if (status.Failed()) - LOG(ERROR) << "Hermes Wrapper: HermesBucketPut failed\n"; -} - -void HermesBucketGet(BucketClass *bkt, char *blob_name, size_t page_size, - unsigned char *buf) { - hermes::api::Bucket *bucket = (hermes::api::Bucket *)bkt; - const hermes::api::Context ctx; - - VLOG(1) << "Hermes Wrapper: Getting blob " << blob_name << " from Bucket " - << bucket->GetName(); - - size_t blob_size = bucket->Get(blob_name, buf, page_size, ctx); - if (blob_size != page_size) - LOG(ERROR) << "Blob size error: expected to get " << page_size - << ", but only got " << blob_size << '\n'; -} - -} // extern "C" diff --git a/wrapper/hermes_wrapper.h b/wrapper/hermes_wrapper.h deleted file mode 100644 index c88ea89f7..000000000 --- a/wrapper/hermes_wrapper.h +++ /dev/null @@ -1,58 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_C_WRAPPER_H -#define HERMES_C_WRAPPER_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct BucketClass; -typedef struct BucketClass BucketClass; - -struct VBucketClass; -typedef struct VBucketClass VBucketClass; - -int HermesInitHermes(char *hermes_config); - -void HermesFinalize(); - -VBucketClass *HermesVBucketCreate(const char *name); - -void HermesVBucketLink(VBucketClass *vbkt, char *blob_name); - -bool HermesVBucketIsValid(VBucketClass *vbkt); - -BucketClass *HermesBucketCreate(const char *name); - -void HermesBucketClose(BucketClass *bkt); - -void HermesBucketDestroy(BucketClass *bucket_ptr); - -bool HermesBucketContainsBlob(BucketClass *bkt, char *name); - -void HermesBucketPut(BucketClass *bkt, char *name, - const unsigned char *put_data, size_t size); - -void HermesBucketGet(BucketClass *bkt, char *blob_name, size_t kPageSize, - unsigned char *buf); - -#ifdef __cplusplus -} -#endif - -#endif From efad3363adc1118367afcc52b81824755304429f Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 21 Dec 2022 03:45:49 -0600 Subject: [PATCH 072/511] GetOrCreateBucket --- src/api/bucket.cc | 2 +- src/api/hermes.cc | 3 ++- src/hermes_types.h | 2 +- src/metadata_manager.cc | 43 +++++++++++++++++++++++++++++------------ src/metadata_manager.h | 32 +++++++++++------------------- test/test_rpc.cc | 1 + 6 files changed, 47 insertions(+), 36 deletions(-) diff --git a/src/api/bucket.cc b/src/api/bucket.cc index a54fdbd24..95ecf397c 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -12,7 +12,7 @@ namespace hermes::api { * */ Bucket::Bucket(std::string name, Context &ctx) : mdm_(&HERMES->mdm_) { lipc::string lname(name); - mdm_->GetOrCreateBucket(lname); + id_ = mdm_->GetOrCreateBucket(lname); } /** diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 76d911b79..5850d1bc7 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -118,7 +118,8 @@ void Hermes::LoadSharedMemory() { } void Hermes::FinalizeServer() { - // NOTE(llogan): Finalize() is called internally by daemon in this case + // NOTE(llogan): rpc_.Finalize() is called internally by daemon in this case + mdm_.shm_destroy(); LABSTOR_MEMORY_MANAGER->DestroyBackend(server_config_.shmem_name_); } diff --git a/src/hermes_types.h b/src/hermes_types.h index ecda2ec7c..9299e0905 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -312,7 +312,7 @@ enum class TraitType : u8 { namespace std { template struct hash> { - std::size_t operator()(const hermes::BlobId &key) const { + std::size_t operator()(const hermes::UniqueID &key) const { return std::hash{}(key.unique_) + std::hash{}(key.node_id_); diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index e8317b349..3888fef43 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -14,24 +14,38 @@ void MetadataManager::shm_init(MetadataManagerShmHeader *header) { header_ = header; rpc_ = &HERMES->rpc_; header_->id_alloc_ = 1; - blob_id_map_owner_ = lipc::make_uptr(nullptr); - bkt_id_map_owner_ = lipc::make_uptr(nullptr); - vbkt_id_map_owner_ = lipc::make_uptr(nullptr); - blob_map_owner_ = lipc::make_uptr(nullptr); - bkt_map_owner_ = lipc::make_uptr(nullptr); - vbkt_map_owner_ = lipc::make_uptr(nullptr); + blob_id_map_ = lipc::make_mptr(nullptr); + bkt_id_map_ = lipc::make_mptr(nullptr); + vbkt_id_map_ = lipc::make_mptr(nullptr); + blob_map_ = lipc::make_mptr(nullptr); + bkt_map_ = lipc::make_mptr(nullptr); + vbkt_map_ = lipc::make_mptr(nullptr); + shm_serialize(); + shm_deserialize(header_); +} + +/** + * Explicitly destroy the MetadataManager + * */ +void MetadataManager::shm_destroy() { + blob_id_map_.shm_destroy(); + bkt_id_map_.shm_destroy(); + vbkt_id_map_.shm_destroy(); + blob_map_.shm_destroy(); + bkt_map_.shm_destroy(); + vbkt_map_.shm_destroy(); } /** * Store the MetadataManager in shared memory. * */ void MetadataManager::shm_serialize() { - blob_id_map_owner_ >> header_->blob_id_map_ar_; - bkt_id_map_owner_ >> header_->bkt_id_map_ar_; - vbkt_id_map_owner_ >> header_->vbkt_id_map_ar_; - blob_map_owner_ >> header_->blob_map_ar_; - bkt_map_owner_ >> header_->bkt_map_ar_; - vbkt_map_owner_ >> header_->vbkt_map_ar_; + blob_id_map_ >> header_->blob_id_map_ar_; + bkt_id_map_ >> header_->bkt_id_map_ar_; + vbkt_id_map_ >> header_->vbkt_id_map_ar_; + blob_map_ >> header_->blob_map_ar_; + bkt_map_ >> header_->bkt_map_ar_; + vbkt_map_ >> header_->vbkt_map_ar_; } /** @@ -62,6 +76,11 @@ BucketId MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { // Emplace bucket if it does not already exist if (bkt_id_map_->try_emplace(bkt_name, bkt_id)) { + BucketInfo info; + info.name_ = lipc::make_mptr(bkt_name); + BucketInfoShmHeader hdr; + info.name_ >> hdr.name_ar_; + bkt_map_->emplace(bkt_id, hdr); } else { auto iter = bkt_id_map_->find(bkt_name); if (iter == bkt_id_map_->end()) { diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 37dc9c269..961ea0c5f 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -29,17 +29,17 @@ typedef lipc::unordered_map VBKT_MAP_T; * */ struct MetadataManagerShmHeader { /// SHM representation of blob id map - lipc::ShmArchive> blob_id_map_ar_; + lipc::ShmArchive> blob_id_map_ar_; /// SHM representation of bucket id map - lipc::ShmArchive> bkt_id_map_ar_; + lipc::ShmArchive> bkt_id_map_ar_; /// SHM representation of vbucket id map - lipc::ShmArchive> vbkt_id_map_ar_; + lipc::ShmArchive> vbkt_id_map_ar_; /// SHM representation of blob map - lipc::ShmArchive> blob_map_ar_; + lipc::ShmArchive> blob_map_ar_; /// SHM representation of bucket map - lipc::ShmArchive> bkt_map_ar_; + lipc::ShmArchive> bkt_map_ar_; /// SHM representation of vbucket map - lipc::ShmArchive> vbkt_map_ar_; + lipc::ShmArchive> vbkt_map_ar_; /// Used to create unique ids. Starts at 1. std::atomic id_alloc_; }; @@ -52,23 +52,8 @@ class MetadataManager { RPC_TYPE* rpc_; MetadataManagerShmHeader *header_; - /** - * The unique pointers representing the different map types. - * They are created in shm_init. They are destroyed automatically when the - * MetadataManager (on the Hermes core) is destroyed. This avoids having - * to manually "delete" the MetadataManager. - * */ - lipc::uptr blob_id_map_owner_; - lipc::uptr bkt_id_map_owner_; - lipc::uptr vbkt_id_map_owner_; - lipc::uptr blob_map_owner_; - lipc::uptr bkt_map_owner_; - lipc::uptr vbkt_map_owner_; - /** * The manual pointers representing the different map types. - * These are references to the objects stored in lipc::uptr - * objects above. * */ lipc::mptr blob_id_map_; lipc::mptr bkt_id_map_; @@ -85,6 +70,11 @@ class MetadataManager { * */ void shm_init(MetadataManagerShmHeader *header); + /** + * Explicitly destroy the MetadataManager + * */ + void shm_destroy(); + /** * Store the MetadataManager in shared memory. * */ diff --git a/test/test_rpc.cc b/test/test_rpc.cc index 92f79a800..ebd32409b 100644 --- a/test/test_rpc.cc +++ b/test/test_rpc.cc @@ -23,6 +23,7 @@ int main(int argc, char* argv[]) { MPI_Init(&argc, &argv); auto hermes = hapi::Hermes::Create(hermes::HermesType::kClient); auto bkt = hermes->GetBucket("hello"); + auto bkt2 = hermes->GetBucket("hello"); hermes->Finalize(); MPI_Finalize(); return 0; From bcad7c3d3b7b8ed7122cdba23d742e9b8d955ffe Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 23 Dec 2022 00:50:01 -0600 Subject: [PATCH 073/511] Use PosixApi class instead of flush_exclusion_list for I/O clients --- CMakeLists.txt | 5 +- adapter/CMakeLists.txt | 33 +- adapter/adapter_generator/README.md | 14 - .../Testing/Temporary/LastTest.log | 3 - .../adapter_generator/create_interceptor.py | 215 --- adapter/adapter_generator/mpiio.py | 42 - adapter/adapter_generator/posix.py | 34 - adapter/adapter_generator/stdio.py | 41 - adapter/adapter_utils.cc | 247 --- adapter/adapter_utils.h | 22 - adapter/constants.h | 128 -- adapter/enumerations.h | 27 - adapter/filesystem/filesystem.cc | 918 ---------- adapter/filesystem/filesystem.h | 475 ------ adapter/filesystem/metadata_manager.cc | 57 - adapter/filesystem/metadata_manager.h | 151 -- adapter/interceptor.cc | 164 -- adapter/interceptor.h | 262 --- adapter/mapper/abstract_mapper.h | 94 -- adapter/mapper/balanced_mapper.cc | 40 - adapter/mapper/balanced_mapper.h | 34 - adapter/mapper/mapper_factory.h | 46 - adapter/metadata_manager.h | 104 -- adapter/mpiio/CMakeLists.txt | 49 - adapter/mpiio/fs_api.cc | 622 ------- adapter/mpiio/fs_api.h | 246 --- adapter/mpiio/mpiio.cc | 462 ------ adapter/mpiio/real_api.h | 301 ---- adapter/posix/CMakeLists.txt | 50 +- adapter/posix/fs_api.cc | 97 -- adapter/posix/fs_api.h | 57 - adapter/posix/real_api.h | 25 +- adapter/posix/singleton.cc | 4 + adapter/posix/singleton_macros.h | 9 + adapter/pubsub/CMakeLists.txt | 33 - adapter/pubsub/datastructures.h | 58 - adapter/pubsub/metadata_manager.cc | 60 - adapter/pubsub/metadata_manager.h | 136 -- adapter/pubsub/pubsub.cc | 177 -- adapter/pubsub/pubsub.h | 129 -- adapter/stdio/CMakeLists.txt | 49 - adapter/stdio/fs_api.cc | 102 -- adapter/stdio/fs_api.h | 64 - adapter/stdio/real_api.h | 300 ---- adapter/stdio/stdio.cc | 565 ------- adapter/test/CMakeLists.txt | 59 - adapter/test/adapter_test_utils.h | 60 - adapter/test/catch_config.h | 42 - adapter/test/data/hermes.yaml | 45 - adapter/test/data/hermes_ares.yaml | 47 - adapter/test/data/hermes_small.yaml | 46 - adapter/test/mpiio/CMakeLists.txt | 46 - .../test/mpiio/mpiio_adapter_basic_test.cpp | 1044 ------------ adapter/test/mpiio/mpiio_adapter_test.cpp | 673 -------- adapter/test/mpiio/parallel.cc | 46 - adapter/test/posix/CMakeLists.txt | 73 - .../test/posix/posix_adapter_basic_test.cpp | 1478 ----------------- adapter/test/posix/posix_adapter_mpi_test.cpp | 401 ----- adapter/test/posix/posix_adapter_rs_test.cpp | 1239 -------------- .../test/posix/posix_adapter_shared_test.cpp | 78 - adapter/test/posix/posix_adapter_test.cpp | 286 ---- adapter/test/posix/simple_io.cc | 106 -- adapter/test/pubsub/CMakeLists.txt | 45 - adapter/test/pubsub/pubsub_end_to_end_test.cc | 64 - .../pubsub/pubsub_end_to_end_test_sync.cc | 68 - adapter/test/pubsub/pubsub_metadata_test.cc | 52 - adapter/test/pubsub/pubsub_topic_test.cc | 41 - adapter/test/pubsub/test_utils.h | 31 - adapter/test/run_hermes.sh | 52 - adapter/test/stdio/CMakeLists.txt | 111 -- adapter/test/stdio/adapter_utils_test.cc | 104 -- .../test/stdio/stdio_adapter_basic_test.cpp | 1308 --------------- .../test/stdio/stdio_adapter_func_test.cpp | 771 --------- .../stdio_adapter_low_buffer_space_test.cpp | 285 ---- .../test/stdio/stdio_adapter_mapper_test.cpp | 195 --- .../test/stdio/stdio_adapter_mode_test.cpp | 340 ---- adapter/test/stdio/stdio_adapter_mpi_test.cpp | 348 ---- adapter/test/stdio/stdio_adapter_rs_test.cpp | 1247 -------------- .../test/stdio/stdio_adapter_shared_test.cpp | 35 - adapter/test/stdio/stdio_adapter_test.cpp | 256 --- adapter/test/vfd/CMakeLists.txt | 68 - adapter/test/vfd/hermes_vfd_basic_test.cc | 718 -------- adapter/test/vfd/hermes_vfd_test.cc | 585 ------- adapter/vfd/CMakeLists.txt | 189 --- adapter/vfd/H5FDhermes.c | 1173 ------------- adapter/vfd/H5FDhermes.h | 60 - adapter/vfd/H5FDhermes_err.h | 199 --- adapter/vfd/README.md | 102 -- benchmarks/borg_bench.cc | 2 +- benchmarks/dpe_bench.cc | 2 +- code_generators/.idea/.gitignore | 3 + code_generators/.idea/code_generators.iml | 12 + .../inspectionProfiles/Project_Default.xml | 21 + .../inspectionProfiles/profiles_settings.xml | 6 + code_generators/.idea/misc.xml | 4 + code_generators/.idea/modules.xml | 8 + code_generators/.idea/vcs.xml | 6 + .../code_generators/singleton/generator.py | 3 +- code_generators/singleton.py | 11 +- config/hermes_server_default.yaml | 14 +- src/CMakeLists.txt | 7 +- src/api/hermes.cc | 8 +- src/buffer_organizer.cc | 30 + src/buffer_organizer.h | 32 + src/buffer_pool.cc | 56 +- src/buffer_pool.h | 17 +- src/config.h | 4 +- src/config_server.cc | 5 +- src/config_server.h | 14 +- src/dpe/minimize_io_time.cc | 2 +- src/dpe/minimize_io_time.h | 2 +- src/dpe/random.cc | 15 +- src/dpe/random.h | 8 +- src/dpe/round_robin.cc | 3 +- src/dpe/round_robin.h | 2 +- src/hermes_types.h | 60 +- src/io_clients/io_client.h | 23 + src/io_clients/io_client_factory.h | 40 + src/io_clients/posix.h | 39 + src/io_clients/ram.h | 8 + src/metadata_manager.cc | 21 +- src/metadata_manager.h | 19 +- src/metadata_types.h | 22 +- src/rpc_thallium.h | 2 +- src/rpc_thallium_serialization.h | 12 +- 125 files changed, 497 insertions(+), 21013 deletions(-) delete mode 100644 adapter/adapter_generator/README.md delete mode 100644 adapter/adapter_generator/Testing/Temporary/LastTest.log delete mode 100644 adapter/adapter_generator/adapter_generator/create_interceptor.py delete mode 100644 adapter/adapter_generator/mpiio.py delete mode 100644 adapter/adapter_generator/posix.py delete mode 100644 adapter/adapter_generator/stdio.py delete mode 100644 adapter/adapter_utils.cc delete mode 100644 adapter/adapter_utils.h delete mode 100644 adapter/constants.h delete mode 100644 adapter/enumerations.h delete mode 100644 adapter/filesystem/filesystem.cc delete mode 100644 adapter/filesystem/filesystem.h delete mode 100644 adapter/filesystem/metadata_manager.cc delete mode 100644 adapter/filesystem/metadata_manager.h delete mode 100644 adapter/interceptor.cc delete mode 100644 adapter/interceptor.h delete mode 100644 adapter/mapper/abstract_mapper.h delete mode 100644 adapter/mapper/balanced_mapper.cc delete mode 100644 adapter/mapper/balanced_mapper.h delete mode 100644 adapter/mapper/mapper_factory.h delete mode 100644 adapter/metadata_manager.h delete mode 100644 adapter/mpiio/CMakeLists.txt delete mode 100644 adapter/mpiio/fs_api.cc delete mode 100644 adapter/mpiio/fs_api.h delete mode 100644 adapter/mpiio/mpiio.cc delete mode 100644 adapter/mpiio/real_api.h delete mode 100644 adapter/posix/fs_api.cc delete mode 100644 adapter/posix/fs_api.h create mode 100644 adapter/posix/singleton.cc create mode 100644 adapter/posix/singleton_macros.h delete mode 100644 adapter/pubsub/CMakeLists.txt delete mode 100644 adapter/pubsub/datastructures.h delete mode 100644 adapter/pubsub/metadata_manager.cc delete mode 100644 adapter/pubsub/metadata_manager.h delete mode 100644 adapter/pubsub/pubsub.cc delete mode 100644 adapter/pubsub/pubsub.h delete mode 100644 adapter/stdio/CMakeLists.txt delete mode 100644 adapter/stdio/fs_api.cc delete mode 100644 adapter/stdio/fs_api.h delete mode 100644 adapter/stdio/real_api.h delete mode 100644 adapter/stdio/stdio.cc delete mode 100644 adapter/test/CMakeLists.txt delete mode 100644 adapter/test/adapter_test_utils.h delete mode 100644 adapter/test/catch_config.h delete mode 100644 adapter/test/data/hermes.yaml delete mode 100644 adapter/test/data/hermes_ares.yaml delete mode 100644 adapter/test/data/hermes_small.yaml delete mode 100644 adapter/test/mpiio/CMakeLists.txt delete mode 100644 adapter/test/mpiio/mpiio_adapter_basic_test.cpp delete mode 100644 adapter/test/mpiio/mpiio_adapter_test.cpp delete mode 100644 adapter/test/mpiio/parallel.cc delete mode 100644 adapter/test/posix/CMakeLists.txt delete mode 100644 adapter/test/posix/posix_adapter_basic_test.cpp delete mode 100644 adapter/test/posix/posix_adapter_mpi_test.cpp delete mode 100644 adapter/test/posix/posix_adapter_rs_test.cpp delete mode 100644 adapter/test/posix/posix_adapter_shared_test.cpp delete mode 100644 adapter/test/posix/posix_adapter_test.cpp delete mode 100644 adapter/test/posix/simple_io.cc delete mode 100644 adapter/test/pubsub/CMakeLists.txt delete mode 100644 adapter/test/pubsub/pubsub_end_to_end_test.cc delete mode 100644 adapter/test/pubsub/pubsub_end_to_end_test_sync.cc delete mode 100644 adapter/test/pubsub/pubsub_metadata_test.cc delete mode 100644 adapter/test/pubsub/pubsub_topic_test.cc delete mode 100644 adapter/test/pubsub/test_utils.h delete mode 100644 adapter/test/run_hermes.sh delete mode 100644 adapter/test/stdio/CMakeLists.txt delete mode 100644 adapter/test/stdio/adapter_utils_test.cc delete mode 100644 adapter/test/stdio/stdio_adapter_basic_test.cpp delete mode 100644 adapter/test/stdio/stdio_adapter_func_test.cpp delete mode 100644 adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp delete mode 100644 adapter/test/stdio/stdio_adapter_mapper_test.cpp delete mode 100644 adapter/test/stdio/stdio_adapter_mode_test.cpp delete mode 100644 adapter/test/stdio/stdio_adapter_mpi_test.cpp delete mode 100644 adapter/test/stdio/stdio_adapter_rs_test.cpp delete mode 100644 adapter/test/stdio/stdio_adapter_shared_test.cpp delete mode 100644 adapter/test/stdio/stdio_adapter_test.cpp delete mode 100644 adapter/test/vfd/CMakeLists.txt delete mode 100644 adapter/test/vfd/hermes_vfd_basic_test.cc delete mode 100644 adapter/test/vfd/hermes_vfd_test.cc delete mode 100644 adapter/vfd/CMakeLists.txt delete mode 100644 adapter/vfd/H5FDhermes.c delete mode 100644 adapter/vfd/H5FDhermes.h delete mode 100644 adapter/vfd/H5FDhermes_err.h delete mode 100644 adapter/vfd/README.md create mode 100644 code_generators/.idea/.gitignore create mode 100644 code_generators/.idea/code_generators.iml create mode 100644 code_generators/.idea/inspectionProfiles/Project_Default.xml create mode 100644 code_generators/.idea/inspectionProfiles/profiles_settings.xml create mode 100644 code_generators/.idea/misc.xml create mode 100644 code_generators/.idea/modules.xml create mode 100644 code_generators/.idea/vcs.xml create mode 100644 src/io_clients/io_client.h create mode 100644 src/io_clients/io_client_factory.h create mode 100644 src/io_clients/posix.h create mode 100644 src/io_clients/ram.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 58624bb65..5e3a7afb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -392,6 +392,8 @@ endif() # Source #----------------------------------------------------------------------------- +set(HERMES_EXPORTED_LIBS "") + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src) if(HERMES_HAVE_GOTCHA) @@ -427,10 +429,11 @@ if(CMAKE_PROJECT_NAME STREQUAL HERMES AND BUILD_TESTING) # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/data_stager/test) endif() +##### ADAPTERS if(HERMES_ENABLE_STDIO_ADAPTER OR HERMES_ENABLE_POSIX_ADAPTER OR HERMES_ENABLE_MPIIO_ADAPTER OR HERMES_ENABLE_PUBSUB_ADAPTER OR HERMES_ENABLE_VFD) - # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/adapter) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/adapter) endif() #----------------------------------------------------------------------------- diff --git a/adapter/CMakeLists.txt b/adapter/CMakeLists.txt index 1f4861e04..4268d3669 100644 --- a/adapter/CMakeLists.txt +++ b/adapter/CMakeLists.txt @@ -2,39 +2,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHERMES_PRELOAD -DHERMES_RPC_THALLIUM") set(HERMES_ADAPTER_DIR ${CMAKE_SOURCE_DIR}/adapter) - -if(HERMES_ENABLE_STDIO_ADAPTER) - add_subdirectory(stdio) -endif() +include_directories(${CMAKE_SOURCE_DIR}/src) if(HERMES_ENABLE_POSIX_ADAPTER) add_subdirectory(posix) endif() - -if(HERMES_ENABLE_MPIIO_ADAPTER) - add_subdirectory(mpiio) -endif() - -if(HERMES_ENABLE_PUBSUB_ADAPTER) - add_subdirectory(pubsub) -endif() - -if(HERMES_ENABLE_VFD) - if(HERMES_ENABLE_WRAPPER) - # The Hermes VFD cannot be installed into the same directory as libhermes.so - # because of the way dynamic plugin loading works in HDF5. When searching - # for a VFD, HDF5 will dlopen and dlclose every shared library in - # HDF5_PLUGIN_PATH looking for a valid VFD. When HDF5 goes through this - # process with libhermes.so it resets some statically initialized variables. - set(HERMES_VFD_DIR_NAME hermes_vfd) - set(HERMES_VFD_LIBRARY_DIR ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${HERMES_VFD_DIR_NAME}) - add_subdirectory(vfd) - else() - message(FATAL_ERROR "The Hermes VFD requires HERMES_ENABLE_WRAPPER=ON") - endif() -endif() - -if(BUILD_TESTING) - enable_testing() - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test) -endif() diff --git a/adapter/adapter_generator/README.md b/adapter/adapter_generator/README.md deleted file mode 100644 index a43b729a1..000000000 --- a/adapter/adapter_generator/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Adapter Generator - -This library generates an interceptor "API" class used to store the original implementations -of a library for an LD_PRELOAD interceptor to use. - -## Usage - -To create the interceptor for POSIX: -```bash -cd /path/to/adapter_generator -python3 posix.py -``` - -This will create the file adapter/posix/posix.h \ No newline at end of file diff --git a/adapter/adapter_generator/Testing/Temporary/LastTest.log b/adapter/adapter_generator/Testing/Temporary/LastTest.log deleted file mode 100644 index f9dee83b3..000000000 --- a/adapter/adapter_generator/Testing/Temporary/LastTest.log +++ /dev/null @@ -1,3 +0,0 @@ -Start testing: Oct 21 10:03 CDT ----------------------------------------------------------- -End testing: Oct 21 10:03 CDT diff --git a/adapter/adapter_generator/adapter_generator/create_interceptor.py b/adapter/adapter_generator/adapter_generator/create_interceptor.py deleted file mode 100644 index 2a7d4033e..000000000 --- a/adapter/adapter_generator/adapter_generator/create_interceptor.py +++ /dev/null @@ -1,215 +0,0 @@ -import sys,os -import re - -preamble = """/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */""" - -class Api: - def __init__(self, api_str): - self.api_str = api_str - self.decompose_prototype(api_str) - - def _is_text(self, tok): - first_is_text = re.match("[_a-zA-Z]", tok[0]) is not None - if not first_is_text: - return False - return re.match("[_a-zA-Z0-9]+", tok) is not None - - def _clean(self, toks): - return [tok for tok in toks if tok is not None and len(tok) > 0] - - def get_arg_tuple(self, arg): - arg_toks = self._clean(re.split("[ ]|(\*+)", arg)) - if len(arg_toks) == 1: - if arg_toks[0] == '...': - type = "" - name = "..." - return (type, name) - type = " ".join(arg_toks[:-1]) - name = arg_toks[-1] - return (type, name) - - def decompose_prototype(self, api_str): - toks = self._clean(re.split("[()]", api_str)) - proto, args = toks[0], toks[1] - - try: - proto = self._clean(re.split("[ ]|(\*+)", proto)) - self.name = proto[-1] - self.ret = " ".join(proto[:-1]) - self.real_name = self.name - self.type = f"{self.name}_t" - except: - print(f"Failed to decompose proto name: {proto}") - exit() - - try: - self.var_defs = [] - args = args.split(',') - for arg in args: - self.var_defs.append(self.get_arg_tuple(arg)) - except: - print(f"Failed to decompose proto args: {args}") - exit(1) - - def get_args(self): - if len(self.var_defs) == 0: - return "" - try: - args = [" ".join(arg_tuple) for arg_tuple in self.var_defs] - except: - print(f"Failed to get arg list: {self.var_defs}") - exit(1) - return ", ".join(args) - - def pass_args(self): - if self.var_defs is None: - return "" - args = [arg[-1] for arg in self.var_defs if arg[0] != ''] - return ", ".join(args) - -class ApiClass: - def __init__(self, namespace, apis, includes, dir=None, - create_h=True, create_cc=False): - self.apis = apis - h_file = None - cc_file = None - # Ensure that directory is set if create_cc or create_h is true - if create_h or create_cc: - if dir is None: - dir = os.path.dirname(os.getcwd()) - dir = os.path.join(dir, namespace) - if dir is not None and create_h: - h_file = os.path.join(dir, "real_api.h") - print(f"Will create header {h_file}") - if dir is not None and create_cc: - cc_file = os.path.join(dir, f"{namespace}.cc") - print(f"Will create cpp file {h_file}") - self.cc_lines = [] - self.h_lines = [] - self._CreateH(namespace, includes, h_file) - self._CreateCC(namespace, cc_file) - - def _CreateCC(self, namespace, path): - self.cc_lines.append(preamble) - self.cc_lines.append("") - - # Includes - self.cc_lines.append(f"bool {namespace}_intercepted = true;") - self.cc_lines.append(f"#include \"real_api.h\"") - self.cc_lines.append(f"#include \"singleton.h\"") - self.cc_lines.append("") - - # Namespace simplification - self.cc_lines.append(f"using hermes::adapter::{namespace}::API;") - self.cc_lines.append(f"using hermes::Singleton;") - self.cc_lines.append("") - - # Intercept function - for api in self.apis: - self.cc_lines.append(f"{api.api_str} {{") - self.cc_lines.append(f" auto real_api = Singleton::GetInstance();") - self.cc_lines.append(f" REQUIRE_API({api.name});") - self.cc_lines.append(f" // auto fs_api = ") - self.cc_lines.append(f" return real_api->{api.name}({api.pass_args()});") - self.cc_lines.append(f"}}") - self.cc_lines.append("") - - text = "\n".join(self.cc_lines) - self.save(path, text) - - def _CreateH(self, namespace, includes, path): - self.h_lines.append(preamble) - self.h_lines.append("") - self.h_lines.append(f"#ifndef HERMES_ADAPTER_{namespace.upper()}_H") - self.h_lines.append(f"#define HERMES_ADAPTER_{namespace.upper()}_H") - - # Include files - self.h_lines.append("#include ") - self.h_lines.append("#include ") - self.h_lines.append("#include ") - self.h_lines.append("#include ") - for include in includes: - self.h_lines.append(f"#include {include}") - self.h_lines.append("") - - # Require API macro - self.require_api() - self.h_lines.append("") - - # Create typedefs - self.h_lines.append(f"extern \"C\" {{") - for api in self.apis: - self.add_typedef(api) - self.h_lines.append(f"}}") - self.h_lines.append(f"") - - # Create the class definition - self.h_lines.append(f"namespace hermes::adapter::{namespace} {{") - self.h_lines.append(f"") - self.h_lines.append(f"/** Pointers to the real {namespace} API */") - self.h_lines.append(f"class API {{") - - # Create class function pointers - self.h_lines.append(f" public:") - for api in self.apis: - self.add_intercept_api(api) - self.h_lines.append(f"") - - # Create the symbol mapper - self.h_lines.append(f" API() {{") - self.h_lines.append(f" void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, \"{namespace}_intercepted\");") - for api in self.apis: - self.init_api(api) - self.h_lines.append(f" }}") - - # End the class, namespace, and header guard - self.h_lines.append(f"}};") - self.h_lines.append(f"}} // namespace hermes::adapter::{namespace}") - self.h_lines.append("") - self.h_lines.append("#undef REQUIRE_API") - self.h_lines.append("") - self.h_lines.append(f"#endif // HERMES_ADAPTER_{namespace.upper()}_H") - self.h_lines.append("") - - text = "\n".join(self.h_lines) - self.save(path, text) - - def require_api(self): - self.h_lines.append(f"#define REQUIRE_API(api_name) \\") - self.h_lines.append(f" if (api_name == nullptr) {{ \\") - self.h_lines.append(f" LOG(FATAL) << \"HERMES Adapter failed to map symbol: \" \\") - self.h_lines.append(f" #api_name << std::endl; \\") - self.h_lines.append(f" std::exit(1); \\") - self.h_lines.append(f" }}") - - def add_typedef(self, api): - self.h_lines.append(f"typedef {api.ret} (*{api.type})({api.get_args()});") - - def add_intercept_api(self, api): - self.h_lines.append(f" /** {api.real_name} */") - self.h_lines.append(f" {api.type} {api.real_name} = nullptr;") - - def init_api(self, api): - self.h_lines.append(f" if (is_intercepted) {{") - self.h_lines.append(f" {api.real_name} = ({api.type})dlsym(RTLD_NEXT, \"{api.name}\");") - self.h_lines.append(f" }} else {{") - self.h_lines.append(f" {api.real_name} = ({api.type})dlsym(RTLD_DEFAULT, \"{api.name}\");") - self.h_lines.append(f" }}") - self.h_lines.append(f" REQUIRE_API({api.real_name})") - - def save(self, path, text): - if path is None: - print(text) - return - with open(path, "w") as fp: - fp.write(text) \ No newline at end of file diff --git a/adapter/adapter_generator/mpiio.py b/adapter/adapter_generator/mpiio.py deleted file mode 100644 index 39df5e39d..000000000 --- a/adapter/adapter_generator/mpiio.py +++ /dev/null @@ -1,42 +0,0 @@ -from adapter_generator.create_interceptor import Api,ApiClass - -apis = [ - Api("int MPI_Init(int *argc, char ***argv)"), - Api("int MPI_Finalize(void)"), - Api("int MPI_Wait(MPI_Request *req, MPI_Status *status)"), - Api("int MPI_Waitall(int count, MPI_Request *req, MPI_Status *status)"), - Api("int MPI_File_open(MPI_Comm comm, const char *filename, int amode, MPI_Info info, MPI_File *fh)"), - Api("int MPI_File_close(MPI_File *fh)"), - Api("int MPI_File_seek_shared(MPI_File fh, MPI_Offset offset, int whence)"), - Api("int MPI_File_seek(MPI_File fh, MPI_Offset offset, int whence)"), - Api("int MPI_File_get_position(MPI_File fh, MPI_Offset *offset)"), - Api("int MPI_File_read_all(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status)"), - Api("int MPI_File_read_at_all(MPI_File fh, MPI_Offset offset, void *buf, int count, MPI_Datatype datatype, MPI_Status *status)"), - Api("int MPI_File_read_at(MPI_File fh, MPI_Offset offset, void *buf, int count, MPI_Datatype datatype, MPI_Status *status)"), - Api("int MPI_File_read(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status)"), - Api("int MPI_File_read_ordered(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status)"), - Api("int MPI_File_read_shared(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status)"), - Api("int MPI_File_write_all(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Status *status)"), - Api("int MPI_File_write_at_all(MPI_File fh, MPI_Offset offset, const void *buf, int count, MPI_Datatype datatype, MPI_Status *status)"), - Api("int MPI_File_write_at(MPI_File fh, MPI_Offset offset, const void *buf, int count, MPI_Datatype datatype, MPI_Status *status)"), - Api("int MPI_File_write(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Status *status)"), - Api("int MPI_File_write_ordered(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Status *status)"), - Api("int MPI_File_write_shared(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Status *status)"), - Api("int MPI_File_iread_at(MPI_File fh, MPI_Offset offset, void *buf, int count, MPI_Datatype datatype, MPI_Request *request)"), - Api("int MPI_File_iread(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Request *request)"), - Api("int MPI_File_iread_shared(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Request *request)"), - Api("int MPI_File_iwrite_at(MPI_File fh, MPI_Offset offset, const void *buf, int count, MPI_Datatype datatype, MPI_Request *request)"), - Api("int MPI_File_iwrite(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Request *request)"), - Api("int MPI_File_iwrite_shared(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Request *request)"), - Api("int MPI_File_sync(MPI_File fh)"), -] - -includes = [ - "", - "", - "\"interceptor.h\"", - "\"filesystem/filesystem.h\"", - "\"filesystem/metadata_manager.h\"" -] - -ApiClass("mpiio", apis, includes) \ No newline at end of file diff --git a/adapter/adapter_generator/posix.py b/adapter/adapter_generator/posix.py deleted file mode 100644 index 2e434897d..000000000 --- a/adapter/adapter_generator/posix.py +++ /dev/null @@ -1,34 +0,0 @@ -from adapter_generator.create_interceptor import Api,ApiClass - -apis = [ - Api("int MPI_Init(int *argc, char ***argv)"), - Api("int MPI_Finalize(void)"), - Api("int open(const char *path, int flags, ...)"), - Api("int open64(const char *path, int flags, ...)"), - Api("int __open_2(const char *path, int oflag)"), - Api("int creat(const char *path, mode_t mode)"), - Api("int creat64(const char *path, mode_t mode)"), - Api("ssize_t read(int fd, void *buf, size_t count)"), - Api("ssize_t write(int fd, const void *buf, size_t count)"), - Api("ssize_t pread(int fd, void *buf, size_t count, off_t offset)"), - Api("ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)"), - Api("ssize_t pread64(int fd, void *buf, size_t count, off64_t offset)"), - Api("ssize_t pwrite64(int fd, const void *buf, size_t count, off64_t offset)"), - Api("off_t lseek(int fd, off_t offset, int whence)"), - Api("off64_t lseek64(int fd, off64_t offset, int whence)"), - Api("int __fxstat(int __ver, int __filedesc, struct stat *__stat_buf)"), - Api("int fsync(int fd)"), - Api("int close(int fd)"), -] - -includes = [ - "", - "", - "", - "", - "\"interceptor.h\"", - "\"filesystem/filesystem.h\"", - "\"filesystem/metadata_manager.h\"" -] - -ApiClass("posix", apis, includes) \ No newline at end of file diff --git a/adapter/adapter_generator/stdio.py b/adapter/adapter_generator/stdio.py deleted file mode 100644 index b8de6ba05..000000000 --- a/adapter/adapter_generator/stdio.py +++ /dev/null @@ -1,41 +0,0 @@ -from adapter_generator.create_interceptor import Api,ApiClass - -apis = [ - Api("int MPI_Init(int *argc, char ***argv)"), - Api("int MPI_Finalize(void)"), - Api("FILE *fopen(const char *path, const char *mode)"), - Api("FILE *fopen64(const char *path, const char *mode)"), - Api("FILE *fdopen(int fd, const char *mode)"), - Api("FILE *freopen(const char *path, const char *mode, FILE *stream)"), - Api("FILE *freopen64(const char *path, const char *mode, FILE *stream)"), - Api("int fflush(FILE *fp)"), - Api("int fclose(FILE *fp)"), - Api("size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp)"), - Api("int fputc(int c, FILE *fp)"), - Api("int fgetpos(FILE *fp, fpos_t *pos)"), - Api("int fgetpos64(FILE *fp, fpos64_t *pos)"), - Api("int putc(int c, FILE *fp)"), - Api("int putw(int w, FILE *fp)"), - Api("int fputs(const char *s, FILE *stream)"), - Api("size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)"), - Api("int fgetc(FILE *stream)"), - Api("int getc(FILE *stream)"), - Api("int getw(FILE *stream)"), - Api("char *fgets(char *s, int size, FILE *stream)"), - Api("void rewind(FILE *stream)"), - Api("int fseek(FILE *stream, long offset, int whence)"), - Api("int fseeko(FILE *stream, off_t offset, int whence)"), - Api("int fseeko64(FILE *stream, off64_t offset, int whence)"), - Api("int fsetpos(FILE *stream, const fpos_t *pos)"), - Api("int fsetpos64(FILE *stream, const fpos64_t *pos)"), - Api("long int ftell(FILE *fp)"), -] - -includes = [ - "", - "\"interceptor.h\"", - "\"filesystem/filesystem.h\"", - "\"filesystem/metadata_manager.h\"" -] - -ApiClass("stdio", apis, includes) \ No newline at end of file diff --git a/adapter/adapter_utils.cc b/adapter/adapter_utils.cc deleted file mode 100644 index 4afc84634..000000000 --- a/adapter/adapter_utils.cc +++ /dev/null @@ -1,247 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "utils.cc" -#include - -using hermes::u8; -namespace stdfs = std::experimental::filesystem; - -namespace { -const stdfs::path::value_type dot = '.'; -inline bool is_dot(stdfs::path::value_type c) { return c == dot; } - -inline bool is_dot(const stdfs::path& path) { - const auto& filename = path.native(); - return filename.size() == 1 && is_dot(filename[0]); -} - -inline bool is_dotdot(const stdfs::path& path) { - const auto& filename = path.native(); - return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]); -} -} // namespace - -namespace hermes { -namespace adapter { -/** - * normalize \a path - * - * \note (chogan): Back port of the C++17 standard fileystem implementation - * from gcc 9.1 to support gcc 7 -*/ -stdfs::path LexicallyNormal(stdfs::path &path) { - /* - C++17 [fs.path.generic] p6 - - If the path is empty, stop. - - Replace each slash character in the root-name with a preferred-separator. - - Replace each directory-separator with a preferred-separator. - - Remove each dot filename and any immediately following directory-separator. - - As long as any appear, remove a non-dot-dot filename immediately followed - by a directory-separator and a dot-dot filename, along with any immediately - following directory-separator. - - If there is a root-directory, remove all dot-dot filenames and any - directory-separators immediately following them. - - If the last filename is dot-dot, remove any trailing directory-separator. - - If the path is empty, add a dot. - */ - stdfs::path ret; - // If the path is empty, stop. - if (path.empty()) { - return ret; - } - for (auto& p : path) { - if (is_dotdot(p)) { - if (ret.has_filename()) { - // remove a non-dot-dot filename immediately followed by /.. - if (!is_dotdot(ret.filename())) { - ret.remove_filename(); - } else { - ret /= p; - } - } else if (!ret.has_relative_path()) { - // remove a dot-dot filename immediately after root-directory - if (!ret.has_root_directory()) { - ret /= p; - } - } else { - // Got a path with a relative path (i.e. at least one non-root - // element) and no filename at the end (i.e. empty last element), - // so must have a trailing slash. See what is before it. - auto elem = (ret.end()--)--; - if (elem->has_filename() && !is_dotdot(*elem)) { - // Remove the filename before the trailing slash - // (equiv. to ret = ret.parent_path().remove_filename()) - ret = ret.parent_path().remove_filename(); - - // if (elem == ret.begin()) { - // ret.clear(); - // } else { - // ret._M_pathname.erase(elem->_M_pos); - // // Remove empty filename at the end: - // ret._M_cmpts.pop_back(); - // // If we still have a trailing non-root dir separator - // // then leave an empty filename at the end: - // if (std::prev(elem)->_M_type() == _Type::_Filename) { - // elem->clear(); - // } - // else { // remove the component completely: - // ret._M_cmpts.pop_back(); - // } - // } - } else { - // Append the ".." to something ending in "../" which happens - // when normalising paths like ".././.." and "../a/../.." - ret /= p; - } - } - } else if (is_dot(p)) { - ret /= stdfs::path(); - } else { - ret /= p; - } - } - - if (std::distance(ret.begin(), ret.end()) >= 2) { - auto back = std::prev(ret.end()); - // If the last filename is dot-dot, ... - if (back->empty() && is_dotdot(*std::prev(back))) { - // ... remove any trailing directory-separator. - ret = ret.parent_path(); - } - } else if (ret.empty()) { - // If the path is empty, add a dot. - ret = "."; - } - - return ret; -} - -/** - convert path \a p to a canonical absolute path - \note (chogan): Backported from GCC 9 -*/ -stdfs::path WeaklyCanonical(const stdfs::path& p) { - stdfs::path result; - if (stdfs::exists(stdfs::status(p))) { - return stdfs::canonical(p); - } - - stdfs::path tmp; - auto iter = p.begin(), end = p.end(); - // find leading elements of p that exist: - while (iter != end) { - tmp = result / *iter; - if (stdfs::exists(stdfs::status(tmp))) { - stdfs::swap(result, tmp); - } else { - break; - } - ++iter; - } - // canonicalize: - if (!result.empty()) { - result = stdfs::canonical(result); - } - // append the non-existing elements: - while (iter != end) { - result /= *iter++; - } - // normalize: - return LexicallyNormal(result); -} - -/** - convert path \a p to a canonical absolute path with \a ec error code - \note (chogan): Backported from GCC 9 -*/ -stdfs::path WeaklyCanonical(const stdfs::path& p, std::error_code& ec) { - stdfs::path result; - stdfs::file_status st = stdfs::status(p, ec); - if (exists(st)) { - return stdfs::canonical(p, ec); - } else if (stdfs::status_known(st)) { - ec.clear(); - } else { - return result; - } - - stdfs::path tmp; - auto iter = p.begin(), end = p.end(); - // find leading elements of p that exist: - while (iter != end) { - tmp = result / *iter; - st = stdfs::status(tmp, ec); - if (exists(st)) { - swap(result, tmp); - } else { - if (stdfs::status_known(st)) { - ec.clear(); - } - break; - } - ++iter; - } - // canonicalize: - if (!ec && !result.empty()) { - result = canonical(result, ec); - } - if (ec) { - result.clear(); - } else { - // append the non-existing elements: - while (iter != end) { - result /= *iter++; - } - // normalize: - result = LexicallyNormal(result); - } - - return result; -} - -/** - Read gap from the original file when BLOB has a gap in write. - */ -void ReadGap(const std::string &filename, size_t seek_offset, u8 *read_ptr, - size_t read_size, size_t file_bounds) { - if (stdfs::exists(filename) && - stdfs::file_size(filename) >= file_bounds) { - LOG(INFO) << "Blob has a gap in write. Read gap from original file.\n"; - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(filename); - int fd = open(filename.c_str(), O_RDONLY); - if (fd) { - if (flock(fd, LOCK_SH) == -1) { - hermes::FailedLibraryCall("flock"); - } - - ssize_t bytes_read = pread(fd, read_ptr, read_size, seek_offset); - if (bytes_read == -1 || (size_t)bytes_read != read_size) { - hermes::FailedLibraryCall("pread"); - } - - if (flock(fd, LOCK_UN) == -1) { - hermes::FailedLibraryCall("flock"); - } - - if (close(fd) != 0) { - hermes::FailedLibraryCall("close"); - } - } else { - hermes::FailedLibraryCall("open"); - } - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(filename); - } -} -} // namespace adapter -} // namespace hermes diff --git a/adapter/adapter_utils.h b/adapter/adapter_utils.h deleted file mode 100644 index ed35d3dce..000000000 --- a/adapter/adapter_utils.h +++ /dev/null @@ -1,22 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -namespace hermes::adapter { - -namespace stdfs = std::experimental::filesystem; - -stdfs::path WeaklyCanonical(const stdfs::path& p); -stdfs::path WeaklyCanonical(const stdfs::path& p, std::error_code& ec); - -} // namespace hermes::adapter diff --git a/adapter/constants.h b/adapter/constants.h deleted file mode 100644 index 602748cdd..000000000 --- a/adapter/constants.h +++ /dev/null @@ -1,128 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_CONSTANTS_H -#define HERMES_ADAPTER_CONSTANTS_H - -#include - -/** - * Constants file for all adapter. - * This file contains common constants across different adapters. - */ - -/** - * kHermesConf env variable is used to define path to kHermesConf in adapters. - * This is used for initialization of Hermes. - */ -const char* kHermesConf = "HERMES_CONF"; - -/** - * Environment variable used to inform Hermes if this run consists of a separate - * client that needs to attach to an existing daemon (1) or if this run is - * co-deployed with a Hermes core (0). This is only relevant for Hermes jobs - * launched with 1 application process, as Hermes jobs run with >1 MPI ranks - * require a daemon. Defaults to 0. - */ -const char* kHermesClient = "HERMES_CLIENT"; - -/** - * Specifies whether or not Hermes should eagerly and asynchronously flush - * writes to their final destinations. - * - * When set to "1", each write will first Put the Blob into the buffering - * system, then trigger a background job to flush the Blob to its file. This is - * useful for write-only workloads. If "0" or unset, normal flushing occurs when - * fclose is intercepted. - */ -const char* kHermesAsyncFlush = "HERMES_ASYNC_FLUSH"; - -/** - * kHermesExtension is the extension of hermes files. These are buffered files - * from I/O. This is needed as we should not intercept these files. - */ -const char* kHermesExtension = ".hermes"; -/** - * ADAPTER_MODE env variable is used to define the mode in which Hermes' - * STDIO adapter operates. - * - * It supports 3 Values: DEFAULT/BYPASS/SCRATCH - * - * DEFAULT: by default adapter operates in Persistent mode. - * BYPASS: the adapter will bypass hermes. - * SCRATCH: the adapter will discard the data operation on close. - */ -const char* kAdapterMode = "ADAPTER_MODE"; -/** - * ADAPTER_MODE_INFO env variable is used to define the additional - * information for the selected mode @see kAdapterMode. - * - * for DEFAULT: which files should be persisted. - * for BYPASS: which files should be bypassed. - * for SCRATCH: which files will be opened in scratch model. - */ -const char* kAdapterModeInfo = "ADAPTER_MODE_INFO"; -/** - * Path delimiter used for defining multiple file paths in Hermes' Adapter. - */ -const char kPathDelimiter = ','; -/** - * Constants for supported buffering modes in Hermes - */ -const char* kAdapterDefaultMode = "DEFAULT"; -const char* kAdapterBypassMode = "BYPASS"; -const char* kAdapterScratchMode = "SCRATCH"; -const char* kAdapterWorkflowMode = "WORKFLOW"; - -/** - * If the \c HERMES_STOP_DAEMON environment variable is unset or has a non-zero - * value, the adapter client will kill the running Hermes daemon when it - * finishes execution. - * - * Default value: \c 1 - */ -const char* kStopDaemon = "HERMES_STOP_DAEMON"; - -/** - * The page size in bytes when mapping files to Hermes Blobs. Hermes will be - * more efficient if you set this number to the most common size of writes in - * your application. This is set via HERMES_PAGE_SIZE. - * - * Example: With a page size of 1MiB, a 100 MiB file will be mapped to 100, 1MiB - * Blobs. In this scenario, doing several smaller writes within the same 1MiB - * region will cause all of those writes to transfer 1MiB of data, which is why - * it's important to align the page size to your workload. - */ -const size_t kPageSize = []() { - const char* kPageSizeVar = "HERMES_PAGE_SIZE"; - const size_t kDefaultPageSize = 1 * 1024 * 1024; - - size_t result = kDefaultPageSize; - char* page_size = getenv(kPageSizeVar); - - if (page_size) { - result = (size_t)std::strtoull(page_size, NULL, 0); - if (result == 0) { - LOG(FATAL) << "Invalid value of " << kPageSizeVar << ": " << page_size; - } - } - - return result; -}(); - -/** - * Set this environment variable to '1' for more efficient performance on - * workloads that are write-only. - */ -const char* kHermesWriteOnlyVar = "HERMES_WRITE_ONLY"; - -#endif // HERMES_ADAPTER_CONSTANTS_H diff --git a/adapter/enumerations.h b/adapter/enumerations.h deleted file mode 100644 index c57dcd080..000000000 --- a/adapter/enumerations.h +++ /dev/null @@ -1,27 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_ENUMERATIONS_H -#define HERMES_ADAPTER_ENUMERATIONS_H -enum class AdapterMode { - kDefault = 0, /**< All/given files are stored on file close or flush. */ - kBypass = 1, /**< All/given files are not buffered. */ - kScratch = 2, /**< All/given files are ignored on file close or flush. */ - kWorkflow = 3 /**< Keep data in hermes until user stages out. */ -}; - -enum class FlushingMode { - kSynchronous, /**< Flush persistent Blobs synchronously on fclose. */ - kAsynchronous, /**< Flush persistent Blobs asynchronously on fwrite. */ -}; - -#endif // HERMES_ADAPTER_ENUMERATIONS_H diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc deleted file mode 100644 index e93b7bca9..000000000 --- a/adapter/filesystem/filesystem.cc +++ /dev/null @@ -1,918 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "filesystem.h" -#include "constants.h" -#include "singleton.h" -#include "mapper/mapper_factory.h" -#include "interceptor.h" -#include "metadata_manager.h" -#include "vbucket.h" -#include "adapter_utils.cc" - -#include -#include - -namespace stdfs = std::experimental::filesystem; - -namespace hermes::adapter::fs { - -static bool IsAsyncFlush(const std::string &path_str) { - bool result = (INTERCEPTOR_LIST->Persists(path_str) && - global_flushing_mode == FlushingMode::kAsynchronous); - return result; -} - -File Filesystem::Open(AdapterStat &stat, const std::string &path) { - std::string path_str = WeaklyCanonical(path).string(); - File f = _RealOpen(stat, path); - if (!f.status_) { return f; } - Open(stat, f, path); - return f; -} - -void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { - std::string path_str = WeaklyCanonical(path).string(); - _InitFile(f); - auto mdm = Singleton::GetInstance(); - auto existing = mdm->Find(f); - int rank = 0; - if (mdm->is_mpi) { - MPI_Comm_rank(stat.comm, &rank); - } - if (!existing.second) { - LOG(INFO) << "File not opened before by adapter" << std::endl; - stat.ref_count = 1; - struct timespec ts; - timespec_get(&ts, TIME_UTC); - stat.st_atim = ts; - stat.st_mtim = ts; - stat.st_ctim = ts; - - /* FIXME(hari) check if this initialization is correct. */ - mdm->InitializeHermes(); - - bool bucket_exists = mdm->GetHermes()->BucketExists(path_str); - - // TODO(llogan): needed for locking in parallel - if (mdm->is_mpi) { - stat.main_lock_blob = "#main_lock"; - if (rank == 0) { - u8 c; - stat.st_bkid = - std::make_shared(path_str, mdm->GetHermes()); - if (!stat.st_bkid->ContainsBlob(stat.main_lock_blob)) { - stat.st_bkid->Put(stat.main_lock_blob, &c, 1); - } - } - MPI_Barrier(stat.comm); - if (rank != 0) { - stat.st_bkid = - std::make_shared(path_str, mdm->GetHermes()); - } - - // Create a vbucket for storing all modified blobs (per-rank) - - } else { - stat.st_bkid = - std::make_shared(path_str, mdm->GetHermes()); - } - - if (IsAsyncFlush(path_str)) { - // TODO(llogan): should we use a vbucket per-rank instead? - std::string vbucket_name = path_str + "#" + std::to_string(rank); - stat.st_vbkt = - std::make_shared(vbucket_name, mdm->GetHermes()); - auto offset_map = std::unordered_map(); - stat.st_persist = - std::make_shared(path_str, offset_map, false); - stat.st_vbkt->Attach(stat.st_persist.get()); - } - _OpenInitStats(f, stat); - _OpenInitStatsInternal(stat, bucket_exists); - mdm->Create(f, stat); - } else { - LOG(INFO) << "File opened before by adapter" << std::endl; - existing.first.ref_count++; - struct timespec ts; - timespec_get(&ts, TIME_UTC); - existing.first.st_atim = ts; - existing.first.st_ctim = ts; - mdm->Update(f, existing.first); - } -} - -void Filesystem::_PutWithFallback(AdapterStat &stat, - const std::string &blob_name, - const std::string &filename, - u8 *data, size_t size, - size_t offset, - IoStatus &io_status, IoOptions &opts) { - hapi::Context ctx; - const char *hermes_write_only = getenv(kHermesWriteOnlyVar); - if (hermes_write_only && hermes_write_only[0] == '1') { - // Custom DPE for write-only apps like VPIC - ctx.rr_retry = true; - ctx.disable_swap = true; - } - hapi::Status put_status = stat.st_bkid->Put(blob_name, data, size, ctx); - if (put_status.Failed()) { - if (opts.with_fallback_) { - LOG(WARNING) << "Failed to Put Blob " << blob_name << " to Bucket " - << filename << ". Falling back to posix I/O." << std::endl; - _RealWrite(filename, offset, size, data, io_status, opts); - } - } else { - stat.st_blobs.emplace(blob_name); - } -} - -size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, - size_t off, size_t total_size, - IoStatus &io_status, IoOptions opts) { - (void) f; - std::shared_ptr &bkt = stat.st_bkid; - std::string filename = bkt->GetName(); - LOG(INFO) << "Write called for filename: " << filename << " on offset: " - << off << " and size: " << total_size << std::endl; - - size_t ret; - auto mdm = Singleton::GetInstance(); - BlobPlacements mapping; - auto mapper = MapperFactory().Get(kMapperType); - mapper->map(off, total_size, mapping); - size_t data_offset = 0; - - for (const auto &p : mapping) { - BlobPlacementIter wi(f, stat, filename, p, bkt, io_status, opts); - wi.blob_name_ = wi.p_.CreateBlobName(); - wi.blob_exists_ = wi.bkt_->ContainsBlob(wi.blob_name_); - wi.blob_start_ = p.page_ * kPageSize; - wi.mem_ptr_ = (u8 *)ptr + data_offset; - if (p.blob_size_ != kPageSize && opts.coordinate_ - && stat.main_lock_blob.size() > 0) { - _CoordinatedPut(wi); - } else { - _UncoordinatedPut(wi); - } - data_offset += p.blob_size_; - } - off_t f_offset = off + data_offset; - if (opts.seek_) { stat.st_ptr = f_offset; } - stat.st_size = std::max(stat.st_size, static_cast(f_offset)); - - struct timespec ts; - timespec_get(&ts, TIME_UTC); - stat.st_mtim = ts; - stat.st_ctim = ts; - - mdm->Update(f, stat); - ret = data_offset; - _IoStats(data_offset, io_status, opts); - return ret; -} - -bool Lock(const std::string &bucket, const std::string &blob_name) { - auto mdm = Singleton::GetInstance(); - auto &hermes = mdm->GetHermes(); - SharedMemoryContext *context = &hermes->context_; - RpcContext *rpc = &hermes->rpc_; - BucketId bucket_id = GetBucketId(context, rpc, bucket.c_str()); - BlobId lock_id = GetBlobId(context, rpc, blob_name, bucket_id, true); - bool ret = LockBlob(context, rpc, lock_id); - return ret; -} - -void Unlock(const std::string &bucket, const std::string &blob_name) { - auto mdm = Singleton::GetInstance(); - auto &hermes = mdm->GetHermes(); - SharedMemoryContext *context = &hermes->context_; - RpcContext *rpc = &hermes->rpc_; - BucketId bucket_id = GetBucketId(context, rpc, bucket.c_str()); - BlobId lock_id = GetBlobId(context, rpc, blob_name, bucket_id, true); - UnlockBlob(context, rpc, lock_id); -} - -void Filesystem::_CoordinatedPut(BlobPlacementIter &wi) { - LOG(INFO) << "Starting coordinate PUT" - << " blob: " << wi.p_.page_ - << " off: " << wi.p_.blob_off_ - << " size: " << wi.p_.blob_size_ - << " pid: " << getpid() << std::endl; - - // TODO(llogan): make put async, instead of doing a lock like this - Lock(wi.filename_, wi.stat_.main_lock_blob); - LOG(INFO) << "Acquire lock: " << wi.stat_.main_lock_blob << - " for process: " << getpid() << std::endl; - wi.blob_exists_ = wi.bkt_->ContainsBlob(wi.blob_name_); - _UncoordinatedPut(wi); - LOG(INFO) << "Unlocking for process: " << getpid() << std::endl; - Unlock(wi.filename_, wi.stat_.main_lock_blob); -} - -void Filesystem::_UncoordinatedPut(BlobPlacementIter &wi) { - LOG(INFO) << "Starting uncoordinate PUT" - << " blob: " << wi.p_.page_ - << " off: " << wi.p_.blob_off_ - << " size: " << wi.p_.blob_size_ - << " pid: " << getpid() << std::endl; - if (wi.blob_exists_) { - if (wi.p_.blob_off_ == 0) { - _WriteToExistingAligned(wi); - } else { - _WriteToExistingUnaligned(wi); - } - } else { - if (wi.p_.blob_off_ == 0) { - _WriteToNewAligned(wi); - } else { - _WriteToNewUnaligned(wi); - } - } - if (IsAsyncFlush(wi.filename_)) { - hapi::Trait *trait = wi.stat_.st_vbkt->GetTrait(hapi::TraitType::PERSIST); - if (trait) { - hapi::PersistTrait *persist_trait = (hapi::PersistTrait *)trait; - persist_trait->offset_map.emplace(wi.blob_name_, wi.blob_start_); - } - wi.stat_.st_vbkt->Link(wi.blob_name_, wi.filename_); - } -} - -void Filesystem::_WriteToNewAligned(BlobPlacementIter &wi) { - LOG(INFO) << "Create new blob (aligned)" - << " offset: " << wi.p_.blob_off_ - << " size: " << wi.p_.blob_size_ << std::endl; - _PutWithFallback(wi.stat_, wi.blob_name_, wi.filename_, wi.mem_ptr_, - wi.p_.blob_size_, wi.p_.bucket_off_, - wi.io_status_, wi.opts_); -} - -void Filesystem::_WriteToNewUnaligned(BlobPlacementIter &wi) { - LOG(INFO) << "Create new blob (unaligned)" - << " offset: " << wi.p_.blob_off_ - << " size: " << wi.p_.blob_size_ << std::endl; - hapi::Blob final_data(wi.p_.blob_off_ + wi.p_.blob_size_); - IoOptions opts = IoOptions::DirectIo(wi.opts_); - Read(wi.f_, wi.stat_, final_data.data(), wi.blob_start_, - wi.p_.blob_off_, wi.io_status_, opts); - memcpy(final_data.data() + wi.p_.blob_off_, wi.mem_ptr_, - wi.p_.blob_size_); - _PutWithFallback(wi.stat_, wi.blob_name_, wi.filename_, - final_data.data(), final_data.size(), wi.blob_start_, - wi.io_status_, wi.opts_); -} - -void Filesystem::_WriteToExistingAligned(BlobPlacementIter &wi) { - LOG(INFO) << "Modify existing blob (aligned)" - << " offset: " << wi.p_.blob_off_ - << " size: " << wi.p_.blob_size_ << std::endl; - - hapi::Blob temp(0); - auto existing_blob_size = wi.bkt_->Get(wi.blob_name_, temp); - if (wi.p_.blob_size_ >= existing_blob_size) { - LOG(INFO) << "Overwrite blob " << wi.blob_name_ - << " of size:" << wi.p_.blob_size_ << "." << std::endl; - _PutWithFallback(wi.stat_, wi.blob_name_, wi.filename_, - wi.mem_ptr_, wi.p_.blob_size_, wi.blob_start_, - wi.io_status_, wi.opts_); - } else { - LOG(INFO) << "Update blob " << wi.blob_name_ - << " of size:" << existing_blob_size << "." << std::endl; - hapi::Blob existing_data(existing_blob_size); - wi.bkt_->Get(wi.blob_name_, existing_data); - memcpy(existing_data.data(), wi.mem_ptr_, wi.p_.blob_size_); - _PutWithFallback(wi.stat_, wi.blob_name_, wi.filename_, - existing_data.data(), existing_data.size(), - wi.blob_start_, wi.io_status_, wi.opts_); - } -} - -void Filesystem::_WriteToExistingUnaligned(BlobPlacementIter &wi) { - LOG(INFO) << "Modify existing blob (unaligned)" - << " offset: " << wi.p_.blob_off_ - << " size: " << wi.p_.blob_size_ << std::endl; - - auto new_size = wi.p_.blob_off_ + wi.p_.blob_size_; - hapi::Blob temp(0); - auto existing_blob_size = wi.bkt_->Get(wi.blob_name_, temp); - hapi::Blob existing_data(existing_blob_size); - wi.bkt_->Get(wi.blob_name_, existing_data); - wi.bkt_->DeleteBlob(wi.blob_name_); - if (new_size < existing_blob_size) { - new_size = existing_blob_size; - } - hapi::Blob final_data(new_size); - - // [0, existing_data) - memcpy(final_data.data(), existing_data.data(), - existing_data.size()); - - // [existing_data, blob_off) - if (existing_data.size() < wi.p_.blob_off_) { - IoOptions opts = IoOptions::DirectIo(wi.opts_); - Read(wi.f_, wi.stat_, - final_data.data() + existing_data.size(), - wi.blob_start_ + existing_data.size(), - wi.p_.blob_off_ - existing_data.size(), - wi.io_status_, - opts); - } - - // [blob_off, blob_off + blob_size) - memcpy(final_data.data() + wi.p_.blob_off_, wi.mem_ptr_, - wi.p_.blob_size_); - - // [blob_off + blob_size, existing_blob_size) - if (existing_blob_size > wi.p_.blob_off_ + wi.p_.blob_size_) { - LOG(INFO) << "Retain last portion of blob as Blob is bigger than the " - "update." << std::endl; - auto off_t = wi.p_.blob_off_ + wi.p_.blob_size_; - memcpy(final_data.data() + off_t, existing_data.data() + off_t, - existing_blob_size - off_t); - } - - // Store updated blob - _PutWithFallback(wi.stat_, wi.blob_name_, wi.filename_, - final_data.data(), - final_data.size(), - wi.blob_start_, - wi.io_status_, - wi.opts_); -} - -size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, - size_t off, size_t total_size, - IoStatus &io_status, IoOptions opts) { - (void) f; - std::shared_ptr &bkt = stat.st_bkid; - LOG(INFO) << "Read called for filename: " << bkt->GetName() - << " (fd: " << f.fd_ << ")" - << " on offset: " << off - << " and size: " << total_size - << " (stored file size: " << stat.st_size - << " true file size: " << stdfs::file_size(bkt->GetName()) - << ")" << std::endl; - if (static_cast(stat.st_ptr) >= stat.st_size) { - LOG(INFO) << "The current offset: " << stat.st_ptr << - " is larger than file size: " << stat.st_size << std::endl; - return 0; - } - size_t ret; - BlobPlacements mapping; - auto mdm = Singleton::GetInstance(); - auto mapper = MapperFactory().Get(kMapperType); - mapper->map(off, total_size, mapping); - - size_t data_offset = 0; - auto filename = bkt->GetName(); - LOG(INFO) << "Mapping for read has " << mapping.size() << " mapping." - << std::endl; - for (const auto &p : mapping) { - BlobPlacementIter ri(f, stat, filename, p, bkt, io_status, opts); - ri.blob_name_ = ri.p_.CreateBlobName(); - ri.blob_exists_ = bkt->ContainsBlob(ri.blob_name_); - ri.blob_start_ = ri.p_.page_ * kPageSize; - ri.mem_ptr_ = (u8 *)ptr + data_offset; - size_t read_size; - if (ri.blob_exists_) { - size_t min_blob_size = p.blob_off_ + p.blob_size_; - auto existing_blob_size = bkt->Get( - ri.blob_name_, ri.blob_, ri.ctx_); - ri.blob_.resize(existing_blob_size); - if (existing_blob_size >= min_blob_size) { - read_size = _ReadExistingContained(ri); - } else { - read_size = _ReadExistingPartial(ri); - } - } else { - read_size = _ReadNew(ri); - } - data_offset += read_size; - } - if (opts.seek_) { stat.st_ptr += data_offset; } - struct timespec ts; - timespec_get(&ts, TIME_UTC); - stat.st_atim = ts; - stat.st_ctim = ts; - ret = data_offset; - mdm->Update(f, stat); - _IoStats(data_offset, io_status, opts); - return ret; -} - -size_t Filesystem::_ReadExistingContained(BlobPlacementIter &ri) { - LOG(INFO) << "Blob exists and need to read from Hermes from blob: " - << ri.blob_name_ << "." << std::endl; - LOG(INFO) << "Blob have data and need to read from hemes " - "blob: " - << ri.blob_name_ << " offset:" << ri.p_.blob_off_ - << " size:" << ri.p_.blob_size_ << "." << std::endl; - - ri.bkt_->Get(ri.blob_name_, ri.blob_, ri.ctx_); - memcpy(ri.mem_ptr_, ri.blob_.data() + ri.p_.blob_off_, ri.p_.blob_size_); - return ri.p_.blob_size_; -} - -size_t Filesystem::_ReadExistingPartial(BlobPlacementIter &ri) { - LOG(INFO) << "Blob exists and need to partially read from Hermes from blob: " - << ri.blob_name_ << "." << std::endl; - /*if (!stdfs::exists(filename) || - stdfs::file_size(filename) < p.bucket_off_ + p.blob_off_ + p.blob_size_) { - return 0; - }*/ - size_t min_blob_size = ri.p_.blob_off_ + ri.p_.blob_size_; - size_t existing_size = ri.blob_.size(); - size_t new_blob_size = std::max(min_blob_size, existing_size); - size_t bytes_to_read = min_blob_size - existing_size; - ri.blob_.resize(new_blob_size); - - LOG(INFO) << "Blob does not have data and need to read from original " - "filename: " - << ri.filename_ << " offset:" << ri.blob_start_ + existing_size - << " size:" << bytes_to_read << "." - << std::endl; - - size_t ret = _RealRead(ri.filename_, - ri.blob_start_ + existing_size, - bytes_to_read, - ri.blob_.data() + existing_size, - ri.io_status_, - ri.opts_); - - if (ri.opts_.dpe_ != PlacementPolicy::kNone) { - IoOptions opts(ri.opts_); - opts.seek_ = false; - opts.with_fallback_ = false; - Write(ri.f_, ri.stat_, - ri.blob_.data() + ri.p_.blob_off_, - ri.p_.bucket_off_, - new_blob_size, ri.io_status_, opts); - } - - if (ret != bytes_to_read) { - LOG(FATAL) << "Was not able to read all data from the file" << std::endl; - } - - memcpy(ri.mem_ptr_, ri.blob_.data() + ri.p_.blob_off_, ri.p_.blob_size_); - return ri.p_.blob_size_; -} - -size_t Filesystem::_ReadNew(BlobPlacementIter &ri) { - LOG(INFO) - << "Blob does not exists and need to read from original filename: " - << ri.filename_ << " offset:" << ri.p_.bucket_off_ - << " size:" << ri.p_.blob_size_ << "." << std::endl; - - /*if (!stdfs::exists(filename) || - stdfs::file_size(filename) < p.bucket_off_ + p.blob_size_) { - return 0; - }*/ - - auto new_blob_size = ri.p_.blob_off_ + ri.p_.blob_size_; - ri.blob_.resize(new_blob_size); - size_t ret = _RealRead(ri.filename_, ri.blob_start_, - new_blob_size, ri.blob_.data(), - ri.io_status_, ri.opts_); - if (ret != new_blob_size) { - LOG(FATAL) << "Was not able to read full content" << std::endl; - } - - if (ri.opts_.dpe_ != PlacementPolicy::kNone) { - LOG(INFO) << "Placing the read blob in the hierarchy" << std::endl; - IoOptions opts = IoOptions::PlaceInHermes(ri.opts_); - Write(ri.f_, ri.stat_, - ri.blob_.data() + ri.p_.blob_off_, - ri.p_.bucket_off_, - new_blob_size, ri.io_status_, opts); - } - - memcpy(ri.mem_ptr_, ri.blob_.data() + ri.p_.blob_off_, ri.p_.blob_size_); - return ri.p_.blob_size_; -} - -HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, - size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { - (void) io_status; - LOG(INFO) << "Starting an asynchronous write" << std::endl; - auto pool = - Singleton::GetInstance(kNumThreads); - HermesRequest *hreq = new HermesRequest(); - auto lambda = - [](Filesystem *fs, File &f, AdapterStat &stat, const void *ptr, - size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { - return fs->Write(f, stat, ptr, off, total_size, io_status, opts); - }; - auto func = std::bind(lambda, this, f, stat, ptr, off, - total_size, hreq->io_status, opts); - hreq->return_future = pool->run(func); - auto mdm = Singleton::GetInstance(); - mdm->request_map.emplace(req_id, hreq); - return hreq; -} - -HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, - size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { - (void) io_status; - auto pool = - Singleton::GetInstance(kNumThreads); - HermesRequest *hreq = new HermesRequest(); - auto lambda = - [](Filesystem *fs, File &f, AdapterStat &stat, void *ptr, - size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { - return fs->Read(f, stat, ptr, off, total_size, io_status, opts); - }; - auto func = std::bind(lambda, this, f, stat, - ptr, off, total_size, hreq->io_status, opts); - hreq->return_future = pool->run(func); - auto mdm = Singleton::GetInstance(); - mdm->request_map.emplace(req_id, hreq); - return hreq; -} - -size_t Filesystem::Wait(uint64_t req_id) { - auto mdm = Singleton::GetInstance(); - auto req_iter = mdm->request_map.find(req_id); - if (req_iter == mdm->request_map.end()) { - return 0; - } - HermesRequest *req = (*req_iter).second; - size_t ret = req->return_future.get(); - delete req; - return ret; -} - -void Filesystem::Wait(std::vector &req_ids, - std::vector &ret) { - for (auto &req_id : req_ids) { - ret.emplace_back(Wait(req_id)); - } -} - -off_t Filesystem::Seek(File &f, AdapterStat &stat, - SeekMode whence, off_t offset) { - if (stat.is_append) { - LOG(INFO) - << "File pointer not updating as file was opened in append mode." - << std::endl; - return -1; - } - auto mdm = Singleton::GetInstance(); - switch (whence) { - case SeekMode::kSet: { - stat.st_ptr = offset; - break; - } - case SeekMode::kCurrent: { - stat.st_ptr += offset; - break; - } - case SeekMode::kEnd: { - stat.st_ptr = stat.st_size + offset; - break; - } - default: { - // TODO(hari): throw not implemented error. - } - } - mdm->Update(f, stat); - return stat.st_ptr; -} - -off_t Filesystem::Tell(File &f, AdapterStat &stat) { - (void) f; - return stat.st_ptr; -} - -int Filesystem::Sync(File &f, AdapterStat &stat) { - int rank = 0; - auto mdm = Singleton::GetInstance(); - if (stat.ref_count != 1) { - LOG(INFO) << "File handler is opened by more than one fopen." - << std::endl; - struct timespec ts; - timespec_get(&ts, TIME_UTC); - stat.st_atim = ts; - stat.st_ctim = ts; - mdm->Update(f, stat); - return 0; - } - if (mdm->is_mpi) { - MPI_Comm_rank(stat.comm, &rank); - MPI_Barrier(stat.comm); - } - - // Wait for all async requests to complete - for (auto &req : mdm->request_map) { - Wait(req.first); - } - - hapi::Context ctx; - auto filename = stat.st_bkid->GetName(); - auto persist = INTERCEPTOR_LIST->Persists(filename); - const auto &blob_names = stat.st_blobs; - if (blob_names.empty() || !persist) { - return 0; - } - if (IsAsyncFlush(filename)) { - LOG(INFO) << "Asynchronous flushing enabled" << std::endl; - stat.st_vbkt->WaitForBackgroundFlush(); - return 0; - } - - LOG(INFO) << "Filesystem Sync flushes " << blob_names.size() - << " blobs to filename:" << filename << "." << std::endl; - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(filename); - - std::string vbucket_name = filename + "#" + - std::to_string(rank) + "#sync"; - hapi::VBucket file_vbucket(vbucket_name, mdm->GetHermes(), ctx); - auto offset_map = std::unordered_map(); - for (const auto &blob_name : blob_names) { - auto status = file_vbucket.Link(blob_name, filename, ctx); - if (!status.Failed()) { - BlobPlacement p; - p.DecodeBlobName(blob_name); - offset_map.emplace(blob_name, p.page_ * kPageSize); - } - } - bool flush_synchronously = true; - hapi::PersistTrait persist_trait(filename, offset_map, - flush_synchronously); - file_vbucket.Attach(&persist_trait, ctx); - file_vbucket.Destroy(ctx); - stat.st_blobs.clear(); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(filename); - mdm->Update(f, stat); - return _RealSync(f); -} - -void SaveModifiedBlobSet(AdapterStat &stat) { - int rank = 0; - auto mdm = Singleton::GetInstance(); - if (mdm->is_mpi) { - MPI_Comm_rank(stat.comm, &rank); - } - auto filename = stat.st_bkid->GetName(); - const auto &blob_names = stat.st_blobs; - std::string vbucket_name = filename + "#" + - std::to_string(rank) + "#sync"; - hapi::VBucket file_vbucket(vbucket_name, mdm->GetHermes()); - auto offset_map = std::unordered_map(); - for (const auto &blob_name : blob_names) { - file_vbucket.Link(blob_name, filename); - } -} - -int Filesystem::Close(File &f, AdapterStat &stat, bool destroy) { - hapi::Context ctx; - int rank = 0; - auto mdm = Singleton::GetInstance(); - if (stat.ref_count > 1) { - LOG(INFO) << "File handler is opened by more than one fopen." - << std::endl; - stat.ref_count--; - struct timespec ts; - timespec_get(&ts, TIME_UTC); - stat.st_atim = ts; - stat.st_ctim = ts; - stat.st_bkid->Release(ctx); - if (stat.st_vbkt) { stat.st_vbkt->Release(); } - mdm->Update(f, stat); - return 0; - } - if (mdm->is_mpi) { - MPI_Comm_rank(stat.comm, &rank); - if (rank != 0) { - stat.st_bkid->Release(ctx); - } - MPI_Barrier(stat.comm); - } - if (INTERCEPTOR_LIST->adapter_mode == AdapterMode::kScratch || - INTERCEPTOR_LIST->adapter_mode == AdapterMode::kWorkflow) { - destroy = false; - } - - Sync(f, stat); // TODO(llogan): should wait until hermes destroyed to flush - auto filename = stat.st_bkid->GetName(); - if (mdm->is_mpi) { MPI_Barrier(stat.comm); } - if (IsAsyncFlush(filename)) { - stat.st_vbkt->Destroy(); - } - mdm->Delete(f); - if (mdm->is_mpi) { MPI_Barrier(stat.comm); } - if (destroy) { - stat.st_bkid->Destroy(ctx); - } - if (stat.amode & MPI_MODE_DELETE_ON_CLOSE) { - stdfs::remove(filename); - } - mdm->FinalizeHermes(); - return _RealClose(f); -} - - -/** - * Variants of Read and Write which do not take an offset as - * input. - * */ - -size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, - size_t total_size, IoStatus &io_status, - IoOptions opts) { - off_t off = Tell(f, stat); - return Write(f, stat, ptr, off, total_size, io_status, opts); -} - -size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, - size_t total_size, - IoStatus &io_status, IoOptions opts) { - off_t off = Tell(f, stat); - return Read(f, stat, ptr, off, total_size, io_status, opts); -} - -HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, - size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { - off_t off = Tell(f, stat); - return AWrite(f, stat, ptr, off, total_size, req_id, io_status, opts); -} - -HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, - size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { - off_t off = Tell(f, stat); - return ARead(f, stat, ptr, off, total_size, req_id, io_status, opts); -} - - -/** - * Variants of the above functions which retrieve the AdapterStat - * data structure internally. - * */ - -size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, - size_t total_size, - IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return 0; - } - stat_exists = true; - return Write(f, stat, ptr, total_size, io_status, opts); -} - -size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, - size_t total_size, - IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return 0; - } - stat_exists = true; - return Read(f, stat, ptr, total_size, io_status, opts); -} - -size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, - size_t off, size_t total_size, - IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return 0; - } - stat_exists = true; - opts.seek_ = false; - return Write(f, stat, ptr, off, total_size, io_status, opts); -} - -size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, - size_t off, size_t total_size, - IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return 0; - } - stat_exists = true; - opts.seek_ = false; - return Read(f, stat, ptr, off, total_size, io_status, opts); -} - -HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, - size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return 0; - } - stat_exists = true; - return AWrite(f, stat, ptr, total_size, req_id, io_status, opts); -} - -HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, - size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return 0; - } - stat_exists = true; - return ARead(f, stat, ptr, total_size, req_id, io_status, opts); -} - -HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, - size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return 0; - } - stat_exists = true; - opts.seek_ = false; - return AWrite(f, stat, ptr, off, total_size, req_id, io_status, opts); -} - -HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, - size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return 0; - } - stat_exists = true; - opts.seek_ = false; - return ARead(f, stat, ptr, off, total_size, req_id, io_status, opts); -} - -off_t Filesystem::Seek(File &f, bool &stat_exists, - SeekMode whence, off_t offset) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Seek(f, stat, whence, offset); -} - -off_t Filesystem::Tell(File &f, bool &stat_exists) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Tell(f, stat); -} - -int Filesystem::Sync(File &f, bool &stat_exists) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Sync(f, stat); -} - -int Filesystem::Close(File &f, bool &stat_exists, bool destroy) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Close(f, stat, destroy); -} - -} // namespace hermes::adapter::fs diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h deleted file mode 100644 index dc7741303..000000000 --- a/adapter/filesystem/filesystem.h +++ /dev/null @@ -1,475 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_H_ -#define HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_H_ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "enumerations.h" -#include "mapper/mapper_factory.h" - -namespace hapi = hermes::api; - -namespace hermes::adapter::fs { - -const char kStringDelimiter = '#'; -const MapperType kMapperType = MapperType::BALANCED; -FlushingMode global_flushing_mode; -const int kNumThreads = 1; - -enum class SeekMode { - kNone = -1, - kSet = SEEK_SET, - kCurrent = SEEK_CUR, - kEnd = SEEK_END -}; - -/** - A structure to represent adapter stat. -*/ -struct AdapterStat { - std::shared_ptr st_bkid; /**< bucket associated with the file */ - /** VBucket for persisting data asynchronously. */ - std::shared_ptr st_vbkt; - /** Blob for locking when coordination is needed. */ - std::string main_lock_blob; - /** Used for async flushing. */ - std::shared_ptr st_persist; - std::set - st_blobs; /**< Blobs access in the bucket */ - i32 ref_count; /**< # of time process opens a file */ - int flags; /**< open() flags for POSIX */ - mode_t st_mode; /**< protection */ - uid_t st_uid; /**< user ID of owner */ - gid_t st_gid; /**< group ID of owner */ - size_t st_size; /**< total size, in bytes */ - off_t st_ptr; /**< Current ptr of FILE */ - blksize_t st_blksize; /**< blocksize for blob within bucket */ - timespec st_atim; /**< time of last access */ - timespec st_mtim; /**< time of last modification */ - timespec st_ctim; /**< time of last status change */ - std::string mode_str; /**< mode used for fopen() */ - - bool is_append; /**< File is in append mode */ - int amode; /**< access mode */ - MPI_Info info; /**< Info object (handle) */ - MPI_Comm comm; /**< Communicator for the file.*/ - bool atomicity; /**< Consistency semantics for data-access */ - - AdapterStat() - : st_bkid(), - st_blobs(CompareBlobs), - ref_count(1), - flags(0), - st_mode(), - st_uid(), - st_gid(), - st_size(0), - st_ptr(0), - st_blksize(4096), - st_atim(), - st_mtim(), - st_ctim(), - is_append(false), - amode(0), - comm(MPI_COMM_SELF), - atomicity(false) {} - /** compare \a a BLOB and \a b BLOB.*/ - static bool CompareBlobs(const std::string &a, const std::string &b) { - return std::stol(a) < std::stol(b); - } -}; - -/** - A structure to represent file -*/ -struct File { - int fd_; /**< file descriptor */ - FILE *fh_; /**< file handler */ - MPI_File mpi_fh_; /**< MPI file handler */ - - dev_t st_dev; /**< device */ - ino_t st_ino; /**< inode */ - bool status_; /**< status */ - int mpi_status_; /**< MPI status */ - - /** default file constructor */ - File() - : fd_(-1), - fh_(nullptr), - mpi_fh_(nullptr), - st_dev(-1), - st_ino(-1), - status_(true), - mpi_status_(MPI_SUCCESS) {} - - /** file constructor that copies \a old file */ - File(const File &old) { Copy(old); } - - /** file assignment operator that copies \a old file */ - File &operator=(const File &old) { - Copy(old); - return *this; - } - - /** copy \a old file */ - void Copy(const File &old) { - fd_ = old.fd_; - fh_ = old.fh_; - mpi_fh_ = old.mpi_fh_; - st_dev = old.st_dev; - st_ino = old.st_ino; - status_ = old.status_; - } - - /** file comparison operator */ - bool operator==(const File &old) const { - return (st_dev == old.st_dev) && (st_ino == old.st_ino) && - (mpi_fh_ == old.mpi_fh_); - } - - /** return hash value of this class */ - std::size_t hash() const { - std::size_t result; - std::size_t h1 = std::hash{}(st_dev); - std::size_t h2 = std::hash{}(st_ino); - std::size_t h3 = std::hash{}(mpi_fh_); - result = h1 ^ h2 ^ h3; - return result; - } -}; - -/** - A structure to represent IO options -*/ -struct IoOptions { - PlacementPolicy dpe_; /**< data placement policy */ - bool coordinate_; /**< use coordinate? */ - bool seek_; /**< use seek? */ - bool with_fallback_; /**< use fallback? */ - MPI_Datatype mpi_type_; /**< MPI data type */ - int count_; /**< option count */ - IoOptions() - : dpe_(PlacementPolicy::kNone), - coordinate_(true), - seek_(true), - with_fallback_(true), - mpi_type_(MPI_CHAR), - count_(0) {} - - /** return options with \a dpe parallel data placement engine */ - static IoOptions WithParallelDpe(PlacementPolicy dpe) { - IoOptions opts; - opts.dpe_ = dpe; - opts.coordinate_ = true; - return opts; - } - - /** return direct IO options by setting placement policy to none */ - static IoOptions DirectIo(IoOptions &cur_opts) { - IoOptions opts(cur_opts); - opts.seek_ = false; - opts.dpe_ = PlacementPolicy::kNone; - opts.with_fallback_ = true; - return opts; - } - - /** return IO options with \a mpi_type MPI data type */ - static IoOptions DataType(MPI_Datatype mpi_type, bool seek = true) { - IoOptions opts; - opts.mpi_type_ = mpi_type; - opts.seek_ = seek; - return opts; - } - - /** - * Ensure that I/O goes only to Hermes, and does not fall back to PFS. - * - * @param orig_opts The original options to modify - * */ - static IoOptions PlaceInHermes(IoOptions &orig_opts) { - IoOptions opts(orig_opts); - opts.seek_ = false; - opts.with_fallback_ = false; - return opts; - } -}; - -/** - A structure to represent IO status -*/ -struct IoStatus { - int mpi_ret_; /**< MPI return value */ - MPI_Status mpi_status_; /**< MPI status */ - MPI_Status *mpi_status_ptr_; /**< MPI status pointer */ - - IoStatus() : mpi_ret_(MPI_SUCCESS), mpi_status_ptr_(&mpi_status_) {} -}; - -/** - A structure to represent Hermes request -*/ -struct HermesRequest { - std::future return_future; /**< future result of async op. */ - IoStatus io_status; /**< IO status */ -}; - -/** - A structure to represent BLOB placement iterator -*/ -struct BlobPlacementIter { - File &f_; /**< file */ - AdapterStat &stat_; /**< adapter stat */ - const std::string &filename_; /**< file name */ - const BlobPlacement &p_; /**< BLOB placement */ - std::shared_ptr &bkt_; /**< bucket*/ - IoStatus &io_status_; /**< IO status */ - IoOptions &opts_; /**< IO options */ - - std::string blob_name_; /**< BLOB name */ - u8 *mem_ptr_; /**< pointer to memory */ - size_t blob_start_; /**< BLOB start */ - hapi::Context ctx_; /**< context */ - hapi::Blob blob_; /**< BLOB */ - int rank_; /**< MPI rank */ - int nprocs_; /**< number of processes */ - bool blob_exists_; /**< Does BLOB exist? */ - - /** iterate \a p BLOB placement */ - explicit BlobPlacementIter(File &f, AdapterStat &stat, - const std::string &filename, - const BlobPlacement &p, - std::shared_ptr &bkt, - IoStatus &io_status, IoOptions &opts) - : f_(f), - stat_(stat), - filename_(filename), - p_(p), - bkt_(bkt), - io_status_(io_status), - opts_(opts) {} -}; - -/** - A class to represent file system -*/ -class Filesystem { - public: - /** open \a path */ - File Open(AdapterStat &stat, const std::string &path); - /** open \a f File in \a path*/ - void Open(AdapterStat &stat, File &f, const std::string &path); - /** write */ - size_t Write(File &f, AdapterStat &stat, const void *ptr, size_t off, - size_t total_size, IoStatus &io_status, - IoOptions opts = IoOptions()); - /** read */ - size_t Read(File &f, AdapterStat &stat, void *ptr, size_t off, - size_t total_size, IoStatus &io_status, - IoOptions opts = IoOptions()); - /** write asynchronously */ - HermesRequest *AWrite(File &f, AdapterStat &stat, const void *ptr, size_t off, - size_t total_size, size_t req_id, IoStatus &io_status, - IoOptions opts = IoOptions()); - /** read asynchronously */ - HermesRequest *ARead(File &f, AdapterStat &stat, void *ptr, size_t off, - size_t total_size, size_t req_id, IoStatus &io_status, - IoOptions opts = IoOptions()); - /** wait for \a req_id request ID */ - size_t Wait(uint64_t req_id); - /** wait for request IDs in \a req_id vector */ - void Wait(std::vector &req_id, std::vector &ret); - /** seek */ - off_t Seek(File &f, AdapterStat &stat, SeekMode whence, off_t offset); - /** tell */ - off_t Tell(File &f, AdapterStat &stat); - /** sync */ - int Sync(File &f, AdapterStat &stat); - /** close */ - int Close(File &f, AdapterStat &stat, bool destroy = true); - - /* - * APIs used internally - * */ - - private: - /** coordinated put */ - void _CoordinatedPut(BlobPlacementIter &wi); - /** uncoordinated put */ - void _UncoordinatedPut(BlobPlacementIter &wi); - /** write to a new aligned buffer */ - void _WriteToNewAligned(BlobPlacementIter &write_iter); - /** write to a new unaligned buffer */ - void _WriteToNewUnaligned(BlobPlacementIter &write_iter); - /** write to an existing aligned buffer */ - void _WriteToExistingAligned(BlobPlacementIter &write_iter); - /** write to an existing unaligned buffer */ - void _WriteToExistingUnaligned(BlobPlacementIter &write_iter); - /** put with fallback */ - void _PutWithFallback(AdapterStat &stat, const std::string &blob_name, - const std::string &filename, u8 *data, size_t size, - size_t offset, IoStatus &io_status_, IoOptions &opts); - /** read existing contained buffer */ - size_t _ReadExistingContained(BlobPlacementIter &read_iter); - /** read existing partial buffer */ - size_t _ReadExistingPartial(BlobPlacementIter &read_iter); - /** read new buffer */ - size_t _ReadNew(BlobPlacementIter &read_iter); - - void _OpenInitStatsInternal(AdapterStat &stat, bool bucket_exists) { - // TODO(llogan): This isn't really parallel-safe. - /** - * Here we assume that the file size can only be growing. - * If the bucket already exists and has content not already in - * the file (e.g., when using ADAPTER_MODE=SCRATCH), we should - * use the size of the bucket instead. - * - * There are other concerns with what happens during multi-tenancy. - * What happens if one process is opening a file, while another - * process is adding content? The mechanics here aren't - * well-defined. - * */ - if (bucket_exists) { - size_t orig = stat.st_size; - size_t bkt_size = stat.st_bkid->GetTotalBlobSize(); - stat.st_size = std::max(bkt_size, orig); - LOG(INFO) << "Since bucket exists, should reset its size to: " - << bkt_size << " or " << orig - << ", winner: " << stat.st_size << std::endl; - } - if (stat.is_append) { - stat.st_ptr = stat.st_size; - } - } - - /* - * The APIs to overload - */ - public: - /** initialize file */ - virtual void _InitFile(File &f) = 0; - - private: - /** open initial status */ - virtual void _OpenInitStats(File &f, AdapterStat &stat) = 0; - /** real open */ - virtual File _RealOpen(AdapterStat &stat, const std::string &path) = 0; - /** real write */ - virtual size_t _RealWrite(const std::string &filename, off_t offset, - size_t size, const u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) = 0; - /** real read */ - virtual size_t _RealRead(const std::string &filename, off_t offset, - size_t size, u8 *data_ptr, IoStatus &io_status, - IoOptions &opts) = 0; - /** io status */ - virtual void _IoStats(size_t count, IoStatus &io_status, IoOptions &opts) { - (void)count; - (void)io_status; - (void)opts; - } - /** real sync */ - virtual int _RealSync(File &f) = 0; - /** real close */ - virtual int _RealClose(File &f) = 0; - - /* - * I/O APIs which seek based on the internal AdapterStat st_ptr, - * instead of taking an offset as input. - */ - - public: - /** write */ - size_t Write(File &f, AdapterStat &stat, const void *ptr, size_t total_size, - IoStatus &io_status, IoOptions opts); - /** read */ - size_t Read(File &f, AdapterStat &stat, void *ptr, size_t total_size, - IoStatus &io_status, IoOptions opts); - /** write asynchronously */ - HermesRequest *AWrite(File &f, AdapterStat &stat, const void *ptr, - size_t total_size, size_t req_id, IoStatus &io_status, - IoOptions opts); - /** read asynchronously */ - HermesRequest *ARead(File &f, AdapterStat &stat, void *ptr, size_t total_size, - size_t req_id, IoStatus &io_status, IoOptions opts); - - /* - * Locates the AdapterStat data structure internally, and - * call the underlying APIs which take AdapterStat as input. - */ - - public: - /** write */ - size_t Write(File &f, bool &stat_exists, const void *ptr, size_t total_size, - IoStatus &io_status, IoOptions opts = IoOptions()); - /** read */ - size_t Read(File &f, bool &stat_exists, void *ptr, size_t total_size, - IoStatus &io_status, IoOptions opts = IoOptions()); - /** write \a off offset */ - size_t Write(File &f, bool &stat_exists, const void *ptr, size_t off, - size_t total_size, IoStatus &io_status, - IoOptions opts = IoOptions()); - /** read \a off offset */ - size_t Read(File &f, bool &stat_exists, void *ptr, size_t off, - size_t total_size, IoStatus &io_status, - IoOptions opts = IoOptions()); - /** write asynchronously */ - HermesRequest *AWrite(File &f, bool &stat_exists, const void *ptr, - size_t total_size, size_t req_id, IoStatus &io_status, - IoOptions opts); - /** read asynchronously */ - HermesRequest *ARead(File &f, bool &stat_exists, void *ptr, size_t total_size, - size_t req_id, IoStatus &io_status, IoOptions opts); - /** write \a off offset asynchronously */ - HermesRequest *AWrite(File &f, bool &stat_exists, const void *ptr, size_t off, - size_t total_size, size_t req_id, IoStatus &io_status, - IoOptions opts); - /** read \a off offset asynchronously */ - HermesRequest *ARead(File &f, bool &stat_exists, void *ptr, size_t off, - size_t total_size, size_t req_id, IoStatus &io_status, - IoOptions opts); - /** seek */ - off_t Seek(File &f, bool &stat_exists, SeekMode whence, off_t offset); - /** tell */ - off_t Tell(File &f, bool &stat_exists); - /** sync */ - int Sync(File &f, bool &stat_exists); - /** close */ - int Close(File &f, bool &stat_exists, bool destroy = true); -}; - -} // namespace hermes::adapter::fs - -namespace std { -/** - A structure to represent hash -*/ -template <> -struct hash { - /** hash creator functor */ - std::size_t operator()(const hermes::adapter::fs::File &key) const { - return key.hash(); - } -}; -} // namespace std - -#endif // HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_H_ diff --git a/adapter/filesystem/metadata_manager.cc b/adapter/filesystem/metadata_manager.cc deleted file mode 100644 index 9c151ccc0..000000000 --- a/adapter/filesystem/metadata_manager.cc +++ /dev/null @@ -1,57 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "metadata_manager.h" - -/** - * Namespace declarations for cleaner code. - */ -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::MetadataManager; - -bool MetadataManager::Create(const File &f, const AdapterStat &stat) { - VLOG(1) << "Create metadata for file handler." << std::endl; - auto ret = metadata.emplace(f, stat); - return ret.second; -} - -bool MetadataManager::Update(const File &f, const AdapterStat &stat) { - VLOG(1) << "Update metadata for file handler." << std::endl; - auto iter = metadata.find(f); - if (iter != metadata.end()) { - metadata.erase(iter); - auto ret = metadata.emplace(f, stat); - return ret.second; - } else { - return false; - } -} - -std::pair MetadataManager::Find(const File &f) { - typedef std::pair MetadataReturn; - auto iter = metadata.find(f); - if (iter == metadata.end()) - return MetadataReturn(AdapterStat(), false); - else - return MetadataReturn(iter->second, true); -} - -bool MetadataManager::Delete(const File &f) { - VLOG(1) << "Delete metadata for file handler." << std::endl; - auto iter = metadata.find(f); - if (iter != metadata.end()) { - metadata.erase(iter); - return true; - } else { - return false; - } -} diff --git a/adapter/filesystem/metadata_manager.h b/adapter/filesystem/metadata_manager.h deleted file mode 100644 index f71030e03..000000000 --- a/adapter/filesystem/metadata_manager.h +++ /dev/null @@ -1,151 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_METADATA_MANAGER_H -#define HERMES_ADAPTER_METADATA_MANAGER_H - -#include -#include - -#include -#include - -#include "constants.h" -#include "enumerations.h" -#include "filesystem.h" -#include "interceptor.h" - -namespace hermes::adapter::fs { -/** - * Metadata manager for POSIX adapter - */ -class MetadataManager { - private: - std::unordered_map metadata; /**< map for metadata*/ - std::shared_ptr hermes; /**< pointers for hermes */ - /** - * references of how many times hermes was tried to initialize. - */ - std::atomic ref; - - public: - /** map for Hermes request */ - std::unordered_map request_map; - bool is_mpi; /**< flag for checking if MPI is used */ - int rank; /**< rank of MPI processor */ - int comm_size; /**< number of MPI processors */ - - /** - * Constructor - */ - MetadataManager() - : metadata(), ref(0), is_mpi(false), rank(0), comm_size(1) {} - /** - * Get the instance of hermes. - */ - std::shared_ptr& GetHermes() { return hermes; } - - /** - * Initialize hermes. Get the kHermesConf from environment else get_env - * returns NULL which is handled internally by hermes. Initialize hermes in - * daemon mode. Keep a reference of how many times Initialize is called. - * Within the adapter, Initialize is called from fopen. - */ - void InitializeHermes(bool is_mpi = false) { - if (ref == 0) { - this->is_mpi = is_mpi; - char* hermes_config = getenv(kHermesConf); - char* hermes_client = getenv(kHermesClient); - char* async_flush_mode = getenv(kHermesAsyncFlush); - - if (async_flush_mode && async_flush_mode[0] == '1') { - global_flushing_mode = FlushingMode::kAsynchronous; - } else { - global_flushing_mode = FlushingMode::kSynchronous; - } - - if (this->is_mpi) { - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &comm_size); - - if ((hermes_client && hermes_client[0] == '1') || comm_size > 1) { - hermes = hermes::InitHermesClient(hermes_config); - } else { - this->is_mpi = false; - hermes = hermes::InitHermesDaemon(hermes_config); - } - } else { - hermes = hermes::InitHermesDaemon(hermes_config); - } - INTERCEPTOR_LIST->SetupAdapterMode(); - } - ref++; - } - /** - * Finalize hermes and close rpc if reference is equal to one. Else just - * decrement the ref counter. - */ - void FinalizeHermes() { - if (ref == 1) { - if (this->is_mpi) { - MPI_Barrier(MPI_COMM_WORLD); - char* stop_daemon = getenv(kStopDaemon); - bool shutdown_daemon = true; - if (stop_daemon && stop_daemon[0] == '0') { - shutdown_daemon = false; - } - hermes->FinalizeClient(shutdown_daemon); - } else { - hermes->Finalize(true); - } - } - ref--; - } - - /** - * Create a metadata entry for POSIX adapter for a given file handler. - * @param f original file handler of the file on the destination - * filesystem. - * @param stat POSIX Adapter version of Stat data structure. - * @return true, if operation was successful. - * false, if operation was unsuccessful. - */ - bool Create(const File& f, const AdapterStat& stat); - - /** - * Update existing metadata entry for POSIX adapter for a given file handler. - * @param f original file handler of the file on the destination. - * @param stat POSIX Adapter version of Stat data structure. - * @return true, if operation was successful. - * false, if operation was unsuccessful or entry doesn't exist. - */ - bool Update(const File& f, const AdapterStat& stat); - - /** - * Delete existing metadata entry for POSIX adapter for a given file handler. - * @param f original file handler of the file on the destination. - * @return true, if operation was successful. - * false, if operation was unsuccessful. - */ - bool Delete(const File& f); - - /** - * Find existing metadata entry for POSIX adapter for a given file handler. - * @param f original file handler of the file on the destination. - * @return The metadata entry if exist. - * The bool in pair indicated whether metadata entry exists. - */ - std::pair Find(const File& f); -}; -} // namespace hermes::adapter::fs - -#endif // HERMES_ADAPTER_METADATA_MANAGER_H diff --git a/adapter/interceptor.cc b/adapter/interceptor.cc deleted file mode 100644 index fb28f5f73..000000000 --- a/adapter/interceptor.cc +++ /dev/null @@ -1,164 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/** - * Internal headers - */ -#include "interceptor.h" -#include -#include -#include -#include "adapter_utils.h" -#include "config.h" - -namespace stdfs = std::experimental::filesystem; -const char* kPathExclusions[] = {"/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:"}; - -namespace hermes::adapter { -/** - * is exit by program called. - */ -bool exit = false; - -/** - * a flag for checking if buffering paths are populated or not - */ -bool populated = false; - -/** - populate buffering path -*/ -void PopulateBufferingPath() { - char* hermes_config = getenv(kHermesConf); - if (hermes_config == NULL) { - LOG(ERROR) << "HERMES_CONF is not set."; - return; - } - - if (stdfs::exists(hermes_config)) { - std::string hermes_conf_abs_path = - WeaklyCanonical(stdfs::path(hermes_config)).string(); - INTERCEPTOR_LIST->hermes_paths_exclusion.push_back(hermes_conf_abs_path); - } - hermes::Config config_stack = {}; - hermes::Config *config = &config_stack; - hermes::InitConfig(config, hermes_config); - for (const auto& item : config->mount_points) { - if (!item.empty()) { - std::string abs_path = WeaklyCanonical(item).string(); - INTERCEPTOR_LIST->hermes_paths_exclusion.push_back(abs_path); - } - } - for (const auto& item : config->path_exclusions) { - if (!item.empty()) { - std::string abs_path = WeaklyCanonical(item).string(); - INTERCEPTOR_LIST->hermes_paths_exclusion.push_back(abs_path); - } - } - for (const auto& item : config->path_inclusions) { - if (!item.empty()) { - std::string abs_path = WeaklyCanonical(item).string(); - INTERCEPTOR_LIST->hermes_paths_inclusion.push_back(abs_path); - } - } - INTERCEPTOR_LIST->hermes_paths_exclusion.push_back( - config->buffer_pool_shmem_name); - INTERCEPTOR_LIST->hermes_paths_exclusion.push_back(kHermesExtension); - - // NOTE(chogan): Logging before setting up hermes_paths_exclusion results in - // deadlocks in GLOG - LOG(INFO) << "Adapter page size: " << kPageSize << "\n"; - populated = true; -} - -/** - check if \a path is being tracked -*/ -bool IsTracked(const std::string& path) { - if (hermes::adapter::exit) { - return false; - } - atexit(OnExit); - - std::string abs_path = WeaklyCanonical(path).string(); - - for (const auto& pth : INTERCEPTOR_LIST->hermes_flush_exclusion) { - if (abs_path.find(pth) != std::string::npos) { - return false; - } - } - - if (INTERCEPTOR_LIST->hermes_paths_exclusion.empty()) { - PopulateBufferingPath(); - } - - for (const auto& pth : INTERCEPTOR_LIST->hermes_paths_inclusion) { - if (abs_path.find(pth) != std::string::npos) { - return true; - } - } - - for (auto &pth : kPathExclusions) { - if (abs_path.find(pth) != std::string::npos) { - return false; - } - } - - for (const auto& pth : INTERCEPTOR_LIST->hermes_paths_exclusion) { - if (abs_path.find(pth) != std::string::npos || - pth.find(abs_path) != std::string::npos) { - return false; - } - } - - auto list = INTERCEPTOR_LIST; - auto buffer_mode = INTERCEPTOR_LIST->adapter_mode; - if (buffer_mode == AdapterMode::kBypass) { - if (list->adapter_paths.empty()) { - return false; - } else { - for (const auto& pth : list->adapter_paths) { - if (path.find(pth) == 0) { - return false; - } - } - return true; - } - } else { - return true; - } -} - -/** - check if \a fh file handler is being tracked -*/ -bool IsTracked(FILE* fh) { - if (hermes::adapter::exit) return false; - atexit(OnExit); - return IsTracked(GetFilenameFromFP(fh)); -} - -/** - check if \a fd file descriptor is being tracked -*/ -bool IsTracked(int fd) { - if (hermes::adapter::exit) return false; - atexit(OnExit); - return IsTracked(GetFilenameFromFD(fd)); -} - -void OnExit(void) { hermes::adapter::exit = true; } - -} // namespace hermes::adapter diff --git a/adapter/interceptor.h b/adapter/interceptor.h deleted file mode 100644 index 9ed25463f..000000000 --- a/adapter/interceptor.h +++ /dev/null @@ -1,262 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_INTERCEPTOR_H -#define HERMES_INTERCEPTOR_H - -#include -#include - -#include -#include -#include -#include -#include - -#include "adapter_utils.h" -#include "constants.h" -#include "enumerations.h" -#include "singleton.h" - -/** - * Define Interceptor list for adapter. - */ -#define INTERCEPTOR_LIST \ - hermes::Singleton::GetInstance<>() - -#define HERMES_CONF hermes::Singleton::GetInstance() - -// Path lengths are up to 4096 bytes -const int kMaxPathLen = 4096; - -namespace hermes::adapter { - -/** - * Splits a string given a delimiter - */ -inline std::vector StringSplit(const char* str, char delimiter) { - std::stringstream ss(str); - std::vector v; - while (ss.good()) { - std::string substr; - getline(ss, substr, delimiter); - v.push_back(substr); - } - return v; -} - -/** - get the file name from \a fp file pointer -*/ -inline std::string GetFilenameFromFP(FILE* fp) { - char proclnk[kMaxPathLen]; - char filename[kMaxPathLen]; - int fno = fileno(fp); - snprintf(proclnk, kMaxPathLen, "/proc/self/fd/%d", fno); - size_t r = readlink(proclnk, filename, kMaxPathLen); - filename[r] = '\0'; - return filename; -} - -/** - get the file name from \a fd file descriptor -*/ -inline std::string GetFilenameFromFD(int fd) { - char proclnk[kMaxPathLen]; - char filename[kMaxPathLen]; - snprintf(proclnk, kMaxPathLen, "/proc/self/fd/%d", fd); - size_t r = readlink(proclnk, filename, kMaxPathLen); - filename[r] = '\0'; - return filename; -} - -/** - * Interceptor list defines files and directory that should be either excluded - * or included for interceptions. - */ -struct InterceptorList { - /** - - * hermes buffering mode. - */ - AdapterMode adapter_mode; - /** - * Scratch paths - */ - std::vector adapter_paths; - /** - * Allow adapter to include hermes specific files. - */ - std::vector hermes_paths_inclusion; - /** - * Allow adapter to exclude hermes specific files. - */ - std::vector hermes_paths_exclusion; - /** - * Allow adapter to exclude files which are currently flushed. - */ - std::unordered_set hermes_flush_exclusion; - - /** - * Default constructor - */ - InterceptorList() - : adapter_mode(AdapterMode::kDefault), - adapter_paths(), - hermes_paths_exclusion(), - hermes_flush_exclusion() {} - /** - set up adapter mode - default, bypass, or scratch - */ - void SetupAdapterMode() { - char* adapter_mode_str = getenv(kAdapterMode); - if (adapter_mode_str == nullptr) { - // default is Persistent mode - adapter_mode = AdapterMode::kDefault; - } else { - if (strcmp(kAdapterDefaultMode, adapter_mode_str) == 0) { - adapter_mode = AdapterMode::kDefault; - } else if (strcmp(kAdapterBypassMode, adapter_mode_str) == 0) { - adapter_mode = AdapterMode::kBypass; - } else if (strcmp(kAdapterScratchMode, adapter_mode_str) == 0) { - adapter_mode = AdapterMode::kScratch; - } else if (strcmp(kAdapterWorkflowMode, adapter_mode_str) == 0) { - adapter_mode = AdapterMode::kWorkflow; - } else { - // TODO(hari): @errorhandling throw error. - return; - } - } - char* adapter_paths_str = getenv(kAdapterModeInfo); - std::vector paths_local; - if (adapter_paths_str) { - paths_local = StringSplit(adapter_paths_str, kPathDelimiter); - } - adapter_paths = paths_local; - } - - /** - check if \a fp file pointer persists - */ - bool Persists(FILE* fp) { return Persists(GetFilenameFromFP(fp)); } - - /** - check if \a fd file descriptor persists - */ - bool Persists(int fd) { return Persists(GetFilenameFromFD(fd)); } - - /** - check if \a path file path persists - */ - bool Persists(std::string path) { - if (adapter_mode == AdapterMode::kDefault || - adapter_mode == AdapterMode::kWorkflow) { - if (adapter_paths.empty()) { - return true; - } else { - for (const auto& pth : adapter_paths) { - if (path.find(pth) == 0) { - return true; - } - } - return false; - } - } else if (adapter_mode == AdapterMode::kScratch) { - if (adapter_paths.empty()) { - return false; - } else { - for (const auto& pth : adapter_paths) { - if (path.find(pth) == 0) { - return false; - } - } - return true; - } - } - return true; - } -}; - -/** - * This method is bind in the runtime of the application. It is called during - * __exit of the program. This function avoid any internal c++ runtime call to - * get intercepted. On invocation, we set the adaptor to not intercept any - * calls. If we do not have this method, the program might try to access - * deallocated structures within adapter. - */ -void OnExit(void); - -} // namespace hermes::adapter - -/** - * HERMES_PRELOAD variable defines if adapter layer should intercept. - */ -#ifdef HERMES_PRELOAD -/** - * Typedef and function declaration for intercepted functions. - */ -#define HERMES_FORWARD_DECL(func_, ret_, args_) \ - typedef ret_(*real_t_##func_##_) args_; \ - ret_(*real_##func_##_) args_ = NULL; - -#define HERMES_DECL(func_) func_ -/** - * The input function is renamed as real__. And a ptr to function - * is obtained using dlsym. - */ -#define MAP_OR_FAIL(func_) \ - if (!(real_##func_##_)) { \ - real_##func_##_ = (real_t_##func_##_)dlsym(RTLD_NEXT, #func_); \ - if (!(real_##func_##_)) { \ - LOG(FATAL) << "HERMES Adapter failed to map symbol: " << #func_ \ - << std::endl; \ - } \ - } - -namespace hermes::adapter { -/** - * Loads the buffering paths for Hermes Adapter to exclude. It inserts the - * buffering mount points in the InclusionsList.hermes_paths_exclusion. - */ -void PopulateBufferingPath(); - -/** - * Check if path should be tracked. In this method, the path is compared against - * multiple inclusion and exclusion lists. - * - * @param path, const std::string&, path to be compared with exclusion and - * inclusion. - * @return true, if file should be tracked. - * false, if file should not be intercepted. - */ -bool IsTracked(const std::string& path); - -/** - * Check if fh should be tracked. In this method, first Convert fh to path. - * Then, call IsTracked(path). - * - * @param fh, file handlers to be compared for exclusion or inclusion. - * @return true, if file should be tracked. - * false, if file should not be intercepted. - */ -bool IsTracked(FILE* fh); -} // namespace hermes::adapter -#else -/** - * Do not intercept if HERMES_PRELOAD is not defined. - */ -#define HERMES_FORWARD_DECL(name_, ret_, args_) \ - extern ret_ real_##name_##_ args_; -#define HERMES_DECL(name_) wrap_##name_##_ -#define MAP_OR_FAIL(func_) -#endif -#endif // HERMES_INTERCEPTOR_H diff --git a/adapter/mapper/abstract_mapper.h b/adapter/mapper/abstract_mapper.h deleted file mode 100644 index f70269cd2..000000000 --- a/adapter/mapper/abstract_mapper.h +++ /dev/null @@ -1,94 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -// -// Created by manihariharan on 12/23/20. -// - -#ifndef HERMES_ABSTRACT_ADAPTER_H -#define HERMES_ABSTRACT_ADAPTER_H - -#include "interceptor.h" - -namespace hermes::adapter { - -/** - * Define different types of mappers supported by POSIX Adapter. - * Also define its construction in the MapperFactory. - */ -enum MapperType { - BALANCED = 0 /* Balanced Mapping */ -}; - -/** - A structure to represent BLOB placement -*/ -struct BlobPlacement { - int rank_; /**< The rank of the process producing the BLOB */ - size_t page_; /**< The index in the array placements */ - size_t bucket_off_; /**< Offset from file start (for FS) */ - size_t blob_off_; /**< Offset from BLOB start */ - size_t blob_size_; /**< Size after offset to read */ - int time_; /**< The order of the blob in a list of blobs */ - - /** create a BLOB name from index. */ - std::string CreateBlobName() const { return std::to_string(page_); } - - /** decode \a blob_name BLOB name to index. */ - void DecodeBlobName(const std::string &blob_name) { - std::stringstream(blob_name) >> page_; - } - - /** create a log entry for this BLOB using \a time. */ - std::string CreateBlobNameLogEntry(int time) const { - std::stringstream ss; - ss << std::to_string(page_); - ss << "#" << std::to_string(blob_off_); - ss << "#" << std::to_string(blob_size_); - ss << "#" << std::to_string(rank_); - ss << "#" << std::to_string(time); - return ss.str(); - } - - /** decode \a blob_name BLOB name by splitting it into index, offset, size, - and rank. */ - void DecodeBlobNameLogEntry(const std::string &blob_name) { - auto str_split = - hermes::adapter::StringSplit(blob_name.data(), '#'); - std::stringstream(str_split[0]) >> page_; - std::stringstream(str_split[1]) >> blob_off_; - std::stringstream(str_split[2]) >> blob_size_; - std::stringstream(str_split[3]) >> rank_; - std::stringstream(str_split[4]) >> time_; - } -}; - -typedef std::vector BlobPlacements; - -/** - A class to represent abstract mapper -*/ -class AbstractMapper { - public: - /** - * This method maps the current operation to Hermes data structures. - * - * @param off offset - * @param size size - * @param ps BLOB placement - * - */ - virtual void map(size_t off, size_t size, BlobPlacements &ps) = 0; -}; -} // namespace hermes::adapter - -#endif // HERMES_ABSTRACT_ADAPTER_H diff --git a/adapter/mapper/balanced_mapper.cc b/adapter/mapper/balanced_mapper.cc deleted file mode 100644 index e79fe81ca..000000000 --- a/adapter/mapper/balanced_mapper.cc +++ /dev/null @@ -1,40 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "balanced_mapper.h" -#include "constants.h" - -namespace hermes::adapter { - - /** - * This method maps the current Operation to Hermes data structures. - */ - void BalancedMapper::map(size_t off, size_t size, BlobPlacements &ps) { - VLOG(1) << "Mapping File with offset:" << off << " and size:" << size << "." - << std::endl; - - size_t size_mapped = 0; - while (size > size_mapped) { - BlobPlacement p; - p.bucket_off_ = off + size_mapped; - p.page_ = p.bucket_off_ / kPageSize; - p.blob_off_ = p.bucket_off_ % kPageSize; - auto left_size_page = kPageSize - p.blob_off_; - p.blob_size_ = left_size_page < size - size_mapped ? left_size_page - : size - size_mapped; - ps.emplace_back(p); - size_mapped += p.blob_size_; - } - } - - -} // namespace hermes::adapter diff --git a/adapter/mapper/balanced_mapper.h b/adapter/mapper/balanced_mapper.h deleted file mode 100644 index 343efc50c..000000000 --- a/adapter/mapper/balanced_mapper.h +++ /dev/null @@ -1,34 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_BALANCED_MAPPER_H -#define HERMES_BALANCED_MAPPER_H - -#include - -#include "abstract_mapper.h" - -namespace hermes::adapter { -/** - * Implement balanced mapping - */ -class BalancedMapper : public AbstractMapper { - public: - /** - * This method maps the current Operation to Hermes data structures. - * - */ - void map(size_t off, size_t size, BlobPlacements &ps) override; -}; -} // namespace hermes::adapter - -#endif // HERMES_BALANCED_MAPPER_H diff --git a/adapter/mapper/mapper_factory.h b/adapter/mapper/mapper_factory.h deleted file mode 100644 index a2d8203dc..000000000 --- a/adapter/mapper/mapper_factory.h +++ /dev/null @@ -1,46 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_FACTORY_H -#define HERMES_ADAPTER_FACTORY_H - -#include "abstract_mapper.h" -#include "balanced_mapper.cc" -#include "balanced_mapper.h" -#include "singleton.h" - -namespace hermes::adapter { -/** - A class to represent mapper factory pattern -*/ -class MapperFactory { - public: - /** - * Return the instance of mapper given a type. Uses factory pattern. - * - * @param[in] type type of mapper to be used by the POSIX adapter. - * @return Instance of mapper given a type. - */ - AbstractMapper* Get(const MapperType& type) { - switch (type) { - case MapperType::BALANCED: { - return hermes::Singleton::GetInstance(); - } - default: { - // TODO(hari): @error_handling Mapper not implemented - } - } - return NULL; - } -}; -} // namespace hermes::adapter -#endif // HERMES_ADAPTER_FACTORY_H diff --git a/adapter/metadata_manager.h b/adapter/metadata_manager.h deleted file mode 100644 index ff7a313b2..000000000 --- a/adapter/metadata_manager.h +++ /dev/null @@ -1,104 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_METADATA_MANAGER_H_ -#define HERMES_ADAPTER_METADATA_MANAGER_H_ - -#include -#include -#include -#include - -#include "constants.h" -#include "enumerations.h" -#include "interceptor.h" - -namespace hapi = hermes::api; - -namespace hermes::adapter { - -/** A variable for synchronous or asynchronous global flusing mode */ -FlushingMode global_flushing_mode; - -/** - A class to represent metadata manager -*/ -class MetadataManager { - protected: - int rank; /**< MPI communicator rank */ - int comm_size; /**< MPI communicator size */ - /** a reference of how many times Initialize is called */ - std::atomic ref; - std::shared_ptr hermes; /**< pointer to hermes instances */ - bool is_mpi_; /**< check whether MPI is being used or not */ - - public: - /** - * Initialize hermes. Get the kHermesConf from environment else get_env - * returns NULL which is handled internally by hermes. Initialize hermes in - * daemon mode. Keep a reference of how many times Initialize is called. - * Within the adapter, Initialize is called from fopen. - */ - - void InitializeHermes(bool is_mpi) { - if (ref == 0) { - is_mpi_ = is_mpi; - char* async_flush_mode = getenv(kHermesAsyncFlush); - - if (async_flush_mode && async_flush_mode[0] == '1') { - global_flushing_mode = FlushingMode::kAsynchronous; - } else { - global_flushing_mode = FlushingMode::kSynchronous; - } - - char* hermes_config = getenv(kHermesConf); - - if (is_mpi_) { - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &comm_size); - // TODO(chogan): Need a better way to distinguish between client and - // daemon. https://github.com/HDFGroup/hermes/issues/206 - if (comm_size > 1) { - hermes = hermes::InitHermesClient(hermes_config); - } else { - is_mpi_ = false; - hermes = hermes::InitHermesDaemon(hermes_config); - } - } else { - hermes = hermes::InitHermesDaemon(hermes_config); - } - } - ref++; - } - - /** - * Finalize hermes and close rpc if reference is equal to one. Else just - * decrement the ref counter. - */ - - void FinalizeHermes() { - if (ref == 1) { - hermes->FinalizeClient(); - } - ref--; - } - - /** - * Get the instance of hermes. - */ - - std::shared_ptr& GetHermes() { return hermes; } -}; - -} // namespace hermes::adapter - -#endif // HERMES_ADAPTER_METADATA_MANAGER_H_ diff --git a/adapter/mpiio/CMakeLists.txt b/adapter/mpiio/CMakeLists.txt deleted file mode 100644 index 556d95567..000000000 --- a/adapter/mpiio/CMakeLists.txt +++ /dev/null @@ -1,49 +0,0 @@ -project(MPIIOAdapter VERSION ${HERMES_PACKAGE_VERSION}) -include_directories(${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) - -# MPIIO src code. We only include mpiio.cc as it includes other cc to reduce compilation time. -set(MPIIO_ADAPTER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/mpiio.cc) - -set(HERMES_MPIIO_ADAPTER_DIR ${HERMES_ADAPTER_DIR}/mpiio) - -# Public headers -set(MPIIO_ADAPTER_PUBLIC_HEADER - ${HERMES_MPIIO_ADAPTER_DIR}/real_api.h - ${HERMES_MPIIO_ADAPTER_DIR}/fs_api.h) - -# Add library hermes_mpiio -add_library(hermes_mpiio_backend ${CMAKE_CURRENT_SOURCE_DIR}/fs_api.cc) -add_dependencies(hermes_mpiio_backend hermes) -target_link_libraries(hermes_mpiio_backend hermes MPI::MPI_CXX glog::glog stdc++fs) - -add_library(hermes_mpiio SHARED ${MPIIO_ADAPTER_PUBLIC_HEADER} ${MPIIO_ADAPTER_SRC}) -add_dependencies(hermes_mpiio hermes_mpiio_backend) -target_link_libraries(hermes_mpiio hermes_mpiio_backend) - -#----------------------------------------------------------------------------- -# Add Target(s) to CMake Install -#----------------------------------------------------------------------------- -install( - TARGETS - hermes_mpiio_backend - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) -install( - TARGETS - hermes_mpiio - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) -#----------------------------------------------------------------------------- -# Add Target(s) to Coverage -#----------------------------------------------------------------------------- -if(HERMES_ENABLE_COVERAGE) - set_coverage_flags(hermes_mpiio) -endif() diff --git a/adapter/mpiio/fs_api.cc b/adapter/mpiio/fs_api.cc deleted file mode 100644 index aff31e030..000000000 --- a/adapter/mpiio/fs_api.cc +++ /dev/null @@ -1,622 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "fs_api.h" - -namespace hermes::adapter::mpiio { - -size_t IoSizeFromCount(int count, MPI_Datatype datatype, IoOptions &opts) { - int datatype_size; - opts.mpi_type_ = datatype; - opts.count_ = count; - MPI_Type_size(datatype, &datatype_size); - return static_cast(count * datatype_size); -} - -int MpiioFS::Read(File &f, AdapterStat &stat, - void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status, IoOptions opts) { - opts.mpi_type_ = datatype; - if (offset + count >= static_cast(stat.st_size)) { - status->count_hi_and_cancelled = 0; - status->count_lo = 0; - return 0; - } - IoStatus io_status; - io_status.mpi_status_ptr_ = status; - size_t total_size = IoSizeFromCount(count, datatype, opts); - Filesystem::Read(f, stat, ptr, offset, - total_size, io_status, opts); - return io_status.mpi_ret_; -} - -int MpiioFS::ARead(File &f, AdapterStat &stat, - void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Request *request, IoOptions opts) { - opts.mpi_type_ = datatype; - IoStatus io_status; - size_t total_size = IoSizeFromCount(count, datatype, opts); - Filesystem::ARead(f, stat, ptr, offset, total_size, - reinterpret_cast(request), - io_status, opts); - return io_status.mpi_ret_; -} - -int MpiioFS::ReadAll(File &f, AdapterStat &stat, - void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status, IoOptions opts) { - opts.mpi_type_ = datatype; - MPI_Barrier(stat.comm); - size_t ret = Read(f, stat, ptr, offset, count, datatype, status, opts); - MPI_Barrier(stat.comm); - return ret; -} - -int MpiioFS::ReadOrdered(File &f, AdapterStat &stat, - void *ptr, int count, - MPI_Datatype datatype, - MPI_Status *status, IoOptions opts) { - opts.mpi_type_ = datatype; - - int total; - MPI_Scan(&count, &total, 1, MPI_INT, MPI_SUM, stat.comm); - MPI_Offset my_offset = total - count; - size_t ret = ReadAll(f, stat, ptr, my_offset, count, datatype, status, opts); - return ret; -} - -int MpiioFS::Write(File &f, AdapterStat &stat, - const void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status, IoOptions opts) { - opts.mpi_type_ = datatype; - IoStatus io_status; - io_status.mpi_status_ptr_ = status; - size_t total_size = IoSizeFromCount(count, datatype, opts); - Filesystem::Write(f, stat, ptr, offset, total_size, - io_status, opts); - return io_status.mpi_ret_; -} - -int MpiioFS::AWrite(File &f, AdapterStat &stat, - const void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Request *request, IoOptions opts) { - opts.mpi_type_ = datatype; - IoStatus io_status; - size_t total_size = IoSizeFromCount(count, datatype, opts); - Filesystem::AWrite(f, stat, ptr, offset, total_size, - reinterpret_cast(request), - io_status, opts); - return io_status.mpi_ret_; -} - -int MpiioFS::WriteAll(File &f, AdapterStat &stat, - const void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status, IoOptions opts) { - opts.mpi_type_ = datatype; - MPI_Barrier(stat.comm); - int ret = Write(f, stat, ptr, offset, count, datatype, status, opts); - MPI_Barrier(stat.comm); - return ret; -} - -int MpiioFS::WriteOrdered(File &f, AdapterStat &stat, - const void *ptr, int count, - MPI_Datatype datatype, - MPI_Status *status, IoOptions opts) { - opts.mpi_type_ = datatype; - int total; - MPI_Scan(&count, &total, 1, MPI_INT, MPI_SUM, stat.comm); - MPI_Offset my_offset = total - count; - size_t ret = WriteAll(f, stat, ptr, my_offset, count, datatype, status, opts); - return ret; -} - -int MpiioFS::AWriteOrdered(File &f, AdapterStat &stat, - const void *ptr, int count, - MPI_Datatype datatype, - MPI_Request *request, IoOptions opts) { - LOG(INFO) << "Starting an asynchronous write" << std::endl; - auto pool = - Singleton::GetInstance(); - HermesRequest *hreq = new HermesRequest(); - auto lambda = - [](MpiioFS *fs, File &f, AdapterStat &stat, - const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status, - IoOptions opts) { - int ret = fs->WriteOrdered(f, stat, ptr, - count, datatype, status, opts); - return static_cast(ret); - }; - auto func = std::bind(lambda, this, f, stat, ptr, - count, datatype, &hreq->io_status.mpi_status_, - opts); - hreq->return_future = pool->run(func); - auto mdm = Singleton::GetInstance(); - mdm->request_map.emplace(reinterpret_cast(request), hreq); - return MPI_SUCCESS; -} - -int MpiioFS::Wait(MPI_Request *req, MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto iter = mdm->request_map.find(reinterpret_cast(req)); - if (iter != mdm->request_map.end()) { - hermes::adapter::fs::HermesRequest *hreq = iter->second; - hreq->return_future.get(); - memcpy(status, - hreq->io_status.mpi_status_ptr_, - sizeof(MPI_Status)); - mdm->request_map.erase(iter); - delete (hreq); - return MPI_SUCCESS; - } - return real_api->MPI_Wait(req, status); -} - -int MpiioFS::WaitAll(int count, MPI_Request *req, MPI_Status *status) { - int ret = 0; - for (int i = 0; i < count; i++) { - auto sub_ret = Wait(&req[i], &status[i]); - if (sub_ret != MPI_SUCCESS) { - ret = sub_ret; - } - } - return ret; -} - -int MpiioFS::Seek(File &f, AdapterStat &stat, - MPI_Offset offset, int whence) { - Filesystem::Seek(f, stat, - MpiioSeekModeConv::Normalize(whence), - offset); - return MPI_SUCCESS; -} - -int MpiioFS::SeekShared(File &f, AdapterStat &stat, - MPI_Offset offset, int whence) { - MPI_Offset sum_offset; - int sum_whence; - int comm_participators; - MPI_Comm_size(stat.comm, &comm_participators); - MPI_Allreduce(&offset, &sum_offset, 1, MPI_LONG_LONG_INT, MPI_SUM, - stat.comm); - MPI_Allreduce(&whence, &sum_whence, 1, MPI_INT, MPI_SUM, - stat.comm); - if (sum_offset / comm_participators != offset) { - LOG(ERROR) - << "Same offset should be passed across the opened file communicator." - << std::endl; - } - if (sum_whence / comm_participators != whence) { - LOG(ERROR) - << "Same whence should be passed across the opened file communicator." - << std::endl; - } - Seek(f, stat, offset, whence); - return 0; -} - -/** - * Variants which internally find the correct offset -* */ - -int MpiioFS::Read(File &f, AdapterStat &stat, - void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - IoOptions opts = IoOptions::DataType(datatype, true); - return Read(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); -} - -int MpiioFS::ARead(File &f, AdapterStat &stat, - void *ptr, int count, MPI_Datatype datatype, MPI_Request *request) { - IoOptions opts = IoOptions::DataType(datatype, true); - return ARead(f, stat, ptr, Tell(f, stat), count, datatype, request, opts); -} - -int MpiioFS::ReadAll(File &f, AdapterStat &stat, - void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - IoOptions opts = IoOptions::DataType(datatype, true); - return ReadAll(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); -} - -int MpiioFS::Write(File &f, AdapterStat &stat, - const void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - IoOptions opts = IoOptions::DataType(datatype, true); - return Write(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); -} - -int MpiioFS::AWrite(File &f, AdapterStat &stat, - const void *ptr, int count, MPI_Datatype datatype, - MPI_Request *request) { - IoOptions opts = IoOptions::DataType(datatype, true); - return AWrite(f, stat, ptr, Tell(f, stat), count, datatype, request, opts); -} - -int MpiioFS::WriteAll(File &f, AdapterStat &stat, - const void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - IoOptions opts = IoOptions::DataType(datatype, true); - return WriteAll(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); -} - - -/** - * Variants which retrieve the stat data structure internally - * */ - -int MpiioFS::Read(File &f, bool &stat_exists, - void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return Read(f, stat, ptr, offset, count, datatype, status, opts); -} - -int MpiioFS::ARead(File &f, bool &stat_exists, - void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Request *request) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return ARead(f, stat, ptr, offset, count, datatype, request, opts); -} - -int MpiioFS::ReadAll(File &f, bool &stat_exists, - void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return ReadAll(f, stat, ptr, offset, count, datatype, status, opts); -} - -int MpiioFS::ReadOrdered(File &f, bool &stat_exists, - void *ptr, int count, - MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return ReadOrdered(f, stat, ptr, count, datatype, status, opts); -} - -int MpiioFS::Write(File &f, bool &stat_exists, - const void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return Write(f, stat, ptr, offset, count, datatype, status, opts); -} - -int MpiioFS::AWrite(File &f, bool &stat_exists, - const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Request *request) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return AWrite(f, stat, ptr, offset, count, datatype, request, opts); -} - -int MpiioFS::WriteAll(File &f, bool &stat_exists, - const void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return WriteAll(f, stat, ptr, offset, count, datatype, status, opts); -} - -int MpiioFS::WriteOrdered(File &f, bool &stat_exists, - const void *ptr, int count, - MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return WriteOrdered(f, stat, ptr, count, datatype, status, opts); -} - -int MpiioFS::AWriteOrdered(File &f, bool &stat_exists, - const void *ptr, int count, - MPI_Datatype datatype, - MPI_Request *request) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return AWriteOrdered(f, stat, ptr, count, datatype, request, opts); -} - -int MpiioFS::Read(File &f, bool &stat_exists, - void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Read(f, stat, ptr, count, datatype, status); -} - -int MpiioFS::ARead(File &f, bool &stat_exists, - void *ptr, int count, MPI_Datatype datatype, - MPI_Request *request) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return ARead(f, stat, ptr, count, datatype, request); -} - -int MpiioFS::ReadAll(File &f, bool &stat_exists, - void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return ReadAll(f, stat, ptr, count, datatype, status); -} - -int MpiioFS::Write(File &f, bool &stat_exists, - const void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Write(f, stat, ptr, count, datatype, status); -} - -int MpiioFS::AWrite(File &f, bool &stat_exists, - const void *ptr, int count, MPI_Datatype datatype, - MPI_Request *request) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return AWrite(f, stat, ptr, count, datatype, request); -} - -int MpiioFS::WriteAll(File &f, bool &stat_exists, - const void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return WriteAll(f, stat, ptr, count, datatype, status); -} - -int MpiioFS::Seek(File &f, bool &stat_exists, - MPI_Offset offset, int whence) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Seek(f, stat, offset, whence); -} - -int MpiioFS::SeekShared(File &f, bool &stat_exists, - MPI_Offset offset, int whence) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return SeekShared(f, stat, offset, whence); -} - -/** - * Internal overrides - * */ - -File MpiioFS::_RealOpen(AdapterStat &stat, const std::string &path) { - File f; - f.mpi_status_ = real_api->MPI_File_open(stat.comm, path.c_str(), stat.amode, - stat.info, &f.mpi_fh_); - if (f.mpi_status_ != MPI_SUCCESS) { - f.status_ = false; - } - // NOTE(llogan): MPI_Info_get does not behave well, so removing - /* - MPI_Info info; - MPI_File_get_info(f.mpi_fh_, &info); - MPI_Info_set(info, "path", path.c_str()); - MPI_File_set_info(f.mpi_fh_, info);*/ - return f; -} - -void MpiioFS::_InitFile(File &f) { - // NOTE(llogan): MPI_Info_get does not behave well, so removing - (void) f; - /*struct stat st; - std::string filename = GetFilenameFromFP(&f.mpi_fh_); - int fd = posix_api->open(filename.c_str(), O_RDONLY); - posix_api->__fxstat(_STAT_VER, fd, &st); - f.st_dev = st.st_dev; - f.st_ino = st.st_ino; - posix_api->close(fd);*/ -} - -void MpiioFS::_OpenInitStats(File &f, AdapterStat &stat) { - MPI_Offset size = static_cast(stat.st_size); - MPI_File_get_size(f.mpi_fh_, &size); - stat.st_size = size; - if (stat.amode & MPI_MODE_APPEND) { - stat.is_append = true; - } -} - -size_t MpiioFS::_RealWrite(const std::string &filename, off_t offset, - size_t size, const u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) { - LOG(INFO) << "Writing to file: " << filename << " offset: " << offset - << " size:" << size << "." - << " offset:" << offset << "." - << " file_size:" << stdfs::file_size(filename) - << " pid: " << getpid() << std::endl; - MPI_File fh; - int write_count = 0; - io_status.mpi_ret_ = real_api->MPI_File_open(MPI_COMM_SELF, filename.c_str(), - MPI_MODE_RDWR, MPI_INFO_NULL, &fh); - if (io_status.mpi_ret_ != MPI_SUCCESS) { - return 0; - } - - io_status.mpi_ret_ = real_api->MPI_File_seek(fh, offset, MPI_SEEK_SET); - if (io_status.mpi_ret_ != MPI_SUCCESS) { - goto ERROR; - } - io_status.mpi_ret_ = real_api->MPI_File_write(fh, data_ptr, - opts.count_, opts.mpi_type_, - io_status.mpi_status_ptr_); - MPI_Get_count(io_status.mpi_status_ptr_, opts.mpi_type_, &write_count); - if (opts.count_ != write_count) { - LOG(ERROR) << "writing failed: write " << write_count << " of " - << opts.count_ << "." << std::endl; - } - -ERROR: - real_api->MPI_File_close(&fh); - return size; -} - -size_t MpiioFS::_RealRead(const std::string &filename, off_t offset, - size_t size, u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) { - LOG(INFO) << "Read called for filename from destination: " << filename - << " on offset: " << offset << " and size: " << size << "." - << " file_size:" << stdfs::file_size(filename) - << " pid: " << getpid() << std::endl; - MPI_File fh; - int read_count = 0; - io_status.mpi_ret_ = real_api->MPI_File_open(MPI_COMM_SELF, filename.c_str(), - MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); - if (io_status.mpi_ret_ != MPI_SUCCESS) { - return 0; - } - - io_status.mpi_ret_ = real_api->MPI_File_seek(fh, offset, MPI_SEEK_SET); - if (io_status.mpi_ret_ != MPI_SUCCESS) { - goto ERROR; - } - io_status.mpi_ret_ = real_api->MPI_File_read(fh, data_ptr, - opts.count_, opts.mpi_type_, - io_status.mpi_status_ptr_); - MPI_Get_count(io_status.mpi_status_ptr_, - opts.mpi_type_, &read_count); - if (read_count != opts.count_) { - LOG(ERROR) << "reading failed: read " << read_count << " of " << opts.count_ - << "." << std::endl; - } - -ERROR: - real_api->MPI_File_close(&fh); - return size; -} - -void MpiioFS::_IoStats(size_t count, IoStatus &io_status, IoOptions &opts) { - (void) opts; - io_status.mpi_status_ptr_->count_hi_and_cancelled = 0; - io_status.mpi_status_ptr_->count_lo = count; -} - -int MpiioFS::_RealSync(File &f) { - return real_api->MPI_File_sync(f.mpi_fh_); -} - -int MpiioFS::_RealClose(File &f) { - return real_api->MPI_File_close(&f.mpi_fh_); -} - -} // namespace hermes::adapter::mpiio diff --git a/adapter/mpiio/fs_api.h b/adapter/mpiio/fs_api.h deleted file mode 100644 index f543b47da..000000000 --- a/adapter/mpiio/fs_api.h +++ /dev/null @@ -1,246 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_MPIIO_FS_API_H_ -#define HERMES_ADAPTER_MPIIO_FS_API_H_ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "filesystem/filesystem.cc" -#include "filesystem/filesystem.h" -#include "filesystem/metadata_manager.cc" -#include "filesystem/metadata_manager.h" -#include "posix/real_api.h" -#include "real_api.h" - -namespace hermes::adapter::mpiio { - -using hermes::Singleton; -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::File; -using hermes::adapter::fs::HermesRequest; -using hermes::adapter::fs::IoOptions; -using hermes::adapter::fs::IoStatus; -using hermes::adapter::fs::MetadataManager; -using hermes::adapter::fs::SeekMode; -using hermes::adapter::mpiio::API; - -/** - A class to represent MPI IO seek mode conversion -*/ -class MpiioSeekModeConv { - public: - /** normalize \a mpi_seek MPI seek mode */ - static SeekMode Normalize(int mpi_seek) { - switch (mpi_seek) { - case MPI_SEEK_SET: - return SeekMode::kSet; - case MPI_SEEK_CUR: - return SeekMode::kCurrent; - case MPI_SEEK_END: - return SeekMode::kEnd; - default: - return SeekMode::kNone; - } - } -}; - -/** - A class to represent MPI IO file system -*/ -class MpiioFS : public hermes::adapter::fs::Filesystem { - private: - API *real_api; /**< pointer to real APIs */ - hermes::adapter::posix::API *posix_api; /**< pointer to POSIX APIs */ - - public: - MpiioFS() { - real_api = Singleton::GetInstance(); - posix_api = Singleton::GetInstance(); - } - ~MpiioFS() = default; - - void _InitFile(File &f) override; - - public: - /** get file name from \a fh MPI file pointer */ - static inline std::string GetFilenameFromFP(MPI_File *fh) { - MPI_Info info; - int status = MPI_File_get_info(*fh, &info); - if (status != MPI_SUCCESS) { - LOG(ERROR) << "MPI_File_get_info on file handler failed." << std::endl; - } - const int kMaxSize = 0xFFF; - int flag; - char filename[kMaxSize] = {0}; - MPI_Info_get(info, "filename", kMaxSize, filename, &flag); - return filename; - } - /** Read */ - int Read(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, - MPI_Datatype datatype, MPI_Status *status, - IoOptions opts = IoOptions()); - /** ARead */ - int ARead(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, - MPI_Datatype datatype, MPI_Request *request, - IoOptions opts = IoOptions()); - /** ReadAll */ - int ReadAll(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, - MPI_Datatype datatype, MPI_Status *status, - IoOptions opts = IoOptions()); - /** ReadOrdered */ - int ReadOrdered(File &f, AdapterStat &stat, void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status, - IoOptions opts = IoOptions()); - /** Write */ - int Write(File &f, AdapterStat &stat, const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Status *status, - IoOptions opts = IoOptions()); - /** AWrite */ - int AWrite(File &f, AdapterStat &stat, const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Request *request, - IoOptions opts = IoOptions()); - /** WriteAll */ - int WriteAll(File &f, AdapterStat &stat, const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Status *status, - IoOptions opts = IoOptions()); - /** WriteOrdered */ - int WriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status, - IoOptions opts = IoOptions()); - /** AWriteOrdered */ - int AWriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, - MPI_Datatype datatype, MPI_Request *request, - IoOptions opts = IoOptions()); - /** Wait */ - int Wait(MPI_Request *req, MPI_Status *status); - /** WaitAll */ - int WaitAll(int count, MPI_Request *req, MPI_Status *status); - /** Seek */ - int Seek(File &f, AdapterStat &stat, MPI_Offset offset, int whence); - /** SeekShared */ - int SeekShared(File &f, AdapterStat &stat, MPI_Offset offset, int whence); - - /** - * Variants which internally find the correct offset - */ - - public: - /** Read */ - int Read(File &f, AdapterStat &stat, void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** ARead */ - int ARead(File &f, AdapterStat &stat, void *ptr, int count, - MPI_Datatype datatype, MPI_Request *request); - /** ReadAll */ - int ReadAll(File &f, AdapterStat &stat, void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** Write */ - int Write(File &f, AdapterStat &stat, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** AWrite */ - int AWrite(File &f, AdapterStat &stat, const void *ptr, int count, - MPI_Datatype datatype, MPI_Request *request); - /** WriteAll */ - int WriteAll(File &f, AdapterStat &stat, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - - /** - * Variants which retrieve the stat data structure internally - */ - - public: - /** Read */ - int Read(File &f, bool &stat_exists, void *ptr, size_t offset, int count, - MPI_Datatype datatype, MPI_Status *status); - /** ARead */ - int ARead(File &f, bool &stat_exists, void *ptr, size_t offset, int count, - MPI_Datatype datatype, MPI_Request *request); - /** ReadAll */ - int ReadAll(File &f, bool &stat_exists, void *ptr, size_t offset, int count, - MPI_Datatype datatype, MPI_Status *status); - /** ReadOrdered */ - int ReadOrdered(File &f, bool &stat_exists, void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** Write */ - int Write(File &f, bool &stat_exists, const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Status *status); - /** AWrite */ - int AWrite(File &f, bool &stat_exists, const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Request *request); - /** WriteAll */ - int WriteAll(File &f, bool &stat_exists, const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Status *status); - /** WriteOrdered */ - int WriteOrdered(File &f, bool &stat_exists, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** AWriteOrdered */ - int AWriteOrdered(File &f, bool &stat_exists, const void *ptr, int count, - MPI_Datatype datatype, MPI_Request *request); - /** Read */ - int Read(File &f, bool &stat_exists, void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** ARead */ - int ARead(File &f, bool &stat_exists, void *ptr, int count, - MPI_Datatype datatype, MPI_Request *request); - /** ReadAll */ - int ReadAll(File &f, bool &stat_exists, void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** Write */ - int Write(File &f, bool &stat_exists, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** AWrite */ - int AWrite(File &f, bool &stat_exists, const void *ptr, int count, - MPI_Datatype datatype, MPI_Request *request); - /** WriteAll */ - int WriteAll(File &f, bool &stat_exists, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** Seek */ - int Seek(File &f, bool &stat_exists, MPI_Offset offset, int whence); - /** SeekShared */ - int SeekShared(File &f, bool &stat_exists, MPI_Offset offset, int whence); - - /** - * Internal overrides - */ - - private: - /** OpenInitStats */ - void _OpenInitStats(File &f, AdapterStat &stat) override; - /** RealOpen */ - File _RealOpen(AdapterStat &stat, const std::string &path) override; - /** RealWrite */ - size_t _RealWrite(const std::string &filename, off_t offset, size_t size, - const u8 *data_ptr, IoStatus &io_status, - IoOptions &opts) override; - /** RealRead */ - size_t _RealRead(const std::string &filename, off_t offset, size_t size, - u8 *data_ptr, IoStatus &io_status, IoOptions &opts) override; - /** IoStats */ - void _IoStats(size_t count, IoStatus &io_status, IoOptions &opts) override; - /** RealSync */ - int _RealSync(File &f) override; - /** RealClose */ - int _RealClose(File &f) override; -}; - -} // namespace hermes::adapter::mpiio - -#endif // HERMES_ADAPTER_MPIIO_FS_API_H_ diff --git a/adapter/mpiio/mpiio.cc b/adapter/mpiio/mpiio.cc deleted file mode 100644 index 91c77f747..000000000 --- a/adapter/mpiio/mpiio.cc +++ /dev/null @@ -1,462 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -bool mpiio_intercepted = true; - -#include -#include -#include - -#include "real_api.h" -#include "fs_api.h" - -#include "constants.h" -#include "singleton.h" -#include "interceptor.h" -#include "interceptor.cc" - -#include "thread_pool.h" - -/** - * Namespace declarations - */ -using hermes::ThreadPool; -using hermes::adapter::fs::MetadataManager; -using hermes::adapter::fs::File; -using hermes::adapter::mpiio::API; -using hermes::adapter::mpiio::MpiioFS; -using hermes::adapter::mpiio::MpiioSeekModeConv; -using hermes::Singleton; - -namespace hapi = hermes::api; -namespace stdfs = std::experimental::filesystem; -using hermes::adapter::WeaklyCanonical; - -/** - * Internal Functions. - */ - - -inline bool IsTracked(MPI_File *fh) { - if (hermes::adapter::exit) return false; - auto mdm = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - File f; f.mpi_fh_ = (*fh); fs_api->_InitFile(f); - auto [stat, exists] = mdm->Find(f); - return exists; -} - -extern "C" { - -/** - * MPI - */ -int HERMES_DECL(MPI_Init)(int *argc, char ***argv) { - auto real_api = Singleton::GetInstance(); - int status = real_api->MPI_Init(argc, argv); - if (status == 0) { - LOG(INFO) << "MPI Init intercepted." << std::endl; - auto mdm = Singleton::GetInstance(); - mdm->InitializeHermes(true); - Singleton::GetInstance(hermes::adapter::fs::kNumThreads); - } - return status; -} - -int HERMES_DECL(MPI_Finalize)(void) { - LOG(INFO) << "MPI Finalize intercepted." << std::endl; - auto real_api = Singleton::GetInstance(); - auto mdm = Singleton::GetInstance(); - mdm->FinalizeHermes(); - int status = real_api->MPI_Finalize(); - return status; -} - -int HERMES_DECL(MPI_Wait)(MPI_Request *req, MPI_Status *status) { - auto fs_api = Singleton::GetInstance(); - return fs_api->Wait(req, status); -} - -int HERMES_DECL(MPI_Waitall)(int count, MPI_Request *req, MPI_Status *status) { - auto fs_api = Singleton::GetInstance(); - return fs_api->WaitAll(count, req, status); -} - -/** - * Metadata functions - */ -int HERMES_DECL(MPI_File_open)(MPI_Comm comm, const char *filename, int amode, - MPI_Info info, MPI_File *fh) { - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(filename)) { - LOG(INFO) << "Intercept MPI_File_open for filename: " << filename - << " and mode: " << amode << " is tracked." << std::endl; - AdapterStat stat; - stat.comm = comm; - stat.amode = amode; - stat.info = info; - File f = fs_api->Open(stat, filename); - (*fh) = f.mpi_fh_; - return f.mpi_status_; - } - return real_api->MPI_File_open(comm, filename, amode, info, fh); -} - -int HERMES_DECL(MPI_File_close)(MPI_File *fh) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(fh)) { - File f; - f.mpi_fh_ = *fh; - fs_api->_InitFile(f); - return fs_api->Close(f, stat_exists); - } - return real_api->MPI_File_close(fh); -} - -int HERMES_DECL(MPI_File_seek)(MPI_File fh, MPI_Offset offset, int whence) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - return fs_api->Seek(f, stat_exists, offset, whence); - } - return real_api->MPI_File_seek(fh, offset, whence); -} - -int HERMES_DECL(MPI_File_seek_shared)(MPI_File fh, MPI_Offset offset, - int whence) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - LOG(INFO) << "Intercept MPI_File_seek_shared offset:" << offset - << " whence:" << whence << "." << std::endl; - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - return fs_api->SeekShared(f, stat_exists, offset, whence); - } - return real_api->MPI_File_seek_shared(fh, offset, whence); -} - -int HERMES_DECL(MPI_File_get_position)(MPI_File fh, MPI_Offset *offset) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - (*offset) = static_cast(fs_api->Tell(f, stat_exists)); - return MPI_SUCCESS; - } - return real_api->MPI_File_get_position(fh, offset); -} - -int HERMES_DECL(MPI_File_read_all)(MPI_File fh, void *buf, int count, - MPI_Datatype datatype, MPI_Status *status) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - LOG(INFO) << "Intercept MPI_File_read_all." << std::endl; - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - return fs_api->ReadAll(f, stat_exists, buf, count, datatype, status); - } - return real_api->MPI_File_read_all(fh, buf, count, datatype, status); -} -int HERMES_DECL(MPI_File_read_at_all)(MPI_File fh, MPI_Offset offset, void *buf, - int count, MPI_Datatype datatype, - MPI_Status *status) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - return fs_api->ReadAll(f, stat_exists, buf, offset, count, datatype, - status); - } - return real_api->MPI_File_read_at_all(fh, offset, buf, count, datatype, - status); -} -int HERMES_DECL(MPI_File_read_at)(MPI_File fh, MPI_Offset offset, void *buf, - int count, MPI_Datatype datatype, - MPI_Status *status) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - return fs_api->Read(f, stat_exists, buf, offset, count, datatype, status); - } - return real_api->MPI_File_read_at(fh, offset, buf, count, datatype, status); -} -int HERMES_DECL(MPI_File_read)(MPI_File fh, void *buf, int count, - MPI_Datatype datatype, MPI_Status *status) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - int ret = fs_api->Read(f, stat_exists, buf, count, datatype, status); - if (stat_exists) return ret; - } - return real_api->MPI_File_read(fh, buf, count, datatype, status); -} -int HERMES_DECL(MPI_File_read_ordered)(MPI_File fh, void *buf, int count, - MPI_Datatype datatype, - MPI_Status *status) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - return fs_api->ReadOrdered(f, stat_exists, buf, count, datatype, status); - } - return real_api->MPI_File_read_ordered(fh, buf, count, datatype, status); -} -int HERMES_DECL(MPI_File_read_shared)(MPI_File fh, void *buf, int count, - MPI_Datatype datatype, - MPI_Status *status) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - LOG(INFO) << "Intercept MPI_File_read_shared." << std::endl; - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - return fs_api->Read(f, stat_exists, buf, count, datatype, status); - } - return real_api->MPI_File_read_shared(fh, buf, count, datatype, status); -} -int HERMES_DECL(MPI_File_write_all)(MPI_File fh, const void *buf, int count, - MPI_Datatype datatype, MPI_Status *status) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - LOG(INFO) << "Intercept MPI_File_write_all." << std::endl; - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - int ret = fs_api->WriteAll(f, stat_exists, buf, count, datatype, status); - if (stat_exists) return ret; - } - return real_api->MPI_File_write_all(fh, buf, count, datatype, status); -} -int HERMES_DECL(MPI_File_write_at_all)(MPI_File fh, MPI_Offset offset, - const void *buf, int count, - MPI_Datatype datatype, - MPI_Status *status) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - int ret = - fs_api->WriteAll(f, stat_exists, buf, offset, count, datatype, status); - if (stat_exists) return ret; - } - return real_api->MPI_File_write_at_all(fh, offset, buf, count, datatype, - status); -} -int HERMES_DECL(MPI_File_write_at)(MPI_File fh, MPI_Offset offset, - const void *buf, int count, - MPI_Datatype datatype, MPI_Status *status) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - LOG(INFO) << "In MPI_File_write_at" << std::endl; - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - return fs_api->Write(f, stat_exists, buf, offset, count, datatype, status); - } - return real_api->MPI_File_write_at(fh, offset, buf, count, datatype, status); -} -int HERMES_DECL(MPI_File_write)(MPI_File fh, const void *buf, int count, - MPI_Datatype datatype, MPI_Status *status) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - LOG(INFO) << "In MPI_File_write" << std::endl; - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - int ret = fs_api->Write(f, stat_exists, buf, count, datatype, status); - if (stat_exists) return ret; - } - return real_api->MPI_File_write(fh, buf, count, datatype, status); -} -int HERMES_DECL(MPI_File_write_ordered)(MPI_File fh, const void *buf, int count, - MPI_Datatype datatype, - MPI_Status *status) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - return fs_api->WriteOrdered(f, stat_exists, buf, count, datatype, status); - } - return real_api->MPI_File_write_ordered(fh, buf, count, datatype, status); -} -int HERMES_DECL(MPI_File_write_shared)(MPI_File fh, const void *buf, int count, - MPI_Datatype datatype, - MPI_Status *status) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - // NOTE(llogan): originally WriteOrdered - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - return fs_api->WriteOrdered(f, stat_exists, buf, count, datatype, status); - } - return real_api->MPI_File_write_shared(fh, buf, count, datatype, status); -} - -/** - * Async Read/Write - */ -int HERMES_DECL(MPI_File_iread_at)(MPI_File fh, MPI_Offset offset, void *buf, - int count, MPI_Datatype datatype, - MPI_Request *request) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - fs_api->ARead(f, stat_exists, buf, offset, count, datatype, request); - return MPI_SUCCESS; - } - return real_api->MPI_File_iread_at(fh, offset, buf, count, datatype, request); -} -int HERMES_DECL(MPI_File_iread)(MPI_File fh, void *buf, int count, - MPI_Datatype datatype, MPI_Request *request) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - fs_api->ARead(f, stat_exists, buf, count, datatype, request); - } - return real_api->MPI_File_iread(fh, buf, count, datatype, request); -} -int HERMES_DECL(MPI_File_iread_shared)(MPI_File fh, void *buf, int count, - MPI_Datatype datatype, - MPI_Request *request) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - fs_api->ARead(f, stat_exists, buf, count, datatype, request); - return MPI_SUCCESS; - } - return real_api->MPI_File_iread_shared(fh, buf, count, datatype, request); -} -int HERMES_DECL(MPI_File_iwrite_at)(MPI_File fh, MPI_Offset offset, - const void *buf, int count, - MPI_Datatype datatype, - MPI_Request *request) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - fs_api->AWrite(f, stat_exists, buf, offset, count, datatype, request); - return MPI_SUCCESS; - } - return real_api->MPI_File_iwrite_at(fh, offset, buf, count, datatype, - request); -} - -int HERMES_DECL(MPI_File_iwrite)(MPI_File fh, const void *buf, int count, - MPI_Datatype datatype, MPI_Request *request) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - fs_api->AWrite(f, stat_exists, buf, count, datatype, request); - return MPI_SUCCESS; - } - return real_api->MPI_File_iwrite(fh, buf, count, datatype, request); -} -int HERMES_DECL(MPI_File_iwrite_shared)(MPI_File fh, const void *buf, int count, - MPI_Datatype datatype, - MPI_Request *request) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - fs_api->AWriteOrdered(f, stat_exists, buf, count, datatype, request); - return MPI_SUCCESS; - } - return real_api->MPI_File_iwrite_shared(fh, buf, count, datatype, request); -} - -/** - * Other functions - */ -int HERMES_DECL(MPI_File_sync)(MPI_File fh) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->_InitFile(f); - fs_api->Sync(f, stat_exists); - return 0; - } - return real_api->MPI_File_sync(fh); -} - -} // extern C diff --git a/adapter/mpiio/real_api.h b/adapter/mpiio/real_api.h deleted file mode 100644 index 93a601367..000000000 --- a/adapter/mpiio/real_api.h +++ /dev/null @@ -1,301 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_MPIIO_H -#define HERMES_ADAPTER_MPIIO_H -#include -#include -#include -#include -#include -#include -#include "interceptor.h" -#include "filesystem/filesystem.h" -#include "filesystem/metadata_manager.h" - -#define REQUIRE_API(api_name) \ - if (api_name == nullptr) { \ - LOG(FATAL) << "HERMES Adapter failed to map symbol: " \ - #api_name << std::endl; \ - std::exit(1); \ - } - -extern "C" { -typedef int (*MPI_Init_t)(int * argc, char *** argv); -typedef int (*MPI_Finalize_t)( void); -typedef int (*MPI_Wait_t)(MPI_Request * req, MPI_Status * status); -typedef int (*MPI_Waitall_t)(int count, MPI_Request * req, MPI_Status * status); -typedef int (*MPI_File_open_t)(MPI_Comm comm, const char * filename, int amode, MPI_Info info, MPI_File * fh); -typedef int (*MPI_File_close_t)(MPI_File * fh); -typedef int (*MPI_File_seek_shared_t)(MPI_File fh, MPI_Offset offset, int whence); -typedef int (*MPI_File_seek_t)(MPI_File fh, MPI_Offset offset, int whence); -typedef int (*MPI_File_get_position_t)(MPI_File fh, MPI_Offset * offset); -typedef int (*MPI_File_read_all_t)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Status * status); -typedef int (*MPI_File_read_at_all_t)(MPI_File fh, MPI_Offset offset, void * buf, int count, MPI_Datatype datatype, MPI_Status * status); -typedef int (*MPI_File_read_at_t)(MPI_File fh, MPI_Offset offset, void * buf, int count, MPI_Datatype datatype, MPI_Status * status); -typedef int (*MPI_File_read_t)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Status * status); -typedef int (*MPI_File_read_ordered_t)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Status * status); -typedef int (*MPI_File_read_shared_t)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Status * status); -typedef int (*MPI_File_write_all_t)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status); -typedef int (*MPI_File_write_at_all_t)(MPI_File fh, MPI_Offset offset, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status); -typedef int (*MPI_File_write_at_t)(MPI_File fh, MPI_Offset offset, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status); -typedef int (*MPI_File_write_t)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status); -typedef int (*MPI_File_write_ordered_t)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status); -typedef int (*MPI_File_write_shared_t)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status); -typedef int (*MPI_File_iread_at_t)(MPI_File fh, MPI_Offset offset, void * buf, int count, MPI_Datatype datatype, MPI_Request * request); -typedef int (*MPI_File_iread_t)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Request * request); -typedef int (*MPI_File_iread_shared_t)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Request * request); -typedef int (*MPI_File_iwrite_at_t)(MPI_File fh, MPI_Offset offset, const void * buf, int count, MPI_Datatype datatype, MPI_Request * request); -typedef int (*MPI_File_iwrite_t)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Request * request); -typedef int (*MPI_File_iwrite_shared_t)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Request * request); -typedef int (*MPI_File_sync_t)(MPI_File fh); -} - -namespace hermes::adapter::mpiio { - -/** Pointers to the real mpiio API */ -class API { - public: - /** MPI_Init */ - MPI_Init_t MPI_Init = nullptr; - /** MPI_Finalize */ - MPI_Finalize_t MPI_Finalize = nullptr; - /** MPI_Wait */ - MPI_Wait_t MPI_Wait = nullptr; - /** MPI_Waitall */ - MPI_Waitall_t MPI_Waitall = nullptr; - /** MPI_File_open */ - MPI_File_open_t MPI_File_open = nullptr; - /** MPI_File_close */ - MPI_File_close_t MPI_File_close = nullptr; - /** MPI_File_seek_shared */ - MPI_File_seek_shared_t MPI_File_seek_shared = nullptr; - /** MPI_File_seek */ - MPI_File_seek_t MPI_File_seek = nullptr; - /** MPI_File_get_position */ - MPI_File_get_position_t MPI_File_get_position = nullptr; - /** MPI_File_read_all */ - MPI_File_read_all_t MPI_File_read_all = nullptr; - /** MPI_File_read_at_all */ - MPI_File_read_at_all_t MPI_File_read_at_all = nullptr; - /** MPI_File_read_at */ - MPI_File_read_at_t MPI_File_read_at = nullptr; - /** MPI_File_read */ - MPI_File_read_t MPI_File_read = nullptr; - /** MPI_File_read_ordered */ - MPI_File_read_ordered_t MPI_File_read_ordered = nullptr; - /** MPI_File_read_shared */ - MPI_File_read_shared_t MPI_File_read_shared = nullptr; - /** MPI_File_write_all */ - MPI_File_write_all_t MPI_File_write_all = nullptr; - /** MPI_File_write_at_all */ - MPI_File_write_at_all_t MPI_File_write_at_all = nullptr; - /** MPI_File_write_at */ - MPI_File_write_at_t MPI_File_write_at = nullptr; - /** MPI_File_write */ - MPI_File_write_t MPI_File_write = nullptr; - /** MPI_File_write_ordered */ - MPI_File_write_ordered_t MPI_File_write_ordered = nullptr; - /** MPI_File_write_shared */ - MPI_File_write_shared_t MPI_File_write_shared = nullptr; - /** MPI_File_iread_at */ - MPI_File_iread_at_t MPI_File_iread_at = nullptr; - /** MPI_File_iread */ - MPI_File_iread_t MPI_File_iread = nullptr; - /** MPI_File_iread_shared */ - MPI_File_iread_shared_t MPI_File_iread_shared = nullptr; - /** MPI_File_iwrite_at */ - MPI_File_iwrite_at_t MPI_File_iwrite_at = nullptr; - /** MPI_File_iwrite */ - MPI_File_iwrite_t MPI_File_iwrite = nullptr; - /** MPI_File_iwrite_shared */ - MPI_File_iwrite_shared_t MPI_File_iwrite_shared = nullptr; - /** MPI_File_sync */ - MPI_File_sync_t MPI_File_sync = nullptr; - - API() { - void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, "mpiio_intercepted"); - if (is_intercepted) { - MPI_Init = (MPI_Init_t)dlsym(RTLD_NEXT, "MPI_Init"); - } else { - MPI_Init = (MPI_Init_t)dlsym(RTLD_DEFAULT, "MPI_Init"); - } - REQUIRE_API(MPI_Init) - if (is_intercepted) { - MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_NEXT, "MPI_Finalize"); - } else { - MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_DEFAULT, "MPI_Finalize"); - } - REQUIRE_API(MPI_Finalize) - if (is_intercepted) { - MPI_Wait = (MPI_Wait_t)dlsym(RTLD_NEXT, "MPI_Wait"); - } else { - MPI_Wait = (MPI_Wait_t)dlsym(RTLD_DEFAULT, "MPI_Wait"); - } - REQUIRE_API(MPI_Wait) - if (is_intercepted) { - MPI_Waitall = (MPI_Waitall_t)dlsym(RTLD_NEXT, "MPI_Waitall"); - } else { - MPI_Waitall = (MPI_Waitall_t)dlsym(RTLD_DEFAULT, "MPI_Waitall"); - } - REQUIRE_API(MPI_Waitall) - if (is_intercepted) { - MPI_File_open = (MPI_File_open_t)dlsym(RTLD_NEXT, "MPI_File_open"); - } else { - MPI_File_open = (MPI_File_open_t)dlsym(RTLD_DEFAULT, "MPI_File_open"); - } - REQUIRE_API(MPI_File_open) - if (is_intercepted) { - MPI_File_close = (MPI_File_close_t)dlsym(RTLD_NEXT, "MPI_File_close"); - } else { - MPI_File_close = (MPI_File_close_t)dlsym(RTLD_DEFAULT, "MPI_File_close"); - } - REQUIRE_API(MPI_File_close) - if (is_intercepted) { - MPI_File_seek_shared = (MPI_File_seek_shared_t)dlsym(RTLD_NEXT, "MPI_File_seek_shared"); - } else { - MPI_File_seek_shared = (MPI_File_seek_shared_t)dlsym(RTLD_DEFAULT, "MPI_File_seek_shared"); - } - REQUIRE_API(MPI_File_seek_shared) - if (is_intercepted) { - MPI_File_seek = (MPI_File_seek_t)dlsym(RTLD_NEXT, "MPI_File_seek"); - } else { - MPI_File_seek = (MPI_File_seek_t)dlsym(RTLD_DEFAULT, "MPI_File_seek"); - } - REQUIRE_API(MPI_File_seek) - if (is_intercepted) { - MPI_File_get_position = (MPI_File_get_position_t)dlsym(RTLD_NEXT, "MPI_File_get_position"); - } else { - MPI_File_get_position = (MPI_File_get_position_t)dlsym(RTLD_DEFAULT, "MPI_File_get_position"); - } - REQUIRE_API(MPI_File_get_position) - if (is_intercepted) { - MPI_File_read_all = (MPI_File_read_all_t)dlsym(RTLD_NEXT, "MPI_File_read_all"); - } else { - MPI_File_read_all = (MPI_File_read_all_t)dlsym(RTLD_DEFAULT, "MPI_File_read_all"); - } - REQUIRE_API(MPI_File_read_all) - if (is_intercepted) { - MPI_File_read_at_all = (MPI_File_read_at_all_t)dlsym(RTLD_NEXT, "MPI_File_read_at_all"); - } else { - MPI_File_read_at_all = (MPI_File_read_at_all_t)dlsym(RTLD_DEFAULT, "MPI_File_read_at_all"); - } - REQUIRE_API(MPI_File_read_at_all) - if (is_intercepted) { - MPI_File_read_at = (MPI_File_read_at_t)dlsym(RTLD_NEXT, "MPI_File_read_at"); - } else { - MPI_File_read_at = (MPI_File_read_at_t)dlsym(RTLD_DEFAULT, "MPI_File_read_at"); - } - REQUIRE_API(MPI_File_read_at) - if (is_intercepted) { - MPI_File_read = (MPI_File_read_t)dlsym(RTLD_NEXT, "MPI_File_read"); - } else { - MPI_File_read = (MPI_File_read_t)dlsym(RTLD_DEFAULT, "MPI_File_read"); - } - REQUIRE_API(MPI_File_read) - if (is_intercepted) { - MPI_File_read_ordered = (MPI_File_read_ordered_t)dlsym(RTLD_NEXT, "MPI_File_read_ordered"); - } else { - MPI_File_read_ordered = (MPI_File_read_ordered_t)dlsym(RTLD_DEFAULT, "MPI_File_read_ordered"); - } - REQUIRE_API(MPI_File_read_ordered) - if (is_intercepted) { - MPI_File_read_shared = (MPI_File_read_shared_t)dlsym(RTLD_NEXT, "MPI_File_read_shared"); - } else { - MPI_File_read_shared = (MPI_File_read_shared_t)dlsym(RTLD_DEFAULT, "MPI_File_read_shared"); - } - REQUIRE_API(MPI_File_read_shared) - if (is_intercepted) { - MPI_File_write_all = (MPI_File_write_all_t)dlsym(RTLD_NEXT, "MPI_File_write_all"); - } else { - MPI_File_write_all = (MPI_File_write_all_t)dlsym(RTLD_DEFAULT, "MPI_File_write_all"); - } - REQUIRE_API(MPI_File_write_all) - if (is_intercepted) { - MPI_File_write_at_all = (MPI_File_write_at_all_t)dlsym(RTLD_NEXT, "MPI_File_write_at_all"); - } else { - MPI_File_write_at_all = (MPI_File_write_at_all_t)dlsym(RTLD_DEFAULT, "MPI_File_write_at_all"); - } - REQUIRE_API(MPI_File_write_at_all) - if (is_intercepted) { - MPI_File_write_at = (MPI_File_write_at_t)dlsym(RTLD_NEXT, "MPI_File_write_at"); - } else { - MPI_File_write_at = (MPI_File_write_at_t)dlsym(RTLD_DEFAULT, "MPI_File_write_at"); - } - REQUIRE_API(MPI_File_write_at) - if (is_intercepted) { - MPI_File_write = (MPI_File_write_t)dlsym(RTLD_NEXT, "MPI_File_write"); - } else { - MPI_File_write = (MPI_File_write_t)dlsym(RTLD_DEFAULT, "MPI_File_write"); - } - REQUIRE_API(MPI_File_write) - if (is_intercepted) { - MPI_File_write_ordered = (MPI_File_write_ordered_t)dlsym(RTLD_NEXT, "MPI_File_write_ordered"); - } else { - MPI_File_write_ordered = (MPI_File_write_ordered_t)dlsym(RTLD_DEFAULT, "MPI_File_write_ordered"); - } - REQUIRE_API(MPI_File_write_ordered) - if (is_intercepted) { - MPI_File_write_shared = (MPI_File_write_shared_t)dlsym(RTLD_NEXT, "MPI_File_write_shared"); - } else { - MPI_File_write_shared = (MPI_File_write_shared_t)dlsym(RTLD_DEFAULT, "MPI_File_write_shared"); - } - REQUIRE_API(MPI_File_write_shared) - if (is_intercepted) { - MPI_File_iread_at = (MPI_File_iread_at_t)dlsym(RTLD_NEXT, "MPI_File_iread_at"); - } else { - MPI_File_iread_at = (MPI_File_iread_at_t)dlsym(RTLD_DEFAULT, "MPI_File_iread_at"); - } - REQUIRE_API(MPI_File_iread_at) - if (is_intercepted) { - MPI_File_iread = (MPI_File_iread_t)dlsym(RTLD_NEXT, "MPI_File_iread"); - } else { - MPI_File_iread = (MPI_File_iread_t)dlsym(RTLD_DEFAULT, "MPI_File_iread"); - } - REQUIRE_API(MPI_File_iread) - if (is_intercepted) { - MPI_File_iread_shared = (MPI_File_iread_shared_t)dlsym(RTLD_NEXT, "MPI_File_iread_shared"); - } else { - MPI_File_iread_shared = (MPI_File_iread_shared_t)dlsym(RTLD_DEFAULT, "MPI_File_iread_shared"); - } - REQUIRE_API(MPI_File_iread_shared) - if (is_intercepted) { - MPI_File_iwrite_at = (MPI_File_iwrite_at_t)dlsym(RTLD_NEXT, "MPI_File_iwrite_at"); - } else { - MPI_File_iwrite_at = (MPI_File_iwrite_at_t)dlsym(RTLD_DEFAULT, "MPI_File_iwrite_at"); - } - REQUIRE_API(MPI_File_iwrite_at) - if (is_intercepted) { - MPI_File_iwrite = (MPI_File_iwrite_t)dlsym(RTLD_NEXT, "MPI_File_iwrite"); - } else { - MPI_File_iwrite = (MPI_File_iwrite_t)dlsym(RTLD_DEFAULT, "MPI_File_iwrite"); - } - REQUIRE_API(MPI_File_iwrite) - if (is_intercepted) { - MPI_File_iwrite_shared = (MPI_File_iwrite_shared_t)dlsym(RTLD_NEXT, "MPI_File_iwrite_shared"); - } else { - MPI_File_iwrite_shared = (MPI_File_iwrite_shared_t)dlsym(RTLD_DEFAULT, "MPI_File_iwrite_shared"); - } - REQUIRE_API(MPI_File_iwrite_shared) - if (is_intercepted) { - MPI_File_sync = (MPI_File_sync_t)dlsym(RTLD_NEXT, "MPI_File_sync"); - } else { - MPI_File_sync = (MPI_File_sync_t)dlsym(RTLD_DEFAULT, "MPI_File_sync"); - } - REQUIRE_API(MPI_File_sync) - } -}; -} // namespace hermes::adapter::mpiio - -#undef REQUIRE_API - -#endif // HERMES_ADAPTER_MPIIO_H diff --git a/adapter/posix/CMakeLists.txt b/adapter/posix/CMakeLists.txt index 56457400b..b53300cc5 100644 --- a/adapter/posix/CMakeLists.txt +++ b/adapter/posix/CMakeLists.txt @@ -1,51 +1,31 @@ -project(PosixAdapter VERSION ${HERMES_PACKAGE_VERSION}) include_directories(${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) -# POSIX src code. We only include posix.cc as it includes other cc to reduce compilation time. -set(POSIX_ADAPTER_SRC posix.cc) - -set(HERMES_POSIX_ADAPTER_DIR ${HERMES_ADAPTER_DIR}/posix) - -# Only posix.h is the public adapter. -set(POSIX_ADAPTER_PUBLIC_HEADER - ${HERMES_POSIX_ADAPTER_DIR}/real_api.h - ${HERMES_POSIX_ADAPTER_DIR}/fs_api.h) - -# Add library hermes_posix_backend -add_library(hermes_posix_backend ${CMAKE_CURRENT_SOURCE_DIR}/fs_api.cc) -target_compile_options(hermes_posix_backend PUBLIC -fPIC) -add_dependencies(hermes_posix_backend hermes) -target_link_libraries(hermes_posix_backend hermes MPI::MPI_CXX glog::glog stdc++fs dl) - -# Add library hermes_posix -add_library(hermes_posix SHARED ${POSIX_ADAPTER_PUBLIC_HEADER} ${POSIX_ADAPTER_SRC}) -add_dependencies(hermes_posix hermes_posix_backend) -target_link_libraries(hermes_posix hermes_posix_backend) +# Create the hermes_posix_singleton +add_library(hermes_posix_singleton SHARED ${CMAKE_CURRENT_SOURCE_DIR}/singleton.cc) +target_compile_options(hermes_posix_singleton PUBLIC -fPIC) #----------------------------------------------------------------------------- # Add Target(s) to CMake Install #----------------------------------------------------------------------------- install( TARGETS - hermes_posix_backend - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) -install( - TARGETS - hermes_posix + hermes_posix_singleton EXPORT ${HERMES_EXPORTED_TARGETS} LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} ) + #----------------------------------------------------------------------------- -# Add Target(s) to Coverage +# Export all exported targets to the build tree for use by parent project #----------------------------------------------------------------------------- -if(HERMES_ENABLE_COVERAGE) - set_coverage_flags(hermes_posix) -endif() +set(HERMES_EXPORTED_LIBS hermes_posix_singleton ${HERMES_EXPORTED_LIBS}) +if(NOT HERMES_EXTERNALLY_CONFIGURED) +EXPORT ( + TARGETS + ${HERMES_EXPORTED_LIBS} + FILE + ${HERMES_EXPORTED_TARGETS}.cmake +) +endif() \ No newline at end of file diff --git a/adapter/posix/fs_api.cc b/adapter/posix/fs_api.cc deleted file mode 100644 index 1a58139bb..000000000 --- a/adapter/posix/fs_api.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "fs_api.h" -#include "real_api.h" - -#include "filesystem/metadata_manager.cc" -#include "filesystem/filesystem.cc" - -namespace hermes::adapter::posix { - -File PosixFS::_RealOpen(AdapterStat &stat, const std::string &path) { - File f; - if (stat.flags & O_CREAT || stat.flags & O_TMPFILE) { - f.fd_ = real_api->open(path.c_str(), stat.flags, stat.st_mode); - } else { - f.fd_ = real_api->open(path.c_str(), stat.flags); - } - if (f.fd_ < 0) { - f.status_ = false; - } - _InitFile(f); - return f; -} - -void PosixFS::_InitFile(File &f) { - struct stat st; - real_api->__fxstat(_STAT_VER, f.fd_, &st); - f.st_dev = st.st_dev; - f.st_ino = st.st_ino; -} - -void PosixFS::_OpenInitStats(File &f, AdapterStat &stat) { - struct stat st; - real_api->__fxstat(_STAT_VER, f.fd_, &st); - stat.st_mode = st.st_mode; - stat.st_uid = st.st_uid; - stat.st_gid = st.st_gid; - stat.st_size = st.st_size; - stat.st_blksize = st.st_blksize; - stat.st_atim = st.st_atim; - stat.st_mtim = st.st_mtim; - stat.st_ctim = st.st_ctim; - if (stat.flags & O_APPEND) { - stat.is_append = true; - } -} - -size_t PosixFS::_RealWrite(const std::string &filename, off_t offset, - size_t size, const u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) { - (void) opts; (void) io_status; - LOG(INFO) << "Writing to file: " << filename - << " offset: " << offset - << " size:" << size << "." - << " file_size:" << stdfs::file_size(filename) << std::endl; - int fd = real_api->open(filename.c_str(), O_RDWR | O_CREAT); - if (fd < 0) { return 0; } - size_t write_size = real_api->pwrite(fd, data_ptr, size, offset); - real_api->close(fd); - return write_size; -} - -size_t PosixFS::_RealRead(const std::string &filename, off_t offset, - size_t size, u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) { - (void) opts; (void) io_status; - LOG(INFO) << "Read called for filename from destination: " << filename - << " on offset: " << offset - << " and size: " << size << "." - << " file_size:" << stdfs::file_size(filename) << std::endl; - int fd = real_api->open(filename.c_str(), O_RDONLY); - if (fd < 0) { return 0; } - size_t read_size = real_api->pread(fd, data_ptr, size, offset); - real_api->close(fd); - return read_size; -} - -int PosixFS::_RealSync(File &f) { - return real_api->fsync(f.fd_); -} - -int PosixFS::_RealClose(File &f) { - return real_api->close(f.fd_); -} - -} // namespace hermes::adapter::posix diff --git a/adapter/posix/fs_api.h b/adapter/posix/fs_api.h deleted file mode 100644 index 1d0ed7f09..000000000 --- a/adapter/posix/fs_api.h +++ /dev/null @@ -1,57 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_POSIX_NATIVE_H_ -#define HERMES_ADAPTER_POSIX_NATIVE_H_ - -#include - -#include "filesystem/filesystem.h" -#include "filesystem/metadata_manager.h" -#include "real_api.h" - -using hermes::Singleton; -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::File; -using hermes::adapter::fs::IoOptions; -using hermes::adapter::fs::IoStatus; -using hermes::adapter::posix::API; - -namespace hermes::adapter::posix { -/** - A class to represent POSIX IO file system -*/ -class PosixFS : public hermes::adapter::fs::Filesystem { - private: - API *real_api; /**< pointer to real APIs */ - - public: - PosixFS() { real_api = Singleton::GetInstance(); } - ~PosixFS() = default; - - void _InitFile(File &f) override; - - private: - void _OpenInitStats(File &f, AdapterStat &stat) override; - File _RealOpen(AdapterStat &stat, const std::string &path) override; - size_t _RealWrite(const std::string &filename, off_t offset, size_t size, - const u8 *data_ptr, IoStatus &io_status, - IoOptions &opts) override; - size_t _RealRead(const std::string &filename, off_t offset, size_t size, - u8 *data_ptr, IoStatus &io_status, IoOptions &opts) override; - int _RealSync(File &f) override; - int _RealClose(File &f) override; -}; - -} // namespace hermes::adapter::posix - -#endif // HERMES_ADAPTER_POSIX_NATIVE_H_ diff --git a/adapter/posix/real_api.h b/adapter/posix/real_api.h index 6dc719972..1f22b94fa 100644 --- a/adapter/posix/real_api.h +++ b/adapter/posix/real_api.h @@ -20,9 +20,6 @@ #include #include #include -#include "interceptor.h" -#include "filesystem/filesystem.h" -#include "filesystem/metadata_manager.h" #define REQUIRE_API(api_name) \ if (api_name == nullptr) { \ @@ -32,8 +29,6 @@ } extern "C" { -typedef int (*MPI_Init_t)(int * argc, char *** argv); -typedef int (*MPI_Finalize_t)( void); typedef int (*open_t)(const char * path, int flags, ...); typedef int (*open64_t)(const char * path, int flags, ...); typedef int (*__open_2_t)(const char * path, int oflag); @@ -55,12 +50,8 @@ typedef int (*close_t)(int fd); namespace hermes::adapter::posix { /** Pointers to the real posix API */ -class API { +class PosixApi { public: - /** MPI_Init */ - MPI_Init_t MPI_Init = nullptr; - /** MPI_Finalize */ - MPI_Finalize_t MPI_Finalize = nullptr; /** open */ open_t open = nullptr; /** open64 */ @@ -94,20 +85,8 @@ class API { /** close */ close_t close = nullptr; - API() { + PosixApi() { void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, "posix_intercepted"); - if (is_intercepted) { - MPI_Init = (MPI_Init_t)dlsym(RTLD_NEXT, "MPI_Init"); - } else { - MPI_Init = (MPI_Init_t)dlsym(RTLD_DEFAULT, "MPI_Init"); - } - REQUIRE_API(MPI_Init) - if (is_intercepted) { - MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_NEXT, "MPI_Finalize"); - } else { - MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_DEFAULT, "MPI_Finalize"); - } - REQUIRE_API(MPI_Finalize) if (is_intercepted) { open = (open_t)dlsym(RTLD_NEXT, "open"); } else { diff --git a/adapter/posix/singleton.cc b/adapter/posix/singleton.cc new file mode 100644 index 000000000..a90232844 --- /dev/null +++ b/adapter/posix/singleton.cc @@ -0,0 +1,4 @@ +#include "singleton.h" + +#include "real_api.h" +template<> std::unique_ptr hermes::Singleton::obj_ = nullptr; diff --git a/adapter/posix/singleton_macros.h b/adapter/posix/singleton_macros.h new file mode 100644 index 000000000..72f6167e7 --- /dev/null +++ b/adapter/posix/singleton_macros.h @@ -0,0 +1,9 @@ +#ifndef HERMES_SINGLETON_ADAPTER_MACROS_H +#define HERMES_SINGLETON_ADAPTER_MACROS_H + +#include "singleton.h" + +#define HERMES_POSIX_API hermes::Singleton::GetInstance() +#define HERMES_POSIX_API_T hermes::adapter::posix::PosixApi* + +#endif // HERMES_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/pubsub/CMakeLists.txt b/adapter/pubsub/CMakeLists.txt deleted file mode 100644 index 35a88f503..000000000 --- a/adapter/pubsub/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -project(PubSubAdapter VERSION ${HERMES_PACKAGE_VERSION}) - -set(HERMES_PUBSUB_ADAPTER_DIR ${HERMES_ADAPTER_DIR}/pubsub) - -set(PUBSUB_ADAPTER_PUBLIC_HEADER pubsub.h) -set(PUBSUB_ADAPTER_PRIVATE_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/metadata_manager.h - ${CMAKE_CURRENT_SOURCE_DIR}/datastructures.h - ${HERMES_ADAPTER_DIR}/constants.h) -set(PUBSUB_ADAPTER_SRC pubsub.cc metadata_manager.cc) - -add_library(hermes_pubsub SHARED ${PUBSUB_ADAPTER_PRIVATE_HEADER} ${PUBSUB_ADAPTER_PUBLIC_HEADER} ${PUBSUB_ADAPTER_SRC}) -target_include_directories(hermes_pubsub PRIVATE ${HERMES_ADAPTER_DIR}) -add_dependencies(hermes_pubsub hermes) -target_link_libraries(hermes_pubsub hermes MPI::MPI_CXX glog::glog) - -#----------------------------------------------------------------------------- -# Add Target(s) to CMake Install -#----------------------------------------------------------------------------- -install( - TARGETS - hermes_pubsub - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) -#----------------------------------------------------------------------------- -# Add Target(s) to Coverage -#----------------------------------------------------------------------------- -if(HERMES_ENABLE_COVERAGE) - set_coverage_flags(hermes_pubsub) -endif() diff --git a/adapter/pubsub/datastructures.h b/adapter/pubsub/datastructures.h deleted file mode 100644 index 1bbe8a226..000000000 --- a/adapter/pubsub/datastructures.h +++ /dev/null @@ -1,58 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_PUBSUB_ADAPTER_DATASTRUCTURES_H -#define HERMES_PUBSUB_ADAPTER_DATASTRUCTURES_H - -/** - * Standard header - */ -#include - -/** - * Internal header - */ -#include -#include -#include - -/** - * Namespace simplification. - */ -namespace hapi = hermes::api; - -namespace hermes::adapter::pubsub { - -/** - * Struct that defines the metadata required for the pubsub adapter. - */ -struct ClientMetadata { - /** bucket associated with the topic */ - std::shared_ptr st_bkid; - u64 last_subscribed_blob; /**< Current blob being used */ - timespec st_atim; /**< time of last access */ - /** - * Constructor - */ - ClientMetadata() - : st_bkid(), - last_subscribed_blob(0), - st_atim() {} /* default constructor */ - explicit ClientMetadata(const struct ClientMetadata &st) - : st_bkid(st.st_bkid), - last_subscribed_blob(st.last_subscribed_blob), - st_atim(st.st_atim) {} /**< parameterized constructor */ -}; - -} // namespace hermes::adapter::pubsub - -#endif // HERMES_PUBSUB_ADAPTER_DATASTRUCTURES_H diff --git a/adapter/pubsub/metadata_manager.cc b/adapter/pubsub/metadata_manager.cc deleted file mode 100644 index 28c755796..000000000 --- a/adapter/pubsub/metadata_manager.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "metadata_manager.h" - -/** - * Namespace declarations for cleaner code. - */ -using hermes::adapter::pubsub::MetadataManager; -using hermes::adapter::pubsub::MetadataManager; - -bool MetadataManager::Create(const std::string& topic, - const ClientMetadata&stat) { - LOG(INFO) << "Create metadata for topic: " << topic << std::endl; - auto ret = metadata.emplace(topic, stat); - return ret.second; -} - -bool MetadataManager::Update(const std::string& topic, - const ClientMetadata&stat) { - LOG(INFO) << "Update metadata for topic: " << topic << std::endl; - auto iter = metadata.find(topic); - if (iter != metadata.end()) { - metadata.erase(iter); - auto ret = metadata.emplace(topic, stat); - return ret.second; - } else { - return false; - } -} - -std::pair MetadataManager::Find( - const std::string& topic) { - typedef std::pair MetadataReturn; - auto iter = metadata.find(topic); - if (iter == metadata.end()) - return MetadataReturn(ClientMetadata(), false); - else - return MetadataReturn(iter->second, true); -} - -bool MetadataManager::Delete(const std::string& topic) { - LOG(INFO) << "Delete metadata for topic: " << topic << std::endl; - auto iter = metadata.find(topic); - if (iter != metadata.end()) { - metadata.erase(iter); - return true; - } else { - return false; - } -} diff --git a/adapter/pubsub/metadata_manager.h b/adapter/pubsub/metadata_manager.h deleted file mode 100644 index 28eb1918f..000000000 --- a/adapter/pubsub/metadata_manager.h +++ /dev/null @@ -1,136 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_PUBSUB_ADAPTER_METADATA_MANAGER_H -#define HERMES_PUBSUB_ADAPTER_METADATA_MANAGER_H - -/** - * Standard headers - */ -#include - -#include - -/** - * Internal headers - */ -#include "datastructures.h" - -using hermes::adapter::pubsub::ClientMetadata; - -namespace hermes::adapter::pubsub { -/** - * Metadata manager for PubSub adapter - */ -class MetadataManager { - private: - /** - * Private members - */ - std::unordered_map metadata; - /** - * hermes attribute to initialize Hermes - */ - std::shared_ptr hermes; - /** - * references of how many times hermes was tried to initialize. - */ - std::atomic ref; - - public: - int mpi_rank; /**< rank of MPI processor */ - /** - * Constructor - */ - explicit MetadataManager(bool is_mpi = true) : metadata(), ref(0) { - if (is_mpi) { - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - } else { - // branch exists for testing puropses - mpi_rank = 0; - } - } - /** - * Get the instance of hermes. - */ - std::shared_ptr& GetHermes() { return hermes; } - - /** - * Initialize hermes. - */ - void InitializeHermes(const char* config_file) { - if (ref == 0) { - hermes = hapi::InitHermes(config_file, false, true); - } - ref++; - } - - /** - * Finalize hermes if reference is equal to one. Else just - * decrement the ref counter. - */ - void FinalizeHermes() { - if (ref == 1) { - hermes->Finalize(); - } - ref--; - } - - /** - check if this application is client or core - */ - bool isClient() { return hermes->IsApplicationCore(); } - - /** - * \brief Create a metadata entry for pubsub adapter for a given topic. - * \param topic name of the managed topic. - * \param stat current metadata of the topic. - * \return true, if operation was successful. - * false, if operation was unsuccessful. - */ - bool Create(const std::string& topic, const ClientMetadata& stat); - - /** - * \brief Update existing metadata entry for pubsub adapter for a given file - * handler. - * \param topic name of the managed topic. - * \param stat current metadata of the topic to replace previous one. - * \return true, if operation was successful. - * false, if operation was unsuccessful or entry doesn't exist. - * \remark Update call will not degenerate into a create call - * if topic is not being tracked. - */ - bool Update(const std::string& topic, const ClientMetadata& stat); - - /** - * \brief Delete existing metadata entry for pubsub adapter for a given file - * handler. - * \param topic name of the managed topic. - * \return true, if operation was successful. - * false, if operation was unsuccessful. - */ - bool Delete(const std::string& topic); - - /** - * \brief Find existing metadata entry for pubsub adapter for a given file - * handler. - * \param topic name of the managed topic. - * \return The metadata entry if exist. - * - * The bool in pair indicates whether metadata entry exists or not. - */ - std::pair Find(const std::string& topic); -}; - -} // namespace hermes::adapter::pubsub - -#endif // HERMES_PUBSUB_ADAPTER_METADATA_MANAGER_H diff --git a/adapter/pubsub/pubsub.cc b/adapter/pubsub/pubsub.cc deleted file mode 100644 index 21c739fd6..000000000 --- a/adapter/pubsub/pubsub.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "pubsub.h" - -namespace hapi = hapi; - -hapi::Status hermes::pubsub::mpiInit(int argc, char **argv) { - LOG(INFO) << "Starting MPI" << std::endl; - int mpi_threads_provided; - MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &mpi_threads_provided); - if (mpi_threads_provided < MPI_THREAD_MULTIPLE) { - fprintf(stderr, "Didn't receive appropriate MPI threading specification\n"); - return hapi::Status(hermes::INVALID_FILE); - } - return hapi::Status(hermes::HERMES_SUCCESS); -} - -hapi::Status hermes::pubsub::connect(const std::string &config_file) { - LOG(INFO) << "Connecting adapter" << std::endl; - auto mdm = hermes::Singleton - ::GetInstance(); - try { - mdm->InitializeHermes(config_file.c_str()); - if (mdm->isClient()) { - return hapi::Status(hermes::HERMES_SUCCESS); - } else { - return hapi::Status(hermes::INVALID_FILE); - } - } catch (const std::exception& e) { - LOG(FATAL) << "Could not connect to hermes daemon" <::GetInstance(); - try { - mdm->FinalizeHermes(); - return hapi::Status(hermes::HERMES_SUCCESS); - } catch (const std::exception& e) { - LOG(FATAL) << "Could not disconnect from hermes" <::GetInstance(); - auto existing = mdm->Find(topic); - if (!existing.second) { - LOG(INFO) << "Topic not currently tracked" << std::endl; - ClientMetadata stat; - struct timespec ts{}; - timespec_get(&ts, TIME_UTC); - stat.st_atim = ts; - stat.st_bkid = std::make_shared(topic, mdm->GetHermes(), ctx); - if (!stat.st_bkid->IsValid()) return hapi::Status(hermes::INVALID_BUCKET); - if (!mdm->Create(topic, stat)) return hapi::Status(hermes::INVALID_BUCKET); - } else { - LOG(INFO) << "Topic is tracked, attaching to it" << std::endl; - struct timespec ts{}; - timespec_get(&ts, TIME_UTC); - existing.first.st_atim = ts; - if (!mdm->Update(topic, existing.first)) { - return hapi::Status(hermes::INVALID_BUCKET); - } - } - return hapi::Status(hermes::HERMES_SUCCESS); -} - -hapi::Status hermes::pubsub::detach(const std::string& topic) { - LOG(INFO) << "Detaching from topic: " << topic << std::endl; - hapi::Context ctx; - auto mdm = hermes::Singleton - ::GetInstance(); - auto existing = mdm->Find(topic); - if (existing.second) { - mdm->Delete(topic); - return existing.first.st_bkid->Release(ctx); - } - return hapi::Status(hermes::INVALID_BUCKET); -} - -hapi::Status hermes::pubsub::publish(const std::string& topic, - const hapi::Blob& message) { - LOG(INFO) << "Publish to : " << topic << std::endl; - auto mdm = hermes::Singleton - ::GetInstance(); - auto metadata = mdm->Find(topic); - - if (!metadata.second) { - if (attach(topic) == hermes::HERMES_SUCCESS) { - metadata = mdm->Find(topic); - } else { - return hapi::Status(hermes::INVALID_BUCKET); - } - } - - hapi::Context ctx; - struct timespec ts{}; - timespec_get(&ts, TIME_UTC); - - std::string blob_name = std::to_string(mdm->mpi_rank) + "_" + - std::to_string(ts.tv_nsec); - LOG(INFO) << "Publishing to blob with id " << blob_name << std::endl; - auto status = metadata.first.st_bkid->Put(blob_name, message, ctx); - if (status.Failed()) { - return hapi::Status(hermes::INVALID_BLOB); - } - - metadata.first.st_atim = ts; - mdm->Update(topic, metadata.first); - - return hapi::Status(hermes::HERMES_SUCCESS); -} - -std::pair hermes::pubsub::subscribe( - const std::string& topic) { - LOG(INFO) << "Subscribe to : " << topic << std::endl; - typedef std::pair SubscribeReturn; - - auto mdm = hermes::Singleton - ::GetInstance(); - auto metadata = mdm->Find(topic); - - if (!metadata.second) { - if (attach(topic) == hermes::HERMES_SUCCESS) { - metadata = mdm->Find(topic); - } else { - return SubscribeReturn(hapi::Blob(), - hapi::Status(hermes::INVALID_BUCKET)); - } - } - - hapi::Context ctx; - u64 index = metadata.first.last_subscribed_blob; - - hapi::Blob read_data(0); - LOG(INFO) << "Subscribing to " << topic << " at blob id " << index - << std::endl; - auto bucket = metadata.first.st_bkid; - auto exiting_blob_size = bucket->GetNext(index, read_data, ctx); - read_data.resize(exiting_blob_size); - - if (bucket->GetNext(index, read_data, ctx) != exiting_blob_size) { - return SubscribeReturn(hapi::Blob(), - hapi::Status(hermes::BLOB_NOT_IN_BUCKET)); - } - - metadata.first.last_subscribed_blob++; - struct timespec ts{}; - timespec_get(&ts, TIME_UTC); - metadata.first.st_atim = ts; - mdm->Update(topic, metadata.first); - - return SubscribeReturn(read_data, - hapi::Status(hermes::HERMES_SUCCESS)); -} diff --git a/adapter/pubsub/pubsub.h b/adapter/pubsub/pubsub.h deleted file mode 100644 index 8ee1e0106..000000000 --- a/adapter/pubsub/pubsub.h +++ /dev/null @@ -1,129 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_PUBSUB_H -#define HERMES_PUBSUB_H - -/** - * Standard header - */ - -#include - -/** - * Dependent library headers - */ -#include - -/** - * Internal headers - */ -#include -#include - -#include "../constants.h" -#include "metadata_manager.h" -#include "singleton.h" - -namespace hermes::pubsub { - -/** - * \brief Helper function to initialize MPI - * - * \return The return code/status - * - */ -hapi::Status mpiInit(int argc, char** argv); - -/** - * \brief Connects to the Hermes instance - * - * \param config_file Path to the config file of Hermes - * - * \return The return code/status - * - */ -hapi::Status connect(const std::string& config_file); - -/** - * \brief Connects to the Hermes instance - * - * \return The return code/status - * - * \pre Assumes that the config file path is loaded into a environment variable - * defined in constants.h under kHermesConf - * - */ -hapi::Status connect(); - -/** - * \brief Connects from the Hermes instance - * - * \return The return code/status - */ -hapi::Status disconnect(); - -/** - * \brief Attaches to a topic, creating it if it doesnt exists. - * - * \param topic The name of the topic - * - * \return The return code/status - * - */ -hapi::Status attach(const std::string& topic); - -/** - * \brief Detaches from the topic. Cleaning up all metadata - * - * \param topic The name of the topic - * - * \return The return code/status - * - * \pre Detaching doesnt delete the topic - * - */ -hapi::Status detach(const std::string& topic); - -/** - * \brief Puts a message to a topic - * - * \param topic The name of the topic - * \param message the data buffer - * - * \return The return code/status - * - * \remark Using std::vector as equivalent to Blob - * - */ -hapi::Status publish(const std::string& topic, - const std::vector& message); - -/** - * \brief Retrieves the next message from the topic - * - * \param topic The name of the topic - * - * \return A pair of: - * the return code/status - * and, if successful, the subscribed message. - * - * \remark Message order is tracked by Hermes. Current message is tracked - * per-process by a metadata manager - * - */ -std::pair, hapi::Status> subscribe( - const std::string& topic); - -} // namespace hermes::pubsub - -#endif // HERMES_PUBSUB_H diff --git a/adapter/stdio/CMakeLists.txt b/adapter/stdio/CMakeLists.txt deleted file mode 100644 index fb34ba472..000000000 --- a/adapter/stdio/CMakeLists.txt +++ /dev/null @@ -1,49 +0,0 @@ -project(StdioAdapter VERSION ${HERMES_PACKAGE_VERSION}) -include_directories(${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) - -# STDIO src code. We only include stdio.cc as it includes other cc to reduce compilation time. -set(STDIO_ADAPTER_SRC stdio.cc) - -set(HERMES_STDIO_ADAPTER_DIR ${HERMES_ADAPTER_DIR}/stdio) - -# Only stdio.h is the public adapter. -set(STDIO_ADAPTER_PUBLIC_HEADER - ${HERMES_STDIO_ADAPTER_DIR}/real_api.h - ${HERMES_STDIO_ADAPTER_DIR}/fs_api.h) - -# Add library hermes_stdio -add_library(hermes_stdio_backend ${CMAKE_CURRENT_SOURCE_DIR}/fs_api.cc) -add_dependencies(hermes_stdio_backend hermes) -target_link_libraries(hermes_stdio_backend hermes MPI::MPI_CXX glog::glog stdc++fs dl) - -add_library(hermes_stdio SHARED ${STDIO_ADAPTER_PUBLIC_HEADER} ${STDIO_ADAPTER_SRC}) -add_dependencies(hermes_stdio hermes_stdio_backend) -target_link_libraries(hermes_stdio hermes_stdio_backend) - -#----------------------------------------------------------------------------- -# Add Target(s) to CMake Install -#----------------------------------------------------------------------------- -install( - TARGETS - hermes_stdio_backend - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) -install( - TARGETS - hermes_stdio - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) -#----------------------------------------------------------------------------- -# Add Target(s) to Coverage -#----------------------------------------------------------------------------- -if(HERMES_ENABLE_COVERAGE) - set_coverage_flags(hermes_stdio) -endif() diff --git a/adapter/stdio/fs_api.cc b/adapter/stdio/fs_api.cc deleted file mode 100644 index 855bc6ad7..000000000 --- a/adapter/stdio/fs_api.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "real_api.h" -#include "fs_api.h" -#include - -namespace hermes::adapter::stdio { - -File StdioFS::_RealOpen(AdapterStat &stat, const std::string &path) { - File f; - f.fh_ = real_api->fopen(path.c_str(), stat.mode_str.c_str()); - if (f.fh_ == nullptr) { - f.status_ = false; - } - _InitFile(f); - return f; -} - -void StdioFS::_InitFile(File &f) { - struct stat st; - if (f.fh_ == nullptr) { - f.fd_ = -1; - return; - } - f.fd_ = fileno(f.fh_); - posix_api->__fxstat(_STAT_VER, f.fd_, &st); - f.st_dev = st.st_dev; - f.st_ino = st.st_ino; -} - -void StdioFS::_OpenInitStats(File &f, AdapterStat &stat) { - struct stat st; - posix_api->__fxstat(_STAT_VER, f.fd_, &st); - stat.st_mode = st.st_mode; - stat.st_uid = st.st_uid; - stat.st_gid = st.st_gid; - stat.st_size = st.st_size; - stat.st_blksize = st.st_blksize; - stat.st_atim = st.st_atim; - stat.st_mtim = st.st_mtim; - stat.st_ctim = st.st_ctim; - if (stat.mode_str.find('a') != std::string::npos) { - stat.is_append = true; - } -} - -size_t StdioFS::_RealWrite(const std::string &filename, off_t offset, - size_t size, const u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) { - (void) opts; (void) io_status; - LOG(INFO) << "Writing to file: " << filename - << " offset: " << offset - << " size:" << size << "." - << " file_size:" << stdfs::file_size(filename) << std::endl; - FILE *fh = real_api->fopen(filename.c_str(), "r+"); - if (fh == nullptr) { return 0; } - real_api->fseek(fh, offset, SEEK_SET); - flock(fileno(fh), LOCK_EX); - size_t write_size = real_api->fwrite(data_ptr, sizeof(char), size, fh); - flock(fileno(fh), LOCK_UN); - real_api->fclose(fh); - return write_size; -} - -size_t StdioFS::_RealRead(const std::string &filename, off_t offset, - size_t size, u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) { - (void) opts; (void) io_status; - LOG(INFO) << "Read called for filename from destination: " << filename - << " on offset: " << offset - << " and size: " << size << "." - << " file_size:" << stdfs::file_size(filename) << std::endl; - FILE *fh = real_api->fopen(filename.c_str(), "r"); - if (fh == nullptr) { return 0; } - real_api->fseek(fh, offset, SEEK_SET); - flock(fileno(fh), LOCK_SH); - size_t read_size = real_api->fread(data_ptr, sizeof(char), size, fh); - flock(fileno(fh), LOCK_UN); - real_api->fclose(fh); - return read_size; -} - -int StdioFS::_RealSync(File &f) { - return real_api->fflush(f.fh_); -} - -int StdioFS::_RealClose(File &f) { - return real_api->fclose(f.fh_); -} - -} // namespace hermes::adapter::stdio diff --git a/adapter/stdio/fs_api.h b/adapter/stdio/fs_api.h deleted file mode 100644 index a10f3f418..000000000 --- a/adapter/stdio/fs_api.h +++ /dev/null @@ -1,64 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_STDIO_NATIVE_H_ -#define HERMES_ADAPTER_STDIO_NATIVE_H_ - -#include - -#include "filesystem/filesystem.cc" -#include "filesystem/filesystem.h" -#include "filesystem/metadata_manager.cc" -#include "filesystem/metadata_manager.h" -#include "posix/real_api.h" -#include "real_api.h" - -using hermes::Singleton; -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::File; -using hermes::adapter::fs::IoOptions; -using hermes::adapter::fs::IoStatus; -using hermes::adapter::stdio::API; - -namespace hermes::adapter::stdio { -/** - A class to represent standard IO file system -*/ -class StdioFS : public hermes::adapter::fs::Filesystem { - private: - API *real_api; /**< pointer to real APIs */ - hermes::adapter::posix::API *posix_api; /**< pointer to POSIX APIs */ - - public: - StdioFS() { - real_api = Singleton::GetInstance(); - posix_api = Singleton::GetInstance(); - } - ~StdioFS() = default; - - void _InitFile(File &f) override; - - private: - void _OpenInitStats(File &f, AdapterStat &stat) override; - File _RealOpen(AdapterStat &stat, const std::string &path) override; - size_t _RealWrite(const std::string &filename, off_t offset, size_t size, - const u8 *data_ptr, IoStatus &io_status, - IoOptions &opts) override; - size_t _RealRead(const std::string &filename, off_t offset, size_t size, - u8 *data_ptr, IoStatus &io_status, IoOptions &opts) override; - int _RealSync(File &f) override; - int _RealClose(File &f) override; -}; - -} // namespace hermes::adapter::stdio - -#endif // HERMES_ADAPTER_STDIO_NATIVE_H_ diff --git a/adapter/stdio/real_api.h b/adapter/stdio/real_api.h deleted file mode 100644 index 7fceff47e..000000000 --- a/adapter/stdio/real_api.h +++ /dev/null @@ -1,300 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_STDIO_H -#define HERMES_ADAPTER_STDIO_H -#include -#include -#include -#include -#include -#include "interceptor.h" -#include "filesystem/filesystem.h" -#include "filesystem/metadata_manager.h" - -#define REQUIRE_API(api_name) \ - if (api_name == nullptr) { \ - LOG(FATAL) << "HERMES Adapter failed to map symbol: " \ - #api_name << std::endl; \ - std::exit(1); \ - } - -extern "C" { -typedef int (*MPI_Init_t)(int * argc, char *** argv); -typedef int (*MPI_Finalize_t)( void); -typedef FILE * (*fopen_t)(const char * path, const char * mode); -typedef FILE * (*fopen64_t)(const char * path, const char * mode); -typedef FILE * (*fdopen_t)(int fd, const char * mode); -typedef FILE * (*freopen_t)(const char * path, const char * mode, FILE * stream); -typedef FILE * (*freopen64_t)(const char * path, const char * mode, FILE * stream); -typedef int (*fflush_t)(FILE * fp); -typedef int (*fclose_t)(FILE * fp); -typedef size_t (*fwrite_t)(const void * ptr, size_t size, size_t nmemb, FILE * fp); -typedef int (*fputc_t)(int c, FILE * fp); -typedef int (*fgetpos_t)(FILE * fp, fpos_t * pos); -typedef int (*fgetpos64_t)(FILE * fp, fpos64_t * pos); -typedef int (*putc_t)(int c, FILE * fp); -typedef int (*putw_t)(int w, FILE * fp); -typedef int (*fputs_t)(const char * s, FILE * stream); -typedef size_t (*fread_t)(void * ptr, size_t size, size_t nmemb, FILE * stream); -typedef int (*fgetc_t)(FILE * stream); -typedef int (*getc_t)(FILE * stream); -typedef int (*getw_t)(FILE * stream); -typedef char * (*fgets_t)(char * s, int size, FILE * stream); -typedef void (*rewind_t)(FILE * stream); -typedef int (*fseek_t)(FILE * stream, long offset, int whence); -typedef int (*fseeko_t)(FILE * stream, off_t offset, int whence); -typedef int (*fseeko64_t)(FILE * stream, off64_t offset, int whence); -typedef int (*fsetpos_t)(FILE * stream, const fpos_t * pos); -typedef int (*fsetpos64_t)(FILE * stream, const fpos64_t * pos); -typedef long int (*ftell_t)(FILE * fp); -} - -namespace hermes::adapter::stdio { - -/** Pointers to the real stdio API */ -class API { - public: - /** MPI_Init */ - MPI_Init_t MPI_Init = nullptr; - /** MPI_Finalize */ - MPI_Finalize_t MPI_Finalize = nullptr; - /** fopen */ - fopen_t fopen = nullptr; - /** fopen64 */ - fopen64_t fopen64 = nullptr; - /** fdopen */ - fdopen_t fdopen = nullptr; - /** freopen */ - freopen_t freopen = nullptr; - /** freopen64 */ - freopen64_t freopen64 = nullptr; - /** fflush */ - fflush_t fflush = nullptr; - /** fclose */ - fclose_t fclose = nullptr; - /** fwrite */ - fwrite_t fwrite = nullptr; - /** fputc */ - fputc_t fputc = nullptr; - /** fgetpos */ - fgetpos_t fgetpos = nullptr; - /** fgetpos64 */ - fgetpos64_t fgetpos64 = nullptr; - /** putc */ - putc_t putc = nullptr; - /** putw */ - putw_t putw = nullptr; - /** fputs */ - fputs_t fputs = nullptr; - /** fread */ - fread_t fread = nullptr; - /** fgetc */ - fgetc_t fgetc = nullptr; - /** getc */ - getc_t getc = nullptr; - /** getw */ - getw_t getw = nullptr; - /** fgets */ - fgets_t fgets = nullptr; - /** rewind */ - rewind_t rewind = nullptr; - /** fseek */ - fseek_t fseek = nullptr; - /** fseeko */ - fseeko_t fseeko = nullptr; - /** fseeko64 */ - fseeko64_t fseeko64 = nullptr; - /** fsetpos */ - fsetpos_t fsetpos = nullptr; - /** fsetpos64 */ - fsetpos64_t fsetpos64 = nullptr; - /** ftell */ - ftell_t ftell = nullptr; - - API() { - void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, "stdio_intercepted"); - if (is_intercepted) { - MPI_Init = (MPI_Init_t)dlsym(RTLD_NEXT, "MPI_Init"); - } else { - MPI_Init = (MPI_Init_t)dlsym(RTLD_DEFAULT, "MPI_Init"); - } - REQUIRE_API(MPI_Init) - if (is_intercepted) { - MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_NEXT, "MPI_Finalize"); - } else { - MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_DEFAULT, "MPI_Finalize"); - } - REQUIRE_API(MPI_Finalize) - if (is_intercepted) { - fopen = (fopen_t)dlsym(RTLD_NEXT, "fopen"); - } else { - fopen = (fopen_t)dlsym(RTLD_DEFAULT, "fopen"); - } - REQUIRE_API(fopen) - if (is_intercepted) { - fopen64 = (fopen64_t)dlsym(RTLD_NEXT, "fopen64"); - } else { - fopen64 = (fopen64_t)dlsym(RTLD_DEFAULT, "fopen64"); - } - REQUIRE_API(fopen64) - if (is_intercepted) { - fdopen = (fdopen_t)dlsym(RTLD_NEXT, "fdopen"); - } else { - fdopen = (fdopen_t)dlsym(RTLD_DEFAULT, "fdopen"); - } - REQUIRE_API(fdopen) - if (is_intercepted) { - freopen = (freopen_t)dlsym(RTLD_NEXT, "freopen"); - } else { - freopen = (freopen_t)dlsym(RTLD_DEFAULT, "freopen"); - } - REQUIRE_API(freopen) - if (is_intercepted) { - freopen64 = (freopen64_t)dlsym(RTLD_NEXT, "freopen64"); - } else { - freopen64 = (freopen64_t)dlsym(RTLD_DEFAULT, "freopen64"); - } - REQUIRE_API(freopen64) - if (is_intercepted) { - fflush = (fflush_t)dlsym(RTLD_NEXT, "fflush"); - } else { - fflush = (fflush_t)dlsym(RTLD_DEFAULT, "fflush"); - } - REQUIRE_API(fflush) - if (is_intercepted) { - fclose = (fclose_t)dlsym(RTLD_NEXT, "fclose"); - } else { - fclose = (fclose_t)dlsym(RTLD_DEFAULT, "fclose"); - } - REQUIRE_API(fclose) - if (is_intercepted) { - fwrite = (fwrite_t)dlsym(RTLD_NEXT, "fwrite"); - } else { - fwrite = (fwrite_t)dlsym(RTLD_DEFAULT, "fwrite"); - } - REQUIRE_API(fwrite) - if (is_intercepted) { - fputc = (fputc_t)dlsym(RTLD_NEXT, "fputc"); - } else { - fputc = (fputc_t)dlsym(RTLD_DEFAULT, "fputc"); - } - REQUIRE_API(fputc) - if (is_intercepted) { - fgetpos = (fgetpos_t)dlsym(RTLD_NEXT, "fgetpos"); - } else { - fgetpos = (fgetpos_t)dlsym(RTLD_DEFAULT, "fgetpos"); - } - REQUIRE_API(fgetpos) - if (is_intercepted) { - fgetpos64 = (fgetpos64_t)dlsym(RTLD_NEXT, "fgetpos64"); - } else { - fgetpos64 = (fgetpos64_t)dlsym(RTLD_DEFAULT, "fgetpos64"); - } - REQUIRE_API(fgetpos64) - if (is_intercepted) { - putc = (putc_t)dlsym(RTLD_NEXT, "putc"); - } else { - putc = (putc_t)dlsym(RTLD_DEFAULT, "putc"); - } - REQUIRE_API(putc) - if (is_intercepted) { - putw = (putw_t)dlsym(RTLD_NEXT, "putw"); - } else { - putw = (putw_t)dlsym(RTLD_DEFAULT, "putw"); - } - REQUIRE_API(putw) - if (is_intercepted) { - fputs = (fputs_t)dlsym(RTLD_NEXT, "fputs"); - } else { - fputs = (fputs_t)dlsym(RTLD_DEFAULT, "fputs"); - } - REQUIRE_API(fputs) - if (is_intercepted) { - fread = (fread_t)dlsym(RTLD_NEXT, "fread"); - } else { - fread = (fread_t)dlsym(RTLD_DEFAULT, "fread"); - } - REQUIRE_API(fread) - if (is_intercepted) { - fgetc = (fgetc_t)dlsym(RTLD_NEXT, "fgetc"); - } else { - fgetc = (fgetc_t)dlsym(RTLD_DEFAULT, "fgetc"); - } - REQUIRE_API(fgetc) - if (is_intercepted) { - getc = (getc_t)dlsym(RTLD_NEXT, "getc"); - } else { - getc = (getc_t)dlsym(RTLD_DEFAULT, "getc"); - } - REQUIRE_API(getc) - if (is_intercepted) { - getw = (getw_t)dlsym(RTLD_NEXT, "getw"); - } else { - getw = (getw_t)dlsym(RTLD_DEFAULT, "getw"); - } - REQUIRE_API(getw) - if (is_intercepted) { - fgets = (fgets_t)dlsym(RTLD_NEXT, "fgets"); - } else { - fgets = (fgets_t)dlsym(RTLD_DEFAULT, "fgets"); - } - REQUIRE_API(fgets) - if (is_intercepted) { - rewind = (rewind_t)dlsym(RTLD_NEXT, "rewind"); - } else { - rewind = (rewind_t)dlsym(RTLD_DEFAULT, "rewind"); - } - REQUIRE_API(rewind) - if (is_intercepted) { - fseek = (fseek_t)dlsym(RTLD_NEXT, "fseek"); - } else { - fseek = (fseek_t)dlsym(RTLD_DEFAULT, "fseek"); - } - REQUIRE_API(fseek) - if (is_intercepted) { - fseeko = (fseeko_t)dlsym(RTLD_NEXT, "fseeko"); - } else { - fseeko = (fseeko_t)dlsym(RTLD_DEFAULT, "fseeko"); - } - REQUIRE_API(fseeko) - if (is_intercepted) { - fseeko64 = (fseeko64_t)dlsym(RTLD_NEXT, "fseeko64"); - } else { - fseeko64 = (fseeko64_t)dlsym(RTLD_DEFAULT, "fseeko64"); - } - REQUIRE_API(fseeko64) - if (is_intercepted) { - fsetpos = (fsetpos_t)dlsym(RTLD_NEXT, "fsetpos"); - } else { - fsetpos = (fsetpos_t)dlsym(RTLD_DEFAULT, "fsetpos"); - } - REQUIRE_API(fsetpos) - if (is_intercepted) { - fsetpos64 = (fsetpos64_t)dlsym(RTLD_NEXT, "fsetpos64"); - } else { - fsetpos64 = (fsetpos64_t)dlsym(RTLD_DEFAULT, "fsetpos64"); - } - REQUIRE_API(fsetpos64) - if (is_intercepted) { - ftell = (ftell_t)dlsym(RTLD_NEXT, "ftell"); - } else { - ftell = (ftell_t)dlsym(RTLD_DEFAULT, "ftell"); - } - REQUIRE_API(ftell) - } -}; -} // namespace hermes::adapter::stdio - -#undef REQUIRE_API - -#endif // HERMES_ADAPTER_STDIO_H diff --git a/adapter/stdio/stdio.cc b/adapter/stdio/stdio.cc deleted file mode 100644 index 4805cd5e4..000000000 --- a/adapter/stdio/stdio.cc +++ /dev/null @@ -1,565 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -bool stdio_intercepted = true; - -#include -#include - -#include "interceptor.cc" -#include -#include "stdio/real_api.h" -#include "stdio/fs_api.h" - -using hermes::adapter::WeaklyCanonical; -using hermes::adapter::stdio::API; -using hermes::adapter::stdio::StdioFS; -using hermes::Singleton; -using hermes::adapter::fs::MetadataManager; -using hermes::adapter::fs::SeekMode; - -namespace hapi = hermes::api; -namespace stdfs = std::experimental::filesystem; -using hermes::u8; -using hermes::u64; - -namespace hapi = hermes::api; -namespace stdfs = std::experimental::filesystem; - -extern "C" { - -/** - * MPI - */ -int HERMES_DECL(MPI_Init)(int *argc, char ***argv) { - auto real_api = Singleton::GetInstance(); - int status = real_api->MPI_Init(argc, argv); - if (status == 0) { - auto mdm = Singleton::GetInstance(); - mdm->InitializeHermes(true); - LOG(INFO) << "MPI Init intercepted." << std::endl; - } - return status; -} - -int HERMES_DECL(MPI_Finalize)(void) { - LOG(INFO) << "MPI Finalize intercepted." << std::endl; - auto real_api = Singleton::GetInstance(); - auto mdm = Singleton::GetInstance(); - mdm->FinalizeHermes(); - int status = real_api->MPI_Finalize(); - return status; -} - -/** - * STDIO - */ - -FILE *reopen_internal(const std::string &user_path, const char *mode, - FILE *stream) { - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - auto mdm = Singleton::GetInstance(); - FILE *ret; - ret = real_api->freopen(user_path.c_str(), mode, stream); - if (!ret) { - return ret; - } - - File f; - f.fh_ = ret; - fs_api->_InitFile(f); - std::string path_str = WeaklyCanonical(user_path).string(); - LOG(INFO) << "Reopen file for filename " << path_str << " in mode " << mode - << std::endl; - auto existing = mdm->Find(f); - if (!existing.second) { - LOG(INFO) << "File not opened before by adapter" << std::endl; - return nullptr; - } else { - LOG(INFO) << "File opened before by adapter" << std::endl; - struct timespec ts; - timespec_get(&ts, TIME_UTC); - existing.first.st_atim = ts; - existing.first.st_ctim = ts; - mdm->Update(f, existing.first); - } - return ret; -} - -FILE *HERMES_DECL(fopen)(const char *path, const char *mode) { - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(path)) { - LOG(INFO) << "Intercepting fopen(" << path << ", " << mode << ")\n"; - AdapterStat stat; - stat.mode_str = mode; - return fs_api->Open(stat, path).fh_; - } else { - return real_api->fopen(path, mode); - } -} - -FILE *HERMES_DECL(fopen64)(const char *path, const char *mode) { - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(path)) { - LOG(INFO) << "Intercepting fopen64(" << path << ", " << mode << ")\n"; - AdapterStat stat; - stat.mode_str = mode; - return fs_api->Open(stat, path).fh_; - } else { - return real_api->fopen64(path, mode); - } -} - -FILE *HERMES_DECL(fdopen)(int fd, const char *mode) { - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - FILE *ret = real_api->fdopen(fd, mode); - if (ret && hermes::adapter::IsTracked(ret)) { - LOG(INFO) << "Intercepting fdopen(" << fd << ", " << mode << ")\n"; - std::string path_str = hermes::adapter::GetFilenameFromFD(fd); - File f; - f.fh_ = ret; - fs_api->_InitFile(f); - AdapterStat stat; - stat.mode_str = mode; - fs_api->Open(stat, f, path_str); - } - return ret; -} - -FILE *HERMES_DECL(freopen)(const char *path, const char *mode, FILE *stream) { - auto real_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(path)) { - LOG(INFO) << "Intercepting freopen(" << path << ", " << mode << ", " - << stream << ")\n"; - return reopen_internal(path, mode, stream); - } - return real_api->freopen(path, mode, stream); -} - -FILE *HERMES_DECL(freopen64)(const char *path, const char *mode, FILE *stream) { - auto real_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(path)) { - LOG(INFO) << "Intercepting freopen64(" << path << ", " << mode << ", " - << stream << ")\n"; - return reopen_internal(path, mode, stream); - } - return real_api->freopen64(path, mode, stream); -} - -int HERMES_DECL(fflush)(FILE *fp) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (fp && hermes::adapter::IsTracked(fp)) { - File f; - f.fh_ = fp; - fs_api->_InitFile(f); - return fs_api->Sync(f, stat_exists); - } - return real_api->fflush(fp); -} - -int HERMES_DECL(fclose)(FILE *fp) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(fp)) { - LOG(INFO) << "Intercepting fclose(" << fp << ")\n"; - File f; - f.fh_ = fp; - fs_api->_InitFile(f); - int ret = fs_api->Close(f, stat_exists); - if (stat_exists) return ret; - } - return real_api->fclose(fp); -} - -size_t HERMES_DECL(fwrite)(const void *ptr, size_t size, size_t nmemb, - FILE *fp) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(fp)) { - LOG(INFO) << "Intercepting fwrite(" << ptr << ", " << size << ", " << nmemb - << ", " << fp << ")\n"; - File f; - f.fh_ = fp; - fs_api->_InitFile(f); - IoStatus io_status; - size_t ret = fs_api->Write(f, stat_exists, ptr, size * nmemb, io_status); - if (stat_exists) { - return ret; - } - } - return real_api->fwrite(ptr, size, nmemb, fp); -} - -int HERMES_DECL(fputc)(int c, FILE *fp) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(fp)) { - LOG(INFO) << "Intercepting fputc(" << c << ", " << fp << ")\n"; - File f; - f.fh_ = fp; - fs_api->_InitFile(f); - IoStatus io_status; - fs_api->Write(f, stat_exists, &c, 1, io_status); - if (stat_exists) { - return c; - } - } - return real_api->fputc(c, fp); -} - -int HERMES_DECL(fgetpos)(FILE *fp, fpos_t *pos) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(fp) && pos) { - File f; - f.fh_ = fp; - fs_api->_InitFile(f); - LOG(INFO) << "Intercept fgetpos." << std::endl; - // TODO(chogan): @portability In the GNU C Library, fpos_t is an opaque - // data structure that contains internal data to represent file offset and - // conversion state information. In other systems, it might have a - // different internal representation. This will need to change to support - // other compilers. - pos->__pos = fs_api->Tell(f, stat_exists); - if (stat_exists) { - return 0; - } - } - return real_api->fgetpos(fp, pos); -} - -int HERMES_DECL(fgetpos64)(FILE *fp, fpos64_t *pos) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(fp) && pos) { - File f; - f.fh_ = fp; - fs_api->_InitFile(f); - LOG(INFO) << "Intercept fgetpos64." << std::endl; - // TODO(chogan): @portability In the GNU C Library, fpos_t is an opaque - // data structure that contains internal data to represent file offset and - // conversion state information. In other systems, it might have a - // different internal representation. This will need to change to support - // other compilers. - pos->__pos = fs_api->Tell(f, stat_exists); - if (stat_exists) { - return 0; - } - } - return real_api->fgetpos64(fp, pos); -} - -int HERMES_DECL(putc)(int c, FILE *fp) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(fp)) { - File f; - f.fh_ = fp; - fs_api->_InitFile(f); - IoStatus io_status; - LOG(INFO) << "Intercept putc." << std::endl; - fs_api->Write(f, stat_exists, &c, 1, io_status); - if (stat_exists) { - return c; - } - } - return real_api->fputc(c, fp); -} - -int HERMES_DECL(putw)(int w, FILE *fp) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(fp)) { - LOG(INFO) << "Intercept putw." << std::endl; - File f; - f.fh_ = fp; - fs_api->_InitFile(f); - IoStatus io_status; - int ret = fs_api->Write(f, stat_exists, &w, sizeof(w), io_status); - if (ret == sizeof(w)) { - return 0; - } else { - return EOF; - } - } - return real_api->putw(w, fp); -} - -int HERMES_DECL(fputs)(const char *s, FILE *stream) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(stream)) { - LOG(INFO) << "Intercept fputs." << std::endl; - File f; - f.fh_ = stream; - fs_api->_InitFile(f); - IoStatus io_status; - int ret = fs_api->Write(f, stat_exists, s, strlen(s), io_status); - if (stat_exists) { - return ret; - } - } - return real_api->fputs(s, stream); -} - -size_t HERMES_DECL(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(stream)) { - LOG(INFO) << "Intercept fread with size: " << size << "." << std::endl; - File f; - f.fh_ = stream; - fs_api->_InitFile(f); - IoStatus io_status; - size_t ret = fs_api->Read(f, stat_exists, ptr, size * nmemb, io_status); - if (stat_exists) { - return ret; - } - } - return real_api->fread(ptr, size, nmemb, stream); -} - -int HERMES_DECL(fgetc)(FILE *stream) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(stream)) { - LOG(INFO) << "Intercept fgetc." << std::endl; - File f; - f.fh_ = stream; - fs_api->_InitFile(f); - IoStatus io_status; - u8 value; - fs_api->Read(f, stat_exists, &value, sizeof(u8), io_status); - if (stat_exists) { - return value; - } - } - return real_api->fgetc(stream); -} - -int HERMES_DECL(getc)(FILE *stream) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(stream)) { - LOG(INFO) << "Intercept getc." << std::endl; - File f; - f.fh_ = stream; - fs_api->_InitFile(f); - IoStatus io_status; - u8 value; - fs_api->Read(f, stat_exists, &value, sizeof(u8), io_status); - if (stat_exists) { - return value; - } - } - return real_api->getc(stream); -} - -int HERMES_DECL(getw)(FILE *stream) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(stream)) { - LOG(INFO) << "Intercept getw." << std::endl; - File f; - f.fh_ = stream; - fs_api->_InitFile(f); - IoStatus io_status; - int value; - fs_api->Read(f, stat_exists, &value, sizeof(int), io_status); - if (stat_exists) { - return value; - } - } - return real_api->getc(stream); -} - -char *HERMES_DECL(fgets)(char *s, int size, FILE *stream) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(stream)) { - LOG(INFO) << "Intercept fgets." << std::endl; - File f; - f.fh_ = stream; - fs_api->_InitFile(f); - IoStatus io_status; - size_t read_size = size - 1; - size_t ret_size = fs_api->Read(f, stat_exists, s, read_size, io_status); - if (ret_size < read_size) { - /* FILE ended */ - read_size = ret_size; - } - /* Check if \0 or \n in s.*/ - size_t copy_pos = 0; - for (size_t i = 0; i < read_size; ++i) { - if (s[i] == '\0' || s[i] == '\n') { - copy_pos = i; - break; - } - } - if (copy_pos > 0) { - /* \n and \0 was found. */ - s[copy_pos + 1] = '\0'; - } else { - s[read_size] = '\0'; - } - if (stat_exists) return s; - } - return real_api->fgets(s, size, stream); -} - -void HERMES_DECL(rewind)(FILE *stream) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(stream)) { - LOG(INFO) << "Intercept rewind." << std::endl; - File f; - f.fh_ = stream; - fs_api->_InitFile(f); - fs_api->Seek(f, stat_exists, SeekMode::kSet, 0); - if (stat_exists) { - return; - } - } - real_api->rewind(stream); -} - -int HERMES_DECL(fseek)(FILE *stream, long offset, int whence) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(stream)) { - LOG(INFO) << "Intercept fseek offset:" << offset << " whence:" << whence - << "." << std::endl; - File f; - f.fh_ = stream; - fs_api->_InitFile(f); - off_t ret = - fs_api->Seek(f, stat_exists, static_cast(whence), offset); - if (stat_exists && ret > 0) { - return 0; - } - } - return real_api->fseek(stream, offset, whence); -} - -int HERMES_DECL(fseeko)(FILE *stream, off_t offset, int whence) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(stream)) { - LOG(INFO) << "Intercept fseeko offset:" << offset << " whence:" << whence - << "." << std::endl; - File f; - f.fh_ = stream; - fs_api->_InitFile(f); - off_t ret = - fs_api->Seek(f, stat_exists, static_cast(whence), offset); - if (stat_exists && ret > 0) { - return 0; - } - } - return real_api->fseeko(stream, offset, whence); -} - -int HERMES_DECL(fseeko64)(FILE *stream, off64_t offset, int whence) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(stream)) { - LOG(INFO) << "Intercept fseeko offset:" << offset << " whence:" << whence - << "." << std::endl; - File f; - f.fh_ = stream; - fs_api->_InitFile(f); - off_t ret = - fs_api->Seek(f, stat_exists, static_cast(whence), offset); - if (stat_exists && ret > 0) { - return 0; - } - } - return real_api->fseeko64(stream, offset, whence); -} - -int HERMES_DECL(fsetpos)(FILE *stream, const fpos_t *pos) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - off_t offset = pos->__pos; - if (hermes::adapter::IsTracked(stream)) { - LOG(INFO) << "Intercept fsetpos offset:" << offset << "." << std::endl; - File f; - f.fh_ = stream; - fs_api->_InitFile(f); - off_t ret = fs_api->Seek(f, stat_exists, SeekMode::kSet, offset); - if (stat_exists && ret > 0) { - return 0; - } - } - return real_api->fsetpos(stream, pos); -} - -int HERMES_DECL(fsetpos64)(FILE *stream, const fpos64_t *pos) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - off_t offset = pos->__pos; - if (hermes::adapter::IsTracked(stream)) { - LOG(INFO) << "Intercept fsetpos64 offset:" << offset << "." << std::endl; - File f; - f.fh_ = stream; - fs_api->_InitFile(f); - off_t ret = fs_api->Seek(f, stat_exists, SeekMode::kSet, offset); - if (stat_exists && ret > 0) { - return 0; - } - } - return real_api->fsetpos64(stream, pos); -} - -long int HERMES_DECL(ftell)(FILE *fp) { - bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(fp)) { - LOG(INFO) << "Intercept ftell." << std::endl; - File f; - f.fh_ = fp; - fs_api->_InitFile(f); - off_t ret = fs_api->Tell(f, stat_exists); - if (stat_exists) { - return ret; - } - } - return real_api->ftell(fp); -} - -} // extern C diff --git a/adapter/test/CMakeLists.txt b/adapter/test/CMakeLists.txt deleted file mode 100644 index 69d1b9e95..000000000 --- a/adapter/test/CMakeLists.txt +++ /dev/null @@ -1,59 +0,0 @@ -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHERMES_PRELOAD -DHERMES_RPC_THALLIUM") -set(ADAPTER_COMMON ${CMAKE_CURRENT_SOURCE_DIR}/catch_config.h) -set(HERMES_ADAPTER_TEST_DIR ${HERMES_ADAPTER_DIR}/test) - -function(gcc exec args) - add_test(NAME Test${exec} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${args}) - set_property(TEST Test${exec} - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) - set_property(TEST Test${exec} APPEND - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) -endfunction() - -function(mpi exec mpi_proc args) - add_test(NAME Test${exec}_${mpi_proc} - COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${mpi_proc} - "${CMAKE_BINARY_DIR}/bin/${exec}" ${args} -d yes) - set_property(TEST Test${exec}_${mpi_proc} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) - set_property(TEST Test${exec}_${mpi_proc} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) -endfunction() - -find_program(BASH_PROGRAM bash) - -function(mpi_daemon test_exec test_mpi_proc test_args arg_name daemon_procs) - #MPI_EXEC=$1 TEST_EXEC=$2 TEST_PROCS=$3 HERMES_EXEC=$4 HERMES_PROCS=$5 HERMES_CONF=$6 - add_test(Test${test_exec}_${test_mpi_proc}_${arg_name} ${BASH_PROGRAM} - ${CMAKE_SOURCE_DIR}/adapter/test/run_hermes.sh ${MPIEXEC_EXECUTABLE} - ${CMAKE_BINARY_DIR}/bin/${test_exec} ${test_mpi_proc} - ${CMAKE_BINARY_DIR}/bin/hermes_daemon ${daemon_procs} - ${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml - ${test_args}) - set_property(TEST Test${test_exec}_${test_mpi_proc}_${arg_name} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) - set_property(TEST Test${test_exec}_${test_mpi_proc}_${arg_name} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) -endfunction() - -enable_testing() - -if(HERMES_ENABLE_STDIO_ADAPTER) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/stdio) -endif() - -if(HERMES_ENABLE_POSIX_ADAPTER) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/posix) -endif() - -if(HERMES_ENABLE_MPIIO_ADAPTER) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/mpiio) -endif() - -if(HERMES_ENABLE_PUBSUB_ADAPTER) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/pubsub) -endif() - -if(HERMES_ENABLE_VFD) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vfd) -endif() diff --git a/adapter/test/adapter_test_utils.h b/adapter/test/adapter_test_utils.h deleted file mode 100644 index e8d4ecb64..000000000 --- a/adapter/test/adapter_test_utils.h +++ /dev/null @@ -1,60 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_TEST_UTILS_H -#define HERMES_ADAPTER_TEST_UTILS_H -#include -#include -#include - -bool FilesystemSupportsTmpfile() { - bool result = false; - -#if O_TMPFILE - // NOTE(chogan): Even if O_TMPFILE is defined, the underlying filesystem might - // not support it. - int tmp_fd = open("/tmp", O_WRONLY | O_TMPFILE, 0600); - if (tmp_fd > 0) { - result = true; - close(tmp_fd); - } -#endif - - return result; -} - -size_t GetRandomOffset(size_t i, unsigned int offset_seed, size_t stride, - size_t total_size) { - return abs((int)(((i * rand_r(&offset_seed)) % stride) % total_size)); -} - -std::string GenRandom(const int len) { - std::string tmp_s; - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - - srand(100); - - tmp_s.reserve(len); - - for (int i = 0; i < len; ++i) { - tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)]; - } - - tmp_s[len - 1] = '\n'; - - return tmp_s; -} - -#endif // HERMES_ADAPTER_TEST_UTILS_H diff --git a/adapter/test/catch_config.h b/adapter/test/catch_config.h deleted file mode 100644 index 1317e1e50..000000000 --- a/adapter/test/catch_config.h +++ /dev/null @@ -1,42 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_CATCH_CONFIG_H -#define HERMES_CATCH_CONFIG_H - -#define CATCH_CONFIG_RUNNER -#include - -#include - -namespace cl = Catch::Clara; - -cl::Parser define_options(); - -int init(int* argc, char*** argv); -int finalize(); - -int main(int argc, char* argv[]) { - Catch::Session session; - auto cli = session.cli() | define_options(); - int returnCode = init(&argc, &argv); - if (returnCode != 0) return returnCode; - session.cli(cli); - returnCode = session.applyCommandLine(argc, argv); - if (returnCode != 0) return returnCode; - int test_return_code = session.run(); - returnCode = finalize(); - if (returnCode != 0) return returnCode; - return test_return_code; -} - -#endif diff --git a/adapter/test/data/hermes.yaml b/adapter/test/data/hermes.yaml deleted file mode 100644 index c17827c11..000000000 --- a/adapter/test/data/hermes.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# Test configuration - -num_devices: 4 -num_targets: 4 - -capacities_mb: [4096, 8192, 16384, 32768] -block_sizes_kb: [4, 4, 4, 4] -num_slabs: [4, 4, 4, 4] - -slab_unit_sizes: [ - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32] -] - -desired_slab_percentages: [ - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25] -] - -bandwidths_mbps: [6000, 300, 150, 70] -latencies_us: [15, 250000, 500000, 1000000] - -buffer_pool_arena_percentage: 0.85 -metadata_arena_percentage: 0.08 -transient_arena_percentage: 0.07 - -max_buckets_per_node: 16 -max_vbuckets_per_node: 32 -system_view_state_update_interval_ms: 1000 - -mount_points: ["", "./", "./", "./"] -swap_mount: "./" -num_buffer_organizer_retries: 3 -rpc_server_base_name: "localhost" -rpc_protocol: "ofi+sockets" -rpc_port: 8080 -buffer_organizer_port: 8081 -rpc_host_number_range: [] -rpc_num_threads: 1 -buffer_organizer_num_threads: 4 -buffer_pool_shmem_name: "/hermes_buffer_pool_" diff --git a/adapter/test/data/hermes_ares.yaml b/adapter/test/data/hermes_ares.yaml deleted file mode 100644 index 336e34ffc..000000000 --- a/adapter/test/data/hermes_ares.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# Test configuration - -num_devices: 4 -num_targets: 4 - -capacities_mb: [16384, 16384, 65536, 131072] -block_sizes_kb: [4, 4, 4, 4] -num_slabs: [4, 4, 4, 4] - -slab_unit_sizes: [ - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32] -] - -desired_slab_percentages: [ - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25] -] - -bandwidths_mbps: [6000, 4000, 2000, 200] -latencies_us: [15, 250000, 500000, 1000000] - -buffer_pool_arena_percentage: 0.85 -metadata_arena_percentage: 0.08 -transient_arena_percentage: 0.07 - -max_buckets_per_node: 16 -max_vbuckets_per_node: 8 -system_view_state_update_interval_ms: 1000 - -mount_points: ["", "./", "./", "./"] -swap_mount: "./" -num_buffer_organizer_retries: 3 -rpc_server_base_name: "ares-comp-" -rpc_server_suffix: "-40g" -rpc_protocol: "ofi+sockets" -rpc_domain: "" -rpc_port: 8080 -buffer_organizer_port: 8081 -rpc_host_number_range: [20-23] -rpc_num_threads: 4 -buffer_organizer_num_threads: 4 -buffer_pool_shmem_name: "/hermes_buffer_pool_" \ No newline at end of file diff --git a/adapter/test/data/hermes_small.yaml b/adapter/test/data/hermes_small.yaml deleted file mode 100644 index d72ad420a..000000000 --- a/adapter/test/data/hermes_small.yaml +++ /dev/null @@ -1,46 +0,0 @@ -# Test configuration - -num_devices: 4 -num_targets: 4 - -#2 is used for RAM because some space is taken by the Arena. -capacities_mb: [2, 1, 1, 1] -block_sizes_kb: [4, 4, 4, 4] -num_slabs: [4, 4, 4, 4] - -slab_unit_sizes: [ - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], -] - -desired_slab_percentages: [ - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], -] - -bandwidths_mbps: [6000, 300, 150, 70] -latencies_us: [15, 250000, 500000, 1000000] - -buffer_pool_arena_percentage: 0.85 -metadata_arena_percentage: 0.08 -transient_arena_percentage: 0.07 - -max_buckets_per_node: 16 -max_vbuckets_per_node: 8 -system_view_state_update_interval_ms: 1000 - -mount_points: ["", "./", "./", "./"] -swap_mount: "./" -num_buffer_organizer_retries: 3 -rpc_server_base_name: "localhost" -rpc_protocol: "ofi+sockets" -rpc_port: 8080 -buffer_organizer_port: 8081 -rpc_host_number_range: [] -rpc_num_threads: 1 -buffer_organizer_num_threads: 4 -buffer_pool_shmem_name: "/hermes_buffer_pool_" diff --git a/adapter/test/mpiio/CMakeLists.txt b/adapter/test/mpiio/CMakeLists.txt deleted file mode 100644 index cfd3a2ab1..000000000 --- a/adapter/test/mpiio/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -add_executable(mpiio_adapter_test mpiio_adapter_test.cpp ${ADAPTER_COMMON}) -mpi(mpiio_adapter_test 2 "") - -add_executable(hermes_mpiio_adapter_test mpiio_adapter_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_mpiio_adapter_test hermes_mpiio) -add_dependencies(hermes_mpiio_adapter_test hermes_mpiio hermes_daemon) -set_target_properties(hermes_mpiio_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") - -mpi_daemon(hermes_mpiio_adapter_test 2 "[synchronicity=async] -d yes" "async" 1) -mpi_daemon(hermes_mpiio_adapter_test 2 "[synchronicity=sync] -d yes" "sync" 1) - -set(MPIIO_TESTS - mpiio_adapter_test - hermes_mpiio_adapter_test -) - -foreach(program ${MPIIO_TESTS}) - target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_DIR}) - target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_TEST_DIR}) - target_link_libraries(${program} Catch2::Catch2 -lstdc++fs -lc MPI::MPI_CXX) -endforeach() - -if(HERMES_INSTALL_TESTS) - foreach(program ${MPIIO_TESTS}) - install( - TARGETS - ${program} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} - ) - endforeach() -endif() - -add_executable(mpi_parallel parallel.cc) -add_dependencies(mpi_parallel hermes_mpiio hermes_daemon) -target_link_libraries(mpi_parallel hermes_mpiio Catch2::Catch2 -lstdc++fs -lc MPI::MPI_CXX) -set_target_properties(mpi_parallel PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") - -install( - TARGETS - mpi_parallel - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) \ No newline at end of file diff --git a/adapter/test/mpiio/mpiio_adapter_basic_test.cpp b/adapter/test/mpiio/mpiio_adapter_basic_test.cpp deleted file mode 100644 index 9035bd5d4..000000000 --- a/adapter/test/mpiio/mpiio_adapter_basic_test.cpp +++ /dev/null @@ -1,1044 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -TEST_CASE("Open", "[process=" + std::to_string(info.comm_size) + - "]" - "[coordination=independent]" - "[synchronicity=sync]" - "[operation=single_open]" - "[repetition=1][file=1]") { - pretest(); - SECTION("open non-existant file") { - test::test_open(info.new_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.new_file.c_str(), MPI_MODE_RDWR | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - } - - SECTION("opening existing file write-only") { - test::test_open(info.existing_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - SECTION("opening existing file and read/write") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("open existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("append write existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_APPEND | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.existing_file.c_str(), MPI_MODE_APPEND, MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.existing_file.c_str(), - MPI_MODE_RDONLY | MPI_MODE_APPEND, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR | MPI_MODE_APPEND, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("append write and read new file") { - test::test_open(info.existing_file.c_str(), - MPI_MODE_RDWR | MPI_MODE_APPEND | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("delete on close mode") { - test::test_open( - info.new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::exists(info.new_file.c_str())); - test::test_close(); - REQUIRE(!stdfs::exists(info.new_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - posttest(); -} - -TEST_CASE("OpenCollective", "[process=" + std::to_string(info.comm_size) + - "]" - "[coordination=collective]" - "[synchronicity=sync]" - "[operation=single_open]" - "[repetition=1][file=1]") { - pretest(); - SECTION("open on non-existant shared file") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_RDONLY | MPI_MODE_EXCL, MPI_COMM_WORLD); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_RDONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.shared_new_file.c_str(), MPI_MODE_RDWR | MPI_MODE_EXCL, - MPI_COMM_WORLD); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_RDWR | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("open on shared existing file") { - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_EXCL, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_RDWR | MPI_MODE_EXCL, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_RDONLY | MPI_MODE_EXCL, MPI_COMM_WORLD); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDWR, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("append write/read on shared existing file") { - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_RDWR | MPI_MODE_APPEND, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("append write and read on shared new file") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_RDWR | MPI_MODE_APPEND | MPI_MODE_CREATE, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("delete on close mode on new file") { - test::test_open( - info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(!stdfs::exists(info.shared_new_file.c_str())); - } - posttest(); -} - -TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[synchronicity=sync]" - "[coordination=independent]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - bool check_bytes = true; - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("write to new file with allocate") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_preallocate(args.request_size * info.comm_size); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(args.request_size * info.rank, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - MPI_Barrier(MPI_COMM_WORLD); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("append to existing file") { - auto existing_size = stdfs::file_size(info.existing_file); - test::test_open(info.existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.existing_file) == - existing_size + test::size_written_orig); - } - - SECTION("append to new file") { - test::test_open(info.new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("write_at to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_at(info.write_data.c_str(), args.request_size, MPI_CHAR, - info.rank * args.request_size); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write_at to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_at(info.write_data.c_str(), args.request_size, MPI_CHAR, - 0); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("delete on close mode on new file") { - test::test_open( - info.new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.new_file.c_str())); - test::test_close(); - REQUIRE(!stdfs::exists(info.new_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("delete on close mode on existing file") { - auto original_size = stdfs::file_size(info.existing_file); - test::test_open(info.existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_EXCL | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.existing_file.c_str())); - auto new_size = - original_size > (size_t)test::size_written_orig * info.comm_size - ? original_size - : test::size_written_orig * info.comm_size; - REQUIRE(stdfs::file_size(info.existing_file) == (size_t)new_size); - test::test_close(); - REQUIRE(!stdfs::exists(info.existing_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - check_bytes = false; - } - posttest(check_bytes); -} - -TEST_CASE("SingleWriteCollective", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[synchronicity=sync]" - "[coordination=collective]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - bool check_bytes = true; - SECTION("write to existing file") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDWR, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write to new file") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig); - } - - // TODO(chogan): This test fails intermittently. Needs diagnosis. - // https://github.com/HDFGroup/hermes/issues/209 - SECTION("write to new file using shared ptr") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write_shared(info.write_data.c_str(), args.request_size, - MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("write to new file with allocate") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_preallocate(args.request_size * info.comm_size); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(args.request_size * info.rank, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - MPI_Barrier(MPI_COMM_WORLD); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("write_at_all to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_at_all(info.write_data.c_str(), args.request_size, - MPI_CHAR, info.rank * args.request_size); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write_at_all to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_at_all(info.write_data.c_str(), args.request_size, - MPI_CHAR, 0); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("append to existing file") { - auto existing_size = stdfs::file_size(info.existing_file); - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_all(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_existing_file) == - existing_size + test::size_written_orig); - } - - SECTION("append to new file") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_all(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig); - } - - SECTION("write_ordered to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_ordered(info.write_data.c_str(), args.request_size, - MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write_ordered to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_ordered(info.write_data.c_str(), args.request_size, - MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - SECTION("delete on close mode on new file") { - test::test_open( - info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.shared_new_file.c_str())); - MPI_Barrier(MPI_COMM_WORLD); - test::test_close(); - REQUIRE(!stdfs::exists(info.shared_new_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("delete on close mode on existing file") { - auto original_size = stdfs::file_size(info.shared_existing_file); - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_EXCL | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.shared_existing_file.c_str())); - auto new_size = - original_size > (size_t)test::size_written_orig * info.comm_size - ? original_size - : test::size_written_orig * info.comm_size; - REQUIRE(stdfs::file_size(info.shared_existing_file) == (size_t)new_size); - test::test_close(); - REQUIRE(!stdfs::exists(info.shared_existing_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - check_bytes = false; - } - posttest(check_bytes); -} - -TEST_CASE("SingleAsyncWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[coordination=independent]" - "[synchronicity=async]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - bool check_bytes = true; - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("write to new file using shared ptr") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite_shared(info.write_data.c_str(), args.request_size, - MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("write to new file with allocate") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_preallocate(args.request_size * info.comm_size); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(args.request_size * info.rank, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - MPI_Barrier(MPI_COMM_WORLD); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("append to existing file") { - auto existing_size = stdfs::file_size(info.existing_file); - test::test_open(info.existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.existing_file) == - existing_size + test::size_written_orig); - } - - SECTION("append to new file") { - test::test_open(info.new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("write_at to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite_at(info.write_data.c_str(), args.request_size, MPI_CHAR, - info.rank * args.request_size); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write_at to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite_at(info.write_data.c_str(), args.request_size, MPI_CHAR, - 0); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("delete on close mode on new file") { - test::test_open( - info.new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.new_file.c_str())); - test::test_close(); - REQUIRE(!stdfs::exists(info.new_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("delete on close mode on existing file") { - test::test_open(info.existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_EXCL | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.existing_file.c_str())); - test::test_close(); - REQUIRE(!stdfs::exists(info.existing_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - check_bytes = false; - } - posttest(check_bytes); -} - -TEST_CASE("SingleAsyncWriteCollective", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[synchronicity=async]" - "[coordination=collective]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - bool check_bytes = true; - SECTION("write to existing file") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDWR, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write to new file") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig); - } - - SECTION("write to new file using shared ptr") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite_shared(info.write_data.c_str(), args.request_size, - MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("write to new file with allocate") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_preallocate(args.request_size * info.comm_size); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(args.request_size * info.rank, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - MPI_Barrier(MPI_COMM_WORLD); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("write_at_all to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite_at_all(info.write_data.c_str(), args.request_size, - MPI_CHAR, info.rank * args.request_size); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write_at_all to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite_at_all(info.write_data.c_str(), args.request_size, - MPI_CHAR, 0); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - SECTION("append to existing file") { - auto existing_size = stdfs::file_size(info.existing_file); - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite_all(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_existing_file) == - existing_size + test::size_written_orig); - } - - SECTION("append to new file") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite_all(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig); - } - SECTION("delete on close mode on new file") { - test::test_open( - info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.shared_new_file.c_str())); - test::test_close(); - REQUIRE(!stdfs::exists(info.shared_new_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("delete on close mode on existing file") { - auto original_size = stdfs::file_size(info.shared_existing_file); - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_EXCL | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.shared_existing_file.c_str())); - auto new_size = - original_size > (size_t)test::size_written_orig * info.comm_size - ? original_size - : test::size_written_orig * info.comm_size; - REQUIRE(stdfs::file_size(info.shared_existing_file) == (size_t)new_size); - test::test_close(); - REQUIRE(!stdfs::exists(info.shared_existing_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - check_bytes = false; - } - posttest(check_bytes); -} - -TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[synchronicity=sync]" - "[coordination=independent]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read from non-existing file") { - test::test_open(info.new_file.c_str(), MPI_MODE_RDONLY | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - } - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_read(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read from existing file using shared ptr") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_read_shared(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read at the end of existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_END); - REQUIRE(test::status_orig == MPI_SUCCESS); - MPI_Offset offset; - MPI_File_get_position(test::fh_orig, &offset); - REQUIRE(offset == (long long)(args.request_size * info.num_iterations)); - test::test_read(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE(test::size_read_orig == 0); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read_at from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_read_at(info.read_data.data(), args.request_size, MPI_CHAR, - info.rank * args.request_size); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - posttest(); -} - -TEST_CASE("SingleReadCollective", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[synchronicity=sync]" - "[coordination=collective]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read from non-existing file") { - test::test_open(info.shared_new_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig != MPI_SUCCESS); - } - - SECTION("read from existing file") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_read_all(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read from existing file using shared ptr") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_read_shared(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read_at_all from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_read_at_all(info.read_data.data(), args.request_size, MPI_CHAR, - info.rank * args.request_size); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read_ordered from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_read_ordered(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - posttest(); -} - -TEST_CASE("SingleAsyncRead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[synchronicity=async]" - "[coordination=independent]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read from non-existing file") { - test::test_open(info.new_file.c_str(), MPI_MODE_RDONLY | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - } - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iread(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read from existing file using shared ptr") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iread_shared(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read at the end of existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_END); - REQUIRE(test::status_orig == MPI_SUCCESS); - MPI_Offset offset; - MPI_File_get_position(test::fh_orig, &offset); - REQUIRE(offset == (long long)(args.request_size * info.num_iterations)); - test::test_iread(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE(test::size_read_orig == 0); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read_at from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iread_at(info.read_data.data(), args.request_size, MPI_CHAR, - info.rank * args.request_size); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - posttest(); -} - -// TODO(chogan): This test fails sporadically. -// https://github.com/HDFGroup/hermes/issues/413 -TEST_CASE("SingleAsyncReadCollective", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[synchronicity=async]" - "[coordination=collective]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read from non-existing file") { - test::test_open(info.shared_new_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig != MPI_SUCCESS); - } - - SECTION("read from existing file") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iread_all(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read from existing file using shared ptr") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iread_shared(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read_at_all from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iread_at_all(info.read_data.data(), args.request_size, MPI_CHAR, - info.rank * args.request_size); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - posttest(); -} diff --git a/adapter/test/mpiio/mpiio_adapter_test.cpp b/adapter/test/mpiio/mpiio_adapter_test.cpp deleted file mode 100644 index 70dc5c018..000000000 --- a/adapter/test/mpiio/mpiio_adapter_test.cpp +++ /dev/null @@ -1,673 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -#include -#include - -#include "adapter_test_utils.h" -#include "catch_config.h" -#if HERMES_INTERCEPT == 1 -#include "filesystem/filesystem.h" -#endif - -#include "adapter_test_utils.h" - -namespace stdfs = std::experimental::filesystem; - -namespace hermes::adapter::mpiio::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp"; - size_t request_size = 65536; -}; -struct Info { - bool debug = false; - int rank = 0; - int comm_size = 1; - std::string write_data; - std::string read_data; - std::string new_file; - std::string existing_file; - std::string shared_new_file; - std::string shared_existing_file; - std::string new_file_cmp; - std::string existing_file_cmp; - std::string shared_new_file_cmp; - std::string shared_existing_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 5; - size_t total_size; - size_t stride_size = 512; - unsigned int temporal_interval_ms = 1; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; - size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::mpiio::test -hermes::adapter::mpiio::test::Arguments args; -hermes::adapter::mpiio::test::Info info; - -int init(int* argc, char*** argv) { - MPI_Init(argc, argv); - info.write_data = GenRandom(args.request_size); - info.read_data = std::string(args.request_size, 'r'); - MPI_Comm_rank(MPI_COMM_WORLD, &info.rank); - MPI_Comm_size(MPI_COMM_WORLD, &info.comm_size); - if (info.debug && info.rank == 0) { - printf("ready for attach\n"); - fflush(stdout); - sleep(30); - } - MPI_Barrier(MPI_COMM_WORLD); - return 0; -} -int finalize() { - MPI_Finalize(); - return 0; -} - -const char* kUser = "USER"; - -int pretest() { - stdfs::path fullpath = args.directory; - fullpath /= args.filename + "_" + std::string(getenv(kUser)); - info.new_file = fullpath.string() + "_new_" + std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext_" + std::to_string(getpid()); - info.new_file_cmp = - fullpath.string() + "_new_cmp" + "_" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp" + "_" + std::to_string(getpid()); - info.shared_new_file = - fullpath.string() + "_shared_new_" + std::to_string(info.comm_size); - info.shared_existing_file = - fullpath.string() + "_shared_ext_" + std::to_string(info.comm_size); - info.shared_new_file_cmp = - fullpath.string() + "_shared_new_cmp_" + std::to_string(info.comm_size); - info.shared_existing_file_cmp = - fullpath.string() + "_shared_ext_cmp_" + std::to_string(info.comm_size); - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + info.existing_file + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - MPI_Barrier(MPI_COMM_WORLD); - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - } - MPI_Barrier(MPI_COMM_WORLD); - if (info.rank == 0) { - if (stdfs::exists(info.shared_new_file)) - stdfs::remove(info.shared_new_file); - if (stdfs::exists(info.shared_existing_file)) - stdfs::remove(info.shared_existing_file); - if (!stdfs::exists(info.shared_existing_file)) { - std::string cmd = - "cp " + info.existing_file + " " + info.shared_existing_file; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.shared_existing_file) == - args.request_size * info.num_iterations); - } - if (stdfs::exists(info.shared_new_file_cmp)) - stdfs::remove(info.shared_new_file_cmp); - if (stdfs::exists(info.shared_existing_file_cmp)) - stdfs::remove(info.shared_existing_file_cmp); - if (!stdfs::exists(info.shared_existing_file_cmp)) { - std::string cmd = - "cp " + info.existing_file + " " + info.shared_existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.shared_existing_file_cmp) == - args.request_size * info.num_iterations); - } - } - MPI_Barrier(MPI_COMM_WORLD); - REQUIRE(info.total_size > 0); -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.shared_new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert( - info.shared_existing_file_cmp); -#endif - return 0; -} - -int posttest(bool compare_data = true) { -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); -#endif - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - /* Clean up. */ - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); -#endif - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -namespace test { -MPI_File fh_orig; -MPI_File fh_cmp; -int status_orig; -int size_read_orig; -int size_written_orig; - -void test_read_data(size_t size_read, size_t count, int type_size, - char* read_data, char* ptr) { - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < count * type_size; ++i) { - if (read_data[i] != ptr[i]) { - unmatching_chars = i; - break; - } - } - REQUIRE(unmatching_chars == 0); - } -} - -void test_open(const char* path, int mode, MPI_Comm comm) { - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else if (strcmp(path, info.existing_file.c_str()) == 0) { - cmp_path = info.existing_file_cmp; - } else if (strcmp(path, info.shared_new_file.c_str()) == 0) { - cmp_path = info.shared_new_file_cmp; - } else { - cmp_path = info.shared_existing_file_cmp; - } - status_orig = MPI_File_open(comm, path, mode, MPI_INFO_NULL, &fh_orig); - auto status_cmp = - MPI_File_open(comm, cmp_path.c_str(), mode, MPI_INFO_NULL, &fh_cmp); - bool is_same = (status_orig != MPI_SUCCESS && status_cmp != MPI_SUCCESS) || - (status_orig == MPI_SUCCESS && status_cmp == MPI_SUCCESS); - REQUIRE(is_same); -} -void test_close() { - status_orig = MPI_File_close(&fh_orig); - int status = MPI_File_close(&fh_cmp); - REQUIRE(status == status_orig); -} - -void test_preallocate(MPI_Offset size) { - status_orig = MPI_File_preallocate(fh_orig, size); - int status = MPI_File_preallocate(fh_cmp, size); - REQUIRE(status == status_orig); -} - -void test_write(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = MPI_File_write(fh_orig, ptr, count, datatype, &stat_orig); - int size_written; - auto ret_cmp = MPI_File_write(fh_cmp, ptr, count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_written_orig); - MPI_Get_count(&stat_cmp, datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_iwrite(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = MPI_File_iwrite(fh_orig, ptr, count, datatype, &request[0]); - int size_written; - auto ret_cmp = MPI_File_iwrite(fh_cmp, ptr, count, datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_written_orig); - MPI_Get_count(&stat[1], datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_write_shared(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_write_shared(fh_orig, ptr, count, datatype, &stat_orig); - int size_written; - auto ret_cmp = MPI_File_write_shared(fh_cmp, ptr, count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_written_orig); - MPI_Get_count(&stat_cmp, datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_iwrite_shared(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iwrite_shared(fh_orig, ptr, count, datatype, &request[0]); - int size_written; - auto ret_cmp = - MPI_File_iwrite_shared(fh_cmp, ptr, count, datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_written_orig); - MPI_Get_count(&stat[1], datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_write_all(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = MPI_File_write_all(fh_orig, ptr, count, datatype, &stat_orig); - int size_written; - auto ret_cmp = MPI_File_write_all(fh_cmp, ptr, count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_written_orig); - MPI_Get_count(&stat_cmp, datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_iwrite_all(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iwrite_all(fh_orig, ptr, count, datatype, &request[0]); - int size_written; - auto ret_cmp = MPI_File_iwrite_all(fh_cmp, ptr, count, datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_written_orig); - MPI_Get_count(&stat[1], datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_write_at(const void* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_write_at(fh_orig, offset, ptr, count, datatype, &stat_orig); - int size_written; - auto ret_cmp = - MPI_File_write_at(fh_cmp, offset, ptr, count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_written_orig); - MPI_Get_count(&stat_cmp, datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_iwrite_at(const void* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iwrite_at(fh_orig, offset, ptr, count, datatype, &request[0]); - int size_written; - auto ret_cmp = - MPI_File_iwrite_at(fh_cmp, offset, ptr, count, datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_written_orig); - MPI_Get_count(&stat[0], datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_write_at_all(const void* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_write_at_all(fh_orig, offset, ptr, count, datatype, &stat_orig); - int size_written; - auto ret_cmp = - MPI_File_write_at_all(fh_cmp, offset, ptr, count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_written_orig); - MPI_Get_count(&stat_cmp, datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_iwrite_at_all(const void* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = MPI_File_iwrite_at_all(fh_orig, offset, ptr, count, datatype, - &request[0]); - int size_written; - auto ret_cmp = - MPI_File_iwrite_at_all(fh_cmp, offset, ptr, count, datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_written_orig); - MPI_Get_count(&stat[1], datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_write_ordered(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_write_ordered(fh_orig, ptr, count, datatype, &stat_orig); - int size_written; - auto ret_cmp = - MPI_File_write_ordered(fh_cmp, ptr, count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_written_orig); - MPI_Get_count(&stat_cmp, datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_read(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = MPI_File_read(fh_orig, ptr, count, datatype, &stat_orig); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = - MPI_File_read(fh_cmp, read_data.data(), count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_read_orig); - MPI_Get_count(&stat_cmp, datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_iread(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = MPI_File_iread(fh_orig, ptr, count, datatype, &request[0]); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = - MPI_File_iread(fh_cmp, read_data.data(), count, datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_read_orig); - MPI_Get_count(&stat[1], datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_read_shared(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_read_shared(fh_orig, ptr, count, datatype, &stat_orig); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_read_shared(fh_cmp, read_data.data(), count, datatype, - &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_read_orig); - MPI_Get_count(&stat_cmp, datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_iread_shared(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iread_shared(fh_orig, ptr, count, datatype, &request[0]); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_iread_shared(fh_cmp, read_data.data(), count, - datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_read_orig); - MPI_Get_count(&stat[1], datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_read_all(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = MPI_File_read_all(fh_orig, ptr, count, datatype, &stat_orig); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = - MPI_File_read_all(fh_cmp, read_data.data(), count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_read_orig); - MPI_Get_count(&stat_cmp, datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_iread_all(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iread_all(fh_orig, ptr, count, datatype, &request[0]); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_iread_all(fh_cmp, read_data.data(), count, datatype, - &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_read_orig); - MPI_Get_count(&stat[1], datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_read_ordered(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_read_ordered(fh_orig, ptr, count, datatype, &stat_orig); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_read_ordered(fh_cmp, read_data.data(), count, - datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_read_orig); - MPI_Get_count(&stat_cmp, datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_read_at(char* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_read_at(fh_orig, offset, ptr, count, datatype, &stat_orig); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_read_at(fh_cmp, offset, read_data.data(), count, - datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_read_orig); - MPI_Get_count(&stat_cmp, datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_iread_at(char* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iread_at(fh_orig, offset, ptr, count, datatype, &request[0]); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_iread_at(fh_cmp, offset, read_data.data(), count, - datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_read_orig); - MPI_Get_count(&stat[1], datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_read_at_all(char* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_read_at_all(fh_orig, offset, ptr, count, datatype, &stat_orig); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_read_at_all(fh_cmp, offset, read_data.data(), count, - datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_read_orig); - MPI_Get_count(&stat_cmp, datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_iread_at_all(char* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iread_at_all(fh_orig, offset, ptr, count, datatype, &request[0]); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_iread_at_all(fh_cmp, offset, read_data.data(), count, - datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_read_orig); - MPI_Get_count(&stat[1], datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_seek(MPI_Offset offset, int whence) { - status_orig = MPI_File_seek(fh_orig, offset, whence); - int status = MPI_File_seek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} - -void test_seek_shared(MPI_Offset offset, int whence) { - status_orig = MPI_File_seek_shared(fh_orig, offset, whence); - int status = MPI_File_seek_shared(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -#include "mpiio_adapter_basic_test.cpp" diff --git a/adapter/test/mpiio/parallel.cc b/adapter/test/mpiio/parallel.cc deleted file mode 100644 index 9f91a59b5..000000000 --- a/adapter/test/mpiio/parallel.cc +++ /dev/null @@ -1,46 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "mpi.h" -#include -#include -#include -#include - -namespace stdfs = std::experimental::filesystem; - -int main(int argc, char **argv) { - MPI_File f; - MPI_Status status; - int count = 1024 * 1024 / 8; - int rank, nprocs; - MPI_Init(&argc, &argv); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nprocs); - std::string path = argv[1]; - std::vector buf(count, rank); - if (rank == 0) { - FILE *fp = fopen(path.c_str(), "w"); - std::vector init(count*nprocs, -1); - fwrite(init.data(), 1, count*nprocs, fp); - fclose(fp); - } - MPI_Barrier(MPI_COMM_WORLD); - - MPI_File_open(MPI_COMM_WORLD, path.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_INFO_NULL, &f); - MPI_File_write_at(f, rank*count, buf.data(), count, - MPI_CHAR, &status); - MPI_File_sync(f); - MPI_File_close(&f); - MPI_Finalize(); -} diff --git a/adapter/test/posix/CMakeLists.txt b/adapter/test/posix/CMakeLists.txt deleted file mode 100644 index 7b7ac5b58..000000000 --- a/adapter/test/posix/CMakeLists.txt +++ /dev/null @@ -1,73 +0,0 @@ -function(gcc_hermes exec tag_name tags conf) - add_test(NAME Test${exec}_${tag_name} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) - set_property(TEST Test${exec}_${tag_name} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/${conf}.yaml) - set_property(TEST Test${exec}_${tag_name} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) -endfunction() - -function(gcc_hermes_mode exec tag_name tags mode path) - set(test_name Test${exec}_${tag_name}_${mode}_${path}) - add_test(NAME ${test_name} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) - set_property(TEST ${test_name} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT ADAPTER_MODE=${mode}) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT SET_PATH=${path}) -endfunction() - -#------------------------------------------------------------------------------ -# Posix Adapter tests -#------------------------------------------------------------------------------ - -add_executable(posix_adapter_test posix_adapter_test.cpp ${ADAPTER_COMMON}) -gcc(posix_adapter_test "") - -add_executable(posix_adapter_mpi_test posix_adapter_mpi_test.cpp ${ADAPTER_COMMON}) -mpi(posix_adapter_mpi_test 2 "") - -add_executable(hermes_posix_adapter_test posix_adapter_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_posix_adapter_test hermes_posix) -add_dependencies(hermes_posix_adapter_test hermes_posix hermes_daemon) -set_target_properties(hermes_posix_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -gcc_hermes(hermes_posix_adapter_test "" "~[request_size=range-large]" hermes) -gcc_hermes(hermes_posix_adapter_test "large" "[request_size=range-large]" hermes) - -add_executable(hermes_posix_adapter_mpi_test posix_adapter_mpi_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_posix_adapter_mpi_test hermes_posix) -add_dependencies(hermes_posix_adapter_mpi_test hermes_posix hermes_daemon) -set_target_properties(hermes_posix_adapter_mpi_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -mpi_daemon(hermes_posix_adapter_mpi_test 2 "~[request_size=range-large]" "" 1) -mpi_daemon(hermes_posix_adapter_mpi_test 2 "[request_size=range-large]" "large" 1) - -include_directories(${CMAKE_SOURCE_DIR}/adapter) -add_executable(posix_simple_io simple_io.cc) - -set(POSIX_TESTS - posix_adapter_test - hermes_posix_adapter_test - posix_adapter_mpi_test - hermes_posix_adapter_mpi_test - posix_simple_io -) - -foreach(program ${POSIX_TESTS}) - target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_DIR}) - target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_TEST_DIR}) - target_link_libraries(${program} Catch2::Catch2 -lstdc++fs -lc MPI::MPI_CXX) -endforeach() - -if(HERMES_INSTALL_TESTS) - foreach(program ${POSIX_TESTS}) - install( - TARGETS - ${program} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} - ) - endforeach() -endif() diff --git a/adapter/test/posix/posix_adapter_basic_test.cpp b/adapter/test/posix/posix_adapter_basic_test.cpp deleted file mode 100644 index ef66c577e..000000000 --- a/adapter/test/posix/posix_adapter_basic_test.cpp +++ /dev/null @@ -1,1478 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -TEST_CASE("Open", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_open]" - "[repetition=1][file=1]") { - pretest(); - SECTION("open non-existant file") { - test::test_open(info.new_file.c_str(), O_WRONLY); - REQUIRE(test::fh_orig == -1); - test::test_open(info.new_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig == -1); - test::test_open(info.new_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig == -1); - } - - SECTION("truncate existing file and write-only") { - test::test_open(info.existing_file.c_str(), O_WRONLY | O_TRUNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("truncate existing file and read/write") { - test::test_open(info.existing_file.c_str(), O_RDWR | O_TRUNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("open existing file") { - test::test_open(info.existing_file.c_str(), O_WRONLY); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("append write existing file") { - test::test_open(info.existing_file.c_str(), O_APPEND); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("create a new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - stdfs::remove(info.new_file); - - test::test_open(info.new_file.c_str(), O_RDONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - stdfs::remove(info.new_file); - - test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("create a existing file") { - test::test_open(info.existing_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - - test::test_open(info.existing_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, - 0600); - REQUIRE(test::fh_orig == -1); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_CREAT | O_EXCL, - 0600); - REQUIRE(test::fh_orig == -1); - test::test_open(info.existing_file.c_str(), O_RDWR | O_CREAT | O_EXCL, - 0600); - REQUIRE(test::fh_orig == -1); - } - SECTION("Async I/O") { - test::test_open(info.existing_file.c_str(), O_WRONLY | O_ASYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_ASYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_ASYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_APPEND | O_ASYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - - test::test_open(info.existing_file.c_str(), O_WRONLY | O_NONBLOCK); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_NONBLOCK); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_NONBLOCK); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_APPEND | O_NONBLOCK); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - - test::test_open(info.existing_file.c_str(), O_WRONLY | O_NDELAY); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_NDELAY); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_NDELAY); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_APPEND | O_NDELAY); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("Async I/O") { - test::test_open(info.existing_file.c_str(), O_WRONLY | O_DIRECT); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_DIRECT); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_DIRECT); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_APPEND | O_DIRECT); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("Write Synchronize") { - /* File synchronicity */ - test::test_open(info.existing_file.c_str(), O_WRONLY | O_DSYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_DSYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_DSYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_APPEND | O_DSYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - - /* Write synchronicity */ - test::test_open(info.existing_file.c_str(), O_WRONLY | O_SYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_SYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_SYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_APPEND | O_SYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("Temporary file") { - if (info.supports_tmpfile) { - test::test_open("/tmp", O_WRONLY | O_TMPFILE, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.new_file.c_str(), O_RDONLY | O_TMPFILE, 0600); - REQUIRE(test::fh_orig == -1); - test::test_open(info.new_file.c_str(), O_RDWR | O_TMPFILE, 0600); - REQUIRE(test::fh_orig == -1); - test::test_open(info.new_file.c_str(), O_APPEND | O_TMPFILE, 0600); - REQUIRE(test::fh_orig == -1); - - test::test_open(info.existing_file.c_str(), O_WRONLY | O_TMPFILE, 0600); - REQUIRE(test::fh_orig == -1); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_TMPFILE, 0600); - REQUIRE(test::fh_orig == -1); - test::test_open(info.existing_file.c_str(), O_RDWR | O_TMPFILE, 0600); - REQUIRE(test::fh_orig == -1); - } - } - posttest(); -} - -TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == test::size_written_orig); - } - - SECTION("write to existing file with truncate") { - test::test_open(info.existing_file.c_str(), O_WRONLY | O_TRUNC); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.existing_file) == test::size_written_orig); - } - - SECTION("write to existing file at the end") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - test::test_seek(0, SEEK_END); - REQUIRE(((size_t)test::status_orig) == - args.request_size * info.num_iterations); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.existing_file) == - test::size_written_orig + args.request_size * info.num_iterations); - } - - SECTION("append to existing file") { - auto existing_size = stdfs::file_size(info.existing_file); - test::test_open(info.existing_file.c_str(), O_RDWR | O_APPEND); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.existing_file) == - existing_size + test::size_written_orig); - } - - SECTION("append to new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == test::size_written_orig); - } - posttest(); -} - -TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read from non-existing file") { - test::test_open(info.new_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig == -1); - } - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - test::test_seek(0, SEEK_CUR); - REQUIRE(test::status_orig == 0); - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("read at the end of existing file") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - test::test_seek(0, SEEK_END); - REQUIRE(((size_t)test::status_orig) == - args.request_size * info.num_iterations); - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == 0); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedWriteSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == args.request_size); - } - - SECTION("write to new file always at start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedReadSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_WRONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - SECTION("update into existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size - 1); - test::test_seek(offset, SEEK_SET); // 630978 - REQUIRE(((size_t)test::status_orig) == offset); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - fsync(test::fh_orig); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (i * info.stride_size) % info.total_size; - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (i * info.stride_size) % info.total_size; - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_write(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamic", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamic", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_write(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedWriteRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - - SECTION("write to new file always at the start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - size_t biggest_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.offset_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_size_written < request_size) - biggest_size_written = request_size; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_size_written); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - size_t total_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - args.request_size + (rand_r(&info.offset_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_size_written += test::size_written_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_size_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = (args.request_size + - (rand_r(&info.offset_seed) % args.request_size)) % - (info.total_size - current_offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.offset_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (i * info.stride_size) % info.total_size; - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (i * info.stride_size) % info.total_size; - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegative", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t prev_offset = info.total_size + 1; - for (size_t i = 0; i < info.num_iterations; ++i) { - auto stride_offset = info.total_size - i * info.stride_size; - REQUIRE(prev_offset > stride_offset); - prev_offset = stride_offset; - size_t offset = (stride_offset) % (info.total_size - args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegative", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - info.total_size - ((i * info.stride_size) % info.total_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_write(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (info.total_size - i * info.stride_size) % - (info.total_size - 2 * args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - info.total_size - ((i * info.stride_size) % info.total_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2D", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2D", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_write(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - 2 * args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - 2 * args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -/** - * Temporal Fixed - */ - -TEST_CASE("BatchedWriteTemporalFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=fixed]") { - pretest(); - - SECTION("write to existing file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == args.request_size); - } - - SECTION("write to new file always at start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialTemporalFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=fixed]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_WRONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedWriteTemporalVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=variable]") { - pretest(); - - SECTION("write to existing file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == args.request_size); - } - - SECTION("write to new file always at start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialTemporalVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=variable]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_WRONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedMixedSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_mixed]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read after write on new file") { - test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - size_t last_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_seek(last_offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == last_offset); - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - last_offset += args.request_size; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("write and read alternative existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - if (i % 2 == 0) { - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } else { - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("update after read existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t last_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_seek(last_offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == last_offset); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - last_offset += args.request_size; - } - - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("read all after write all on new file in single open") { - test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("read all after write all on new file in different open") { - test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.new_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("SingleMixed", "[process=" + std::to_string(info.comm_size) + - "][operation=single_mixed]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read after write from new file") { - test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("update after read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("read after write from new file different opens") { - test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.new_file.c_str(), O_RDWR); - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("fstat") { - pretest(); - - SECTION("fstat on new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - - struct stat buf = {}; - int result = __fxstat(_STAT_VER, test::fh_orig, &buf); - REQUIRE(result == 0); - REQUIRE(buf.st_size == (off_t)test::size_written_orig); - - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - posttest(); -} diff --git a/adapter/test/posix/posix_adapter_mpi_test.cpp b/adapter/test/posix/posix_adapter_mpi_test.cpp deleted file mode 100644 index 2dbdeeec0..000000000 --- a/adapter/test/posix/posix_adapter_mpi_test.cpp +++ /dev/null @@ -1,401 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include -#include - -#include "catch_config.h" - -#ifndef O_TMPFILE -#define O_TMPFILE 0 -#endif - -#include "adapter_test_utils.h" - -#if HERMES_INTERCEPT == 1 -#include "posix/real_api.h" -#endif - -namespace stdfs = std::experimental::filesystem; - -namespace hermes::adapter::posix::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp"; - size_t request_size = 65536; -}; -struct Info { - bool debug = false; - bool supports_tmpfile; - int rank = 0; - int comm_size = 1; - std::vector write_data; - std::vector read_data; - std::string new_file; - std::string existing_file; - std::string shared_new_file; - std::string existing_shared_file; - std::string new_file_cmp; - std::string existing_file_cmp; - std::string existing_shared_file_cmp; - std::string shared_new_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 1; - size_t total_size; - size_t stride_size = 4 * 1024; - unsigned int temporal_interval_ms = 5; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 512 * 1024; - size_t large_min = 512 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::posix::test - -hermes::adapter::posix::test::Arguments args; -hermes::adapter::posix::test::Info info; -std::vector gen_random(const int len) { - std::vector tmp_s(len); - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - - srand((unsigned)time(NULL) * getpid()); - - tmp_s.reserve(len); - - for (int i = 0; i < len; ++i) - tmp_s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; - - return tmp_s; -} - -int init(int* argc, char*** argv) { - MPI_Init(argc, argv); - info.write_data = gen_random(args.request_size); - info.read_data = std::vector(args.request_size, 'r'); - info.supports_tmpfile = FilesystemSupportsTmpfile(); - MPI_Comm_rank(MPI_COMM_WORLD, &info.rank); - MPI_Comm_size(MPI_COMM_WORLD, &info.comm_size); - if (info.debug && info.rank == 0) { - printf("%d ready for attach\n", info.comm_size); - fflush(stdout); - sleep(30); - } - MPI_Barrier(MPI_COMM_WORLD); - return 0; -} - -int finalize() { - MPI_Finalize(); - return 0; -} - -int pretest() { - REQUIRE(info.comm_size > 1); - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new_" + std::to_string(info.rank) + - "_of_" + std::to_string(info.comm_size) + "_" + - std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext_" + std::to_string(info.rank) + - "_of_" + std::to_string(info.comm_size) + "_" + - std::to_string(getpid()); - info.new_file_cmp = - fullpath.string() + "_new_cmp_" + std::to_string(info.rank) + "_of_" + - std::to_string(info.comm_size) + "_" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp_" + std::to_string(info.rank) + "_of_" + - std::to_string(info.comm_size) + "_" + std::to_string(getpid()); - info.existing_shared_file = - fullpath.string() + "_shared_ext_" + std::to_string(info.comm_size); - info.existing_shared_file_cmp = - fullpath.string() + "_shared_ext_cmp_" + std::to_string(info.comm_size); - info.shared_new_file = - fullpath.string() + "_shared_new_" + std::to_string(info.comm_size); - info.shared_new_file_cmp = - fullpath.string() + "_shared_new_cmp_" + std::to_string(info.comm_size); - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - if (stdfs::exists(info.existing_shared_file)) - stdfs::remove(info.existing_shared_file); - if (stdfs::exists(info.existing_shared_file_cmp)) - stdfs::remove(info.existing_shared_file_cmp); - if (stdfs::exists(info.shared_new_file)) stdfs::remove(info.shared_new_file); - if (stdfs::exists(info.shared_new_file_cmp)) - stdfs::remove(info.shared_new_file_cmp); - stdfs::path temp_fullpath = "/tmp"; - temp_fullpath /= args.filename; - std::string temp_ext_file = - temp_fullpath.string() + "_temp_" + std::to_string(info.rank) + "_of_" + - std::to_string(info.comm_size) + "_" + std::to_string(getpid()); - if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); - if (!stdfs::exists(temp_ext_file)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + temp_ext_file + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(temp_ext_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(temp_ext_file); - } - if (info.rank == 0 && !stdfs::exists(info.existing_shared_file)) { - std::string cmd = "cp " + temp_ext_file + " " + info.existing_shared_file; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_shared_file) == - args.request_size * info.num_iterations); - } - if (info.rank == 0 && !stdfs::exists(info.existing_shared_file_cmp)) { - std::string cmd = - "cp " + temp_ext_file + " " + info.existing_shared_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_shared_file_cmp) == - args.request_size * info.num_iterations); - } - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "cp " + temp_ext_file + " " + info.existing_file; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - } - if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); - REQUIRE(info.total_size > 0); - MPI_Barrier(MPI_COMM_WORLD); -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert( - info.existing_shared_file_cmp); -#endif - return 0; -} - -int posttest(bool compare_data = true) { -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_shared_file); -#endif - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_shared_file) && - stdfs::exists(info.existing_shared_file_cmp)) { - size_t size = stdfs::file_size(info.existing_shared_file); - if (size != stdfs::file_size(info.existing_shared_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_shared_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_shared_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_shared_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - /* Clean up. */ - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - MPI_Barrier(MPI_COMM_WORLD); - if (info.rank == 0) { - if (stdfs::exists(info.existing_shared_file)) - stdfs::remove(info.existing_shared_file); - if (stdfs::exists(info.existing_shared_file_cmp)) - stdfs::remove(info.existing_shared_file_cmp); - } - -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file_cmp); -#endif - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -namespace test { -int fh_orig; -int fh_cmp; -int status_orig; -size_t size_read_orig; -size_t size_written_orig; - -void test_open(const char* path, int flags, ...) { - int mode = 0; - if (flags & O_CREAT || flags & O_TMPFILE) { - va_list arg; - va_start(arg, flags); - mode = va_arg(arg, int); - va_end(arg); - } - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else if (strcmp(path, info.shared_new_file.c_str()) == 0) { - cmp_path = info.shared_new_file_cmp; - } else if (strcmp(path, "/tmp") == 0) { - cmp_path = "/tmp"; - } else { - cmp_path = info.existing_file_cmp; - } - if (flags & O_CREAT || flags & O_TMPFILE) { - fh_orig = open(path, flags, mode); - fh_cmp = open(cmp_path.c_str(), flags, mode); - } else { - fh_orig = open(path, flags); - fh_cmp = open(cmp_path.c_str(), flags); - } - bool is_same = - (fh_cmp != -1 && fh_orig != -1) || (fh_cmp == -1 && fh_orig == -1); - REQUIRE(is_same); -} -void test_close() { - status_orig = close(fh_orig); - int status = close(fh_cmp); - REQUIRE(status == status_orig); -} -void test_write(const void* ptr, size_t size) { - size_written_orig = write(fh_orig, ptr, size); - size_t size_written = write(fh_cmp, ptr, size); - REQUIRE(size_written == size_written_orig); -} -void test_read(char* ptr, size_t size) { - size_read_orig = read(fh_orig, ptr, size); - std::vector read_data(size, 'r'); - size_t size_read = read(fh_cmp, read_data.data(), size); - REQUIRE(size_read == size_read_orig); - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < size; ++i) { - if (read_data[i] != ptr[i]) { - unmatching_chars = i; - break; - } - } - REQUIRE(unmatching_chars == 0); - } -} -void test_seek(long offset, int whence) { - status_orig = lseek(fh_orig, offset, whence); - int status = lseek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -#include "posix_adapter_basic_test.cpp" -#include "posix_adapter_rs_test.cpp" -// TODO(chogan): Disabling until issue #302 is fixed -// #include "posix_adapter_shared_test.cpp" diff --git a/adapter/test/posix/posix_adapter_rs_test.cpp b/adapter/test/posix/posix_adapter_rs_test.cpp deleted file mode 100644 index d52d4438d..000000000 --- a/adapter/test/posix/posix_adapter_rs_test.cpp +++ /dev/null @@ -1,1239 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -TEST_CASE("BatchedWriteRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at the start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - size_t biggest_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_size_written < request_size) - biggest_size_written = request_size; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_size_written); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - size_t total_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_size_written += test::size_written_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_size_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - (i * info.stride_size) % (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - (i * info.stride_size) % (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (info.total_size - i * info.stride_size) % - (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = info.total_size - ((i * info.stride_size) % - (info.total_size - info.small_max)); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} -/** - * Medium RS - **/ - -TEST_CASE("BatchedWriteRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at the start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - size_t biggest_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_size_written < request_size) - biggest_size_written = request_size; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_size_written); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - size_t total_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_size_written += test::size_written_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_size_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - (info.medium_min + (rand_r(&info.rs_seed) % info.medium_max)) % - (info.total_size - current_offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - (i * info.stride_size) % (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - (i * info.stride_size) % (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (info.total_size - i * info.stride_size) % - (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = info.total_size - ((i * info.stride_size) % - (info.total_size - info.medium_max)); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} -/** - * Large RS - **/ - -TEST_CASE("BatchedWriteRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at the start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - size_t biggest_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_size_written < request_size) - biggest_size_written = request_size; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_size_written); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - size_t total_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_size_written += test::size_written_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_size_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % - (info.total_size - current_offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % - (info.total_size - test::status_orig); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - (i * info.stride_size) % (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - (i * info.stride_size) % (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (info.total_size - i * info.stride_size) % - (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % - (info.total_size - info.large_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = info.total_size - ((i * info.stride_size) % - (info.total_size - info.large_max)); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} diff --git a/adapter/test/posix/posix_adapter_shared_test.cpp b/adapter/test/posix/posix_adapter_shared_test.cpp deleted file mode 100644 index 0b64d299e..000000000 --- a/adapter/test/posix/posix_adapter_shared_test.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -TEST_CASE("SharedFile", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[mode=shared]" - "[pattern=sequential][file=1]") { - pretest(); - REQUIRE(info.comm_size == 2); - SECTION("producer-consumer") { - bool producer = info.rank % 2 == 0; - struct flock lock; - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - lock.l_pid = getpid(); - if (producer) { - int fd = open(info.shared_new_file.c_str(), O_RDWR | O_CREAT, 0666); - REQUIRE(fd != -1); - MPI_Barrier(MPI_COMM_WORLD); - int status = -1; - for (size_t i = 0; i < info.num_iterations; ++i) { - status = fcntl(fd, F_SETLKW, &lock); - REQUIRE(status != -1); - size_t write_bytes = - write(fd, info.write_data.data(), args.request_size); - REQUIRE(write_bytes == args.request_size); - lock.l_type = F_UNLCK; - status = fcntl(fd, F_SETLK, &lock); - REQUIRE(status != -1); - } - status = close(fd); - REQUIRE(status != -1); - } else { - MPI_Barrier(MPI_COMM_WORLD); - int fd = open(info.shared_new_file.c_str(), O_RDONLY); - REQUIRE(fd != -1); - int status = -1; - size_t bytes_read = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - lock.l_type = F_RDLCK; - status = fcntl(fd, F_SETLKW, &lock); - REQUIRE(status != -1); - size_t file_size = lseek(fd, 0, SEEK_END); - size_t cur_offset = lseek(fd, bytes_read, SEEK_SET); - REQUIRE(cur_offset == bytes_read); - if (file_size > bytes_read) { - size_t read_size = args.request_size < file_size - bytes_read - ? args.request_size - : file_size - bytes_read; - size_t read_bytes = read(fd, info.read_data.data(), read_size); - REQUIRE(read_bytes == read_size); - bytes_read += read_bytes; - } - lock.l_type = F_UNLCK; - status = fcntl(fd, F_SETLK, &lock); - REQUIRE(status != -1); - } - status = close(fd); - REQUIRE(status != -1); - } - } - posttest(); -} diff --git a/adapter/test/posix/posix_adapter_test.cpp b/adapter/test/posix/posix_adapter_test.cpp deleted file mode 100644 index c57c0a402..000000000 --- a/adapter/test/posix/posix_adapter_test.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include -#include - -#include "catch_config.h" -#if HERMES_INTERCEPT == 1 -#include "posix/real_api.h" -#endif - -#ifndef O_TMPFILE -#define O_TMPFILE 0 -#endif - -#include "adapter_test_utils.h" - -namespace stdfs = std::experimental::filesystem; - -namespace hermes::adapter::posix::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp"; - size_t request_size = 65536; -}; -struct Info { - int rank = 0; - int comm_size = 1; - bool supports_tmpfile; - std::vector write_data; - std::vector read_data; - std::string new_file; - std::string existing_file; - std::string new_file_cmp; - std::string existing_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 5; - size_t total_size; - size_t stride_size = 1024; - unsigned int temporal_interval_ms = 1; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; - size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::posix::test -hermes::adapter::posix::test::Arguments args; -hermes::adapter::posix::test::Info info; -std::vector gen_random(const int len) { - auto tmp_s = std::vector(len); - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - - srand(100); - for (int i = 0; i < len; ++i) - tmp_s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; - return tmp_s; -} - -int init(int* argc, char*** argv) { - MPI_Init(argc, argv); - info.write_data = gen_random(args.request_size); - info.read_data = std::vector(args.request_size, 'r'); - info.supports_tmpfile = FilesystemSupportsTmpfile(); - return 0; -} - -int finalize() { - MPI_Finalize(); - return 0; -} - -int pretest() { - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new_" + std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext_" + std::to_string(getpid()); - info.new_file_cmp = - fullpath.string() + "_new_cmp" + "_" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp" + "_" + std::to_string(getpid()); - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + info.existing_file + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - } - REQUIRE(info.total_size > 0); -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); -#endif - return 0; -} - -int posttest(bool compare_data = true) { -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); -#endif - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, 'r'); - std::vector d2(size, 'w'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), sizeof(unsigned char), size, fh1); - REQUIRE(read_d1 == size); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), sizeof(unsigned char), size, fh2); - REQUIRE(read_d2 == size); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) { - char_mismatch = pos; - break; - } - } - REQUIRE(char_mismatch == 0); - } - } - /* Clean up. */ - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); -#endif - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -namespace test { -int fh_orig; -int fh_cmp; -int status_orig; -size_t size_read_orig; -size_t size_written_orig; -void test_open(const char* path, int flags, ...) { - int mode = 0; - if (flags & O_CREAT || flags & O_TMPFILE) { - va_list arg; - va_start(arg, flags); - mode = va_arg(arg, int); - va_end(arg); - } - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else if (strcmp(path, "/tmp") == 0) { - cmp_path = "/tmp"; - } else { - cmp_path = info.existing_file_cmp; - } - if (flags & O_CREAT || flags & O_TMPFILE) { - fh_orig = open(path, flags, mode); - fh_cmp = open(cmp_path.c_str(), flags, mode); - } else { - fh_orig = open(path, flags); - fh_cmp = open(cmp_path.c_str(), flags); - } - bool is_same = - (fh_cmp != -1 && fh_orig != -1) || (fh_cmp == -1 && fh_orig == -1); - REQUIRE(is_same); -} -void test_close() { - status_orig = close(fh_orig); - int status = close(fh_cmp); - REQUIRE(status == status_orig); -} -void test_write(const void* ptr, size_t size) { - size_written_orig = write(fh_orig, ptr, size); - size_t size_written = write(fh_cmp, ptr, size); - REQUIRE(size_written == size_written_orig); -} -void test_read(char* ptr, size_t size) { - size_read_orig = read(fh_orig, ptr, size); - std::vector read_data(size, 'r'); - size_t size_read = read(fh_cmp, read_data.data(), size); - REQUIRE(size_read == size_read_orig); - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < size; ++i) { - if (read_data[i] != ptr[i]) { - unmatching_chars = i; - break; - } - } - REQUIRE(unmatching_chars == 0); - } -} -void test_seek(long offset, int whence) { - status_orig = lseek(fh_orig, offset, whence); - int status = lseek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -#include "posix_adapter_basic_test.cpp" -#include "posix_adapter_rs_test.cpp" diff --git a/adapter/test/posix/simple_io.cc b/adapter/test/posix/simple_io.cc deleted file mode 100644 index 78db64ab9..000000000 --- a/adapter/test/posix/simple_io.cc +++ /dev/null @@ -1,106 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "mpi.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool VerifyBuffer(char *ptr, size_t size, char nonce) { - for (size_t i = 0; i < size; ++i) { - if (ptr[i] != nonce) { - std::cout << (int)ptr[i] << " != " << (int)nonce << std::endl; - return false; - } - } - return true; -} - -int main(int argc, char **argv) { - int rank, nprocs; - MPI_Init(&argc, &argv); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nprocs); - if (argc != 7) { - std::cout << "USAGE: ./posix_simple_io" - << " [path] [read] [block_size (kb)] [count]" - << " [off (blocks)] [lag (sec)]"; - exit(1); - } - - char *path = argv[1]; - int do_read = atoi(argv[2]); - int block_size = atoi(argv[3])*1024; - int count = atoi(argv[4]); - int block_off = atoi(argv[5]); - int lag = atoi(argv[6]); - if (do_read) { - count -= block_off; - } else { - block_off = 0; - } - size_t size = count * block_size; - size_t total_size = size * nprocs; - int off = (rank * size) + block_off * block_size; - - std::stringstream ss; - ss << "RANK: " << rank << std::endl - << " PATH: " << path << std::endl - << " READ or WRITE: " << (do_read ? "READ" : "WRITE") << std::endl - << " Block Off: " << block_off << std::endl - << " Block Size: " << block_size << std::endl - << " Count: " << count << std::endl - << " Proc Size (MB): " << size / (1<<20) << std::endl; - std::cout << ss.str() << std::endl; - - sleep(lag); - - char *buf = (char*)malloc(size); - int fd = open(path, O_CREAT | O_RDWR, 0666); - lseek(fd, off, SEEK_SET); - - struct stat st; - __fxstat(_STAT_VER, fd, &st); - if (do_read && (st.st_size - total_size) > 3) { - if (rank == 0) { - std::cout << "File sizes aren't equivalent: " - << " stat: " << st.st_size - << " real: " << total_size << std::endl; - } - exit(1); - } - - for (int i = 0; i < count; ++i) { - char nonce = i; - if (!do_read) { - memset(buf, nonce, block_size); - write(fd, buf, block_size); - } else { - memset(buf, 0, block_size); - read(fd, buf, block_size); - if (!VerifyBuffer(buf, block_size, nonce)) { - std::cout << "Buffer verification failed!" << std::endl; - exit(1); - } - } - } - - close(fd); - MPI_Finalize(); -} diff --git a/adapter/test/pubsub/CMakeLists.txt b/adapter/test/pubsub/CMakeLists.txt deleted file mode 100644 index 9224dc707..000000000 --- a/adapter/test/pubsub/CMakeLists.txt +++ /dev/null @@ -1,45 +0,0 @@ -#------------------------------------------------------------------------------ -# PubSub Adapter tests -#------------------------------------------------------------------------------ -add_executable(pubsub_metadata_test ${CMAKE_CURRENT_SOURCE_DIR}/pubsub_metadata_test.cc) -add_test(NAME "pubsub_metadata_test" COMMAND "${CMAKE_BINARY_DIR}/bin/pubsub_metadata_test") -target_link_libraries(pubsub_metadata_test ${LIBRT} hermes MPI::MPI_CXX - $<$:thallium> hermes_pubsub) -add_dependencies(pubsub_metadata_test hermes_pubsub) - -set(SINGLE_NODE_PUBSUB_TESTS pubsub_topic_test pubsub_end_to_end_test) -set(MULTI_NODE_PUBSUB_TESTS pubsub_end_to_end_test_sync) -set(EXTENDED_PUBSUB_TESTS ${SINGLE_NODE_PUBSUB_TESTS} ${MULTI_NODE_PUBSUB_TESTS} pubsub_metadata_test) - -foreach(program ${SINGLE_NODE_PUBSUB_TESTS}) - add_executable(${program} ${CMAKE_CURRENT_SOURCE_DIR}/${program}.cc) - add_dependencies(${program} hermes_pubsub) - target_link_libraries(${program} ${LIBRT} hermes MPI::MPI_CXX - $<$:thallium> hermes_pubsub) - mpi_daemon(${program} 1 "" "" 1) -endforeach() - -foreach(program ${MULTI_NODE_PUBSUB_TESTS}) - add_executable(${program} ${CMAKE_CURRENT_SOURCE_DIR}/${program}.cc) - add_dependencies(${program} hermes_pubsub) - target_link_libraries(${program} ${LIBRT} hermes MPI::MPI_CXX - $<$:thallium> hermes_pubsub) - mpi_daemon(${program} 2 "" "" 1) -endforeach() - -foreach(program ${EXTENDED_PUBSUB_TESTS}) - target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_DIR}) - target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_TEST_DIR}) -endforeach() - -if(HERMES_INSTALL_TESTS) - foreach(program ${EXTENDED_PUBSUB_TESTS}) - install( - TARGETS - ${program} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} - ) - endforeach() -endif() diff --git a/adapter/test/pubsub/pubsub_end_to_end_test.cc b/adapter/test/pubsub/pubsub_end_to_end_test.cc deleted file mode 100644 index 15ffa4d04..000000000 --- a/adapter/test/pubsub/pubsub_end_to_end_test.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "test_utils.h" - -int main(int argc, char **argv) { - hermes::pubsub::mpiInit(argc, argv); - - char *config_file = 0; - if (argc == 2) { - config_file = argv[1]; - } else { - config_file = getenv(kHermesConf); - } - - auto connect_ret = hermes::pubsub::connect(config_file); - Assert(connect_ret.Succeeded()); - - if (connect_ret.Succeeded()) { - auto attach_ret = hermes::pubsub::attach("test"); - Assert(attach_ret.Succeeded()); - - hapi::Blob data1(4*1024, rand() % 255); - hapi::Blob data2(4*1024, rand() % 255); - hapi::Blob data3(4*1024, rand() % 255); - - auto publish_ret = hermes::pubsub::publish("test", data1); - Assert(publish_ret.Succeeded()); - - auto subscribe_ret_1 = hermes::pubsub::subscribe("test"); - Assert(subscribe_ret_1.second.Succeeded()); - Assert(data1 == subscribe_ret_1.first); - - publish_ret = hermes::pubsub::publish("test", data2); - Assert(publish_ret.Succeeded()); - - publish_ret = hermes::pubsub::publish("test", data3); - Assert(publish_ret.Succeeded()); - - // this subscribe reads data2; - hermes::pubsub::subscribe("test"); - - auto subscribe_ret_2 = hermes::pubsub::subscribe("test"); - Assert(subscribe_ret_2.second.Succeeded()); - Assert(data3 == subscribe_ret_2.first); - - auto detach_ret = hermes::pubsub::detach("test"); - Assert(detach_ret.Succeeded()); - } - auto disconnect_ret = hermes::pubsub::disconnect(); - Assert(disconnect_ret.Succeeded()); - - MPI_Finalize(); -} diff --git a/adapter/test/pubsub/pubsub_end_to_end_test_sync.cc b/adapter/test/pubsub/pubsub_end_to_end_test_sync.cc deleted file mode 100644 index 6e5839e08..000000000 --- a/adapter/test/pubsub/pubsub_end_to_end_test_sync.cc +++ /dev/null @@ -1,68 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "test_utils.h" - -int main(int argc, char **argv) { - hermes::pubsub::mpiInit(argc, argv); - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - int comm_size; - MPI_Comm_size(MPI_COMM_WORLD, &comm_size); - - char *config_file = 0; - if (argc == 2) { - config_file = argv[1]; - } else { - config_file = getenv(kHermesConf); - } - - auto connect_ret = hermes::pubsub::connect(config_file); - - if (connect_ret.Succeeded()) { - auto attach_ret = hermes::pubsub::attach("test"); - Assert(attach_ret.Succeeded()); - - std::vector full_data; - hapi::Blob data1(4*1024, rand() % 255); - hapi::Blob data2(4*1024, rand() % 255); - hapi::Blob data3(4*1024, rand() % 255); - full_data.push_back(data1); - full_data.push_back(data2); - full_data.push_back(data3); - - for (const auto& data : full_data) { - auto publish_ret = hermes::pubsub::publish("test", data); - Assert(publish_ret.Succeeded()); - } - - auto hermes = hermes::Singleton - ::GetInstance()->GetHermes(); - MPI_Comm comm = *(MPI_Comm*)hermes->GetAppCommunicator(); - MPI_Barrier(comm); - - unsigned long num_messages = full_data.size(); - std::pair subscribe_ret; - for (unsigned long i = 0; i < num_messages*comm_size; i++) { - subscribe_ret = hermes::pubsub::subscribe("test"); - Assert(subscribe_ret.second.Succeeded()); - } - - auto detach_ret = hermes::pubsub::detach("test"); - Assert(detach_ret.Succeeded()); - } - auto disconnect_ret = hermes::pubsub::disconnect(); - Assert(disconnect_ret.Succeeded()); - - MPI_Finalize(); -} diff --git a/adapter/test/pubsub/pubsub_metadata_test.cc b/adapter/test/pubsub/pubsub_metadata_test.cc deleted file mode 100644 index 051fc2ab2..000000000 --- a/adapter/test/pubsub/pubsub_metadata_test.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "singleton.h" -#include "test_utils.h" - -int main() { - auto mdm = hermes::Singleton - ::GetInstance(false); - ClientMetadata stat; - struct timespec ts{}; - timespec_get(&ts, TIME_UTC); - stat.st_atim = ts; - - auto create_ret = mdm->Create("test", stat); - Assert(create_ret == true); - create_ret = mdm->Create("test", stat); - Assert(create_ret == false); - - auto find_ret = mdm->Find("test"); - Assert(find_ret.second == true); - Assert(find_ret.first.st_atim.tv_nsec == ts.tv_nsec); - - struct timespec ts1{}; - timespec_get(&ts1, TIME_UTC); - stat.st_atim = ts1; - auto update_ret = mdm->Update("test", stat); - Assert(update_ret == true); - find_ret = mdm->Find("test"); - Assert(find_ret.second == true); - Assert(find_ret.first.st_atim.tv_nsec >= ts.tv_nsec); - Assert(find_ret.first.st_atim.tv_nsec == ts1.tv_nsec); - - auto delete_ret = mdm->Delete("test"); - Assert(delete_ret == true); - delete_ret = mdm->Delete("test"); - Assert(delete_ret == false); - find_ret = mdm->Find("test"); - Assert(find_ret.second == false); - update_ret = mdm->Update("test", stat); - Assert(update_ret == false); -} diff --git a/adapter/test/pubsub/pubsub_topic_test.cc b/adapter/test/pubsub/pubsub_topic_test.cc deleted file mode 100644 index aa8de63ac..000000000 --- a/adapter/test/pubsub/pubsub_topic_test.cc +++ /dev/null @@ -1,41 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "test_utils.h" - -int main(int argc, char **argv) { - hermes::pubsub::mpiInit(argc, argv); - - char *config_file = 0; - if (argc == 2) { - config_file = argv[1]; - } else { - config_file = getenv(kHermesConf); - } - - auto connect_ret = hermes::pubsub::connect(config_file); - Assert(connect_ret.Succeeded()); - - auto attach_ret = hermes::pubsub::attach("test"); - Assert(attach_ret.Succeeded()); - - auto detach_ret = hermes::pubsub::detach("test"); - Assert(detach_ret.Succeeded()); - - auto disconnect_ret = hermes::pubsub::disconnect(); - Assert(disconnect_ret.Succeeded()); - - MPI_Finalize(); - - return 0; -} diff --git a/adapter/test/pubsub/test_utils.h b/adapter/test/pubsub/test_utils.h deleted file mode 100644 index 2fcece367..000000000 --- a/adapter/test/pubsub/test_utils.h +++ /dev/null @@ -1,31 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_PUBSUB_TEST_UTILS_H_ -#define HERMES_PUBSUB_TEST_UTILS_H_ - -namespace hermes::pubsub::testing { - -void Assert(bool expr, const char *file, int lineno, const char *message) { - if (!expr) { - fprintf(stderr, "Assertion failed at %s: line %d: %s\n", file, lineno, - message); - exit(-1); - } -} - -#define Assert(expr) \ - hermes::pubsub::testing::Assert((expr), __FILE__, __LINE__, #expr) - -} // namespace hermes::pubsub::testing - -#endif // HERMES_PUBSUB_TEST_UTILS_H_ diff --git a/adapter/test/run_hermes.sh b/adapter/test/run_hermes.sh deleted file mode 100644 index cfa45b668..000000000 --- a/adapter/test/run_hermes.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -MPI_EXEC=$1 -TEST_EXEC=$2 -TEST_PROCS=$3 -HERMES_EXEC=$4 -HERMES_PROCS=$5 -HERMES_CONF=$6 -TEST_ARGS="${@:7}" -SLEEP_TIME=3 - -error_ct=0 -if [[ ! -f "$MPI_EXEC" ]]; then - echo "MPI_EXEC ${MPI_EXEC} does not exists." >&2 - error_ct=$((error_ct + 1)) -fi -if [[ ! -f "${TEST_EXEC}" ]]; then - echo "TEST_EXEC ${TEST_EXEC} does not exists." >&2 - error_ct=$((error_ct + 1)) -fi -if [[ ! -f "${HERMES_EXEC}" ]]; then - echo "HERMES_EXEC ${HERMES_EXEC} does not exists." >&2 - error_ct=$((error_ct + 1)) -fi -if [[ ! -f "${HERMES_CONF}" ]]; then - echo "HERMES_CONF ${HERMES_CONF} does not exists." >&2 - error_ct=$((error_ct + 1)) -fi -if [ $error_ct -gt 0 ]; then - echo "Arguments are wrong !!!" >&2 - exit $error_ct -fi - -echo "${MPI_EXEC} -n ${HERMES_PROCS} ${HERMES_EXEC} ${HERMES_CONF} &" -${MPI_EXEC} -n ${HERMES_PROCS} ${HERMES_EXEC} ${HERMES_CONF} & -HERMES_EXEC_PID=$! -echo "process spawned ${HERMES_EXEC_PID}" - -echo "Started hermes daemon with ${HERMES_PROCS} procs. sleeping for ${SLEEP_TIME} seconds" -sleep ${SLEEP_TIME} - -echo "${MPI_EXEC} -n ${TEST_PROCS} ${TEST_EXEC} ${TEST_ARGS}" -${MPI_EXEC} -n ${TEST_PROCS} ${TEST_EXEC} ${TEST_ARGS} -status=$? -echo "Killing Hermes daemon with PID ${HERMES_EXEC_PID}" -kill ${HERMES_EXEC_PID} -if [ $status -gt 0 ]; then - echo "Test failed with code $status!" >&2 - exit $status -fi -echo "Finishing test." -exit 0 diff --git a/adapter/test/stdio/CMakeLists.txt b/adapter/test/stdio/CMakeLists.txt deleted file mode 100644 index c1d2fb4f8..000000000 --- a/adapter/test/stdio/CMakeLists.txt +++ /dev/null @@ -1,111 +0,0 @@ -function(gcc_hermes exec tag_name tags conf async) - set(TEST_NAME Test${exec}_${tag_name}_${async}) - add_test(NAME ${TEST_NAME} - COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) - set_property(TEST ${TEST_NAME} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/${conf}.yaml) - set_property(TEST ${TEST_NAME} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) - - if ("${async}" STREQUAL "async") - set_property(TEST ${TEST_NAME} APPEND PROPERTY ENVIRONMENT HERMES_ASYNC_FLUSH=1) - endif() -endfunction() - -function(gcc_hermes_mode exec tag_name tags mode path) - set(test_name Test${exec}_${tag_name}_${mode}_${path}) - add_test(NAME ${test_name} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) - set_property(TEST ${test_name} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT ADAPTER_MODE=${mode}) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT SET_PATH=${path}) -endfunction() - -#------------------------------------------------------------------------------ -# STDIO Adapter Internal tests -#------------------------------------------------------------------------------ -add_executable(stdio_adapter_mapper_test stdio_adapter_mapper_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(stdio_adapter_mapper_test hermes_stdio) -add_dependencies(stdio_adapter_mapper_test hermes_stdio) -gcc(stdio_adapter_mapper_test "") - -#------------------------------------------------------------------------------ -# STDIO Adapter End to End tests -#------------------------------------------------------------------------------ -add_executable(stdio_adapter_test stdio_adapter_test.cpp ${ADAPTER_COMMON}) -gcc(stdio_adapter_test "") - -add_executable(stdio_adapter_mpi_test stdio_adapter_mpi_test.cpp ${ADAPTER_COMMON}) -mpi(stdio_adapter_mpi_test 2 "") - -add_executable(hermes_stdio_adapter_test stdio_adapter_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_stdio_adapter_test hermes_stdio) -add_dependencies(hermes_stdio_adapter_test hermes_stdio hermes_daemon) -set_target_properties(hermes_stdio_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -gcc_hermes(hermes_stdio_adapter_test "" "~[request_size=range-large]" hermes "") -gcc_hermes(hermes_stdio_adapter_test "large" "[request_size=range-large]" hermes "") -gcc_hermes(hermes_stdio_adapter_test "" "~[request_size=range-large]" hermes async) -gcc_hermes(hermes_stdio_adapter_test "large" "[request_size=range-large]" hermes async) - -add_executable(hermes_stdio_low_buf_adapter_test stdio_adapter_low_buffer_space_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_stdio_low_buf_adapter_test hermes_stdio) -add_dependencies(hermes_stdio_low_buf_adapter_test hermes_stdio hermes_daemon) -set_target_properties(hermes_stdio_low_buf_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -gcc_hermes(hermes_stdio_low_buf_adapter_test "" "" hermes_small "") -gcc_hermes(hermes_stdio_low_buf_adapter_test "" "" hermes_small async) - -add_executable(hermes_stdio_adapter_mode_test stdio_adapter_mode_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_stdio_adapter_mode_test hermes_stdio) -add_dependencies(hermes_stdio_adapter_mode_test hermes_stdio hermes_daemon) -set_target_properties(hermes_stdio_adapter_mode_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -gcc_hermes_mode(hermes_stdio_adapter_mode_test "persistent" "[hermes_mode=persistent]" "DEFAULT" "0") -gcc_hermes_mode(hermes_stdio_adapter_mode_test "scratch" "[hermes_mode=scratch]" "SCRATCH" "0") -gcc_hermes_mode(hermes_stdio_adapter_mode_test "bypass" "[hermes_mode=bypass]" "BYPASS" "0") -gcc_hermes_mode(hermes_stdio_adapter_mode_test "persistent" "[hermes_mode=persistent]" "DEFAULT" "1") -gcc_hermes_mode(hermes_stdio_adapter_mode_test "scratch" "[hermes_mode=scratch]" "SCRATCH" "1") -gcc_hermes_mode(hermes_stdio_adapter_mode_test "bypass" "[hermes_mode=bypass]" "BYPASS" "1") - -add_executable(hermes_stdio_adapter_mpi_test stdio_adapter_mpi_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_stdio_adapter_mpi_test hermes_stdio) -add_dependencies(hermes_stdio_adapter_mpi_test hermes_stdio hermes_daemon) -set_target_properties(hermes_stdio_adapter_mpi_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -mpi_daemon(hermes_stdio_adapter_mpi_test 2 "~[request_size=range-large]" "" 1) -mpi_daemon(hermes_stdio_adapter_mpi_test 2 "[request_size=range-large]" "large" 1) - -add_executable(adapter_utils_test adapter_utils_test.cc ${ADAPTER_COMMON}) -target_link_libraries(adapter_utils_test hermes_stdio) -add_dependencies(adapter_utils_test hermes_stdio) -gcc(adapter_utils_test "") - -set(STDIO_TESTS - stdio_adapter_mapper_test - stdio_adapter_test - hermes_stdio_adapter_test - hermes_stdio_low_buf_adapter_test - hermes_stdio_adapter_mode_test - stdio_adapter_mpi_test - hermes_stdio_adapter_mpi_test - adapter_utils_test -) - -foreach(program ${STDIO_TESTS}) - target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_DIR}) - target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_TEST_DIR}) - target_link_libraries(${program} Catch2::Catch2 -lstdc++fs -lc MPI::MPI_CXX) -endforeach() - -if(HERMES_INSTALL_TESTS) - foreach(program ${STDIO_TESTS}) - install( - TARGETS - ${program} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} - ) - endforeach() -endif() diff --git a/adapter/test/stdio/adapter_utils_test.cc b/adapter/test/stdio/adapter_utils_test.cc deleted file mode 100644 index c9bd32ef4..000000000 --- a/adapter/test/stdio/adapter_utils_test.cc +++ /dev/null @@ -1,104 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "catch_config.h" -#include "adapter_utils.h" - -namespace stdfs = std::experimental::filesystem; - -int init(int* argc, char*** argv) { - (void)argc; - (void)argv; - return 0; -} - -int finalize() { - return 0; -} - -cl::Parser define_options() { - return cl::Parser(); -} - -// NOTE(chogan) GCC's test for weakly_canonical -TEST_CASE("WeaklyCanonical") { - namespace had = hermes::adapter; - - const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); - std::error_code ec; - - auto dir = stdfs::path("tmp"); - if (stdfs::exists(dir)) { - stdfs::remove_all(dir, ec); - } - - stdfs::create_directory(dir); - const auto dirc = stdfs::canonical(dir); - stdfs::path foo = dir/"foo", bar = dir/"bar"; - stdfs::create_directory(foo); - stdfs::create_directory(bar); - stdfs::create_directory(bar/"baz"); - stdfs::path p; - - stdfs::create_symlink("../bar", foo/"bar"); - - p = had::WeaklyCanonical(dir/"foo//./bar///../biz/."); - REQUIRE(p == dirc/"biz"); - p = had::WeaklyCanonical(dir/"foo/.//bar/././baz/."); - REQUIRE(p == dirc/"bar/baz"); - p = had::WeaklyCanonical(stdfs::current_path()/dir/"bar//../foo/bar/baz"); - REQUIRE(p == dirc/"bar/baz"); - - ec = bad_ec; - p = had::WeaklyCanonical(dir/"foo//./bar///../biz/.", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"biz"); - ec = bad_ec; - p = had::WeaklyCanonical(dir/"foo/.//bar/././baz/.", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"bar/baz"); - ec = bad_ec; - p = had::WeaklyCanonical(stdfs::current_path()/dir/"bar//../foo/bar/baz", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"bar/baz"); - - ec = bad_ec; - p = had::WeaklyCanonical(dir/"bar/", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"bar"); - - // As above, but using "foo/.." instead of "foo", - // because there is no "foo/bar" symlink - - p = had::WeaklyCanonical(dir/"./bar///../biz/."); - REQUIRE(p == dirc/"biz"); - p = had::WeaklyCanonical(dir/"foo/.././/bar/././baz/."); - REQUIRE(p == dirc/"bar/baz"); - p = had::WeaklyCanonical(stdfs::current_path()/dir/"bar//../foo/../bar/baz"); - REQUIRE(p == dirc/"bar/baz"); - - ec = bad_ec; - p = had::WeaklyCanonical(dir/"foo/..//./bar///../biz/.", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"biz"); - ec = bad_ec; - p = had::WeaklyCanonical(dir/"foo/.././/bar/././baz/.", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"bar/baz"); - ec = bad_ec; - p = had::WeaklyCanonical( - stdfs::current_path()/dir/"bar//../foo/../bar/baz", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"bar/baz"); - - stdfs::remove_all(dir, ec); -} diff --git a/adapter/test/stdio/stdio_adapter_basic_test.cpp b/adapter/test/stdio/stdio_adapter_basic_test.cpp deleted file mode 100644 index 7dacb3f52..000000000 --- a/adapter/test/stdio/stdio_adapter_basic_test.cpp +++ /dev/null @@ -1,1308 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -TEST_CASE("Open", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_open]" - "[repetition=1][file=1]") { - pretest(); - SECTION("open non-existant file") { - test::test_fopen(info.new_file.c_str(), "r"); - REQUIRE(test::fh_orig == nullptr); - test::test_fopen(info.new_file.c_str(), "r+"); - REQUIRE(test::fh_orig == nullptr); - } - - SECTION("truncate existing file and write-only") { - test::test_fopen(info.existing_file.c_str(), "w"); - REQUIRE(test::fh_orig != nullptr); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("truncate existing file and read/write") { - test::test_fopen(info.existing_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("open existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("append write existing file") { - test::test_fopen(info.existing_file.c_str(), "a"); - REQUIRE(test::fh_orig != nullptr); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("append write and read existing file") { - test::test_fopen(info.existing_file.c_str(), "a+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("write to new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == test::size_written_orig); - } - - SECTION("write to existing file with truncate") { - test::test_fopen(info.existing_file.c_str(), "w"); - REQUIRE(test::fh_orig != nullptr); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.existing_file) == test::size_written_orig); - } - - SECTION("write to existing file at the end") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fseek(0, SEEK_END); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == args.request_size * info.num_iterations); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.existing_file) == - test::size_written_orig + offset); - } - - SECTION("append to existing file") { - auto existing_size = stdfs::file_size(info.existing_file); - test::test_fopen(info.existing_file.c_str(), "a+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.existing_file) == - existing_size + test::size_written_orig); - } - - SECTION("append to new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == test::size_written_orig); - } - posttest(); -} - -TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read from non-existing file") { - test::test_fopen(info.new_file.c_str(), "r"); - REQUIRE(test::fh_orig == nullptr); - } - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("read at the end of existing file") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - test::test_fseek(0, SEEK_END); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == args.request_size * info.num_iterations); - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == 0); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedWriteSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at beginning") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == args.request_size); - } - - SECTION("write to new file sequentially") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedReadSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - SECTION("update into existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - fflush(test::fh_orig); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % info.total_size; - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("update from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % info.total_size; - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fwrite(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamic", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamic", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("update from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fwrite(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedWriteRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - - SECTION("write to new file always at the start") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t biggest_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - args.request_size + (rand_r(&info.offset_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_written < request_size) biggest_written = request_size; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_written); - } - - SECTION("write to new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t total_test_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - args.request_size + (rand_r(&info.offset_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_test_written += test::size_written_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_test_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = (args.request_size + - (rand_r(&info.offset_seed) % args.request_size)) % - (info.total_size - current_offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - args.request_size + (rand_r(&info.offset_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % info.total_size; - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % info.total_size; - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegative", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t prev_offset = info.total_size + 1; - for (size_t i = 0; i < info.num_iterations; ++i) { - auto stride_offset = info.total_size - i * info.stride_size; - REQUIRE(prev_offset > stride_offset); - prev_offset = stride_offset; - auto offset = (stride_offset) % (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegative", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - info.total_size - ((i * info.stride_size) % info.total_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fwrite(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (info.total_size - i * info.stride_size) % - (info.total_size - 2 * args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - info.total_size - ((i * info.stride_size) % info.total_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2D", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2D", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fwrite(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - 2 * args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - 2 * args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -/** - * Temporal Fixed - */ - -TEST_CASE("BatchedWriteTemporalFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=fixed]") { - pretest(); - - SECTION("write to existing file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == args.request_size); - } - - SECTION("write to new file always at start") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialTemporalFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=fixed]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedWriteTemporalVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=variable]") { - pretest(); - - SECTION("write to existing file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == args.request_size); - } - - SECTION("write to new file always at start") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialTemporalVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=variable]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedMixedSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_mixed]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read after write on new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t last_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fseek(last_offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - last_offset += args.request_size; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("write and read alternative existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - if (i % 2 == 0) { - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } else { - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("update after read existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t last_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_fseek(last_offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - last_offset += args.request_size; - } - - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("read all after write all on new file in single open") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("read all after write all on new file in different open") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - test::test_fopen(info.new_file.c_str(), "r"); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("SingleMixed", "[process=" + std::to_string(info.comm_size) + - "][operation=single_mixed]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read after write from new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("update after read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("read after write from new file different opens") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - test::test_fopen(info.new_file.c_str(), "r+"); - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} diff --git a/adapter/test/stdio/stdio_adapter_func_test.cpp b/adapter/test/stdio/stdio_adapter_func_test.cpp deleted file mode 100644 index b3dda30a5..000000000 --- a/adapter/test/stdio/stdio_adapter_func_test.cpp +++ /dev/null @@ -1,771 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -TEST_CASE("FFlush", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fflush]" - "[repetition=1][file=1]") { - pretest(); - SECTION("Flushing contents of file in different modes") { - FILE* fd = fopen(info.existing_file.c_str(), "w"); - REQUIRE(fd != nullptr); - int status = fflush(fd); - REQUIRE(status == 0); - status = fclose(fd); - REQUIRE(status == 0); - - fd = fopen(info.existing_file.c_str(), "w+"); - REQUIRE(fd != nullptr); - status = fflush(fd); - REQUIRE(status == 0); - status = fclose(fd); - REQUIRE(status == 0); - - fd = fopen(info.existing_file.c_str(), "r+"); - REQUIRE(fd != nullptr); - status = fflush(fd); - REQUIRE(status == 0); - status = fclose(fd); - REQUIRE(status == 0); - - fd = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fd != nullptr); - status = fflush(fd); - REQUIRE(status == 0); - status = fclose(fd); - REQUIRE(status == 0); - - fd = fopen(info.existing_file.c_str(), "a"); - REQUIRE(fd != nullptr); - status = fflush(fd); - REQUIRE(status == 0); - status = fclose(fd); - REQUIRE(status == 0); - - fd = fopen(info.existing_file.c_str(), "a+"); - REQUIRE(fd != nullptr); - status = fflush(fd); - REQUIRE(status == 0); - status = fclose(fd); - REQUIRE(status == 0); - } - SECTION("Flushing contents of all files") { - int status = fflush(nullptr); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("Fdopen", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fdopen]" - "[repetition=1][file=1]") { - pretest(); - SECTION("Associate a FILE ptr with read mode") { - int fd = open(info.existing_file.c_str(), O_RDWR); - REQUIRE(fd != -1); - - FILE* fh = fdopen(fd, "r"); - REQUIRE(fh != nullptr); - size_t read_size = - fread(info.read_data.data(), sizeof(char), args.request_size, fh); - REQUIRE(read_size == args.request_size); - int status = fclose(fh); - REQUIRE(status == 0); - - status = fcntl(fd, F_GETFD); - REQUIRE(fd != -1); - - status = close(fd); - REQUIRE(status == -1); - } - SECTION("Associate a FILE ptr with write mode") { - int fd = open(info.existing_file.c_str(), O_RDWR); - REQUIRE(fd != -1); - - FILE* fh = fdopen(fd, "w"); - REQUIRE(fh != nullptr); - size_t write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fh); - REQUIRE(write_size == args.request_size); - int status = fclose(fh); - REQUIRE(status == 0); - - status = close(fd); - REQUIRE(status == -1); - } - SECTION("Associate a FILE ptr with read plus mode") { - int fd = open(info.existing_file.c_str(), O_RDWR); - REQUIRE(fd != -1); - - FILE* fh = fdopen(fd, "r"); - REQUIRE(fh != nullptr); - size_t read_size = - fread(info.read_data.data(), sizeof(char), args.request_size, fh); - REQUIRE(read_size == args.request_size); - int status = fclose(fh); - REQUIRE(status == 0); - - status = fcntl(fd, F_GETFD); - REQUIRE(fd != -1); - - status = close(fd); - REQUIRE(status == -1); - } - SECTION("Associate a FILE ptr with write plus mode") { - int fd = open(info.existing_file.c_str(), O_RDWR); - REQUIRE(fd != -1); - - FILE* fh = fdopen(fd, "w+"); - REQUIRE(fh != nullptr); - size_t write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fh); - REQUIRE(write_size == args.request_size); - int status = fclose(fh); - REQUIRE(status == 0); - - status = fcntl(fd, F_GETFD); - REQUIRE(fd != -1); - - status = close(fd); - REQUIRE(status == -1); - } - SECTION("Associate a FILE ptr with append mode") { - int fd = open(info.existing_file.c_str(), O_RDWR | O_APPEND); - REQUIRE(fd != -1); - - FILE* fh = fdopen(fd, "a"); - REQUIRE(fh != nullptr); - size_t write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fh); - REQUIRE(write_size == args.request_size); - int status = fclose(fh); - REQUIRE(status == 0); - - status = fcntl(fd, F_GETFD); - REQUIRE(fd != -1); - - status = close(fd); - REQUIRE(status == -1); - } - SECTION("Associate a FILE ptr with append plus mode") { - int fd = open(info.existing_file.c_str(), O_RDWR | O_APPEND); - REQUIRE(fd != -1); - - FILE* fh = fdopen(fd, "a+"); - REQUIRE(fh != nullptr); - size_t write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fh); - REQUIRE(write_size == args.request_size); - int status = fclose(fh); - REQUIRE(status == 0); - - status = fcntl(fd, F_GETFD); - REQUIRE(fd != -1); - - status = close(fd); - REQUIRE(status == -1); - } - SECTION("Associate a FILE ptr with read mode twice") { - int fd = open(info.existing_file.c_str(), O_RDWR); - REQUIRE(fd != -1); - - FILE* fh = fdopen(fd, "r"); - REQUIRE(fh != nullptr); - size_t read_size = - fread(info.read_data.data(), sizeof(char), args.request_size, fh); - REQUIRE(read_size == args.request_size); - - int status = fclose(fh); - REQUIRE(status == 0); - - status = close(fd); - REQUIRE(status == -1); - } - SECTION("Associate a FILE ptr with read mode twice after one closes") { - int fd = open(info.existing_file.c_str(), O_RDWR); - REQUIRE(fd != -1); - - FILE* fh = fdopen(fd, "r"); - REQUIRE(fh != nullptr); - size_t read_size = - fread(info.read_data.data(), sizeof(char), args.request_size, fh); - REQUIRE(read_size == args.request_size); - - int status = fcntl(fd, F_GETFD); - REQUIRE(fd != -1); - - status = fclose(fh); - REQUIRE(status == 0); - - FILE* fh2 = fdopen(fd, "r"); - REQUIRE(fh2 == nullptr); - - status = close(fd); - REQUIRE(status == -1); - } - posttest(false); -} - -TEST_CASE("Freopen", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_freopen]" - "[repetition=1][file=1]") { - pretest(); - SECTION("change different modes") { - FILE* fhr = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fhr != nullptr); - - FILE* fhw = freopen(info.existing_file.c_str(), "w", fhr); - REQUIRE(fhw != nullptr); - size_t write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhw); - REQUIRE(write_size == args.request_size); - - FILE* fhwp = freopen(info.existing_file.c_str(), "w+", fhw); - REQUIRE(fhwp != nullptr); - write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhwp); - REQUIRE(write_size == args.request_size); - - FILE* fha = freopen(info.existing_file.c_str(), "a", fhwp); - REQUIRE(fha != nullptr); - write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhwp); - REQUIRE(write_size == args.request_size); - - FILE* fhap = freopen(info.existing_file.c_str(), "a+", fha); - REQUIRE(fhap != nullptr); - write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhap); - REQUIRE(write_size == args.request_size); - - int status = fclose(fhap); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("fgetc", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_fgetc]" - "[repetition=" + - std::to_string(info.num_iterations) + "][file=1]") { - pretest(); - SECTION("iterate and get all characters") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - size_t total_chars = 0; - int c = '0'; - do { - c = fgetc(fh); - total_chars++; - if (total_chars >= info.num_iterations) break; - } while (c != EOF); - REQUIRE(total_chars == info.num_iterations); - int status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("getc", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_getc]" - "[repetition=" + - std::to_string(info.num_iterations) + "][file=1]") { - pretest(); - SECTION("iterate and get all characters") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - size_t total_chars = 0; - int c = '0'; - do { - c = getc(fh); - total_chars++; - if (total_chars >= info.num_iterations) break; - } while (c != EOF); - REQUIRE(total_chars == info.num_iterations); - int status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("getw", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_getw]" - "[repetition=" + - std::to_string(info.num_iterations) + "][file=1]") { - pretest(); - SECTION("iterate and get all characters") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - size_t total_chars = 0; - int c = '0'; - do { - c = getw(fh); - total_chars++; - if (total_chars >= info.num_iterations) break; - } while (c != EOF); - REQUIRE(total_chars == info.num_iterations); - int status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("fgets", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fgets]" - "[repetition=1][file=1]") { - pretest(); - SECTION("iterate and get all characters") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - auto ret_str = fgets(info.read_data.data(), args.request_size, fh); - REQUIRE(ret_str != NULL); - REQUIRE(strlen(ret_str) == args.request_size - 1); - int status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("fputc", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_fputc]" - "[repetition=" + - std::to_string(info.num_iterations) + "][file=1]") { - pretest(); - SECTION("iterate and get all characters") { - FILE* fh = fopen(info.new_file.c_str(), "w+"); - REQUIRE(fh != nullptr); - size_t total_chars = info.num_iterations; - char c = 'w'; - for (size_t i = 0; i < total_chars; ++i) { - int ret_char = fputc(c, fh); - REQUIRE(ret_char == c); - } - int status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("putc", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_putc]" - "[repetition=" + - std::to_string(info.num_iterations) + "][file=1]") { - pretest(); - SECTION("iterate and get all characters") { - FILE* fh = fopen(info.new_file.c_str(), "w+"); - REQUIRE(fh != nullptr); - size_t total_chars = info.num_iterations; - char c = 'w'; - for (size_t i = 0; i < total_chars; ++i) { - int ret_char = putc(c, fh); - REQUIRE(ret_char == c); - } - int status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} -TEST_CASE("putw", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_putw]" - "[repetition=" + - std::to_string(info.num_iterations) + "][file=1]") { - pretest(); - SECTION("iterate and get all characters") { - FILE* fh = fopen(info.new_file.c_str(), "w+"); - REQUIRE(fh != nullptr); - size_t total_chars = info.num_iterations; - int c = 'w'; - for (size_t i = 0; i < total_chars; ++i) { - int ret = putw(c, fh); - REQUIRE(ret == 0); - } - int status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("fputs", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fputs]" - "[repetition=1][file=1]") { - pretest(); - SECTION("iterate and get all characters") { - FILE* fh = fopen(info.existing_file.c_str(), "w+"); - REQUIRE(fh != nullptr); - int status = fputs(info.write_data.c_str(), fh); - REQUIRE(status != -1); - status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("fseek", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fseek]" - "[repetition=1][file=1]") { - pretest(); - SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - int status = fseek(fh, 0, SEEK_SET); - REQUIRE(status == 0); - size_t offset = ftell(fh); - REQUIRE(offset == 0); - - status = fseek(fh, 0, SEEK_CUR); - REQUIRE(status == 0); - offset = ftell(fh); - REQUIRE(offset == 0); - - status = fseek(fh, 0, SEEK_END); - REQUIRE(status == 0); - offset = ftell(fh); - REQUIRE(offset == info.total_size); - - status = fseek(fh, 0, SEEK_CUR); - REQUIRE(status == 0); - offset = ftell(fh); - REQUIRE(offset == info.total_size); - - status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("fseeko", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fseeko]" - "[repetition=1][file=1]") { - pretest(); - SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - int status = fseeko(fh, 0, SEEK_SET); - REQUIRE(status == 0); - size_t offset = ftell(fh); - REQUIRE(offset == 0); - - status = fseeko(fh, 0, SEEK_CUR); - REQUIRE(status == 0); - offset = ftell(fh); - REQUIRE(offset == 0); - - status = fseeko(fh, 0, SEEK_END); - REQUIRE(status == 0); - offset = ftell(fh); - REQUIRE(offset == info.total_size); - - status = fseeko(fh, 0, SEEK_CUR); - REQUIRE(status == 0); - offset = ftell(fh); - REQUIRE(offset == info.total_size); - - status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("fseeko64", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fseeko64]" - "[repetition=1][file=1]") { - pretest(); - SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - int status = fseeko64(fh, 0, SEEK_SET); - REQUIRE(status == 0); - size_t offset = ftell(fh); - REQUIRE(offset == 0); - - status = fseeko64(fh, 0, SEEK_CUR); - REQUIRE(status == 0); - offset = ftell(fh); - REQUIRE(offset == 0); - - status = fseeko64(fh, 0, SEEK_END); - REQUIRE(status == 0); - offset = ftell(fh); - REQUIRE(offset == info.total_size); - - status = fseeko64(fh, 0, SEEK_CUR); - REQUIRE(status == 0); - offset = ftell(fh); - REQUIRE(offset == info.total_size); - - status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("rewind", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_rewind]" - "[repetition=1][file=1]") { - pretest(); - SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - int status = fseeko(fh, 0, SEEK_SET); - REQUIRE(status == 0); - size_t offset = ftell(fh); - REQUIRE(offset == 0); - rewind(fh); - offset = ftell(fh); - REQUIRE(offset == 0); - - status = fseeko(fh, 0, SEEK_END); - REQUIRE(status == 0); - offset = ftell(fh); - REQUIRE(offset == info.total_size); - rewind(fh); - offset = ftell(fh); - REQUIRE(offset == 0); - - status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("fsetpos", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fsetpos]" - "[repetition=1][file=1]") { - pretest(); - SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - fpos_t position; - fgetpos(fh, &position); - - position.__pos = 0; - int status = fsetpos(fh, &position); - REQUIRE(status == 0); - size_t offset = ftell(fh); - REQUIRE(offset == 0); - - position.__pos = info.total_size; - status = fsetpos(fh, &position); - REQUIRE(status == 0); - offset = ftell(fh); - REQUIRE(offset == info.total_size); - - status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("fsetpos64", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fsetpos64]" - "[repetition=1][file=1]") { - pretest(); - SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - fpos64_t position; - fgetpos64(fh, &position); - - position.__pos = 0; - int status = fsetpos64(fh, &position); - REQUIRE(status == 0); - size_t offset = ftell(fh); - REQUIRE(offset == 0); - - position.__pos = info.total_size; - status = fsetpos64(fh, &position); - REQUIRE(status == 0); - offset = ftell(fh); - REQUIRE(offset == info.total_size); - - status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("fgetpos", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fgetpos]" - "[repetition=1][file=1]") { - pretest(); - SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - fpos_t position; - - int status = fseek(fh, 0, SEEK_SET); - REQUIRE(status == 0); - status = fgetpos(fh, &position); - REQUIRE(position.__pos == 0); - - status = fseek(fh, 0, SEEK_END); - REQUIRE(status == 0); - status = fgetpos(fh, &position); - REQUIRE(position.__pos == (long int)info.total_size); - - status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("fgetpos64", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fgetpos64]" - "[repetition=1][file=1]") { - pretest(); - SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - fpos64_t position; - - int status = fseek(fh, 0, SEEK_SET); - REQUIRE(status == 0); - status = fgetpos64(fh, &position); - REQUIRE(position.__pos == 0); - - status = fseek(fh, 0, SEEK_END); - REQUIRE(status == 0); - status = fgetpos64(fh, &position); - REQUIRE(position.__pos == (long int)info.total_size); - - status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("Open64", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_open]" - "[repetition=1][file=1]") { - pretest(); - SECTION("open non-existant file") { - FILE* fh = fopen64(info.new_file.c_str(), "r"); - REQUIRE(fh == nullptr); - fh = fopen64(info.new_file.c_str(), "r+"); - REQUIRE(fh == nullptr); - } - - SECTION("truncate existing file and write-only") { - FILE* fh = fopen64(info.existing_file.c_str(), "w"); - REQUIRE(fh != nullptr); - int status = fclose(fh); - REQUIRE(status == 0); - } - SECTION("truncate existing file and read/write") { - FILE* fh = fopen64(info.existing_file.c_str(), "w+"); - REQUIRE(fh != nullptr); - int status = fclose(fh); - REQUIRE(status == 0); - } - - SECTION("open existing file") { - FILE* fh = fopen64(info.existing_file.c_str(), "r+"); - REQUIRE(fh != nullptr); - int status = fclose(fh); - REQUIRE(status == 0); - fh = fopen64(info.existing_file.c_str(), "r"); - REQUIRE(fh != nullptr); - status = fclose(fh); - REQUIRE(status == 0); - } - - SECTION("append write existing file") { - FILE* fh = fopen64(info.existing_file.c_str(), "a"); - REQUIRE(fh != nullptr); - int status = fclose(fh); - REQUIRE(status == 0); - } - - SECTION("append write and read existing file") { - FILE* fh = fopen64(info.existing_file.c_str(), "a+"); - REQUIRE(fh != nullptr); - int status = fclose(fh); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("Freopen64", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_freopen]" - "[repetition=1][file=1]") { - pretest(); - SECTION("change different modes") { - FILE* fhr = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fhr != nullptr); - - FILE* fhw = freopen64(info.existing_file.c_str(), "w", fhr); - REQUIRE(fhw != nullptr); - size_t write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhw); - REQUIRE(write_size == args.request_size); - - FILE* fhwp = freopen64(info.existing_file.c_str(), "w+", fhw); - REQUIRE(fhwp != nullptr); - write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhwp); - REQUIRE(write_size == args.request_size); - - FILE* fha = freopen64(info.existing_file.c_str(), "a", fhwp); - REQUIRE(fha != nullptr); - write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhwp); - REQUIRE(write_size == args.request_size); - - FILE* fhap = freopen64(info.existing_file.c_str(), "a+", fha); - REQUIRE(fhap != nullptr); - write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhap); - REQUIRE(write_size == args.request_size); - - int status = fclose(fhap); - REQUIRE(status == 0); - } - posttest(false); -} - -TEST_CASE("MultiOpen", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=multi_open]" - "[repetition=1][file=1]") { - pretest(); - SECTION("Open same file twice and then close both fps") { - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - FILE* fh2 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh2 != nullptr); - int status = fclose(fh1); - REQUIRE(status == 0); - status = fclose(fh2); - REQUIRE(status == 0); - } - posttest(false); -} diff --git a/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp b/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp deleted file mode 100644 index 3f8903321..000000000 --- a/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include -#include - -#include "adapter_test_utils.h" -#include "catch_config.h" -#if HERMES_INTERCEPT == 1 -#include "stdio/real_api.h" -#endif - -namespace stdfs = std::experimental::filesystem; - -namespace hermes::adapter::stdio::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp"; - size_t request_size = 65536; -}; -struct Info { - int rank = 0; - int comm_size = 1; - std::string write_data; - std::string read_data; - std::string new_file; - std::string existing_file; - std::string new_file_cmp; - std::string existing_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 5; - size_t total_size; - size_t stride_size = 512; - unsigned int temporal_interval_ms = 1; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; - size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::stdio::test -hermes::adapter::stdio::test::Arguments args; -hermes::adapter::stdio::test::Info info; - -int init(int* argc, char*** argv) { - MPI_Init(argc, argv); - info.write_data = GenRandom(args.request_size); - info.read_data = std::string(args.request_size, 'r'); - return 0; -} -int finalize() { - MPI_Finalize(); - return 0; -} - -int pretest() { - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new_" + std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext_" + std::to_string(getpid()); - info.new_file_cmp = - fullpath.string() + "_new_cmp" + "_" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp" + "_" + std::to_string(getpid()); - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + info.existing_file + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - } - REQUIRE(info.total_size > 0); -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); -#endif - return 0; -} - -int posttest(bool compare_data = true) { -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); -#endif - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) { - char_mismatch = pos; - break; - } - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - /* Clean up. */ - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); -#endif - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -namespace test { -FILE* fh_orig; -FILE* fh_cmp; -int status_orig; -size_t size_read_orig; -size_t size_written_orig; -void test_fopen(const char* path, const char* mode) { - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else { - cmp_path = info.existing_file_cmp; - } - fh_orig = fopen(path, mode); - fh_cmp = fopen(cmp_path.c_str(), mode); - bool is_same = (fh_cmp != nullptr && fh_orig != nullptr) || - (fh_cmp == nullptr && fh_orig == nullptr); - REQUIRE(is_same); -} -void test_fclose() { - status_orig = fclose(fh_orig); - int status = fclose(fh_cmp); - REQUIRE(status == status_orig); -} -void test_fwrite(const void* ptr, size_t size) { - size_written_orig = fwrite(ptr, sizeof(char), size, fh_orig); - size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp); - REQUIRE(size_written == size_written_orig); -} -void test_fread(char* ptr, size_t size) { - size_read_orig = fread(ptr, sizeof(char), size, fh_orig); - std::vector read_data(size, 'r'); - size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp); - REQUIRE(size_read == size_read_orig); - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < size; ++i) { - if (read_data[i] != ptr[i]) { - unmatching_chars = i; - break; - } - } - REQUIRE(unmatching_chars == 0); - } -} -void test_fseek(long offset, int whence) { - status_orig = fseek(fh_orig, offset, whence); - int status = fseek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -TEST_CASE("BatchedWriteSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file one big write") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - auto write_size = args.request_size * (info.num_iterations + 1); - info.write_data = GenRandom(write_size); - test::test_fwrite(info.write_data.c_str(), write_size); - REQUIRE(test::size_written_orig == write_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == write_size); - } - SECTION("write to new file multiple write") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i <= info.num_iterations; ++i) { - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - args.request_size * (info.num_iterations + 1)); - } - posttest(); -} diff --git a/adapter/test/stdio/stdio_adapter_mapper_test.cpp b/adapter/test/stdio/stdio_adapter_mapper_test.cpp deleted file mode 100644 index 1d5eb7ede..000000000 --- a/adapter/test/stdio/stdio_adapter_mapper_test.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -#include "catch_config.h" -#include "constants.h" -#include "mapper/mapper_factory.h" -#include "stdio/fs_api.h" - -using hermes::adapter::BlobPlacements; -using hermes::adapter::MapperFactory; -using hermes::adapter::fs::kMapperType; -using hermes::adapter::fs::MetadataManager; - -namespace stdfs = std::experimental::filesystem; - -namespace hermes::adapter::stdio::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp"; - size_t request_size = 65536; - size_t num_iterations = 1024; -}; -struct Info { - int rank = 0; - int comm_size = 1; - std::string new_file; - std::string existing_file; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - size_t total_size; - size_t stride_size = 1024; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; - size_t large_min = 256 * 1024 + 1, large_max = 4 * 1024 * 1024; -}; -} // namespace hermes::adapter::stdio::test -hermes::adapter::stdio::test::Arguments args; -hermes::adapter::stdio::test::Info info; - -int init(int* argc, char*** argv) { - MPI_Init(argc, argv); - - return 0; -} -int finalize() { - MPI_Finalize(); - - return 0; -} - -int pretest() { - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new"; - info.existing_file = fullpath.string() + "_ext"; - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "dd if=/dev/zero of=" + info.existing_file + - " bs=1 count=0 seek=" + - std::to_string(args.request_size * args.num_iterations) + - " > /dev/null 2>&1"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * args.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - REQUIRE(info.total_size > 0); - return 0; -} - -int posttest() { - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O") | - cl::Opt(args.num_iterations, "iterations")["-n"]["--iterations"]( - "Number of iterations of requests"); -} - -TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[request_size=type-fixed][repetition=1]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("Map a one request") { - auto mapper = MapperFactory().Get(kMapperType); - size_t total_size = args.request_size; - FILE* fp = fopen(info.new_file.c_str(), "w+"); - REQUIRE(fp != nullptr); - size_t offset = 0; - REQUIRE(kPageSize > total_size + offset); - BlobPlacements mapping; - mapper->map(offset, total_size, mapping); - REQUIRE(mapping.size() == 1); - REQUIRE(mapping[0].bucket_off_ == offset); - REQUIRE(mapping[0].blob_size_ == total_size); - REQUIRE(mapping[0].blob_off_ == offset); - int status = fclose(fp); - REQUIRE(status == 0); - } - SECTION("Map a one big request") { - auto mapper = MapperFactory().Get(kMapperType); - size_t total_size = args.request_size * args.num_iterations; - FILE* fp = fopen(info.new_file.c_str(), "w+"); - REQUIRE(fp != nullptr); - size_t offset = 0; - BlobPlacements mapping; - mapper->map(offset, total_size, mapping); - REQUIRE(mapping.size() == ceil((double)total_size / kPageSize)); - for (const auto& item : mapping) { - size_t mapped_size = - total_size - offset > kPageSize ? kPageSize : total_size - offset; - REQUIRE(item.bucket_off_ == offset); - REQUIRE(item.blob_size_ == mapped_size); - REQUIRE(item.blob_off_ == offset % kPageSize); - offset += mapped_size; - } - int status = fclose(fp); - REQUIRE(status == 0); - } - SECTION("Map a one large unaligned request") { - auto mapper = MapperFactory().Get(kMapperType); - size_t total_size = args.request_size * args.num_iterations; - FILE* fp = fopen(info.new_file.c_str(), "w+"); - REQUIRE(fp != nullptr); - size_t offset = 1; - BlobPlacements mapping; - mapper->map(offset, total_size, mapping); - bool has_rem = (total_size + offset) % kPageSize != 0; - if (has_rem) { - REQUIRE(mapping.size() == ceil((double)total_size / kPageSize) + 1); - } else { - REQUIRE(mapping.size() == ceil((double)total_size / kPageSize)); - } - - size_t i = 0; - size_t current_offset = offset; - for (const auto& item : mapping) { - size_t mapped_size = 0; - if (i == 0) { - mapped_size = kPageSize - offset; - } else if (i == mapping.size() - 1) { - mapped_size = offset; - } else { - mapped_size = kPageSize; - } - REQUIRE(item.bucket_off_ == current_offset); - REQUIRE(item.blob_size_ == mapped_size); - REQUIRE(item.blob_off_ == current_offset % kPageSize); - current_offset += mapped_size; - i++; - } - int status = fclose(fp); - REQUIRE(status == 0); - } - SECTION("Map a one small unaligned request") { - auto mapper = MapperFactory().Get(kMapperType); - size_t total_size = args.request_size; - FILE* fp = fopen(info.new_file.c_str(), "w+"); - REQUIRE(fp != nullptr); - size_t offset = 1; - REQUIRE(kPageSize > total_size + offset); - BlobPlacements mapping; - mapper->map(offset, total_size, mapping); - REQUIRE(mapping.size() == 1); - REQUIRE(mapping[0].bucket_off_ == offset); - REQUIRE(mapping[0].blob_size_ == total_size); - REQUIRE(mapping[0].blob_off_ == 1); - int status = fclose(fp); - REQUIRE(status == 0); - } - posttest(); -} diff --git a/adapter/test/stdio/stdio_adapter_mode_test.cpp b/adapter/test/stdio/stdio_adapter_mode_test.cpp deleted file mode 100644 index d315c56e5..000000000 --- a/adapter/test/stdio/stdio_adapter_mode_test.cpp +++ /dev/null @@ -1,340 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include -#include - -#include -#include - -#if HERMES_INTERCEPT == 1 -#include "stdio/real_api.h" -#endif - -#include "adapter_test_utils.h" - -namespace stdfs = std::experimental::filesystem; - -namespace hermes::adapter::stdio::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp"; - size_t request_size = 65536; -}; -struct Info { - int rank = 0; - int comm_size = 1; - std::string write_data; - std::string read_data; - std::string new_file; - std::string existing_file; - std::string new_file_cmp; - std::string existing_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 5; - size_t total_size; - size_t stride_size = 512; - unsigned int temporal_interval_ms = 1; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; - size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::stdio::test -hermes::adapter::stdio::test::Arguments args; -hermes::adapter::stdio::test::Info info; - -int init(int* argc, char*** argv) { - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new" + std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext" + std::to_string(getpid()); - info.new_file_cmp = fullpath.string() + "_new_cmp" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp" + std::to_string(getpid()); - char* set_path = getenv("SET_PATH"); - if (set_path && strcmp(set_path, "1") == 0) { - auto paths = info.new_file + "," + info.existing_file; - setenv(kAdapterModeInfo, paths.c_str(), 1); - } - MPI_Init(argc, argv); - info.write_data = GenRandom(args.request_size); - info.read_data = std::string(args.request_size, 'r'); - return 0; -} -int finalize() { - MPI_Finalize(); - return 0; -} - -int pretest() { - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + info.existing_file + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - } - REQUIRE(info.total_size > 0); -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); -#endif - return 0; -} - -int posttest(bool compare_data = true) { -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); -#endif - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - /* Clean up. */ - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); -#endif - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -namespace test { -FILE* fh_orig; -FILE* fh_cmp; -int status_orig; -size_t size_read_orig; -size_t size_written_orig; -void test_fopen(const char* path, const char* mode) { - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else { - cmp_path = info.existing_file_cmp; - } - fh_orig = fopen(path, mode); - fh_cmp = fopen(cmp_path.c_str(), mode); - bool is_same = (fh_cmp != nullptr && fh_orig != nullptr) || - (fh_cmp == nullptr && fh_orig == nullptr); - REQUIRE(is_same); -} -void test_fclose() { - status_orig = fclose(fh_orig); - int status = fclose(fh_cmp); - REQUIRE(status == status_orig); -} -void test_fwrite(const void* ptr, size_t size) { - size_written_orig = fwrite(ptr, sizeof(char), size, fh_orig); - size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp); - REQUIRE(size_written == size_written_orig); -} -void test_fread(char* ptr, size_t size) { - size_read_orig = fread(ptr, sizeof(char), size, fh_orig); - std::vector read_data(size, 'r'); - size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp); - REQUIRE(size_read == size_read_orig); - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < size; ++i) { - if (read_data[i] != ptr[i]) { - unmatching_chars = i; - break; - } - } - REQUIRE(unmatching_chars == 0); - } -} -void test_fseek(long offset, int whence) { - status_orig = fseek(fh_orig, offset, whence); - int status = fseek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -TEST_CASE("BatchedWriteSequentialPersistent", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[hermes_mode=persistent]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - char* adapter_mode = getenv(kAdapterMode); - REQUIRE(adapter_mode != nullptr); - bool is_same = strcmp(kAdapterDefaultMode, adapter_mode) == 0; - REQUIRE(is_same); - pretest(); - SECTION("write to new file always at end") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedWriteSequentialBypass", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[hermes_mode=bypass]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - char* adapter_mode = getenv(kAdapterMode); - REQUIRE(adapter_mode != nullptr); - bool is_same = strcmp(kAdapterBypassMode, adapter_mode) == 0; - REQUIRE(is_same); - pretest(); - SECTION("write to new file always at end") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedWriteSequentialScratch", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[hermes_mode=scratch]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - char* adapter_mode = getenv(kAdapterMode); - REQUIRE(adapter_mode != nullptr); - bool is_same = strcmp(kAdapterScratchMode, adapter_mode) == 0; - REQUIRE(is_same); - pretest(); - SECTION("write to new file always at end") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == 0); - } - posttest(false); -} diff --git a/adapter/test/stdio/stdio_adapter_mpi_test.cpp b/adapter/test/stdio/stdio_adapter_mpi_test.cpp deleted file mode 100644 index c279dd786..000000000 --- a/adapter/test/stdio/stdio_adapter_mpi_test.cpp +++ /dev/null @@ -1,348 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include -#include -#include - -#include -#include -#if HERMES_INTERCEPT == 1 -#include "stdio/real_api.h" -#endif - -namespace stdfs = std::experimental::filesystem; - -namespace hermes::adapter::stdio::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp"; - size_t request_size = 65536; -}; -struct Info { - bool debug = false; - int rank = 0; - int comm_size = 1; - std::string write_data; - std::string read_data; - std::string new_file; - std::string existing_file; - std::string existing_shared_file; - std::string new_file_cmp; - std::string existing_file_cmp; - std::string existing_shared_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 1; - size_t total_size; - size_t stride_size = 4 * 1024; - unsigned int temporal_interval_ms = 5; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 512 * 1024; - size_t large_min = 512 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::stdio::test - -hermes::adapter::stdio::test::Arguments args; -hermes::adapter::stdio::test::Info info; - -int init(int* argc, char*** argv) { - MPI_Init(argc, argv); - info.write_data = GenRandom(args.request_size); - info.read_data = std::string(args.request_size, 'r'); - MPI_Comm_rank(MPI_COMM_WORLD, &info.rank); - MPI_Comm_size(MPI_COMM_WORLD, &info.comm_size); - if (info.debug && info.rank == 0) { - printf("%d ready for attach\n", info.comm_size); - fflush(stdout); - sleep(30); - } - MPI_Barrier(MPI_COMM_WORLD); - return 0; -} -int finalize() { - MPI_Finalize(); - return 0; -} - -namespace test { -FILE* fh_orig; -FILE* fh_cmp; -int status_orig; -size_t size_read_orig; -size_t size_written_orig; -void test_fopen(const char* path, const char* mode) { - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else if (strcmp(path, info.existing_file.c_str()) == 0) { - cmp_path = info.existing_file_cmp; - } else { - cmp_path = info.existing_shared_file_cmp; - } - fh_orig = fopen(path, mode); - fh_cmp = fopen(cmp_path.c_str(), mode); - bool is_same = (fh_cmp != nullptr && fh_orig != nullptr) || - (fh_cmp == nullptr && fh_orig == nullptr); - REQUIRE(is_same); -} -void test_fclose() { - status_orig = fclose(fh_orig); - int status = fclose(fh_cmp); - REQUIRE(status == status_orig); -} -void test_fwrite(const void* ptr, size_t size) { - size_written_orig = fwrite(ptr, sizeof(char), size, fh_orig); - size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp); - REQUIRE(size_written == size_written_orig); -} -void test_fread(char* ptr, size_t size) { - size_read_orig = fread(ptr, sizeof(char), size, fh_orig); - std::vector read_data(size, 'r'); - size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp); - REQUIRE(size_read == size_read_orig); - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < size; ++i) { - if (read_data[i] != ptr[i]) unmatching_chars++; - } - REQUIRE(unmatching_chars == 0); - } -} -void test_fseek(long offset, int whence) { - status_orig = fseek(fh_orig, offset, whence); - int status = fseek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -int pretest() { - REQUIRE(info.comm_size > 1); - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new_" + std::to_string(info.rank) + - "_of_" + std::to_string(info.comm_size) + "_" + - std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext_" + std::to_string(info.rank) + - "_of_" + std::to_string(info.comm_size) + "_" + - std::to_string(getpid()); - info.new_file_cmp = - fullpath.string() + "_new_cmp_" + std::to_string(info.rank) + "_of_" + - std::to_string(info.comm_size) + "_" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp_" + std::to_string(info.rank) + "_of_" + - std::to_string(info.comm_size) + "_" + std::to_string(getpid()); - info.existing_shared_file = - fullpath.string() + "_ext_" + std::to_string(info.comm_size); - info.existing_shared_file_cmp = - fullpath.string() + "_ext_cmp_" + std::to_string(info.comm_size); - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - if (stdfs::exists(info.existing_shared_file)) - stdfs::remove(info.existing_shared_file); - if (stdfs::exists(info.existing_shared_file_cmp)) - stdfs::remove(info.existing_shared_file_cmp); - stdfs::path temp_fullpath = "/tmp"; - temp_fullpath /= args.filename; - std::string temp_ext_file = - temp_fullpath.string() + "_temp_" + std::to_string(info.rank) + "_of_" + - std::to_string(info.comm_size) + "_" + std::to_string(getpid()); - if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); - if (!stdfs::exists(temp_ext_file)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + temp_ext_file + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(temp_ext_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(temp_ext_file); - } - if (info.rank == 0 && !stdfs::exists(info.existing_shared_file)) { - std::string cmd = "cp " + temp_ext_file + " " + info.existing_shared_file; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_shared_file) == - args.request_size * info.num_iterations); - } - if (info.rank == 0 && !stdfs::exists(info.existing_shared_file_cmp)) { - std::string cmd = - "cp " + temp_ext_file + " " + info.existing_shared_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_shared_file_cmp) == - args.request_size * info.num_iterations); - } - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "cp " + temp_ext_file + " " + info.existing_file; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - } - if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); - REQUIRE(info.total_size > 0); - MPI_Barrier(MPI_COMM_WORLD); -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert( - info.existing_shared_file_cmp); -#endif - return 0; -} - -int posttest(bool compare_data = true) { -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_shared_file); -#endif - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_shared_file) && - stdfs::exists(info.existing_shared_file_cmp)) { - size_t size = stdfs::file_size(info.existing_shared_file); - if (size != stdfs::file_size(info.existing_shared_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_shared_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_shared_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_shared_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - /* Clean up. */ - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - MPI_Barrier(MPI_COMM_WORLD); - if (info.rank == 0) { - if (stdfs::exists(info.existing_shared_file)) - stdfs::remove(info.existing_shared_file); - if (stdfs::exists(info.existing_shared_file_cmp)) - stdfs::remove(info.existing_shared_file_cmp); - } - -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file_cmp); -#endif - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -#include "stdio_adapter_basic_test.cpp" -#include "stdio_adapter_func_test.cpp" -#include "stdio_adapter_rs_test.cpp" -#include "stdio_adapter_shared_test.cpp" diff --git a/adapter/test/stdio/stdio_adapter_rs_test.cpp b/adapter/test/stdio/stdio_adapter_rs_test.cpp deleted file mode 100644 index b6a4ea629..000000000 --- a/adapter/test/stdio/stdio_adapter_rs_test.cpp +++ /dev/null @@ -1,1247 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -TEST_CASE("BatchedWriteRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at the start") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t biggest_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_written < request_size) biggest_written = request_size; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_written); - } - - SECTION("write to new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t total_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_written += test::size_written_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (info.total_size - i * info.stride_size) % - (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = info.total_size - ((i * info.stride_size) % - (info.total_size - info.small_max)); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} -/** - * Medium RS - **/ - -TEST_CASE("BatchedWriteRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at the start") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t biggest_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_written < request_size) biggest_written = request_size; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_written); - } - - SECTION("write to new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t total_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_written += test::size_written_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - (info.medium_min + (rand_r(&info.rs_seed) % info.medium_max)) % - (info.total_size - current_offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - (i * info.stride_size) % (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - (i * info.stride_size) % (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (info.total_size - i * info.stride_size) % - (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = info.total_size - ((i * info.stride_size) % - (info.total_size - info.medium_max)); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} -/** - * Large RS - **/ - -TEST_CASE("BatchedWriteRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at the start") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t biggest_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_written < request_size) biggest_written = request_size; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("write to new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t total_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_written += test::size_written_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % - (info.total_size - current_offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("write into existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data = GenRandom(request_size); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (info.total_size - i * info.stride_size) % - (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % - (info.total_size - info.large_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = info.total_size - ((i * info.stride_size) % - (info.total_size - info.large_max)); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} diff --git a/adapter/test/stdio/stdio_adapter_shared_test.cpp b/adapter/test/stdio/stdio_adapter_shared_test.cpp deleted file mode 100644 index 5a9f437e3..000000000 --- a/adapter/test/stdio/stdio_adapter_shared_test.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -TEST_CASE("SharedSTDIORead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[mode=shared]" - "[pattern=sequential][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_shared_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} diff --git a/adapter/test/stdio/stdio_adapter_test.cpp b/adapter/test/stdio/stdio_adapter_test.cpp deleted file mode 100644 index a88853f45..000000000 --- a/adapter/test/stdio/stdio_adapter_test.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include -#include - -#include "adapter_test_utils.h" -#include "catch_config.h" -#if HERMES_INTERCEPT == 1 -#include "stdio/real_api.h" -#endif - -#include "adapter_test_utils.h" - -namespace stdfs = std::experimental::filesystem; - -namespace hermes::adapter::stdio::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp"; - size_t request_size = 65536; -}; -struct Info { - int rank = 0; - int comm_size = 1; - std::string write_data; - std::string read_data; - std::string new_file; - std::string existing_file; - std::string new_file_cmp; - std::string existing_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 5; - size_t total_size; - size_t stride_size = 512; - unsigned int temporal_interval_ms = 1; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; - size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::stdio::test - -hermes::adapter::stdio::test::Arguments args; -hermes::adapter::stdio::test::Info info; - -int init(int* argc, char*** argv) { - MPI_Init(argc, argv); - info.write_data = GenRandom(args.request_size); - info.read_data = std::string(args.request_size, 'r'); - return 0; -} - -int finalize() { - MPI_Finalize(); - return 0; -} - -int pretest() { - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new_" + std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext_" + std::to_string(getpid()); - info.new_file_cmp = - fullpath.string() + "_new_cmp" + "_" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp" + "_" + std::to_string(getpid()); - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + info.existing_file + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - } - REQUIRE(info.total_size > 0); -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); -#endif - return 0; -} - -int posttest(bool compare_data = true) { -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); -#endif - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) { - char_mismatch++; - } - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - /* Clean up. */ - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); -#endif - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -namespace test { -FILE* fh_orig; -FILE* fh_cmp; -int status_orig; -size_t size_read_orig; -size_t size_written_orig; -void test_fopen(const char* path, const char* mode) { - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else { - cmp_path = info.existing_file_cmp; - } - fh_orig = fopen(path, mode); - fh_cmp = fopen(cmp_path.c_str(), mode); - bool is_same = (fh_cmp != nullptr && fh_orig != nullptr) || - (fh_cmp == nullptr && fh_orig == nullptr); - REQUIRE(is_same); -} -void test_fclose() { - status_orig = fclose(fh_orig); - int status = fclose(fh_cmp); - REQUIRE(status == status_orig); -} -void test_fwrite(const void* ptr, size_t size) { - size_written_orig = fwrite(ptr, sizeof(char), size, fh_orig); - size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp); - REQUIRE(size_written == size_written_orig); -} -void test_fread(char* ptr, size_t size) { - size_read_orig = fread(ptr, sizeof(char), size, fh_orig); - std::vector read_data(size, 'r'); - size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp); - REQUIRE(size_read == size_read_orig); - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < size; ++i) { - if (read_data[i] != ptr[i]) { - unmatching_chars = i; - break; - } - } - REQUIRE(unmatching_chars == 0); - } -} -void test_fseek(long offset, int whence) { - status_orig = fseek(fh_orig, offset, whence); - int status = fseek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -#include "stdio_adapter_basic_test.cpp" -#include "stdio_adapter_func_test.cpp" -#include "stdio_adapter_rs_test.cpp" diff --git a/adapter/test/vfd/CMakeLists.txt b/adapter/test/vfd/CMakeLists.txt deleted file mode 100644 index 3903fc5a8..000000000 --- a/adapter/test/vfd/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -set(HERMES_VFD_DIR ${HERMES_ADAPTER_DIR}/vfd) - -set(hermes_vfd_tests - hermes_vfd_test -) - -add_executable(hermes_vfd_test ${CMAKE_CURRENT_SOURCE_DIR}/hermes_vfd_test.cc) -target_include_directories(hermes_vfd_test PRIVATE ${HERMES_VFD_DIR}) -target_include_directories(hermes_vfd_test PRIVATE ${HERMES_ADAPTER_TEST_DIR}) -target_include_directories(hermes_vfd_test - SYSTEM PRIVATE ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} -) - -target_link_libraries(hermes_vfd_test - hermes - Catch2::Catch2 - MPI::MPI_CXX - glog::glog - stdc++fs - ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES} -) - -if(HERMES_USE_ADDRESS_SANITIZER) - execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=libasan.so - OUTPUT_VARIABLE LIBASAN_PATH - RESULT_VARIABLE ASAN_PRINT_FILE_NAME_RESULT - OUTPUT_STRIP_TRAILING_WHITESPACE) - - if(ASAN_PRINT_FILE_NAME_RESULT EQUAL 0) - message(STATUS "Found libasan.so at ${LIBASAN_PATH}") - else() - message(FATAL_ERROR - "Couldn't find the path to libasan.so which is required by the Hermes HDF5 VFD tests. \ - Recompile with HERMES_ENABLE_ADDRESS_SANITIZER=OFF") - endif() -endif() - -function(set_vfd_test_properties test_name) - set_property(TEST ${test_name} - PROPERTY ENVIRONMENT HERMES_CONF=${HERMES_ADAPTER_TEST_DIR}/data/hermes.yaml) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT HDF5_PLUGIN_PATH=${HERMES_VFD_LIBRARY_DIR}) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT HDF5_DRIVER=hermes) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT LD_PRELOAD=${LIBASAN_PATH}:$) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) -endfunction() - -add_test(NAME "TestVfd" COMMAND hermes_vfd_test --reporter compact -d yes) -set_vfd_test_properties("TestVfd") -set_property(TEST "TestVfd" APPEND - PROPERTY ENVIRONMENT HDF5_DRIVER_CONFIG=true\ 65536) - -add_test(NAME "TestVfdScratchMode" COMMAND hermes_vfd_test "[scratch]" --reporter compact -d yes) -set_vfd_test_properties("TestVfdScratchMode") -set_property(TEST "TestVfdScratchMode" APPEND - PROPERTY ENVIRONMENT HDF5_DRIVER_CONFIG=false\ 65536) - -# IOR tests -if(HERMES_HAVE_IOR) - set(IOR_TEST_NAME "TestVfdIor") - add_test(NAME ${IOR_TEST_NAME} COMMAND ${IOR_EXE} -a HDF5 -w -W -r -R) - set_vfd_test_properties(${IOR_TEST_NAME}) - set_property(TEST ${IOR_TEST_NAME} APPEND - PROPERTY ENVIRONMENT HDF5_DRIVER_CONFIG=true\ 262144) -endif() diff --git a/adapter/test/vfd/hermes_vfd_basic_test.cc b/adapter/test/vfd/hermes_vfd_basic_test.cc deleted file mode 100644 index 67f8b9277..000000000 --- a/adapter/test/vfd/hermes_vfd_basic_test.cc +++ /dev/null @@ -1,718 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -using hermes::adapter::vfd::test::MuteHdf5Errors; - -/** Returns a number in the range [1, upper_bound] */ -static inline size_t Random1ToUpperBound(size_t upper_bound) { - size_t result = ((size_t)GenNextRandom() % upper_bound) + 1; - - return result; -} - -/** Returns a string in the range ["0", "upper_bound") */ -static inline std::string RandomDatasetName(size_t upper_bound) { - size_t dset_index = Random1ToUpperBound(upper_bound) - 1; - std::string result = std::to_string(dset_index); - - return result; -} - -TEST_CASE("H5FOpen", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_open]" - "[repetition=1][file=1]") { - Pretest(); - SECTION("open non-existent file") { - MuteHdf5Errors mute; - test::TestOpen(info.new_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid == H5I_INVALID_HID); - test::TestOpen(info.new_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid == H5I_INVALID_HID); - } - - SECTION("truncate existing file") { - test::TestOpen(info.existing_file, H5F_ACC_TRUNC, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("open existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("create existing file exclusively") { - MuteHdf5Errors mute; - test::TestOpen(info.existing_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid == H5I_INVALID_HID); - } - - Posttest(); -} - -TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - Pretest(); - - SECTION("overwrite dataset in existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWritePartial1d("0", info.write_data.data(), 0, - info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("write to new file") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWriteDataset("0", info.write_data); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("write to existing file with truncate") { - test::TestOpen(info.existing_file, H5F_ACC_TRUNC, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWriteDataset("0", info.write_data); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("add dataset to existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWriteDataset(std::to_string(info.num_iterations), - info.write_data); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - Pretest(); - SECTION("read from non-existing file") { - MuteHdf5Errors mute; - test::TestOpen(info.new_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid == H5I_INVALID_HID); - } - - SECTION("read first dataset from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestRead("0", info.read_data, 0, info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("read last dataset of existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestRead(std::to_string(info.num_iterations - 1), info.read_data, 0, - info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); -} - -TEST_CASE("BatchedWriteSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - Pretest(); - SECTION("write to new file") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestWriteDataset(std::to_string(i), info.write_data); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("overwrite first dataset") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - test::TestWriteDataset("0", info.write_data); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestWritePartial1d("0", info.write_data.data(), 0, - info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); -} - -TEST_CASE("BatchedReadSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - Pretest(); - SECTION("read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - std::vector buf(info.nelems_per_dataset, 0.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestRead(std::to_string(i), buf, 0, info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("read from existing file always at start") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestRead("0", info.read_data, 0, info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); -} - -TEST_CASE("BatchedReadRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - Pretest(); - SECTION("read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - std::vector buf(info.nelems_per_dataset, 0.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - u32 dataset = GenNextRandom() % info.num_iterations; - test::TestRead(std::to_string(dataset), buf, 0, info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); -} - -TEST_CASE("BatchedUpdateRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - Pretest(); - SECTION("update entire dataset in existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - u32 dataset = GenNextRandom() % info.num_iterations; - test::TestWritePartial1d(std::to_string(dataset), info.write_data.data(), - 0, info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("update partial dataset in existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - u32 dataset = GenNextRandom() % info.num_iterations; - // NOTE(chogan): Subtract 1 from size so we're always writing at least 1 - // element - hsize_t offset = GenNextRandom() % (info.write_data.size() - 1); - hsize_t elements_to_write = info.write_data.size() - offset; - test::TestWritePartial1d(std::to_string(dataset), info.write_data.data(), - offset, elements_to_write); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); -} - -TEST_CASE("BatchedWriteRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - Pretest(); - - SECTION("write to new file always at the start") { - MuteHdf5Errors mute; - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); - std::vector data(request_size, 2.0f); - test::TestWritePartial1d(std::to_string(i), data.data(), 0, request_size); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("BatchedReadSequentialRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - Pretest(); - - SECTION("read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); - size_t starting_element = info.nelems_per_dataset - request_size; - std::vector data(request_size, 1.5f); - test::TestRead(std::to_string(i), data, starting_element, request_size); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("read from existing file always at start") { - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); - std::vector data(request_size, 3.0f); - test::TestRead(std::to_string(i), data, 0, request_size); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("BatchedReadRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - Pretest(); - - SECTION("read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - std::vector data(info.nelems_per_dataset, 5.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = RandomDatasetName(info.num_iterations); - size_t starting_element = Random1ToUpperBound(info.nelems_per_dataset); - size_t request_elements = - Random1ToUpperBound(info.nelems_per_dataset - starting_element); - std::vector data(request_elements, 3.8f); - test::TestRead(dset_name, data, starting_element, request_elements); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - Pretest(); - - SECTION("write to existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - std::vector data(info.nelems_per_dataset, 8.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = RandomDatasetName(info.num_iterations); - size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); - test::TestWritePartial1d(dset_name, data.data(), 0, request_size); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("BatchedWriteTemporalFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=fixed]") { - Pretest(); - - SECTION("write to existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::TestWritePartial1d(std::to_string(i), info.write_data.data(), 0, - info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("write to new file always at start") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::TestWriteDataset(std::to_string(i), info.write_data); - } - test::TestClose(); - } - - Posttest(); -} - -TEST_CASE("BatchedWriteTemporalVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=variable]") { - Pretest(); - - SECTION("write to existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t sleep_interval_ms = - GenNextRandom() % (info.temporal_interval_ms + 2); - usleep(sleep_interval_ms * 1000); - test::TestWritePartial1d(std::to_string(i), info.write_data.data(), 0, - info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("write to new file always at start") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t sleep_interval_ms = - GenNextRandom() % (info.temporal_interval_ms + 2); - usleep(sleep_interval_ms * 1000); - test::TestWriteDataset(std::to_string(i), info.write_data); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("BatchedMixedSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_mixed]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - Pretest(); - - SECTION("read after write on new file") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = std::to_string(i); - test::TestWriteDataset(dset_name, info.write_data); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("alternate write and read existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = std::to_string(i); - - if (i % 2 == 0) { - test::TestWritePartial1d(dset_name, info.write_data.data(), 0, - info.nelems_per_dataset); - } else { - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - } - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("update after read existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = std::to_string(i); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - test::TestWritePartial1d(dset_name, info.write_data.data(), 0, - info.nelems_per_dataset); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("read all after write all on new file in single open") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = std::to_string(i); - test::TestWriteDataset(dset_name, info.write_data); - } - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = std::to_string(i); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("read all after write all on new file in different open") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestWriteDataset(std::to_string(i), info.write_data); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - - test::TestOpen(info.new_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestRead(std::to_string(i), info.read_data, 0, - info.nelems_per_dataset); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); -} - -TEST_CASE("SingleMixed", "[process=" + std::to_string(info.comm_size) + - "][operation=single_mixed]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - Pretest(); - - SECTION("read after write from new file") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - std::string dset_name("0"); - test::TestWriteDataset(dset_name, info.write_data); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("update after read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - std::string dset_name("0"); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - test::TestWritePartial1d(dset_name, info.write_data.data(), 0, - info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("read after write from new file different opens") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - std::string dset_name("0"); - test::TestWriteDataset(dset_name, info.write_data); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - - test::TestOpen(info.new_file, H5F_ACC_RDWR); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("CompactDatasets") { - Pretest(); - - SECTION("create many and read randomly") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - size_t num_elements = KILOBYTES(32) / sizeof(f32); - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::vector data(num_elements); - for (size_t i = 0; i < data.size(); ++i) { - data[i] = GenRandom0to1(); - } - test::TestMakeCompactDataset(std::to_string(i), data); - } - - std::vector read_buf(num_elements, 0.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = RandomDatasetName(info.num_iterations); - test::TestRead(dset_name, read_buf, 0, num_elements); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("PartialUpdateToLastPage") { - Pretest(); - - SECTION("beginning of last page") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWritePartial1d(std::to_string(info.num_iterations - 1), - info.write_data.data(), 0, - info.nelems_per_dataset / 2); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("in middle of last page") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWritePartial1d(std::to_string(info.num_iterations - 1), - info.write_data.data(), - info.nelems_per_dataset / 4, - info.nelems_per_dataset / 2); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("at end of last page") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWritePartial1d(std::to_string(info.num_iterations - 1), - info.write_data.data(), - info.nelems_per_dataset / 2, - info.nelems_per_dataset / 2); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("ScratchMode", "[scratch]") { - Pretest(); - - SECTION("created files shouldn't persist") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestWriteDataset(std::to_string(i), info.write_data); - } - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = RandomDatasetName(info.num_iterations); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - - if (info.scratch_mode) { - REQUIRE(!stdfs::exists(info.new_file)); - } - } - - Posttest(); -} diff --git a/adapter/test/vfd/hermes_vfd_test.cc b/adapter/test/vfd/hermes_vfd_test.cc deleted file mode 100644 index e3458950e..000000000 --- a/adapter/test/vfd/hermes_vfd_test.cc +++ /dev/null @@ -1,585 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "hermes_types.h" -#include "adapter_test_utils.h" -#include "catch_config.h" - -namespace stdfs = std::experimental::filesystem; -using hermes::f32; -using hermes::u32; - -namespace hermes::adapter::vfd::test { - -/** - A structure to represent test arguments -*/ -struct Arguments { - std::string filename = "test"; /**< test file name */ - std::string directory = "/tmp"; /**< test directory name */ - size_t request_size = 65536; /**< test request size */ -}; - -/** - A structure to represent test information -*/ -struct TestInfo { - static const int element_size = sizeof(f32); /**< test element size */ - - // int rank = 0; - int comm_size = 1; /**< communicator size */ - std::vector write_data; /**< test data for writing */ - std::vector read_data; /**< test data for reading */ - std::string new_file; /**< new file name */ - std::string existing_file; /**< existing file name */ - std::string new_file_cmp; /**< new file name to compare */ - std::string existing_file_cmp; /**< existing file name to compare */ - std::string hdf5_extension = ".h5"; /**< HDF5 file extention to use */ - size_t num_iterations = 64; /**< number of iterations */ - // int offset_seed = 1; - // unsigned int rs_seed = 1; - // unsigned int temporal_interval_seed = 5; - size_t total_size; /**< total size */ - // size_t stride_size = 512; - unsigned int temporal_interval_ms = 1; /**< interval in milliseconds */ - // size_t small_min = 1; - // size_t small_max = KILOBYTES(4); - // size_t medium_min = KILOBYTES(4) + 1; - // size_t medium_max = KILOBYTES(256); - // size_t large_min = KILOBYTES(256) + 1; - // size_t large_max = MEGABYTES(3); - size_t nelems_per_dataset; /**< number of elements per dataset */ - bool scratch_mode = false; /**< flag for scratch mode */ -}; - -/** - * Temporarily disable printing of the HDF5 error stack. - * - * Some tests intentionally trigger HDF5 errors, and in those cases we don't - * want to clutter the output with HDF5 error messages. - */ -class MuteHdf5Errors { - H5E_auto2_t old_func; /**< error handler callback function */ - void *old_client_data; /**< pointer to client data for old_func */ - - public: - MuteHdf5Errors() { - // Save old error handler - H5Eget_auto(H5E_DEFAULT, &old_func, &old_client_data); - - // Turn off error stack printing - H5Eset_auto(H5E_DEFAULT, NULL, NULL); - } - - ~MuteHdf5Errors() { - // Restore previous error handler - H5Eset_auto(H5E_DEFAULT, old_func, old_client_data); - } -}; - -/** - * HDF5 identifiers required for reads and writes. - */ -struct RwIds { - hid_t dset_id; /**< dataset ID */ - hid_t dspace_id; /**< data space ID */ - hid_t mspace_id; /**< memory space ID */ -}; - -/** - * The I/O API for this adapter layer. - * - * Ideally we would have a high level Adapter I/O API that each adapter inherits - * from so that the adapter tests can reuse more code. This is a step in that - * direction. - */ -struct Hdf5Api { - /** - * A file access property list representing the sec2 (POSIX) VFD. - */ - hid_t sec2_fapl; - - Hdf5Api() : sec2_fapl(H5I_INVALID_HID) { - sec2_fapl = H5Pcreate(H5P_FILE_ACCESS); - REQUIRE(sec2_fapl != H5I_INVALID_HID); - REQUIRE(H5Pset_fapl_sec2(sec2_fapl) >= 0); - } - - ~Hdf5Api() { - REQUIRE(H5Pclose(sec2_fapl) >= 0); - sec2_fapl = H5I_INVALID_HID; - } - - /** - * Open an existing file using the default VFD. Since the tests are run with - * HDF5_DRIVER=hermes, the default VFD will be the Hermes VFD. - */ - hid_t Open(const std::string &fname, unsigned flags) { - hid_t result = H5Fopen(fname.c_str(), flags, H5P_DEFAULT); - - return result; - } - - /** - * Open an existing file using the POSIX VFD. This will bypass Hermes. - */ - hid_t OpenPosix(const std::string &fname, unsigned flags) { - hid_t result = H5Fopen(fname.c_str(), flags, sec2_fapl); - - return result; - } - - /** - * Create a file using the default VFD. - */ - hid_t Create(const std::string &fname, unsigned flags) { - hid_t result = H5Fcreate(fname.c_str(), flags, H5P_DEFAULT, H5P_DEFAULT); - - return result; - } - - /** - * Create a file using the POSIX VFD. - */ - hid_t CreatePosix(const std::string &fname, unsigned flags) { - hid_t result = H5Fcreate(fname.c_str(), flags, H5P_DEFAULT, sec2_fapl); - - return result; - } - - /** - * Boilerplate necessary before calling H5Dread or H5Dwrite. - */ - RwIds RwPreamble(hid_t hid, const std::string &dset_name, hsize_t offset, - hsize_t nelems, hsize_t stride = 1) { - hid_t dset_id = H5Dopen2(hid, dset_name.c_str(), H5P_DEFAULT); - - hid_t memspace_id = H5Screate_simple(1, &nelems, NULL); - REQUIRE(memspace_id != H5I_INVALID_HID); - - if (dset_id == H5I_INVALID_HID) { - dset_id = H5Dcreate2(hid, dset_name.c_str(), H5T_NATIVE_FLOAT, - memspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - } - - REQUIRE(dset_id != H5I_INVALID_HID); - hid_t dspace_id = H5Dget_space(dset_id); - REQUIRE(dspace_id != H5I_INVALID_HID); - herr_t status = H5Sselect_hyperslab(dspace_id, H5S_SELECT_SET, &offset, - &stride, &nelems, NULL); - REQUIRE(status >= 0); - - RwIds result = {dset_id, dspace_id, memspace_id}; - - return result; - } - - /** - * Cleanup code required after H5Dread and H5Dwrite. - */ - void RwCleanup(RwIds *ids) { - REQUIRE(H5Sclose(ids->mspace_id) >= 0); - REQUIRE(H5Sclose(ids->dspace_id) >= 0); - REQUIRE(H5Dclose(ids->dset_id) >= 0); - } - - /** - * Reads @p nelems elements from the object represented by @p hid into @p buf, - * starting at element @p offset. - */ - void Read(hid_t hid, const std::string &dset_name, std::vector &buf, - hsize_t offset, hsize_t nelems) { - RwIds ids = RwPreamble(hid, dset_name, offset, nelems); - herr_t status = H5Dread(ids.dset_id, H5T_NATIVE_FLOAT, ids.mspace_id, - ids.dspace_id, H5P_DEFAULT, buf.data()); - REQUIRE(status >= 0); - - RwCleanup(&ids); - } - /** - Create a 1-dimensional dataset using \a data vector. - */ - void MakeDataset(hid_t hid, const std::string &dset_name, - const std::vector &data, bool compact = false) { - MakeDataset(hid, dset_name, data.data(), data.size(), compact); - } - - /** - * Create a 1-dimensional dataset named @p dset_name in object @p hid with @p - * nelems elements from the array @p data. - */ - void MakeDataset(hid_t hid, const std::string &dset_name, const f32 *data, - hsize_t nelems, bool compact = false) { - hid_t dcpl = H5P_DEFAULT; - herr_t status = 0; - - if (compact) { - REQUIRE(nelems * sizeof(f32) <= KILOBYTES(64)); - dcpl = H5Pcreate(H5P_DATASET_CREATE); - REQUIRE(dcpl != H5I_INVALID_HID); - status = H5Pset_layout(dcpl, H5D_COMPACT); - REQUIRE(status >= 0); - } - - hid_t memspace_id = H5Screate_simple(1, &nelems, NULL); - REQUIRE(memspace_id != H5I_INVALID_HID); - - hid_t dset_id = H5Dcreate2(hid, dset_name.c_str(), H5T_NATIVE_FLOAT, - memspace_id, H5P_DEFAULT, dcpl, H5P_DEFAULT); - REQUIRE(dset_id != H5I_INVALID_HID); - - hid_t dspace_id = H5Dget_space(dset_id); - REQUIRE(dspace_id != H5I_INVALID_HID); - - status = H5Dwrite(dset_id, H5T_NATIVE_FLOAT, memspace_id, - dspace_id, H5P_DEFAULT, data); - REQUIRE(status >= 0); - REQUIRE(H5Sclose(memspace_id) >= 0); - REQUIRE(H5Sclose(dspace_id) >= 0); - REQUIRE(H5Dclose(dset_id) >= 0); - - if (compact) { - REQUIRE(H5Pclose(dcpl) >= 0); - } - } - - /** - * Write @p nelems elements to the dataset @p dset_name in file @p hid - * starting at element @p offset. The dataset will be created if it doesn't - * already exist. - */ - void WritePartial1d(hid_t hid, const std::string &dset_name, - const f32 *data, hsize_t offset, hsize_t nelems) { - RwIds ids = RwPreamble(hid, dset_name, offset, nelems); - herr_t status = H5Dwrite(ids.dset_id, H5T_NATIVE_FLOAT, ids.mspace_id, - ids.dspace_id, H5P_DEFAULT, data); - REQUIRE(status >= 0); - - RwCleanup(&ids); - } - /** - Close HDF5 file. - */ - herr_t Close(hid_t id) { - herr_t result = H5Fclose(id); - - return result; - } -}; - -// xoshiro128+ random number generation. 2x speedup over std::mt19937: -// https://prng.di.unimi.it/xoshiro128plus.c - -static inline u32 RotateLeft(const u32 x, int k) { - u32 result = (x << k) | (x >> (32 - k)); - - return result; -} - -static u32 random_state[4] = {111, 222, 333, 444}; - -u32 GenNextRandom() { - const u32 random = random_state[0] + random_state[3]; - - const u32 t = random_state[1] << 9; - - random_state[2] ^= random_state[0]; - random_state[3] ^= random_state[1]; - random_state[1] ^= random_state[2]; - random_state[0] ^= random_state[3]; - - random_state[2] ^= t; - - random_state[3] = RotateLeft(random_state[3], 11); - - return random; -} - -/** - * Return a random float in the range [0.0f, 1.0f] - */ -f32 GenRandom0to1() { - u32 random_u32 = GenNextRandom(); - - f32 result = (random_u32 >> 8) * 0x1.0p-24f; - - return result; -} - -/** - * Create an HDF5 file called @p fname with @p num_datasets datasets, each with - * @p num_dataset_elems elements. - */ -void GenHdf5File(std::string fname, size_t num_dataset_elems, - size_t num_datasets) { - std::vector data(num_dataset_elems * num_datasets); - - for (size_t i = 0; i < data.size(); ++i) { - data[i] = GenRandom0to1(); - } - - Hdf5Api api; - f32 *at = data.data(); - - hid_t file_id = api.CreatePosix(fname, H5F_ACC_TRUNC); - REQUIRE(file_id != H5I_INVALID_HID); - - for (size_t i = 0; i < num_datasets; ++i) { - api.MakeDataset(file_id, std::to_string(i), at, num_dataset_elems); - at += num_dataset_elems; - } - - REQUIRE(api.Close(file_id) > -1); -} - -} // namespace hermes::adapter::vfd::test - -hermes::adapter::vfd::test::Arguments args; -hermes::adapter::vfd::test::TestInfo info; - -using hermes::adapter::vfd::test::GenHdf5File; -using hermes::adapter::vfd::test::GenNextRandom; -using hermes::adapter::vfd::test::GenRandom0to1; - -/** - * Called in the Catch2 main function (see catch_config.h) before any tests are - * run. Initialize sizes, filenames, and read/write buffers. - */ -int init(int* argc, char*** argv) { - MPI_Init(argc, argv); - if (args.request_size % info.element_size != 0) { - LOG(FATAL) << "request_size must be a multiple of " << info.element_size; - } - info.nelems_per_dataset = args.request_size / info.element_size; - - info.write_data.resize(info.nelems_per_dataset); - for (size_t i = 0; i < info.write_data.size(); ++i) { - info.write_data[i] = GenRandom0to1(); - } - info.read_data.resize(info.nelems_per_dataset); - for (size_t i = 0; i < info.read_data.size(); ++i) { - info.read_data[i] = 0.0f; - } - - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - std::string suffix = std::to_string(getpid()) + info.hdf5_extension; - info.new_file = fullpath.string() + "_new_" + suffix; - info.existing_file = fullpath.string() + "_ext_" + suffix; - info.new_file_cmp = fullpath.string() + "_new_cmp_" + suffix; - info.existing_file_cmp = fullpath.string() + "_ext_cmp_" + suffix; - - char *driver_config = getenv("HDF5_DRIVER_CONFIG"); - if (driver_config) { - std::string looking_for("false"); - std::string conf_str(driver_config); - if (!conf_str.compare(0, looking_for.size(), looking_for)) { - info.scratch_mode = true; - } - } - - return 0; -} - -/** - * Called from catch_config.h after all tests are run. - */ -int finalize() { - MPI_Finalize(); - return 0; -} - -/** - * Remove all files generated by the tests - */ -void CleanupFiles() { - if (stdfs::exists(info.new_file)) - stdfs::remove(info.new_file); - if (stdfs::exists(info.new_file_cmp)) - stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file)) - stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); -} - -/** - * Called before each individual test. - * - * Generates files for tests that operate on existing files. - */ -int Pretest() { - CleanupFiles(); - - GenHdf5File(info.existing_file, info.nelems_per_dataset, info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(info.total_size > 0); - - return 0; -} - -/** - * Use h5diff to ensure that the resulting files from the Hermes VFD and the - * POSIX VFD are the same. - */ -void CheckResults(const std::string &file1, const std::string &file2) { - if (stdfs::exists(file1) && stdfs::exists(file2)) { - std::string h5diff_cmd = "h5diff " + file1 + " " + file2; - int status = system(h5diff_cmd.c_str()); - if (status != 0) { - LOG(ERROR) << "Failing h5diff command: " << h5diff_cmd; - } - REQUIRE(status == 0); - } -} - -/** - * Called after each individual test. - */ -int Posttest() { - if (!info.scratch_mode) { - // NOTE(chogan): This is necessary so that h5diff doesn't use the Hermes VFD - // in CheckResults. We don't need to reset LD_PRELOAD because it only has an - // effect when an application first starts. - unsetenv("LD_PRELOAD"); - unsetenv("HDF5_DRIVER"); - CheckResults(info.new_file, info.new_file_cmp); - CheckResults(info.existing_file, info.existing_file_cmp); - setenv("HDF5_DRIVER", "hermes", 1); - } - - CleanupFiles(); - - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -using hermes::adapter::vfd::test::Hdf5Api; - -/** - * The functions in this namespace perform operations on 2 files: the "main" - * file, which is the one going through the Hermes VFD, and a comparison file - * (with a "_cmp" suffix) which goes through the POSIX VFD. The idea is to - * perfrom each test on 2 files (Hermes VFD and POSIX VFD) and then compare the - * results at the end with h5diff. In persistent mode, the file produced by the - * Hermes VFD should be exactly the same as the one produced by the POSIX VFD. - */ -namespace test { - -hid_t hermes_hid; /**< Hermes handle ID */ -hid_t sec2_hid; /**< POSIX driver handle ID */ -herr_t hermes_herr; /**< Hermes error return value */ -/** - Test creating and opening a new file. -*/ -void TestOpen(const std::string &path, unsigned flags, bool create = false) { - Hdf5Api api; - - std::string cmp_path; - if (path == info.new_file) { - cmp_path = info.new_file_cmp; - } else { - cmp_path = info.existing_file_cmp; - } - - if (create) { - hermes_hid = api.Create(path, flags); - sec2_hid = api.CreatePosix(cmp_path, flags); - } else { - hermes_hid = api.Open(path, flags); - sec2_hid = api.OpenPosix(cmp_path, flags); - } - bool is_same = - (sec2_hid != H5I_INVALID_HID && hermes_hid != H5I_INVALID_HID) || - (sec2_hid == H5I_INVALID_HID && hermes_hid == H5I_INVALID_HID); - - REQUIRE(is_same); -} -/** - Test Close() calls. -*/ -void TestClose() { - Hdf5Api api; - hermes_herr = api.Close(hermes_hid); - herr_t status = api.Close(sec2_hid); - REQUIRE(status == hermes_herr); -} - -/** - Test writing partial 1-D dataset. -*/ -void TestWritePartial1d(const std::string &dset_name, const f32 *data, - hsize_t offset, hsize_t nelems) { - Hdf5Api api; - api.WritePartial1d(test::hermes_hid, dset_name, data, offset, nelems); - api.WritePartial1d(test::sec2_hid, dset_name, data, offset, nelems); -} - -/** - Test making dataset. -*/ -void TestWriteDataset(const std::string &dset_name, - const std::vector &data) { - Hdf5Api api; - api.MakeDataset(test::hermes_hid, dset_name, data); - api.MakeDataset(test::sec2_hid, dset_name, data); -} - - -/** - Test making compact dataset. -*/ -void TestMakeCompactDataset(const std::string &dset_name, - const std::vector &data) { - Hdf5Api api; - api.MakeDataset(test::hermes_hid, dset_name, data, true); - api.MakeDataset(test::sec2_hid, dset_name, data, true); -} - -/** - Test reading dataset. -*/ -void TestRead(const std::string &dset_name, std::vector &buf, - hsize_t offset, hsize_t nelems) { - Hdf5Api api; - api.Read(test::hermes_hid, dset_name, buf, offset, nelems); - std::vector sec2_read_buf(nelems, 0.0f); - api.Read(test::sec2_hid, dset_name, sec2_read_buf, offset, nelems); - - REQUIRE(std::equal(buf.begin(), buf.begin() + nelems, sec2_read_buf.begin())); -} -} // namespace test - -#include "hermes_vfd_basic_test.cc" diff --git a/adapter/vfd/CMakeLists.txt b/adapter/vfd/CMakeLists.txt deleted file mode 100644 index cae8406c7..000000000 --- a/adapter/vfd/CMakeLists.txt +++ /dev/null @@ -1,189 +0,0 @@ -# CMakeLists files in this project can -# refer to the root source directory of the project as ${HDF5_HERMES_SOURCE_DIR} and -# to the root binary directory of the project as ${HDF5_HERMES_BINARY_DIR}. - -project(HDF5_HERMES_VFD) - -#------------------------------------------------------------------------------ -# Version information -#------------------------------------------------------------------------------ -set(HDF5_HERMES_VFD_VERSION_MAJOR ${HERMES_VERSION_MAJOR}) -set(HDF5_HERMES_VFD_VERSION_MINOR ${HERMES_VERSION_MINOR}) -set(HDF5_HERMES_VFD_VERSION_PATCH ${HERMES_VERSION_PATCH}) -set(HDF5_HERMES_VFD_PACKAGE "hdf5_hermes_vfd") -set(HDF5_HERMES_VFD_PACKAGE_NAME "HDF5_HERMES_VFD") -set(HDF5_HERMES_VFD_PACKAGE_VERSION "${HDF5_HERMES_VFD_VERSION_MAJOR}.${HDF5_HERMES_VFD_VERSION_MINOR}.${HDF5_HERMES_VFD_VERSION_PATCH}") -set(HDF5_HERMES_VFD_PACKAGE_VERSION_MAJOR "${HDF5_HERMES_VFD_VERSION_MAJOR}.${HDF5_HERMES_VFD_VERSION_MINOR}") -set(HDF5_HERMES_VFD_PACKAGE_VERSION_MINOR "${HDF5_HERMES_VFD_VERSION_PATCH}") -set(HDF5_HERMES_VFD_PACKAGE_STRING "${HDF5_HERMES_VFD_PACKAGE_NAME} ${HDF5_HERMES_VFD_PACKAGE_VERSION}") -set(HDF5_HERMES_VFD_PACKAGE_TARNAME "${HDF5_HERMES_VFD_PACKAGE}") - -# Dynamically loaded VFDs must be shared libraries -set(HDF5_HERMES_VFD_LIBTYPE SHARED) - -#----------------------------------------------------------------------------- -# Targets built within this project are exported at Install time for use -# by other projects. -#----------------------------------------------------------------------------- -if(NOT HDF5_HERMES_VFD_EXPORTED_TARGETS) - set(HDF5_HERMES_VFD_EXPORTED_TARGETS "${HDF5_HERMES_VFD_PACKAGE}-targets") -endif() - -set(HDF5_HERMES_VFD_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/H5FDhermes.h - ${CMAKE_CURRENT_SOURCE_DIR}/H5FDhermes.c - ) - -add_library(hdf5_hermes_vfd ${HDF5_HERMES_VFD_SRCS}) -set_target_properties(hdf5_hermes_vfd PROPERTIES LIBRARY_OUTPUT_DIRECTORY - ${HERMES_VFD_LIBRARY_DIR} -) -target_include_directories(hdf5_hermes_vfd PRIVATE ${CMAKE_SOURCE_DIR}/wrapper) -target_include_directories(hdf5_hermes_vfd - SYSTEM PUBLIC ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} -) - -target_link_libraries(hdf5_hermes_vfd - hermes_wrapper - MPI::MPI_C - ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES} -) - -set(HDF5_HERMES_VFD_EXPORTED_LIBS hdf5_hermes_vfd ${HDF5_HERMES_VFD_EXPORTED_LIBS} PARENT_SCOPE) - -#----------------------------------------------------------------------------- -# Specify project header files to be installed -#----------------------------------------------------------------------------- -set(HDF5_HERMES_VFD_HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/H5FDhermes.h -) - -#----------------------------------------------------------------------------- -# Add file(s) to CMake Install -#----------------------------------------------------------------------------- -install( - FILES - ${HDF5_HERMES_VFD_HEADERS} - DESTINATION - ${HERMES_INSTALL_INCLUDE_DIR} - COMPONENT - headers -) - -#----------------------------------------------------------------------------- -# Add Target(s) to CMake Install -#----------------------------------------------------------------------------- -install( - TARGETS - hdf5_hermes_vfd - EXPORT - ${HDF5_HERMES_VFD_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR}/${HERMES_VFD_DIR_NAME} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR}/${HERMES_VFD_DIR_NAME} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) - -#----------------------------------------------------------------------------- -# Add Target(s) to CMake Install for import into other projects -#----------------------------------------------------------------------------- -install( - EXPORT - ${HDF5_HERMES_VFD_EXPORTED_TARGETS} - DESTINATION - ${HERMES_INSTALL_DATA_DIR}/cmake/hdf5_hermes_vfd - FILE - ${HDF5_HERMES_VFD_EXPORTED_TARGETS}.cmake -) - -#----------------------------------------------------------------------------- -# Export all exported targets to the build tree for use by parent project - -if(NOT HDF5_HERMES_VFD_EXTERNALLY_CONFIGURED) - export( - TARGETS - ${HDF5_HERMES_VFD_EXPORTED_LIBS} - FILE - ${HDF5_HERMES_VFD_EXPORTED_TARGETS}.cmake - ) -endif() - -#------------------------------------------------------------------------------ -# Set variables for parent scope -#------------------------------------------------------------------------------ - -# Pkg-config configuration -if(CMAKE_BUILD_TYPE) - string(TOLOWER ${CMAKE_BUILD_TYPE} lower_cmake_build_type) -endif() - -# Hermes VFD package dependencies -foreach(pkg_dep ${HDF5_HERMES_VFD_EXT_PKG_DEPENDENCIES}) - set(HDF5_HERMES_VFD_PKG_DEPENDENCIES ${HDF5_HERMES_VFD_PKG_DEPENDENCIES} ${pkg_dep}) -endforeach() -set(HDF5_HERMES_VFD_PKG_DEPENDENCIES ${HDF5_HERMES_VFD_PKG_DEPENDENCIES} PARENT_SCOPE) - -# Hermes VFD private library dependencies -foreach(exported_lib ${HDF5_HERMES_VFD_EXPORTED_LIBS}) - if(lower_cmake_build_type MATCHES "debug") - get_target_property(HDF5_HERMES_VFD_LIBRARY ${exported_lib} DEBUG_OUTPUT_NAME) - else() - get_target_property(HDF5_HERMES_VFD_LIBRARY ${exported_lib} RELEASE_OUTPUT_NAME) - endif() - set(HDF5_HERMES_VFD_LIBRARIES "${HDF5_HERMES_VFD_LIBRARIES} -l${HDF5_HERMES_VFD_LIBRARY}") -endforeach() -set(HDF5_HERMES_VFD_LIBRARIES ${HDF5_HERMES_VFD_LIBRARIES} PARENT_SCOPE) -# Hermes VFD external library dependencies -# Need to generate -lib if not already passed -set(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES - ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES} - ${HDF5_HERMES_VFD_EXT_PKG_LIB_DEPENDENCIES} - PARENT_SCOPE -) -foreach(lib_dep ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES}) - # get library name - get_filename_component(lib_name ${lib_dep} NAME_WE) - if(lib_name MATCHES "^-l") - # lib_name found is -lxxx - set(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST} ${lib_name}) - else() - # lib_name is /path/to/lib so get library path and name - get_filename_component(lib_path ${lib_dep} PATH) - string(REGEX REPLACE "^lib" "" lib_name ${lib_name}) - set(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST} -L${lib_path} -l${lib_name}) - endif() -endforeach() -if(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST) - list(REMOVE_DUPLICATES HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST) -endif() -foreach(lib_dep ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST}) - set(HDF5_HERMES_VFD_LIB_DEPENDENCIES "${HDF5_HERMES_VFD_LIB_DEPENDENCIES} ${lib_dep}") -endforeach() -set(HDF5_HERMES_VFD_LIB_DEPENDENCIES ${HDF5_HERMES_VFD_LIB_DEPENDENCIES} PARENT_SCOPE) - -# External include dependencies -set(HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES - ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} - ${HDF5_HERMES_VFD_EXT_PKG_INCLUDE_DEPENDENCIES} - PARENT_SCOPE -) -if(HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES) - list(REMOVE_DUPLICATES HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES) -endif() -foreach(inc_dep ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES}) - set(HDF5_HERMES_VFD_INCLUDE_DEPENDENCIES "${HDF5_HERMES_VFD_INCLUDE_DEPENDENCIES} -I${inc_dep}") -endforeach() -set(HDF5_HERMES_VFD_INCLUDE_DEPENDENCIES ${HDF5_HERMES_VFD_INCLUDE_DEPENDENCIES} PARENT_SCOPE) - -set(HDF5_HERMES_VFD_INCLUDES_BUILD_TIME - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} - PARENT_SCOPE -) - -set(HDF5_HERMES_VFD_INCLUDES_INSTALL_TIME - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} - PARENT_SCOPE -) diff --git a/adapter/vfd/H5FDhermes.c b/adapter/vfd/H5FDhermes.c deleted file mode 100644 index 09ca87094..000000000 --- a/adapter/vfd/H5FDhermes.c +++ /dev/null @@ -1,1173 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright by The HDF Group. * - * Copyright by the Board of Trustees of the University of Illinois. * - * All rights reserved. * - * * - * This file is part of HDF5. The full HDF5 copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the root of the source code * - * distribution tree, or in https://www.hdfgroup.org/licenses. * - * If you do not have access to either file, you may request a copy from * - * help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* - * Programmer: Kimmy Mu - * March 2021 - * - * Purpose: The hermes file driver using only the HDF5 public API - * and buffer datasets in Hermes buffering systems with - * multiple storage tiers. - */ -#ifndef _GNU_SOURCE - #define _GNU_SOURCE -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -/* HDF5 header for dynamic plugin loading */ -#include "H5PLextern.h" - -#include "H5FDhermes.h" /* Hermes file driver */ -#include "H5FDhermes_err.h" /* error handling */ - -/* Necessary hermes headers */ -#include "hermes_wrapper.h" - -#define H5FD_HERMES (H5FD_hermes_init()) - -/* HDF5 doesn't currently have a driver init callback. Use - * macro to initialize driver if loaded as a plugin. - */ -#define H5FD_HERMES_INIT \ - do { \ - if (H5FD_HERMES_g < 0) \ - H5FD_HERMES_g = H5FD_HERMES; \ - } while (0) - -/* The driver identification number, initialized at runtime */ -static hid_t H5FD_HERMES_g = H5I_INVALID_HID; - -/* Identifiers for HDF5's error API */ -hid_t H5FDhermes_err_stack_g = H5I_INVALID_HID; -hid_t H5FDhermes_err_class_g = H5I_INVALID_HID; - -/* Whether Hermes is initialized */ -static htri_t hermes_initialized = FAIL; -static hbool_t mpi_is_initialized = FALSE; - -/* File operations */ -#define OP_UNKNOWN 0 -#define OP_READ 1 -#define OP_WRITE 2 - -/* POSIX I/O mode used as the third parameter to open/_open - * when creating a new file (O_CREAT is set). */ -#if defined(H5_HAVE_WIN32_API) -#define H5FD_HERMES_POSIX_CREATE_MODE_RW (_S_IREAD | _S_IWRITE) -#else -#define H5FD_HERMES_POSIX_CREATE_MODE_RW 0666 -#endif - -/* Define length of blob name, which is converted from page index */ -#define LEN_BLOB_NAME 10 - -#define BIT_SIZE_OF_UNSIGNED (sizeof(uint)*8) - -/* kHermesConf env variable is used to define path to kHermesConf in adapters. - * This is used for initialization of Hermes. */ -const char *kHermesConf = "HERMES_CONF"; - -/* The description of bit representation of blobs in Hermes buffering system. */ -typedef struct bitv_t { - uint *blobs; - size_t capacity; - size_t end_pos; -} bitv_t; - -/* The description of a file/bucket belonging to this driver. */ -typedef struct H5FD_hermes_t { - H5FD_t pub; /* public stuff, must be first */ - haddr_t eoa; /* end of allocated region */ - haddr_t eof; /* end of file; current file size */ - haddr_t pos; /* current file I/O position */ - int op; /* last operation */ - hbool_t persistence; /* write to file name on close */ - int fd; /* the filesystem file descriptor */ - size_t buf_size; - char *bktname; /* Copy of file name from open operation */ - BucketClass *bkt_handle; - int ref_count; - unsigned char *page_buf; - bitv_t blob_in_bucket; - unsigned flags; /* The flags passed from H5Fcreate/H5Fopen */ -} H5FD_hermes_t; - -/* Driver-specific file access properties */ -typedef struct H5FD_hermes_fapl_t { - hbool_t persistence; /* write to file name on flush */ - size_t page_size; /* page size */ -} H5FD_hermes_fapl_t; - -/* - * These macros check for overflow of various quantities. These macros - * assume that HDoff_t is signed and haddr_t and size_t are unsigned. - * - * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t' - * is too large to be represented by the second argument - * of the file seek function. - * - * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too - * large to be represented by the `size_t' type. - * - * REGION_OVERFLOW: Checks whether an address and size pair describe data - * which can be addressed entirely by the second - * argument of the file seek function. - */ -#define MAXADDR (((haddr_t)1 << (8 * sizeof(off_t) - 1)) - 1) -#define ADDR_OVERFLOW(A) (HADDR_UNDEF == (A) || ((A) & ~(haddr_t)MAXADDR)) -#define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR) -#define REGION_OVERFLOW(A, Z) \ - (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || HADDR_UNDEF == (A) + (Z) || \ - (off_t)((A) + (Z)) < (off_t)(A)) - -/* Prototypes */ -static herr_t H5FD__hermes_term(void); -static herr_t H5FD__hermes_fapl_free(void *_fa); -static H5FD_t *H5FD__hermes_open(const char *name, unsigned flags, - hid_t fapl_id, haddr_t maxaddr); -static herr_t H5FD__hermes_close(H5FD_t *_file); -static int H5FD__hermes_cmp(const H5FD_t *_f1, const H5FD_t *_f2); -static herr_t H5FD__hermes_query(const H5FD_t *_f1, unsigned long *flags); -static haddr_t H5FD__hermes_get_eoa(const H5FD_t *_file, H5FD_mem_t type); -static herr_t H5FD__hermes_set_eoa(H5FD_t *_file, H5FD_mem_t type, - haddr_t addr); -static haddr_t H5FD__hermes_get_eof(const H5FD_t *_file, H5FD_mem_t type); -static herr_t H5FD__hermes_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, - haddr_t addr, size_t size, void *buf); -static herr_t H5FD__hermes_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, - haddr_t addr, size_t size, const void *buf); - -static const H5FD_class_t H5FD_hermes_g = { - H5FD_HERMES_VALUE, /* value */ - H5FD_HERMES_NAME, /* name */ - MAXADDR, /* maxaddr */ - H5F_CLOSE_STRONG, /* fc_degree */ - H5FD__hermes_term, /* terminate */ - NULL, /* sb_size */ - NULL, /* sb_encode */ - NULL, /* sb_decode */ - sizeof(H5FD_hermes_fapl_t),/* fapl_size */ - NULL, /* fapl_get */ - NULL, /* fapl_copy */ - H5FD__hermes_fapl_free, /* fapl_free */ - 0, /* dxpl_size */ - NULL, /* dxpl_copy */ - NULL, /* dxpl_free */ - H5FD__hermes_open, /* open */ - H5FD__hermes_close, /* close */ - H5FD__hermes_cmp, /* cmp */ - H5FD__hermes_query, /* query */ - NULL, /* get_type_map */ - NULL, /* alloc */ - NULL, /* free */ - H5FD__hermes_get_eoa, /* get_eoa */ - H5FD__hermes_set_eoa, /* set_eoa */ - H5FD__hermes_get_eof, /* get_eof */ - NULL, /* get_handle */ - H5FD__hermes_read, /* read */ - H5FD__hermes_write, /* write */ - NULL, /* flush */ - NULL, /* truncate */ - NULL, /* lock */ - NULL, /* unlock */ - NULL, /* del */ - NULL, /* ctl */ - H5FD_FLMAP_DICHOTOMY /* fl_map */ -}; - -/* Check if the blob at POS is set */ -static bool check_blob(bitv_t *bits, size_t bit_pos) { - bool result = false; - - if (bit_pos >= bits->capacity) - return false; - - size_t unit_pos = bit_pos / BIT_SIZE_OF_UNSIGNED; - size_t blob_pos_in_unit = bit_pos % BIT_SIZE_OF_UNSIGNED; - result = bits->blobs[unit_pos] & (1 << blob_pos_in_unit); - - return result; -} - -/* Set the bit at POS and reallocate 2*capacity for blobs as needed */ -static void set_blob(bitv_t *bits, size_t bit_pos) { - if (bit_pos >= bits->capacity) { - size_t current_units = bits->capacity/BIT_SIZE_OF_UNSIGNED; - size_t need_units = bit_pos/BIT_SIZE_OF_UNSIGNED + 1; - bits->capacity = need_units * BIT_SIZE_OF_UNSIGNED * 2; - bits->blobs = realloc(bits->blobs, bits->capacity); - memset(&bits->blobs[current_units], 0, - sizeof(uint)*(need_units*2-current_units+1)); - } - - size_t unit_pos = bit_pos / BIT_SIZE_OF_UNSIGNED; - size_t blob_pos_in_unit = bit_pos % BIT_SIZE_OF_UNSIGNED; - bits->blobs[unit_pos] |= 1 << blob_pos_in_unit; - if (bit_pos > bits->end_pos) - bits->end_pos = bit_pos; -} - -/** Returns true if @p page_index is the last page in the file. */ -bool H5FD__hermes_is_last_page(H5FD_hermes_t *file, size_t page_index) { - size_t total_pages = (size_t)ceil(file->eof / (float)file->buf_size); - size_t last_page_index = total_pages > 0 ? total_pages - 1 : 0; - bool ret_value = page_index == last_page_index; - - return ret_value; -} - -/** Returns the size of page @page_index. This is only different from - * H5FD_hermes_t::buf_size if it's the last page in the file. */ -size_t H5FD__hermes_get_gap_size(H5FD_hermes_t *file, size_t page_index) { - size_t ret_value = file->buf_size; - if (H5FD__hermes_is_last_page(file, page_index)) { - ret_value = file->eof - (page_index * file->buf_size); - } - - return ret_value; -} - -/** - * If the Hermes VFD recieves a partial page update to an existing file, we - * first need to fill the page with exising data from the file with a read - * before the Blob can be buffered. We refer to these partial pages as "gaps." - */ -herr_t H5FD__hermes_read_gap(H5FD_hermes_t *file, size_t seek_offset, - unsigned char *read_ptr, size_t read_size) { - herr_t ret_value = SUCCEED; - - if (!(file->flags & H5F_ACC_CREAT || file->flags & H5F_ACC_TRUNC || - file->flags & H5F_ACC_EXCL)) { - if (file->fd > -1) { - if (flock(file->fd, LOCK_SH) == -1) { - H5FD_HERMES_SYS_GOTO_ERROR(H5E_IO, H5E_CANTLOCKFILE, FAIL, - file->bktname); - } - - ssize_t bytes_read = pread(file->fd, read_ptr, read_size, seek_offset); - if (bytes_read == -1 || - ((size_t)bytes_read != read_size && bytes_read != 0)) { - H5FD_HERMES_SYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, file->bktname); - } - - if (flock(file->fd, LOCK_UN) == -1) { - H5FD_HERMES_SYS_GOTO_ERROR(H5E_IO, H5E_CANTUNLOCKFILE, FAIL, - file->bktname); - } - } - } - -done: - H5FD_HERMES_FUNC_LEAVE; -} - -/*------------------------------------------------------------------------- - * Function: H5FD_hermes_init - * - * Purpose: Initialize this driver by registering the driver with the - * library. - * - * Return: Success: The driver ID for the hermes driver - * Failure: H5I_INVALID_HID - * - *------------------------------------------------------------------------- - */ -hid_t -H5FD_hermes_init(void) { - hid_t ret_value = H5I_INVALID_HID; /* Return value */ - - /* Initialize error reporting */ - if ((H5FDhermes_err_stack_g = H5Ecreate_stack()) < 0) - H5FD_HERMES_GOTO_ERROR(H5E_VFL, H5E_CANTINIT, H5I_INVALID_HID, - "can't create HDF5 error stack"); - if ((H5FDhermes_err_class_g = H5Eregister_class(H5FD_HERMES_ERR_CLS_NAME, - H5FD_HERMES_ERR_LIB_NAME, - H5FD_HERMES_ERR_VER)) < 0) - H5FD_HERMES_GOTO_ERROR(H5E_VFL, H5E_CANTINIT, H5I_INVALID_HID, - "can't register error class with HDF5 error API"); - - if (H5I_VFL != H5Iget_type(H5FD_HERMES_g)) - H5FD_HERMES_g = H5FDregister(&H5FD_hermes_g); - - /* Set return value */ - ret_value = H5FD_HERMES_g; - -done: - H5FD_HERMES_FUNC_LEAVE; -} /* end H5FD_hermes_init() */ - -/*--------------------------------------------------------------------------- - * Function: H5FD__hermes_term - * - * Purpose: Shut down the VFD - * - * Returns: SUCCEED (Can't fail) - * - *--------------------------------------------------------------------------- - */ -static herr_t -H5FD__hermes_term(void) { - herr_t ret_value = SUCCEED; - - /* Unregister from HDF5 error API */ - if (H5FDhermes_err_class_g >= 0) { - if (H5Eunregister_class(H5FDhermes_err_class_g) < 0) - H5FD_HERMES_GOTO_ERROR( - H5E_VFL, H5E_CLOSEERROR, FAIL, - "can't unregister error class from HDF5 error API"); - - /* Print the current error stack before destroying it */ - PRINT_ERROR_STACK; - - /* Destroy the error stack */ - if (H5Eclose_stack(H5FDhermes_err_stack_g) < 0) { - H5FD_HERMES_GOTO_ERROR(H5E_VFL, H5E_CLOSEERROR, FAIL, - "can't close HDF5 error stack"); - PRINT_ERROR_STACK; - } /* end if */ - - H5FDhermes_err_stack_g = H5I_INVALID_HID; - H5FDhermes_err_class_g = H5I_INVALID_HID; - } - - /* Reset VFL ID */ - H5FD_HERMES_g = H5I_INVALID_HID; - -done: - H5FD_HERMES_FUNC_LEAVE_API; -} /* end H5FD__hermes_term() */ - -/*------------------------------------------------------------------------- - * Function: H5Pset_fapl_hermes - * - * Purpose: Modify the file access property list to use the H5FD_HERMES - * driver defined in this source file. There are no driver - * specific properties. - * - * Return: SUCCEED/FAIL - * - *------------------------------------------------------------------------- - */ -herr_t -H5Pset_fapl_hermes(hid_t fapl_id, hbool_t persistence, size_t page_size) { - H5FD_hermes_fapl_t fa; /* Hermes VFD info */ - herr_t ret_value = SUCCEED; /* Return value */ - - /* Check argument */ - if (H5I_GENPROP_LST != H5Iget_type(fapl_id) || - TRUE != H5Pisa_class(fapl_id, H5P_FILE_ACCESS)) { - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, - "not a file access property list"); - } - - /* Set VFD info values */ - memset(&fa, 0, sizeof(H5FD_hermes_fapl_t)); - fa.persistence = persistence; - fa.page_size = page_size; - - /* Set the property values & the driver for the FAPL */ - if (H5Pset_driver(fapl_id, H5FD_HERMES, &fa) < 0) { - H5FD_HERMES_GOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, - "can't set Hermes VFD as driver"); - } - -done: - H5FD_HERMES_FUNC_LEAVE_API; -} /* end H5Pset_fapl_hermes() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_fapl_free - * - * Purpose: Frees the family-specific file access properties. - * - * Return: SUCCEED/FAIL - * - *------------------------------------------------------------------------- - */ -static herr_t H5FD__hermes_fapl_free(void *_fa) { - H5FD_hermes_fapl_t *fa = (H5FD_hermes_fapl_t *)_fa; - herr_t ret_value = SUCCEED; /* Return value */ - - free(fa); - - H5FD_HERMES_FUNC_LEAVE; -} - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_open - * - * Purpose: Create and/or opens a bucket in Hermes. - * - * Return: Success: A pointer to a new bucket data structure. - * Failure: NULL - * - *------------------------------------------------------------------------- - */ -static H5FD_t * -H5FD__hermes_open(const char *name, unsigned flags, hid_t fapl_id, - haddr_t maxaddr) { - H5FD_hermes_t *file = NULL; /* hermes VFD info */ - int fd = -1; /* File descriptor */ - int o_flags = 0; /* Flags for open() call */ - struct stat sb = {0}; - const H5FD_hermes_fapl_t *fa = NULL; - H5FD_hermes_fapl_t new_fa = {0}; - char *hermes_config = NULL; - H5FD_t *ret_value = NULL; /* Return value */ - - /* Sanity check on file offsets */ - assert(sizeof(off_t) >= sizeof(size_t)); - - H5FD_HERMES_INIT; - - /* Check arguments */ - if (!name || !*name) - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name"); - if (0 == maxaddr || HADDR_UNDEF == maxaddr) - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr"); - if (ADDR_OVERFLOW(maxaddr)) - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr"); - - /* Get the driver specific information */ - H5E_BEGIN_TRY { - fa = H5Pget_driver_info(fapl_id); - } - H5E_END_TRY; - if (!fa || (H5P_FILE_ACCESS_DEFAULT == fapl_id)) { - ssize_t config_str_len = 0; - char config_str_buf[128]; - if ((config_str_len = - H5Pget_driver_config_str(fapl_id, config_str_buf, 128)) < 0) { - printf("H5Pget_driver_config_str() error\n"); - } - char *saveptr = NULL; - char* token = strtok_r(config_str_buf, " ", &saveptr); - if (!strcmp(token, "true") || !strcmp(token, "TRUE") || - !strcmp(token, "True")) { - new_fa.persistence = true; - } - token = strtok_r(0, " ", &saveptr); - sscanf(token, "%zu", &(new_fa.page_size)); - fa = &new_fa; - } - - /* Initialize Hermes */ - if ((H5OPEN hermes_initialized) == FAIL) { - hermes_config = getenv(kHermesConf); - if (HermesInitHermes(hermes_config) < 0) { - H5FD_HERMES_GOTO_ERROR(H5E_SYM, H5E_UNINITIALIZED, NULL, - "Hermes initialization failed"); - } else { - hermes_initialized = TRUE; - } - } - - bool creating_file = false; - - /* Build the open flags */ - o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY; - if (H5F_ACC_TRUNC & flags) { - o_flags |= O_TRUNC; - } - if (H5F_ACC_CREAT & flags) { - o_flags |= O_CREAT; - creating_file = true; - } - if (H5F_ACC_EXCL & flags) { - o_flags |= O_EXCL; - } - - if (fa->persistence || !creating_file) { - // NOTE(chogan): We're either in persistent mode, or we're in scratch mode - // and dealing with an existing file. - if ((fd = open(name, o_flags, H5FD_HERMES_POSIX_CREATE_MODE_RW)) < 0) { - int myerrno = errno; - H5FD_HERMES_GOTO_ERROR( - H5E_FILE, H5E_CANTOPENFILE, NULL, - "unable to open file: name = '%s', errno = %d, error message = '%s'," - "flags = %x, o_flags = %x", name, myerrno, strerror(myerrno), flags, - (unsigned)o_flags); - } - - if (__fxstat(_STAT_VER, fd, &sb) < 0) { - H5FD_HERMES_SYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, - "unable to fstat file"); - } - } - - /* Create the new file struct */ - if (NULL == (file = calloc(1, sizeof(H5FD_hermes_t)))) { - H5FD_HERMES_GOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, - "unable to allocate file struct"); - } - - if (name && *name) { - file->bktname = strdup(name); - } - - file->persistence = fa->persistence; - file->fd = fd; - file->bkt_handle = HermesBucketCreate(name); - file->page_buf = malloc(fa->page_size); - file->buf_size = fa->page_size; - file->ref_count = 1; - file->op = OP_UNKNOWN; - file->blob_in_bucket.capacity = BIT_SIZE_OF_UNSIGNED; - file->blob_in_bucket.blobs = (uint *)calloc(1, sizeof(uint)); - file->blob_in_bucket.end_pos = 0; - file->flags = flags; - file->eof = (haddr_t)sb.st_size; - - /* Set return value */ - ret_value = (H5FD_t *)file; - -done: - if (NULL == ret_value) { - if (fd >= 0) - close(fd); - if (file) { - if (file->bkt_handle) { - HermesBucketDestroy(file->bkt_handle); - } - free(file->blob_in_bucket.blobs); - free(file->bktname); - free(file->page_buf); - free(file); - } - } /* end if */ - - H5FD_HERMES_FUNC_LEAVE_API; -} /* end H5FD__hermes_open() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_close - * - * Purpose: Closes an HDF5 file. - * - * Return: Success: SUCCEED - * Failure: FAIL, file not closed. - * - *------------------------------------------------------------------------- - */ -static herr_t H5FD__hermes_close(H5FD_t *_file) { - H5FD_hermes_t *file = (H5FD_hermes_t *)_file; - size_t blob_size = file->buf_size; - size_t i; - herr_t ret_value = SUCCEED; /* Return value */ - - /* Sanity check */ - assert(file); - - if (file->persistence) { - if (file->op == OP_WRITE) { - /* TODO: if there is user blobk, the logic is not working, - including offset, but not 0 */ - for (i = 0; i <= file->blob_in_bucket.end_pos; i++) { - /* Check if this blob exists */ - bool blob_exists = check_blob(&file->blob_in_bucket, i); - if (!blob_exists) - continue; - - char i_blob[LEN_BLOB_NAME]; - snprintf(i_blob, sizeof(i_blob), "%zu\n", i); - HermesBucketGet(file->bkt_handle, i_blob, blob_size, file->page_buf); - - bool is_last_page = H5FD__hermes_is_last_page(file, i); - size_t bytes_to_write = blob_size; - - if (is_last_page) { - size_t bytes_in_last_page = file->eof - (i * blob_size); - bytes_to_write = bytes_in_last_page; - } - - ssize_t bytes_written = pwrite(file->fd, file->page_buf, bytes_to_write, - i * blob_size); - assert(bytes_written == bytes_to_write); - } - } - if (close(file->fd) < 0) - H5FD_HERMES_SYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, - "unable to close file"); - } - - if (file->ref_count == 1) { - HermesBucketDestroy(file->bkt_handle); - } else { - HermesBucketClose(file->bkt_handle); - } - - /* Release the file info */ - free(file->blob_in_bucket.blobs); - free(file->page_buf); - free(file->bktname); - free(file); - -done: - H5FD_HERMES_FUNC_LEAVE_API; -} /* end H5FD__hermes_close() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_cmp - * - * Purpose: Compares two buckets belonging to this driver using an - * arbitrary (but consistent) ordering. - * - * Return: Success: A value like strcmp() - * Failure: never fails (arguments were checked by the - * caller). - * - *------------------------------------------------------------------------- - */ -static int H5FD__hermes_cmp(const H5FD_t *_f1, const H5FD_t *_f2) { - const H5FD_hermes_t *f1 = (const H5FD_hermes_t *)_f1; - const H5FD_hermes_t *f2 = (const H5FD_hermes_t *)_f2; - int ret_value = 0; - - ret_value = strcmp(f1->bktname, f2->bktname); - - H5FD_HERMES_FUNC_LEAVE; -} /* end H5FD__hermes_cmp() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_query - * - * Purpose: Set the flags that this VFL driver is capable of supporting. - * (listed in H5FDpublic.h) - * - * Return: SUCCEED (Can't fail) - * - *------------------------------------------------------------------------- - */ -static herr_t H5FD__hermes_query(const H5FD_t *_file, - unsigned long *flags /* out */) { - /* Set the VFL feature flags that this driver supports */ - /* Notice: the Mirror VFD Writer currently uses only the hermes driver as - * the underying driver -- as such, the Mirror VFD implementation copies - * these feature flags as its own. Any modifications made here must be - * reflected in H5FDmirror.c - * -- JOS 2020-01-13 - */ - herr_t ret_value = SUCCEED; - - if (flags) { - *flags = 0; - } /* end if */ - - H5FD_HERMES_FUNC_LEAVE; -} /* end H5FD__hermes_query() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_get_eoa - * - * Purpose: Gets the end-of-address marker for the file. The EOA marker - * is the first address past the last byte allocated in the - * format address space. - * - * Return: The end-of-address marker. - * - *------------------------------------------------------------------------- - */ -static haddr_t H5FD__hermes_get_eoa(const H5FD_t *_file, - H5FD_mem_t H5_ATTR_UNUSED type) { - haddr_t ret_value = HADDR_UNDEF; - - const H5FD_hermes_t *file = (const H5FD_hermes_t *)_file; - - ret_value = file->eoa; - - H5FD_HERMES_FUNC_LEAVE; -} /* end H5FD__hermes_get_eoa() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_set_eoa - * - * Purpose: Set the end-of-address marker for the file. This function is - * called shortly after an existing HDF5 file is opened in order - * to tell the driver where the end of the HDF5 data is located. - * - * Return: SUCCEED (Can't fail) - * - *------------------------------------------------------------------------- - */ -static herr_t H5FD__hermes_set_eoa(H5FD_t *_file, - H5FD_mem_t H5_ATTR_UNUSED type, - haddr_t addr) { - herr_t ret_value = SUCCEED; - - H5FD_hermes_t *file = (H5FD_hermes_t *)_file; - - file->eoa = addr; - - H5FD_HERMES_FUNC_LEAVE; -} /* end H5FD__hermes_set_eoa() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_get_eof - * - * Purpose: Returns the end-of-file marker, which is the greater of - * either the filesystem end-of-file or the HDF5 end-of-address - * markers. - * - * Return: End of file address, the first address past the end of the - * "file", either the filesystem file or the HDF5 file. - * - *------------------------------------------------------------------------- - */ -static haddr_t H5FD__hermes_get_eof(const H5FD_t *_file, - H5FD_mem_t H5_ATTR_UNUSED type) { - haddr_t ret_value = HADDR_UNDEF; - - const H5FD_hermes_t *file = (const H5FD_hermes_t *)_file; - - ret_value = file->eof; - - H5FD_HERMES_FUNC_LEAVE; -} /* end H5FD__hermes_get_eof() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_read - * - * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR - * into buffer BUF according to data transfer properties in - * DXPL_ID. Determine the number of file pages affected by this - * call from ADDR and SIZE. Utilize transfer buffer PAGE_BUF to - * read the data from Blobs. Exercise care for the first and last - * pages to prevent overwriting existing data. - * - * Return: Success: SUCCEED. Result is stored in caller-supplied - * buffer BUF. - * Failure: FAIL, Contents of buffer BUF are undefined. - * - *------------------------------------------------------------------------- - */ -static herr_t H5FD__hermes_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, - hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, - size_t size, void *buf /*out*/) { - H5FD_hermes_t *file = (H5FD_hermes_t *)_file; - size_t num_pages; /* Number of pages of transfer buffer */ - size_t start_page_index; /* First page index of tranfer buffer */ - size_t end_page_index; /* End page index of tranfer buffer */ - size_t transfer_size = 0; - size_t blob_size = file->buf_size; - size_t k; - haddr_t addr_end = addr+size-1; - herr_t ret_value = SUCCEED; /* Return value */ - - assert(file && file->pub.cls); - assert(buf); - - /* Check for overflow conditions */ - if (HADDR_UNDEF == addr) { - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "addr undefined, addr = %llu", - (unsigned long long)addr); - } - if (REGION_OVERFLOW(addr, size)) { - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, - "addr overflow, addr = %llu", - (unsigned long long)addr); - } - if (NULL == file->page_buf) { - H5FD_HERMES_GOTO_ERROR(H5E_INTERNAL, H5E_UNINITIALIZED, FAIL, - "transfer buffer not initialized"); - } - - /* Check easy cases */ - if (0 == size) - return 0; - if ((haddr_t)addr >= file->eof) { - memset(buf, 0, size); - return 0; - } - - start_page_index = addr/blob_size; - end_page_index = addr_end/blob_size; - num_pages = end_page_index - start_page_index + 1; - - for (k = start_page_index; k <= end_page_index; ++k) { - size_t bytes_in; - char k_blob[LEN_BLOB_NAME]; - snprintf(k_blob, sizeof(k_blob), "%zu\n", k); - /* Check if this blob exists */ - bool blob_exists = check_blob(&file->blob_in_bucket, k); - - /* Check if addr is in the range of (k*blob_size, (k+1)*blob_size) */ - /* NOTE: The range does NOT include the start address of page k, - but includes the end address of page k */ - if (addr > k*blob_size && addr < (k+1)*blob_size) { - /* Calculate the starting address of transfer buffer update within page - * k */ - size_t offset = addr - k*blob_size; - assert(offset > 0); - - if (addr_end <= (k+1)*blob_size-1) - bytes_in = size; - else - bytes_in = (k+1)*blob_size-addr; - - if (!blob_exists) { - size_t bytes_copy; - if (file->eof < (k+1)*blob_size-1) - bytes_copy = file->eof-k*blob_size; - else - bytes_copy = blob_size; - - size_t bytes_read = pread(file->fd, file->page_buf, bytes_copy, - k*blob_size); - if (bytes_read != bytes_copy) - H5FD_HERMES_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "pread failed"); - memcpy(buf, file->page_buf+offset, bytes_in); - - /* Write Blob k to Hermes buffering system */ - HermesBucketPut(file->bkt_handle, k_blob, file->page_buf, blob_size); - set_blob(&file->blob_in_bucket, k); - } else { - /* Read blob back to transfer buffer */ - HermesBucketGet(file->bkt_handle, k_blob, blob_size, file->page_buf); - - memcpy(buf, file->page_buf+offset, bytes_in); - } - transfer_size += bytes_in; - /* Check if addr_end is in the range of [k*blob_size, - * (k+1)*blob_size-1) */ - /* NOTE: The range includes the start address of page k, - but does NOT include the end address of page k */ - } else if (addr_end >= k*blob_size && addr_end < (k+1)*blob_size-1) { - bytes_in = addr_end-k*blob_size+1; - if (!blob_exists) { - size_t bytes_copy; - if (file->eof < (k+1)*blob_size-1) - bytes_copy = file->eof-k*blob_size; - else - bytes_copy = blob_size; - - ssize_t bytes_read = pread(file->fd, file->page_buf, bytes_copy, - k*blob_size); - if (bytes_read != bytes_copy) - H5FD_HERMES_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "pread failed"); - - memcpy((char *)buf + transfer_size, file->page_buf, bytes_in); - - /* Write Blob k to Hermes buffering system */ - HermesBucketPut(file->bkt_handle, k_blob, file->page_buf, blob_size); - set_blob(&file->blob_in_bucket, k); - } else { - /* Read blob back to transfer buffer */ - HermesBucketGet(file->bkt_handle, k_blob, blob_size, file->page_buf); - - /* Update transfer buffer */ - memcpy((char *)buf + transfer_size, file->page_buf, bytes_in); - } - transfer_size += bytes_in; - /* Page/Blob k is within the range of (addr, addr+size) */ - /* addr <= k*blob_size && addr_end >= (k+1)*blob_size-1 */ - } else { - if (!blob_exists) { - ssize_t bytes_read = pread(file->fd, (char *)buf + transfer_size, - blob_size, addr+transfer_size); - if (bytes_read != blob_size) - H5FD_HERMES_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "pread failed"); - - /* Write Blob k to Hermes buffering system */ - HermesBucketPut(file->bkt_handle, k_blob, (char *)buf + transfer_size, - blob_size); - set_blob(&file->blob_in_bucket, k); - } else { - /* Read blob back directly */ - HermesBucketGet(file->bkt_handle, k_blob, blob_size, - (char *)buf + transfer_size); - } - transfer_size += blob_size; - } - } - - /* Update current position */ - file->pos = addr+size; - file->op = OP_READ; - -done: - if (ret_value < 0) { - /* Reset last file I/O information */ - file->pos = HADDR_UNDEF; - file->op = OP_UNKNOWN; - } /* end if */ - - H5FD_HERMES_FUNC_LEAVE_API; -} /* end H5FD__hermes_read() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_write - * - * Purpose: Writes SIZE bytes of data contained in buffer BUF to Hermes - * buffering system according to data transfer properties in - * DXPL_ID. Determine the number of file pages affected by this - * call from ADDR and SIZE. Utilize transfer buffer PAGE_BUF to - * put the data into Blobs. Exercise care for the first and last - * pages to prevent overwriting existing data. - * - * Return: SUCCEED/FAIL - * - *------------------------------------------------------------------------- - */ -static herr_t H5FD__hermes_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, - hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, - size_t size, const void *buf) { - H5FD_hermes_t *file = (H5FD_hermes_t *)_file; - size_t start_page_index; /* First page index of tranfer buffer */ - size_t end_page_index; /* End page index of tranfer buffer */ - size_t transfer_size = 0; - size_t blob_size = file->buf_size; - size_t k; - haddr_t addr_end = addr+size-1; - herr_t ret_value = SUCCEED; /* Return value */ - - assert(file && file->pub.cls); - assert(buf); - - /* Check for overflow conditions */ - if (HADDR_UNDEF == addr) { - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "addr undefined, addr = %llu", - (unsigned long long)addr); - } - if (REGION_OVERFLOW(addr, size)) { - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, - "addr overflow, addr = %llu, size = %llu", - (unsigned long long)addr, (unsigned long long)size); - } - if (NULL == file->page_buf) { - H5FD_HERMES_GOTO_ERROR(H5E_INTERNAL, H5E_UNINITIALIZED, FAIL, - "transfer buffer not initialized"); - } - start_page_index = addr/blob_size; - end_page_index = addr_end/blob_size; - - for (k = start_page_index; k <= end_page_index; ++k) { - char k_blob[LEN_BLOB_NAME]; - snprintf(k_blob, sizeof(k_blob), "%zu\n", k); - bool blob_exists = check_blob(&file->blob_in_bucket, k); - size_t page_start = k * blob_size; - size_t next_page_start = (k + 1) * blob_size; - - /* Check if addr is in the range of (page_start, next_page_start) */ - /* NOTE: The range does NOT include the start address of page k, - but includes the end address of page k */ - if (addr > page_start && addr < next_page_start) { - size_t page_offset = addr - page_start; - size_t page_write_size; - - if (addr_end < next_page_start) { - /* addr + size is within the same page (only one page) */ - page_write_size = size; - } else { - /* More than one page. Only copy until the end of this page. */ - page_write_size = next_page_start - addr; - } - - /* Fill transfer buffer with existing data, if any. */ - if (blob_exists) { - HermesBucketGet(file->bkt_handle, k_blob, blob_size, file->page_buf); - } else { - /* Populate this page from the original file */ - size_t gap_size = H5FD__hermes_get_gap_size(file, k); - herr_t status = H5FD__hermes_read_gap(file, page_start, file->page_buf, - gap_size); - if (status != SUCCEED) { - H5FD_HERMES_GOTO_DONE(FAIL); - } - } - - memcpy(file->page_buf + page_offset, (char *)buf + transfer_size, - page_write_size); - transfer_size += page_write_size; - - /* Write Blob k to Hermes. */ - HermesBucketPut(file->bkt_handle, k_blob, file->page_buf, blob_size); - set_blob(&file->blob_in_bucket, k); - } else if (addr_end >= page_start && addr_end < next_page_start - 1) { - /* NOTE: The range includes the start address of page k, but does NOT - include the end address of page k */ - - /* Read blob back */ - if (blob_exists) { - HermesBucketGet(file->bkt_handle, k_blob, blob_size, file->page_buf); - } else { - /* Populate this page from the original file */ - size_t gap_size = H5FD__hermes_get_gap_size(file, k); - herr_t status = H5FD__hermes_read_gap(file, page_start, file->page_buf, - gap_size); - if (status != SUCCEED) { - H5FD_HERMES_GOTO_DONE(FAIL); - } - } - - /* Update transfer buffer */ - memcpy(file->page_buf, (char *)buf + transfer_size, - addr_end-page_start + 1); - transfer_size += addr_end-page_start + 1; - /* Write Blob k to Hermes. */ - HermesBucketPut(file->bkt_handle, k_blob, file->page_buf, blob_size); - set_blob(&file->blob_in_bucket, k); - } else if (addr <= page_start && addr_end >= next_page_start-1) { - /* The write spans this page entirely */ - /* Write Blob k to Hermes buffering system */ - HermesBucketPut(file->bkt_handle, k_blob, (char *)buf + transfer_size, - blob_size); - set_blob(&(file->blob_in_bucket), k); - transfer_size += blob_size; - } - } - - /* Update current position and eof */ - file->pos = addr+size; - file->op = OP_WRITE; - if (file->pos > file->eof) - file->eof = file->pos; - -done: - if (ret_value < 0) { - /* Reset last file I/O information */ - file->pos = HADDR_UNDEF; - file->op = OP_UNKNOWN; - } /* end if */ - - H5FD_HERMES_FUNC_LEAVE_API; -} /* end H5FD__hermes_write() */ - -/* - * Stub routines for dynamic plugin loading - */ -H5PL_type_t -H5PLget_plugin_type(void) { - return H5PL_TYPE_VFD; -} - -const void* -H5PLget_plugin_info(void) { - return &H5FD_hermes_g; -} - -/* NOTE(chogan): Question: Why do we intercept initialization and termination of - * HDF5 and MPI? Answer: We have to handle several possible cases in order to - * get the initialization and finalization order of Hermes correct. First, the - * HDF5 application using the Hermes VFD can be either an MPI application or a - * serial application. If it's a serial application, we simply initialize Hermes - * before initializing the HDF5 library by intercepting H5_init_library. See - * https://github.com/HDFGroup/hermes/issues/385 for an explanation of why we - * need to initialize Hermes before HDF5. - * - * If we're dealing with an MPI application, then there are two possibilities: - * the app called MPI_Init before any HDF5 calls, or it made at least one HDF5 - * call before calling MPI_Init. If HDF5 was called first, then we have to - * initialize MPI ourselves and then intercept the app's call to MPI_Init to - * ensure MPI_Init is not called twice. - * - * For finalization, there are two cases to handle: 1) The application called - * MPI_Finalize(). In this case we need to intercept MPI_Finalize and shut down - * Hermes before MPI is finalized because Hermes finalization requires MPI. 2) - * If the app is serial, we need to call MPI_Finalize ourselves, so we intercept - * H5_term_library().*/ - -herr_t H5_init_library() { - herr_t ret_value = SUCCEED; - - if (mpi_is_initialized == FALSE) { - int status = PMPI_Init(NULL, NULL); - if (status != MPI_SUCCESS) { - // NOTE(chogan): We can't use the HDF5 error reporting functions here - // because HDF5 isn't initialized yet. - fprintf(stderr, "Hermes VFD: can't initialize MPI\n"); - ret_value = FAIL; - } else { - mpi_is_initialized = TRUE; - } - } - - if (ret_value == SUCCEED) { - if (hermes_initialized == FAIL) { - char *hermes_config = getenv(kHermesConf); - int status = HermesInitHermes(hermes_config); - if (status == 0) { - hermes_initialized = TRUE; - } else { - fprintf(stderr, "Hermes VFD: can't initialize Hermes\n"); - ret_value = FAIL; - } - } - - if (hermes_initialized == TRUE) { - MAP_OR_FAIL(H5_init_library); - ret_value = real_H5_init_library_(); - } - } - - return ret_value; -} - -herr_t H5_term_library() { - MAP_OR_FAIL(H5_term_library); - herr_t ret_value = real_H5_term_library_(); - - if (hermes_initialized == TRUE) { - HermesFinalize(); - hermes_initialized = FALSE; - } - - if (mpi_is_initialized) { - MPI_Finalize(); - mpi_is_initialized = FALSE; - } - - return ret_value; -} - -/** Only Initialize MPI if it hasn't already been initialized. */ -int MPI_Init(int *argc, char ***argv) { - int status = MPI_SUCCESS; - if (mpi_is_initialized == FALSE) { - int status = PMPI_Init(argc, argv); - if (status == MPI_SUCCESS) { - mpi_is_initialized = TRUE; - } - } - - return status; -} - -int MPI_Finalize() { - MAP_OR_FAIL(H5_term_library); - real_H5_term_library_(); - - if (hermes_initialized == TRUE) { - HermesFinalize(); - hermes_initialized = FALSE; - } - - int status = PMPI_Finalize(); - if (status == MPI_SUCCESS) { - mpi_is_initialized = FALSE; - } - - return status; -} diff --git a/adapter/vfd/H5FDhermes.h b/adapter/vfd/H5FDhermes.h deleted file mode 100644 index fb347273a..000000000 --- a/adapter/vfd/H5FDhermes.h +++ /dev/null @@ -1,60 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright by The HDF Group. * - * Copyright by the Board of Trustees of the University of Illinois. * - * All rights reserved. * - * * - * This file is part of HDF5. The full HDF5 copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the root of the source code * - * distribution tree, or in https://www.hdfgroup.org/licenses. * - * If you do not have access to either file, you may request a copy from * - * help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* - * Programmer: Kimmy Mu - * April 2021 - * - * Purpose: The public header file for the Hermes driver. - */ -#ifndef H5FDhermes_H -#define H5FDhermes_H - -#include -#include -#include - -#define H5FD_HERMES_NAME "hermes" -#define H5FD_HERMES_VALUE ((H5FD_class_value_t)(513)) - -#define HERMES_FORWARD_DECL(func_, ret_, args_) \ - typedef ret_(*real_t_##func_##_) args_; \ - ret_(*real_##func_##_) args_ = NULL; - -#define MAP_OR_FAIL(func_) \ - if (!(real_##func_##_)) { \ - real_##func_##_ = (real_t_##func_##_)dlsym(RTLD_NEXT, #func_); \ - if (!(real_##func_##_)) { \ - fprintf(stderr, "HERMES Adapter failed to map symbol: %s\n", #func_); \ - exit(1); \ - } \ - } - -#ifdef __cplusplus -extern "C" { -#endif - -hid_t H5FD_hermes_init(); -herr_t H5Pset_fapl_hermes(hid_t fapl_id, hbool_t persistence, size_t page_size); - -HERMES_FORWARD_DECL(H5_init_library, herr_t, ()); -HERMES_FORWARD_DECL(H5_term_library, herr_t, ()); - -HERMES_FORWARD_DECL(MPI_Init, int, (int *argc, char ***argv)); -HERMES_FORWARD_DECL(MPI_Finalize, int, (void)); - -#ifdef __cplusplus -} -#endif - -#endif /* end H5FDhermes_H */ diff --git a/adapter/vfd/H5FDhermes_err.h b/adapter/vfd/H5FDhermes_err.h deleted file mode 100644 index 3d910b670..000000000 --- a/adapter/vfd/H5FDhermes_err.h +++ /dev/null @@ -1,199 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright by The HDF Group. * - * All rights reserved. * - * * - * This file is part of the HDF5 HERMES Virtual File Driver. The full * - * copyright notice, including terms governing use, modification, and * - * redistribution, is contained in the COPYING file, which can be found at * - * the root of the source code distribution tree. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* - * Error handling for the HERMES VFD - */ - -#ifndef H5FDhermes_err_h -#define H5FDhermes_err_h - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include "H5Epublic.h" - -extern hid_t H5FDhermes_err_stack_g; -extern hid_t H5FDhermes_err_class_g; - -#define H5FD_HERMES_ERR_CLS_NAME "HDF5 HERMES VFD" -#define H5FD_HERMES_ERR_LIB_NAME "HDF5 HERMES VFD" -#define H5FD_HERMES_ERR_VER "0.1.0" - -#define SUCCEED 0 -#define FAIL (-1) - -#ifndef FALSE - #define FALSE false -#endif -#ifndef TRUE - #define TRUE true -#endif - -#define H5_ATTR_UNUSED __attribute__((unused)) - -/* Error macros */ - -/* - * Macro to push the current function to the current error stack - * and then goto the "done" label, which should appear inside the - * function. (compatible with v1 and v2 errors) - */ -#define H5FD_HERMES_GOTO_ERROR(err_major, err_minor, ret_val, ...) \ - do { \ - unsigned is_v2_err; \ - union { \ - H5E_auto1_t err_func_v1; \ - H5E_auto2_t err_func_v2; \ - } err_func; \ - \ - /* Determine version of error */ \ - (void)H5Eauto_is_v2(H5E_DEFAULT, &is_v2_err); \ - \ - if (is_v2_err) { \ - (void)H5Eget_auto2(H5E_DEFAULT, &err_func.err_func_v2, NULL); \ - } else { \ - (void)H5Eget_auto1(&err_func.err_func_v1, NULL); \ - } \ - /* Check whether automatic error reporting has been disabled */ \ - if ( (is_v2_err && err_func.err_func_v2) || \ - (!is_v2_err && err_func.err_func_v1) ) { \ - if (H5FDhermes_err_stack_g >= 0 && H5FDhermes_err_class_g >= 0) { \ - H5Epush2(H5FDhermes_err_stack_g, __FILE__, __func__, __LINE__, \ - H5FDhermes_err_class_g, err_major, err_minor, __VA_ARGS__); \ - } else { \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } \ - } \ - \ - ret_value = ret_val; \ - goto done; \ - } while (0) - -/* - * Macro to push the current function to the current error stack - * without calling goto. This is used for handling the case where - * an error occurs during cleanup past the "done" label inside a - * function so that an infinite loop does not occur where goto - * continually branches back to the label. (compatible with v1 - * and v2 errors) - */ -#define H5FD_HERMES_DONE_ERROR(err_major, err_minor, ret_val, ...) \ - do { \ - unsigned is_v2_err; \ - union { \ - H5E_auto1_t err_func_v1; \ - H5E_auto2_t err_func_v2; \ - } err_func; \ - \ - /* Determine version of error */ \ - (void)H5Eauto_is_v2(H5E_DEFAULT, &is_v2_err); \ - \ - if (is_v2_err) { \ - (void)H5Eget_auto2(H5E_DEFAULT, &err_func.err_func_v2, NULL); \ - } else { \ - (void)H5Eget_auto1(&err_func.err_func_v1, NULL); \ - } \ - /* Check whether automatic error reporting has been disabled */ \ - if ( (is_v2_err && err_func.err_func_v2) || \ - (!is_v2_err && err_func.err_func_v1) ) { \ - if (H5FDhermes_err_stack_g >= 0 && H5FDhermes_err_class_g >= 0) { \ - H5Epush2(H5FDhermes_err_stack_g, __FILE__, __func__, __LINE__, \ - H5FDhermes_err_class_g, err_major, err_minor, __VA_ARGS__); \ - } else { \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } \ - } \ - \ - ret_value = ret_val; \ - } while (0) - -/* - * Macro to print out the current error stack and then clear it - * for future use. (compatible with v1 and v2 errors) - */ -#define PRINT_ERROR_STACK \ - do { \ - unsigned is_v2_err; \ - union { \ - H5E_auto1_t err_func_v1; \ - H5E_auto2_t err_func_v2; \ - } err_func; \ - \ - /* Determine version of error */ \ - (void)H5Eauto_is_v2(H5E_DEFAULT, &is_v2_err); \ - \ - if (is_v2_err) { \ - (void)H5Eget_auto2(H5E_DEFAULT, &err_func.err_func_v2, NULL); \ - } else { \ - (void)H5Eget_auto1(&err_func.err_func_v1, NULL); \ - } \ - /* Check whether automatic error reporting has been disabled */ \ - if ( (is_v2_err && err_func.err_func_v2) || \ - (!is_v2_err && err_func.err_func_v1) ) { \ - if ((H5FDhermes_err_stack_g >= 0) && \ - (H5Eget_num(H5FDhermes_err_stack_g) > 0)) { \ - H5Eprint2(H5FDhermes_err_stack_g, NULL); \ - H5Eclear2(H5FDhermes_err_stack_g); \ - } \ - } \ - } while (0) - -#define H5FD_HERMES_SYS_GOTO_ERROR(err_major, err_minor, ret_val, str) \ - do { \ - int myerrno = errno; \ - H5FD_HERMES_GOTO_ERROR(err_major, err_minor, ret_val, \ - "%s, errno = %d, error message = '%s'", str, \ - myerrno, strerror(myerrno)); \ - } while (0) - -/* - * Macro to simply jump to the "done" label inside the function, - * setting ret_value to the given value. This is often used for - * short circuiting in functions when certain conditions arise. - */ -#define H5FD_HERMES_GOTO_DONE(ret_val) \ - do { \ - ret_value = ret_val; \ - goto done; \ - } while (0) - -/* - * Macro to return from a top-level API function, printing - * out the error stack on the way out. - * It should be ensured that this macro is only called once - * per HDF5 operation. If it is called multiple times per - * operation (e.g. due to calling top-level API functions - * internally), the error stack will be inconsistent/incoherent. - */ -#define H5FD_HERMES_FUNC_LEAVE_API \ - do { \ - PRINT_ERROR_STACK; \ - return ret_value; \ - } while (0) - -/* - * Macro to return from internal functions. - */ -#define H5FD_HERMES_FUNC_LEAVE \ - do { \ - return ret_value; \ - } while (0) - -#ifdef __cplusplus -} -#endif - -#endif /* H5FDhermes_err_h */ diff --git a/adapter/vfd/README.md b/adapter/vfd/README.md deleted file mode 100644 index b89c17050..000000000 --- a/adapter/vfd/README.md +++ /dev/null @@ -1,102 +0,0 @@ -# HDF5 Hermes VFD - -## 1. Description -The HDF5 Hermes VFD is a [Virtual File -Driver](https://portal.hdfgroup.org/display/HDF5/Virtual+File+Drivers) (VFD) for -HDF5 that can be used to interface with the Hermes API. The driver is built as a -plugin library that is external to HDF5. - -## 2. Dependencies -The Hermes VFD requires [HDF5](https://github.com/HDFGroup/hdf5) >= `1.13.0`, -which is the version that first introduced dynamically loadable VFDs. - -## 3. Usage -To use the HDF5 Hermes VFD in an HDF5 application, the driver can either be -linked with the application during compilation, or it can be dynamically loaded -via an environment variable. It is more convenient to load the VFD as a dynamic -plugin because it does not require code changes or recompilation. - -### Method 1: Dynamically loaded by environment variable (recommended) - -As of HDF5 `1.13.0` each file in an HDF5 app opened or created with the default -file access property list (FAPL) will use the VFD specified in the `HDF5_DRIVER` -environment variable rather than the default "sec2" (POSIX) driver. To use the -Hermes VFD, simply set - -```sh -HDF5_DRIVER=hermes -``` - -Now we must tell the HDF5 library where to find the Hermes VFD. That is done -with the following environment variable: - -```sh -HDF5_PLUGIN_PATH=/lib/hermes_vfd -``` - -The Hermes VFD has two configuration options. -1. persistence - if `true`, the HDF5 application will produce the same output - files with the Hermes VFD as it would without it. If `false`, the files are - buffered in Hermes during the application run, but are not persisted when the - application terminates. Thus, no files are produced. -2. page size - The Hermes VFD works by mapping HDF5 files into its internal data - structures. This happens in pages. The `page size` configuration option - allows the user to specify the size, in bytes, of these pages. If your app - does lots 2 MiB writes, then it's a good idea to set the page size to 2 - MiB. A smaller page size, 1 KiB for example, would convert each 2 MiB write - into 2048 1 KiB writes. However, be aware that using pages that are too large - can slow down metadata operations, which are usually less than 2 KiB. To - combat the tradeoff between small metadata pages and large raw data pages, - the Hermes VFD can be stacked underneath the [split VFD](https://docs.hdfgroup.org/hdf5/develop/group___f_a_p_l.html#ga502f1ad38f5143cf281df8282fef26ed). - - -These two configuration options are passed as a space-delimited string through -an environment variable: - -```sh -# Example of configuring the Hermes VFD with `persistent_mode=true` and -# `page_size=64KiB` -HDF5_DRIVER_CONFIG="true 65536" -``` - -Finally we need to provide a configuration file for Hermes itself, and -`LD_PRELOAD` the Hermes VFD so we can intercept HDF5 and MPI calls for proper -initialization and finalization: - -```sh -HERMES_CONF=/hermes.yaml -LD_PRELOAD=/hermes_vfd/libhdf5_hermes_vfd.so -``` - -Heres is a full example of running an HDF5 app with the Hermes VFD: - -```sh -HDF5_DRIVER=hermes \ - HDF5_PLUGIN_PATH=/hermes.yaml \ - LD_PRELOAD=/hermes_vfd/libhdf5_hermes_vfd.so \ - ./my_hdf5_app -``` - -### Method 2: Linked into application - -To link the Hermes VFD into an HDF5 application, the application should include -the `H5FDhermes.h` header and should link the installed VFD library, -`libhdf5_hermes_vfd.so`, into the application. Once this has been done, Hermes -VFD access can be set up by calling `H5Pset_fapl_hermes()` on a FAPL within the -HDF5 application. In this case, the `persistence` and `page_size` configuration -options are pass directly to this function: - -```C -herr_t H5Pset_fapl_hermes(hid_t fapl_id, hbool_t persistence, size_t page_size) -``` - -The resulting `fapl_id` should then be passed to each file open or creation for -which you wish to use the Hermes VFD. - -## 4. More Information -* [Hermes VFD performance results](https://github.com/HDFGroup/hermes/wiki/HDF5-Hermes-VFD) - -* [Hermes VFD with hdf5-iotest](https://github.com/HDFGroup/hermes/tree/master/benchmarks/HermesVFD) -* [HDF5 VFD Plugins RFC](https://github.com/HDFGroup/hdf5doc/blob/master/RFCs/HDF5_Library/VFL_DriverPlugins/RFC__A_Plugin_Interface_for_HDF5_Virtual_File_Drivers.pdf) diff --git a/benchmarks/borg_bench.cc b/benchmarks/borg_bench.cc index 6e8516f22..d8cc211a8 100644 --- a/benchmarks/borg_bench.cc +++ b/benchmarks/borg_bench.cc @@ -317,7 +317,7 @@ static void OptimizeReads(Options &options) { const int kNumRanks = hermes->GetNumProcesses(); // const size_t kTotalBytes = kNumRanks * options.blob_size * options.iters; MetadataManager *mdm = GetMetadataManagerFromContext(&hermes->context_); - std::vector targets(mdm->node_targets.length); + std::vector targets(mdm->node_targets.length); for (u16 i = 0; i < mdm->node_targets.length; ++i) { targets[i] = {1, i, i}; diff --git a/benchmarks/dpe_bench.cc b/benchmarks/dpe_bench.cc index 712c6b6d2..08037d4ae 100644 --- a/benchmarks/dpe_bench.cc +++ b/benchmarks/dpe_bench.cc @@ -133,7 +133,7 @@ int main(int argc, char **argv) { assert(tgt_state.num_devices == dpe_total_targets); std::vector output_tmp, schemas; - std::vector targets = + std::vector targets = testing::GetDefaultTargets(tgt_state.num_devices); api::Context ctx; diff --git a/code_generators/.idea/.gitignore b/code_generators/.idea/.gitignore new file mode 100644 index 000000000..26d33521a --- /dev/null +++ b/code_generators/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/code_generators/.idea/code_generators.iml b/code_generators/.idea/code_generators.iml new file mode 100644 index 000000000..8b8c39547 --- /dev/null +++ b/code_generators/.idea/code_generators.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/code_generators/.idea/inspectionProfiles/Project_Default.xml b/code_generators/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..7c745c6a7 --- /dev/null +++ b/code_generators/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,21 @@ + + + + \ No newline at end of file diff --git a/code_generators/.idea/inspectionProfiles/profiles_settings.xml b/code_generators/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 000000000..105ce2da2 --- /dev/null +++ b/code_generators/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/code_generators/.idea/misc.xml b/code_generators/.idea/misc.xml new file mode 100644 index 000000000..d1e22ecb8 --- /dev/null +++ b/code_generators/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/code_generators/.idea/modules.xml b/code_generators/.idea/modules.xml new file mode 100644 index 000000000..7ff40af9a --- /dev/null +++ b/code_generators/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/code_generators/.idea/vcs.xml b/code_generators/.idea/vcs.xml new file mode 100644 index 000000000..6c0b86358 --- /dev/null +++ b/code_generators/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/code_generators/code_generators/singleton/generator.py b/code_generators/code_generators/singleton/generator.py index dfe841834..37fbcb087 100644 --- a/code_generators/code_generators/singleton/generator.py +++ b/code_generators/code_generators/singleton/generator.py @@ -7,6 +7,7 @@ """ import re +from code_generators.util.naming import to_snake_case class SingletonDefinition: def __init__(self, namespace, class_name, include): @@ -42,7 +43,7 @@ def _generate_cc(self, path): lines.append(f"#include {self.singleton_include}") lines.append("") for defn in self.defs: - lines.append(f"#include <{defn.include}>") + lines.append(f"#include {defn.include}") lines.append(f"template<> std::unique_ptr<{defn.class_name}> hermes::Singleton<{defn.class_name}>::obj_ = nullptr;") self._save_lines(lines, path) diff --git a/code_generators/singleton.py b/code_generators/singleton.py index 827beee61..1b3695c9e 100644 --- a/code_generators/singleton.py +++ b/code_generators/singleton.py @@ -10,7 +10,14 @@ from code_generators.singleton.generator import SingletonGenerator from code_generators.util.paths import HERMES_ROOT +# Hermes singleton gen = SingletonGenerator("SRC", "\"singleton.h\"") -gen.add("hermes::api", "Hermes", "hermes.h") +gen.add("hermes::api", "Hermes", "") gen.generate(f"{HERMES_ROOT}/src/singleton.cc", - f"{HERMES_ROOT}/src/singleton_macros.h") \ No newline at end of file + f"{HERMES_ROOT}/src/singleton_macros.h") + +# POSIX RealAPI singleton +gen = SingletonGenerator("ADAPTER", "\"singleton.h\"") +gen.add("hermes::adapter::posix", "PosixApi", "\"real_api.h\"") +gen.generate(f"{HERMES_ROOT}/adapter/posix/singleton.cc", + f"{HERMES_ROOT}/adapter/posix/singleton_macros.h") \ No newline at end of file diff --git a/config/hermes_server_default.yaml b/config/hermes_server_default.yaml index 37ec3564c..3f8b968bb 100644 --- a/config/hermes_server_default.yaml +++ b/config/hermes_server_default.yaml @@ -36,13 +36,13 @@ devices: # buffers), or '0' if it is per node (e.g., local NVMe). is_shared_device: 0 - # For each device, the minimum and maximum percent capacity threshold at which - # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause - # the BufferOrganizer to move data to lower devices, making more room in faster - # devices (ideal for write-heavy workloads). Conversely, increasing the minimum - # threshold will cause data to be moved from slower devices into faster devices - # (ideal for read-heavy workloads). For example, a maximum capacity threshold of - # 0.8 would have the effect of always keeping 20% of the device's space free for + # For each device, the minimum and maximum percent capacity threshold at which + # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause + # the BufferOrganizer to move data to lower devices, making more room in faster + # devices (ideal for write-heavy workloads). Conversely, increasing the minimum + # threshold will cause data to be moved from slower devices into faster devices + # (ideal for read-heavy workloads). For example, a maximum capacity threshold of + # 0.8 would have the effect of always keeping 20% of the device's space free for # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure # that the device is always at least 30% occupied. borg_capacity_thresh: [0.0, 1.0] diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 10354758d..63204b334 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,7 +52,8 @@ set(HERMES_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/api/bucket.cc ${CMAKE_CURRENT_SOURCE_DIR}/api/hermes.cc ${CMAKE_CURRENT_SOURCE_DIR}/api/vbucket.cc - #${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cc + ${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cc + ${CMAKE_CURRENT_SOURCE_DIR}/buffer_organizer.cc #${CMAKE_CURRENT_SOURCE_DIR}/prefetcher.cc #${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/sequential.cc #${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/apriori.cc @@ -83,7 +84,10 @@ target_include_directories(hermes SYSTEM PUBLIC ${HERMES_EXT_INCLUDE_DEPENDENCIES} ) +add_dependencies(hermes hermes_posix_singleton) + target_link_libraries(hermes + PUBLIC hermes_posix_singleton PUBLIC ${GLPK_LIBRARIES} PUBLIC ${CMAKE_HERMES_COMMUNICATION_TYPE_LIB} PUBLIC ${CMAKE_HERMES_RPC_TYPE_LIB} @@ -153,6 +157,7 @@ install( ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} ) +message(${HERMES_EXPORTED_TARGETS}) install( TARGETS hermes_daemon diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 5850d1bc7..525c5915f 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -58,7 +58,7 @@ void Hermes::StopDaemon() { void Hermes::InitServer(std::string server_config_path) { LoadServerConfig(server_config_path); InitSharedMemory(); - mdm_.shm_init(&header_->mdm_); + mdm_.shm_init(&server_config_, &header_->mdm_); rpc_.InitServer(); rpc_.InitClient(); } @@ -77,7 +77,7 @@ void Hermes::InitColocated(std::string server_config_path, LoadServerConfig(server_config_path); LoadClientConfig(client_config_path); InitSharedMemory(); - mdm_.shm_init(&header_->mdm_); + mdm_.shm_init(&server_config_, &header_->mdm_); rpc_.InitColocated(); } @@ -99,12 +99,12 @@ void Hermes::InitSharedMemory() { // Create shared-memory allocator auto mem_mngr = LABSTOR_MEMORY_MANAGER; mem_mngr->CreateBackend(lipc::MemoryBackendType::kPosixShmMmap, + lipc::MemoryManager::kDefaultBackendSize, server_config_.shmem_name_); main_alloc_ = mem_mngr->CreateAllocator(lipc::AllocatorType::kPageAllocator, server_config_.shmem_name_, main_alloc_id, - sizeof(HermesShmHeader), - lipc::MemoryManager::kDefaultSlotSize); + sizeof(HermesShmHeader)); header_ = main_alloc_->GetCustomHeader(); } diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 323c15a1d..39c1d6c9e 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -3,3 +3,33 @@ // #include "buffer_organizer.h" +#include "metadata_manager.h" +#include "io_clients/io_client_factory.h" + +namespace hermes { + +/** Stores a blob into a set of buffers */ +RPC void BufferOrganizer::LocalPlaceBlobInBuffers( + Blob &blob, lipc::vector &buffers) { + for (auto &buffer_info : buffers) { + auto &dev_info = mdm_->devices_[buffer_info.tid_.GetDeviceId()]; + auto io_client = IoClientFactory::Get(dev_info.io_api_); + bool ret = io_client->Write(dev_info, blob.data(), + buffer_info.off_, buffer_info.size_); + if (!ret) { + LOG(FATAL) << "Could not perform I/O in BORG" << std::endl; + } + } +} + +/** Stores a blob into a set of buffers */ +RPC void LocalReadBlobFromBuffers(Blob &blob, + lipc::vector &buffers) { +} + +/** Copies one buffer set into another buffer set */ +RPC void LocalCopyBuffers(lipc::vector &dst, + lipc::vector &src) { +} + +} // namespace hermes \ No newline at end of file diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index f4ea48547..bd309f1a7 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -5,9 +5,41 @@ #ifndef HERMES_SRC_BUFFER_ORGANIZER_H_ #define HERMES_SRC_BUFFER_ORGANIZER_H_ +#include "rpc.h" +#include "hermes_types.h" +#include "buffer_pool.h" + +namespace hermes { + +/** + * Manages the organization of blobs in the hierarchy. + * */ class BufferOrganizer { + public: + MetadataManager *mdm_; + public: BufferOrganizer() = default; + + /** Initialize the BORG */ + void shm_init(MetadataManager *mdm); + + /** Finalize the BORG */ + void shm_destroy(); + + /** Stores a blob into a set of buffers */ + RPC void LocalPlaceBlobInBuffers(Blob &blob, + lipc::vector &buffers); + + /** Stores a blob into a set of buffers */ + RPC void LocalReadBlobFromBuffers(Blob &blob, + lipc::vector &buffers); + + /** Copies one buffer set into another buffer set */ + RPC void LocalCopyBuffers(lipc::vector &dst, + lipc::vector &src); }; +} // namespace hermes + #endif // HERMES_SRC_BUFFER_ORGANIZER_H_ diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 8a01c7e5b..c415332d7 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -3,9 +3,63 @@ // #include "buffer_pool.h" +#include "metadata_manager.h" namespace hermes { -bool LocalPlaceBlob(PlacementSchema &schema, Blob &blob) {} +/** Initialize the BPM and its shared memory. */ +void BufferPoolManager::shm_init(MetadataManager *mdm) { + mdm_ = mdm; + target_allocs_.shm_init(nullptr); + target_allocs_.resize(mdm_->targets_.size()); + for (auto &target : mdm_->targets_) { + auto &dev_info = mdm_->devices_[target.id_.GetDeviceId()]; + dev_info.mount_point_; + } +} + +/** Store the BPM in shared memory */ +void BufferPoolManager::shm_serialize(BufferPoolManagerShmHeader *header) { + target_allocs_ >> header->alloc_ar_; +} + +/** Deserialize the BPM from shared memory */ +void BufferPoolManager::shm_deserialize(BufferPoolManagerShmHeader *header) { + target_allocs_ << header->alloc_ar_; +} + +/** + * Allocate buffers from the targets according to the schema + * + * TODO(llogan): use better allocator policy + * */ +lipc::vector +BufferPoolManager::LocalAllocateBuffers(PlacementSchema &schema, Blob &blob) { + lipc::vector buffers(nullptr); + for (auto plcmnt : schema.plcmnts_) { + if (plcmnt.tid_.GetNodeId() != mdm_->rpc_->node_id_) { + continue; + } + auto &alloc = target_allocs_[plcmnt.tid_.GetDeviceId()]; + BufferInfo info; + info.off_ = alloc.cur_off_; + info.size_ = plcmnt.size_; + info.tid_ = plcmnt.tid_; + alloc.cur_off_ += plcmnt.size_; + buffers.emplace_back(info); + mdm_->LocalUpdateTargetCapacity(info.tid_, + static_cast(info.size_)); + } + return buffers; +} + +/** + * Free buffers from the BufferPool + * + * TODO(llogan): actually implement + * */ +bool BufferPoolManager::LocalReleaseBuffers(lipc::vector &buffers) { + return true; +} } // namespace hermes \ No newline at end of file diff --git a/src/buffer_pool.h b/src/buffer_pool.h index 56df5f44a..a1f2e2345 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -12,11 +12,16 @@ class MetadataManager; namespace hermes { +struct BufferPoolAllocator { + std::atomic max_size_; + std::atomic cur_off_; +}; + /** * The shared-memory representation of the BufferPool * */ struct BufferPoolManagerShmHeader { - lipc::vector targets_; + lipc::ShmArchive> alloc_ar_; }; /** @@ -25,15 +30,19 @@ struct BufferPoolManagerShmHeader { class BufferPoolManager { private: MetadataManager *mdm_; + lipc::vector target_allocs_; /**< Per-target allocator */ public: BufferPoolManager() = default; - void shm_init(); + /** Initialize the BPM and its shared memory. */ + void shm_init(MetadataManager *mdm); - void shm_serialize(); + /** Store the BPM in shared memory */ + void shm_serialize(BufferPoolManagerShmHeader *header); - void shm_deserialize(); + /** Deserialize the BPM from shared memory */ + void shm_deserialize(BufferPoolManagerShmHeader *header); /** * Allocate buffers from the targets according to the schema diff --git a/src/config.h b/src/config.h index 43d179cae..8f0ad42b7 100644 --- a/src/config.h +++ b/src/config.h @@ -73,8 +73,8 @@ static void PrintExpectedAndFail(const std::string &expected, u32 line_number = } /** parse \a list_node vector from configuration file in YAML */ -template -static void ParseVector(YAML::Node list_node, std::vector &list) { +template> +static void ParseVector(YAML::Node list_node, VEC_TYPE &list) { for (auto val_node : list_node) { list.emplace_back(val_node.as()); } diff --git a/src/config_server.cc b/src/config_server.cc index 17de5deec..4d745df88 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -25,14 +25,15 @@ void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { for (auto device : yaml_conf["devices"]) { DeviceInfo dev; auto dev_info = device.second; - dev.mount_point_ = dev_info["mount_point"].as(); + dev.mount_point_ = lipc::string(dev_info["mount_point"].as()); dev.capacity_ = ParseSize(dev_info["capacity"].as()); dev.bandwidth_ = ParseSize(dev_info["bandwidth"].as()); dev.latency_ = ParseLatency(dev_info["latency"].as()); - ParseVector(dev_info["slab_sizes"], dev.slab_sizes_); + ParseVector>( + dev_info["slab_sizes"], dev.slab_sizes_); devices_.emplace_back(dev); } } diff --git a/src/config_server.h b/src/config_server.h index 6b8f5de7b..755ec2785 100644 --- a/src/config_server.h +++ b/src/config_server.h @@ -9,16 +9,26 @@ namespace hermes::config { +/** + * The type of interface the device exposes + * */ +enum class IoInterface { + kRam, + kPosix +}; + /** * Device information defined in server config * */ struct DeviceInfo { + /** The I/O interface for the device */ + IoInterface io_api_; /** The minimum transfer size of each device */ size_t block_size_; /** The unit of each slab, a multiple of the Device's block size */ - std::vector slab_sizes_; + lipc::vector slab_sizes_; /** The mount point of a device */ - std::string mount_point_; + lipc::string mount_point_; /** Device capacity (bytes) */ size_t capacity_; /** Bandwidth of a device (MBps) */ diff --git a/src/dpe/minimize_io_time.cc b/src/dpe/minimize_io_time.cc index 72848faa1..5de152784 100644 --- a/src/dpe/minimize_io_time.cc +++ b/src/dpe/minimize_io_time.cc @@ -20,7 +20,7 @@ namespace hermes { Status MinimizeIoTime::Placement(const std::vector &blob_sizes, const std::vector &node_state, - const std::vector &targets, + const std::vector &targets, const api::Context &ctx, std::vector &output) { Status result; diff --git a/src/dpe/minimize_io_time.h b/src/dpe/minimize_io_time.h index fcec7403c..0ea899a0b 100644 --- a/src/dpe/minimize_io_time.h +++ b/src/dpe/minimize_io_time.h @@ -28,7 +28,7 @@ class MinimizeIoTime : public DPE { ~MinimizeIoTime() = default; Status Placement(const std::vector &blob_sizes, const std::vector &node_state, - const std::vector &targets, + const std::vector &targets, const api::Context &ctx, std::vector &output); diff --git a/src/dpe/random.cc b/src/dpe/random.cc index 528f416a3..913437007 100644 --- a/src/dpe/random.cc +++ b/src/dpe/random.cc @@ -18,7 +18,7 @@ namespace hermes { -Status Random::AddSchema(std::multimap &ordered_cap, +Status Random::AddSchema(std::multimap &ordered_cap, size_t blob_size, PlacementSchema &schema) { std::random_device rd; std::mt19937 gen(rd()); @@ -34,7 +34,7 @@ Status Random::AddSchema(std::multimap &ordered_cap, dst_dist(1, std::distance(itlow, ordered_cap.end())); size_t dst_relative = dst_dist(gen); std::advance(itlow, dst_relative-1); - ordered_cap.insert(std::pair((*itlow).first-blob_size, + ordered_cap.insert(std::pair((*itlow).first-blob_size, (*itlow).second)); schema.push_back(std::make_pair(blob_size, (*itlow).second)); @@ -45,21 +45,20 @@ Status Random::AddSchema(std::multimap &ordered_cap, } void Random::GetOrderedCapacities(const std::vector &node_state, - const std::vector &targets, - std::multimap &ordered_cap) { + const std::vector &targets, + std::multimap &ordered_cap) { for (size_t i = 0; i < node_state.size(); ++i) { - ordered_cap.insert(std::pair(node_state[i], targets[i])); + ordered_cap.insert(std::pair(node_state[i], targets[i])); } } Status Random::Placement(const std::vector &blob_sizes, const std::vector &node_state, - const std::vector &targets, + const std::vector &targets, const api::Context &ctx, std::vector &output) { Status result; - std::multimap ordered_cap; - VERIFY_DPE_POLICY(ctx) + std::multimap ordered_cap; GetOrderedCapacities(node_state, targets, ordered_cap); diff --git a/src/dpe/random.h b/src/dpe/random.h index 383b656d3..f41b41329 100644 --- a/src/dpe/random.h +++ b/src/dpe/random.h @@ -25,7 +25,7 @@ class Random : public DPE { ~Random() = default; Status Placement(const std::vector &blob_sizes, const std::vector &node_state, - const std::vector &targets, + const std::vector &targets, const api::Context &ctx, std::vector &output); @@ -34,10 +34,10 @@ class Random : public DPE { get the capacities of each \a node_state and \a targets and store them into \a ordered_cap.*/ void GetOrderedCapacities(const std::vector &node_state, - const std::vector &targets, - std::multimap &ordered_cap); + const std::vector &targets, + std::multimap &ordered_cap); /** add placement schema */ - Status AddSchema(std::multimap &ordered_cap, size_t blob_size, + Status AddSchema(std::multimap &ordered_cap, size_t blob_size, PlacementSchema &schema); }; diff --git a/src/dpe/round_robin.cc b/src/dpe/round_robin.cc index 0df127675..bebc9d558 100644 --- a/src/dpe/round_robin.cc +++ b/src/dpe/round_robin.cc @@ -20,13 +20,12 @@ std::vector RoundRobin::devices_; Status RoundRobin::Placement(const std::vector &blob_sizes, const std::vector &node_state, - const std::vector &targets, + const std::vector &targets, const api::Context &ctx, std::vector &output) { Status result; std::vector ns_local(node_state.begin(), node_state.end()); bool split = ctx.rr_split; - VERIFY_DPE_POLICY(ctx) for (auto &blob_size : blob_sizes) { for (auto &target : targets) { diff --git a/src/dpe/round_robin.h b/src/dpe/round_robin.h index d7f8dc9c1..04f062f5a 100644 --- a/src/dpe/round_robin.h +++ b/src/dpe/round_robin.h @@ -36,7 +36,7 @@ class RoundRobin : public DPE { Status Placement(const std::vector &blob_sizes, const std::vector &node_state, - const std::vector &targets, + const std::vector &targets, const api::Context &ctx, std::vector &output); }; diff --git a/src/hermes_types.h b/src/hermes_types.h index 9299e0905..7c8dd4a30 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -85,31 +85,31 @@ enum class TopologyType { /** Represents unique ID for BlobId, BucketId, and VBucketId */ template -struct UniqueID { +struct UniqueId { u64 unique_; /**< A unique id for the blob */ i32 node_id_; /**< The node the content is on */ bool IsNull() const { return unique_ == 0; } - static UniqueID GetNull() { - UniqueID id; + static UniqueId GetNull() { + UniqueId id; id.unique_ = 0; return id; } i32 GetNodeId() const { return node_id_; } - bool operator==(const UniqueID &other) const { + bool operator==(const UniqueId &other) const { return unique_ == other.unique_ && node_id_ == other.node_id_; } - bool operator!=(const UniqueID &other) const { + bool operator!=(const UniqueId &other) const { return unique_ != other.unique_ || node_id_ != other.node_id_; } }; -typedef UniqueID<0> BucketId; -typedef UniqueID<1> VBucketId; -typedef UniqueID<2> BlobId; +typedef UniqueId<0> BucketId; +typedef UniqueId<1> VBucketId; +typedef UniqueId<2> BlobId; /** A definition for logging something that is not yet implemented */ #define HERMES_NOT_IMPLEMENTED_YET \ @@ -118,8 +118,8 @@ typedef UniqueID<2> BlobId; /** A definition for logging invalid code path */ #define HERMES_INVALID_CODE_PATH LOG(FATAL) << "Invalid code path." << std::endl -/** A TargetID uniquely identifies a buffering target within the system. */ -union TargetID { +/** A TargetId uniquely identifies a buffering target within the system. */ +union TargetId { /** The Target ID as bitfield */ struct { /** The ID of the node in charge of this target. */ @@ -131,9 +131,29 @@ union TargetID { u16 index_; } bits_; - /** The TargetID as a unsigned 64-bit integer */ + /** The TargetId as a unsigned 64-bit integer */ u64 as_int_; + TargetId() = default; + + TargetId(u32 node_id, u16 device_id, u16 index) { + bits_.node_id_ = node_id; + bits_.device_id_ = device_id; + bits_.index_ = index; + } + + u32 GetNodeId() { + return bits_.node_id_; + } + + u16 GetDeviceId() { + return bits_.device_id_; + } + + u16 GetIndex() { + return bits_.index_; + } + bool IsNull() const { return as_int_ == 0; } }; @@ -143,9 +163,9 @@ union TargetID { * */ struct SubPlacement { size_t size_; /**> Size (bytes) */ - TargetID tid_; /**> Target destination of data */ + TargetId tid_; /**> Target destination of data */ - SubPlacement(size_t size, TargetID tid) + SubPlacement(size_t size, TargetId tid) : size_(size), tid_(tid) {} }; @@ -154,14 +174,14 @@ struct SubPlacement { * hierarchy during data placement. */ struct PlacementSchema { - std::vector plcmnt_; + std::vector plcmnts_; - void AddSubPlacement(size_t size, TargetID tid) { - plcmnt_.emplace_back(size, tid); + void AddSubPlacement(size_t size, TargetId tid) { + plcmnts_.emplace_back(size, tid); } void Clear() { - plcmnt_.clear(); + plcmnts_.clear(); } }; @@ -174,7 +194,7 @@ struct Thresholds { }; /** Trait ID type */ -struct TraitID { +struct TraitId { u64 type_; }; @@ -311,8 +331,8 @@ enum class TraitType : u8 { namespace std { template -struct hash> { - std::size_t operator()(const hermes::UniqueID &key) const { +struct hash> { + std::size_t operator()(const hermes::UniqueId &key) const { return std::hash{}(key.unique_) + std::hash{}(key.node_id_); diff --git a/src/io_clients/io_client.h b/src/io_clients/io_client.h new file mode 100644 index 000000000..e36653e11 --- /dev/null +++ b/src/io_clients/io_client.h @@ -0,0 +1,23 @@ +// +// Created by lukemartinlogan on 12/22/22. +// + +#ifndef HERMES_SRC_IO_CLIENTS_IO_CLIENT_H_ +#define HERMES_SRC_IO_CLIENTS_IO_CLIENT_H_ + +#include "hermes_types.h" +#include "metadata_types.h" + +namespace hermes { + +class IoClient { + public: + virtual bool Write(DeviceInfo &dev_info, void *data, + size_t off, size_t size) = 0; + virtual bool Read(DeviceInfo &dev_info, void *data, + size_t off, size_t size) = 0; +}; + +} // namespace hermes + +#endif // HERMES_SRC_IO_CLIENTS_IO_CLIENT_H_ diff --git a/src/io_clients/io_client_factory.h b/src/io_clients/io_client_factory.h new file mode 100644 index 000000000..5e446bf0b --- /dev/null +++ b/src/io_clients/io_client_factory.h @@ -0,0 +1,40 @@ +// +// Created by lukemartinlogan on 12/22/22. +// + +#ifndef HERMES_SRC_IO_CLIENTS_IO_CLIENT_FACTORY_H_ +#define HERMES_SRC_IO_CLIENTS_IO_CLIENT_FACTORY_H_ + +#include "io_client.h" +#include "metadata_types.h" +#include "posix.h" +#include "ram.h" + +namespace hermes { + +/** + A class to represent Data Placement Engine Factory +*/ +class IoClientFactory { + public: + /** + * Get the I/O api corresponding to a particular device type + * */ + static std::unique_ptr Get(IoInterface type) { + switch (type) { + case IoInterface::kPosix: { + return std::make_unique(); + } + case IoInterface::kRam: + default: { + // TODO(llogan): @errorhandling not implemented + LOG(FATAL) << "IoClient not implemented" << std::endl; + return NULL; + } + } + } +}; + +} // namespace hermes + +#endif // HERMES_SRC_IO_CLIENTS_IO_CLIENT_FACTORY_H_ diff --git a/src/io_clients/posix.h b/src/io_clients/posix.h new file mode 100644 index 000000000..5f87fa0a2 --- /dev/null +++ b/src/io_clients/posix.h @@ -0,0 +1,39 @@ +// +// Created by lukemartinlogan on 12/22/22. +// + +#ifndef HERMES_SRC_IO_CLIENTS_POSIX_H_ +#define HERMES_SRC_IO_CLIENTS_POSIX_H_ + +#include "io_client.h" +#include "adapter/posix/real_api.h" +#include "adapter/posix/singleton_macros.h" + +namespace hermes { + +class PosixIoClient : public IoClient { + public: + bool Write(DeviceInfo &dev_info, void *data, + size_t off, size_t size) override { + auto api = HERMES_POSIX_API; + int fd = api->open(dev_info.mount_point_.c_str(), O_RDWR); + if (fd < 0) { return false; } + size_t count = api->pwrite(fd, data, size, off); + api->close(fd); + return count == size; + } + + bool Read(DeviceInfo &dev_info, void *data, + size_t off, size_t size) override { + auto api = HERMES_POSIX_API; + int fd = api->open(dev_info.mount_point_.c_str(), O_RDWR); + if (fd < 0) { return false; } + size_t count = api->pread(fd, data, size, off); + api->close(fd); + return count == size; + } +}; + +} // namespace hermes + +#endif // HERMES_SRC_IO_CLIENTS_POSIX_H_ diff --git a/src/io_clients/ram.h b/src/io_clients/ram.h new file mode 100644 index 000000000..134a61b09 --- /dev/null +++ b/src/io_clients/ram.h @@ -0,0 +1,8 @@ +// +// Created by lukemartinlogan on 12/22/22. +// + +#ifndef HERMES_SRC_IO_CLIENTS_RAM_H_ +#define HERMES_SRC_IO_CLIENTS_RAM_H_ + +#endif // HERMES_SRC_IO_CLIENTS_RAM_H_ diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 3888fef43..52d65901d 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -10,16 +10,35 @@ namespace hermes { /** * Explicitly initialize the MetadataManager * */ -void MetadataManager::shm_init(MetadataManagerShmHeader *header) { +void MetadataManager::shm_init(ServerConfig *config, + MetadataManagerShmHeader *header) { header_ = header; rpc_ = &HERMES->rpc_; header_->id_alloc_ = 1; + + // Create the metadata maps blob_id_map_ = lipc::make_mptr(nullptr); bkt_id_map_ = lipc::make_mptr(nullptr); vbkt_id_map_ = lipc::make_mptr(nullptr); blob_map_ = lipc::make_mptr(nullptr); bkt_map_ = lipc::make_mptr(nullptr); vbkt_map_ = lipc::make_mptr(nullptr); + + // Create the DeviceInfo vector + devices_.shm_init(config->devices_); + + // Create the TargetInfo vector + targets_.resize(devices_.size()); + int dev_id = 0; + for (auto &dev_info : config->devices_) { + targets_.emplace_back( + TargetId(rpc_->node_id_, dev_id, dev_id), + dev_info.capacity_, + dev_info.capacity_); + ++dev_id; + } + + // Ensure all local processes can access data structures shm_serialize(); shm_deserialize(header_); } diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 961ea0c5f..0b8a37d34 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -48,7 +48,7 @@ struct MetadataManagerShmHeader { * Manages the metadata for blobs, buckets, and vbuckets. * */ class MetadataManager { - private: + public: RPC_TYPE* rpc_; MetadataManagerShmHeader *header_; @@ -62,13 +62,19 @@ class MetadataManager { lipc::mptr bkt_map_; lipc::mptr vbkt_map_; + /** + * Information about targets and devices + * */ + lipc::vector devices_; + lipc::vector targets_; + public: MetadataManager() = default; /** * Explicitly initialize the MetadataManager * */ - void shm_init(MetadataManagerShmHeader *header); + void shm_init(ServerConfig *config, MetadataManagerShmHeader *header); /** * Explicitly destroy the MetadataManager @@ -286,6 +292,15 @@ class MetadataManager { * */ RPC bool LocalDestroyVBucket(VBucketId vbkt_id); + + /** + * Update the capacity of the target device + * */ + RPC void LocalUpdateTargetCapacity(TargetId tid, off64_t offset) { + auto &target = targets_[tid.GetIndex()]; + target.rem_cap_ += offset; + } + public: RPC_AUTOGEN_START BucketId GetOrCreateBucket(lipc::charbuf& bkt_name) { diff --git a/src/metadata_types.h b/src/metadata_types.h index e3467d2ae..f9e07b8fd 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -6,28 +6,38 @@ #define HERMES_SRC_METADATA_TYPES_H_ #include "hermes_types.h" +#include "config_server.h" namespace hermes { using api::Blob; -/** */ -struct DeviceInfo { - -}; +/** Device information required by other processes */ +using config::DeviceInfo; +using config::IoInterface; /** Represents the current status of a target */ struct TargetInfo { - TargetID tid_; /**< unique Target ID */ + TargetId id_; /**< unique Target ID */ size_t max_cap_; /**< maximum capacity of the target */ size_t rem_cap_; /**< remaining capacity of the target */ + + TargetInfo() = default; + + TargetInfo(TargetId id, size_t max_cap, size_t rem_cap) + : id_(id), max_cap_(max_cap), rem_cap_(rem_cap) {} }; /** Represents an allocated fraction of a target */ struct BufferInfo { size_t off_; size_t size_; - TargetID target_; + TargetId tid_; + + BufferInfo() = default; + + BufferInfo(size_t off, size_t size, TargetId tid) + : off_(off), size_(size), tid_(tid) {} }; /** Represents BlobInfo in shared memory */ diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index 0190eeab7..285616053 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -67,7 +67,7 @@ class ThalliumRpc : public RpcContext { /** I/O transfers */ size_t IoCall(u32 node_id, IoType type, u8 *data, - TargetID id, size_t off, size_t size) { + TargetId id, size_t off, size_t size) { std::string server_name = GetServerName(node_id); const char *func_name; tl::bulk_mode flag; diff --git a/src/rpc_thallium_serialization.h b/src/rpc_thallium_serialization.h index d1c36506a..2ee8504b2 100644 --- a/src/rpc_thallium_serialization.h +++ b/src/rpc_thallium_serialization.h @@ -60,31 +60,31 @@ void serialize(A &ar, BlobId &blob_id) { } /** - * Lets Thallium know how to serialize a TargetID. + * Lets Thallium know how to serialize a TargetId. * * This function is called implicitly by Thallium. * * @param ar An archive provided by Thallium. - * @param target_id The TargetID to serialize. + * @param target_id The TargetId to serialize. */ template -void serialize(A &ar, TargetID &target_id) { +void serialize(A &ar, TargetId &target_id) { ar &target_id.as_int_; } /** - * Lets Thallium know how to serialize a TargetID. + * Lets Thallium know how to serialize a TargetId. * * This function is called implicitly by Thallium. * * @param ar An archive provided by Thallium. - * @param target_id The TargetID to serialize. + * @param target_id The TargetId to serialize. */ template void serialize(A &ar, BufferInfo &info) { ar &info.off_; ar &info.size_; - ar &info.target_; + ar &info.tid_; } } // namespace hermes From 3d8521f2a05c13cc76f3a5e710b85ec2f494db04 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 23 Dec 2022 03:37:06 -0600 Subject: [PATCH 074/511] MinimizeIoTime DPE --- src/CMakeLists.txt | 8 ++-- src/api/bucket.cc | 21 +++++---- src/api/bucket.h | 1 + src/api/hermes.h | 4 ++ src/buffer_pool.cc | 3 +- src/buffer_pool.h | 2 +- src/data_placement_engine.cc | 23 +++------- src/data_placement_engine.h | 5 +-- src/dpe/minimize_io_time.cc | 52 +++++++++++----------- src/dpe/minimize_io_time.h | 9 ++-- src/dpe/random.cc | 69 +----------------------------- src/dpe/random.h | 18 ++------ src/dpe/round_robin.cc | 17 +------- src/dpe/round_robin.h | 13 +----- src/hermes_types.h | 4 +- src/io_clients/io_client_factory.h | 4 +- src/metadata_manager.cc | 2 +- src/metadata_manager.h | 21 ++++++++- src/metadata_types.h | 3 +- src/status.h | 6 ++- src/statuses.h | 3 +- 21 files changed, 106 insertions(+), 182 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 63204b334..7878793bc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,10 +57,10 @@ set(HERMES_SRCS #${CMAKE_CURRENT_SOURCE_DIR}/prefetcher.cc #${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/sequential.cc #${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/apriori.cc - #${CMAKE_CURRENT_SOURCE_DIR}/data_placement_engine.cc - #${CMAKE_CURRENT_SOURCE_DIR}/dpe/random.cc - #${CMAKE_CURRENT_SOURCE_DIR}/dpe/round_robin.cc - #${CMAKE_CURRENT_SOURCE_DIR}/dpe/minimize_io_time.cc + ${CMAKE_CURRENT_SOURCE_DIR}/data_placement_engine.cc + ${CMAKE_CURRENT_SOURCE_DIR}/dpe/random.cc + ${CMAKE_CURRENT_SOURCE_DIR}/dpe/round_robin.cc + ${CMAKE_CURRENT_SOURCE_DIR}/dpe/minimize_io_time.cc ) #------------------------------------------------------------------------------ diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 95ecf397c..6be4ccd69 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -3,14 +3,15 @@ // #include "bucket.h" -// #include "data_placement_engine_factory.h" +#include "data_placement_engine_factory.h" namespace hermes::api { /** * Either initialize or fetch the bucket. * */ -Bucket::Bucket(std::string name, Context &ctx) : mdm_(&HERMES->mdm_) { +Bucket::Bucket(std::string name, Context &ctx) + : mdm_(&HERMES->mdm_), bpm_(&HERMES->bpm_) { lipc::string lname(name); id_ = mdm_->GetOrCreateBucket(lname); } @@ -33,13 +34,17 @@ void Bucket::Destroy(std::string blob_name) { Status Bucket::Put(std::string blob_name, Blob blob, BlobId &blob_id, Context &ctx) { // Calculate placement - /*auto dpe = DPEFactory::Get(ctx.policy); + auto dpe = DPEFactory::Get(ctx.policy); std::vector blob_sizes(1, blob.size()); - std::vector schema; - dpe->CalculatePlacement(blob_sizes, schema, ctx);*/ - - // Allocate buffers for the blob - + std::vector schemas; + dpe->CalculatePlacement(blob_sizes, schemas, ctx); + + // Allocate buffers for the blob & enqueue placement + for (auto &schema : schemas) { + // TODO(llogan): Use RPC if-else, not Local + auto buffers = bpm_->LocalAllocateAndSetBuffers(schema, blob); + mdm_->LocalBucketPutBlob(id_, lipc::string(blob_name), blob, buffers); + } } /** diff --git a/src/api/bucket.h b/src/api/bucket.h index 69f6c6524..ec3004bd7 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -14,6 +14,7 @@ namespace hermes::api { class Bucket { private: MetadataManager *mdm_; + BufferPoolManager *bpm_; BucketId id_; std::string name_; Context ctx_; diff --git a/src/api/hermes.h b/src/api/hermes.h index 1c27790f2..c1b02748e 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -13,6 +13,8 @@ #include "communication_factory.h" #include "rpc.h" #include "metadata_manager.h" +#include "buffer_pool.h" +#include "buffer_organizer.h" namespace hermes::api { @@ -37,6 +39,8 @@ class Hermes { ServerConfig server_config_; ClientConfig client_config_; MetadataManager mdm_; + BufferPoolManager bpm_; + BufferOrganizer borg_; COMM_TYPE comm_; RPC_TYPE rpc_; lipc::Allocator *main_alloc_; diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index c415332d7..b13a5a348 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -34,7 +34,8 @@ void BufferPoolManager::shm_deserialize(BufferPoolManagerShmHeader *header) { * TODO(llogan): use better allocator policy * */ lipc::vector -BufferPoolManager::LocalAllocateBuffers(PlacementSchema &schema, Blob &blob) { +BufferPoolManager::LocalAllocateAndSetBuffers(PlacementSchema &schema, + Blob &blob) { lipc::vector buffers(nullptr); for (auto plcmnt : schema.plcmnts_) { if (plcmnt.tid_.GetNodeId() != mdm_->rpc_->node_id_) { diff --git a/src/buffer_pool.h b/src/buffer_pool.h index a1f2e2345..f5e7bc1f3 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -48,7 +48,7 @@ class BufferPoolManager { * Allocate buffers from the targets according to the schema * */ RPC lipc::vector - LocalAllocateBuffers(PlacementSchema &schema, Blob &blob); + LocalAllocateAndSetBuffers(PlacementSchema &schema, Blob &blob); /** * Free buffers from the BufferPool diff --git a/src/data_placement_engine.cc b/src/data_placement_engine.cc index f957c39a0..0ad46b789 100644 --- a/src/data_placement_engine.cc +++ b/src/data_placement_engine.cc @@ -25,15 +25,6 @@ namespace hermes { -/** topology */ -enum Topology { - Topology_Local, - Topology_Neighborhood, - Topology_Global, - - Topology_Count -}; - /** calculate data placement */ Status DPE::CalculatePlacement(const std::vector &blob_sizes, std::vector &output, @@ -42,24 +33,22 @@ Status DPE::CalculatePlacement(const std::vector &blob_sizes, // NOTE(chogan): Start with local targets and gradually expand the target // list until the placement succeeds. - for (int i = 0; i < Topology_Count; ++i) { + for (int i = 0; i < static_cast(TopologyType::kCount); ++i) { // Reset the output schema output.clear(); // Get the capacity/bandwidth of targets - std::vector targets; + lipc::vector targets; switch (static_cast(i)) { case TopologyType::Local: { - // TODO(chogan): @optimization We can avoid the copy here when getting - // local targets by just getting a pointer and length. - targets = mdm_->LocalGetNodeTargetInfo(); + targets = mdm_->LocalGetTargetInfo(); break; } case TopologyType::Neighborhood: { - targets = mdm_->GetNeighborhoodTargets(); + // targets = mdm_->GetNeighborhoodTargetInfo(); break; } case TopologyType::Global: { - targets = mdm_->GetGlobalTargets(); + // targets = mdm_->GetGlobalTargetInfo(); break; } } @@ -69,7 +58,7 @@ Status DPE::CalculatePlacement(const std::vector &blob_sizes, } // Calculate a placement schema result = Placement(blob_sizes, targets, ctx, output); - if (!result.Failed()) { + if (!result.Fail()) { break; } } diff --git a/src/data_placement_engine.h b/src/data_placement_engine.h index 09c99ac81..d45db0f18 100644 --- a/src/data_placement_engine.h +++ b/src/data_placement_engine.h @@ -30,14 +30,13 @@ using hermes::api::PlacementPolicy; */ class DPE { protected: - PlacementPolicy policy_; /**< data placement policy */ MetadataManager *mdm_; /**< A pointer to the MDM */ public: std::vector bandwidths; /**< a vector of bandwidths */ /** Constructor. */ - explicit DPE(PlacementPolicy policy) : policy_(policy) {} + explicit DPE() {} /** Destructor. */ virtual ~DPE() = default; @@ -47,7 +46,7 @@ class DPE { * algorithm given a context. * */ virtual Status Placement(const std::vector &blob_sizes, - const std::vector &targets, + const lipc::vector &targets, const api::Context &ctx, std::vector &output) = 0; diff --git a/src/dpe/minimize_io_time.cc b/src/dpe/minimize_io_time.cc index 5de152784..38ae78133 100644 --- a/src/dpe/minimize_io_time.cc +++ b/src/dpe/minimize_io_time.cc @@ -19,10 +19,9 @@ namespace hermes { Status MinimizeIoTime::Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, - const api::Context &ctx, - std::vector &output) { + const lipc::vector &targets, + const api::Context &ctx, + std::vector &output) { Status result; const size_t num_targets = targets.size(); const size_t num_blobs = blob_sizes.size(); @@ -31,7 +30,7 @@ Status MinimizeIoTime::Placement(const std::vector &blob_sizes, ctx.minimize_io_time_options.minimum_remaining_capacity; const double capacity_change_threshold = ctx.minimize_io_time_options.capacity_change_threshold; - GetPlacementRatios(node_state, ctx); + GetPlacementRatios(targets, ctx); size_t constraints_per_target = 2; VLOG(1) << "MinimizeIoTimePlacement()::minimum_remaining_capacity=" << @@ -48,8 +47,6 @@ Status MinimizeIoTime::Placement(const std::vector &blob_sizes, for (size_t i = 0; i < num_blobs; ++i) { // Ensure the entire row sums up to 1 lp.AddConstraint("blob_row_", GLP_FX, 1.0, 1.0); - - // TODO(KIMMY): consider remote nodes? for (size_t j = 0; j < num_targets; ++j) { lp.SetConstraintCoeff(var.Get(i, j), 1); if (placement_ratios_[j] > 0) { @@ -64,8 +61,8 @@ Status MinimizeIoTime::Placement(const std::vector &blob_sizes, // Constraint #2: Capacity constraints for (size_t j = 0; j < num_targets; ++j) { double rem_cap_thresh = - static_cast(node_state[j]) * (1 - minimum_remaining_capacity); - double est_rem_cap = capacity_change_threshold * node_state[j]; + static_cast(targets[j].rem_cap_) * (1 - minimum_remaining_capacity); + double est_rem_cap = capacity_change_threshold * targets[j].rem_cap_; double max_capacity = std::max({rem_cap_thresh, est_rem_cap}); if (max_capacity > 0) { lp.AddConstraint("rem_cap_", GLP_DB, 0.0, max_capacity); @@ -90,7 +87,7 @@ Status MinimizeIoTime::Placement(const std::vector &blob_sizes, // Solve the problem lp.Solve(); if (!lp.IsOptimal()) { - result = DPE_ORTOOLS_NO_SOLUTION; + result = DPE_MIN_IO_TIME_NO_SOLUTION; LOG(ERROR) << result.Msg(); return result; } @@ -117,28 +114,28 @@ Status MinimizeIoTime::Placement(const std::vector &blob_sizes, ssize_t est_io_size = static_cast(est_io_size_u); ssize_t true_io_size = static_cast(blob_sizes[i]); ssize_t io_diff = true_io_size - est_io_size; - PlaceBytes(0, io_diff, vars_bytes, node_state); + PlaceBytes(0, io_diff, vars_bytes, targets); // Push all non-zero schemas to target for (size_t j = 0; j < num_targets; ++j) { size_t io_to_target = vars_bytes[j]; if (io_to_target != 0) { - schema.push_back(std::make_pair(io_to_target, targets[j])); + schema.AddSubPlacement(io_to_target, targets[j].id_); } } - output.push_back(schema); + output.emplace_back(std::move(schema)); } return result; } void MinimizeIoTime::PlaceBytes(size_t j, ssize_t bytes, std::vector &vars_bytes, - const std::vector &node_state) { + const lipc::vector &targets) { if (vars_bytes[j] == 0) { - PlaceBytes(j+1, bytes, vars_bytes, node_state); + PlaceBytes(j+1, bytes, vars_bytes, targets); return; } - ssize_t node_cap = static_cast(node_state[j]); + ssize_t node_cap = static_cast(targets[j].rem_cap_); ssize_t req_bytes = static_cast(vars_bytes[j]); req_bytes += bytes; ssize_t io_diff = req_bytes - node_cap; @@ -146,30 +143,35 @@ void MinimizeIoTime::PlaceBytes(size_t j, ssize_t bytes, vars_bytes[j] = static_cast(req_bytes); return; } - if (j == node_state.size() - 1) { + if (j == targets.size() - 1) { LOG(FATAL) << "No capacity left to buffer blob" << std::endl; return; } req_bytes -= io_diff; vars_bytes[j] = static_cast(req_bytes); - PlaceBytes(j+1, io_diff, vars_bytes, node_state); + PlaceBytes(j+1, io_diff, vars_bytes, targets); } -void MinimizeIoTime::GetPlacementRatios(const std::vector &node_state, +void MinimizeIoTime::GetPlacementRatios(const lipc::vector &targets, const api::Context &ctx) { - placement_ratios_.reserve(node_state.size()); + placement_ratios_.reserve(targets.size()); if (ctx.minimize_io_time_options.use_placement_ratio) { - size_t total_bytes = std::accumulate( - node_state.begin(), node_state.end(), (size_t)0); + // Total number of bytes remaining across all targets + size_t total_bytes = 0; + for (auto iter = targets.cbegin(); iter != targets.cend(); ++iter) { + total_bytes += (*iter).rem_cap_; + } double total = static_cast(total_bytes); - for (size_t j = 0; j < node_state.size() - 1; ++j) { - double target_cap = static_cast(node_state[j]); + // Get percentage of total capacity each target has + for (size_t j = 0; j < targets.size() - 1; ++j) { + double target_cap = static_cast(targets[j].rem_cap_); double placement_ratio = target_cap / total; placement_ratios_.emplace_back(placement_ratio); } + // Last tier always has a 1.0 to guarantee it's utilized placement_ratios_.emplace_back(1.0); } else { - for (size_t j = 0; j < node_state.size(); ++j) { + for (size_t j = 0; j < targets.size(); ++j) { placement_ratios_.emplace_back(1.0); } } diff --git a/src/dpe/minimize_io_time.h b/src/dpe/minimize_io_time.h index 0ea899a0b..dbab495fc 100644 --- a/src/dpe/minimize_io_time.h +++ b/src/dpe/minimize_io_time.h @@ -24,11 +24,10 @@ class MinimizeIoTime : public DPE { std::vector placement_ratios_; /**< a vector of placement ratios */ public: - MinimizeIoTime() : DPE(PlacementPolicy::kMinimizeIoTime) {} + MinimizeIoTime() = default; ~MinimizeIoTime() = default; Status Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, + const lipc::vector &targets, const api::Context &ctx, std::vector &output); @@ -37,9 +36,9 @@ class MinimizeIoTime : public DPE { size_t AbsDiff(size_t x, size_t y, bool &y_gt_x); /** place bytes */ void PlaceBytes(size_t j, ssize_t bytes, std::vector &vars_bytes, - const std::vector &node_state); + const lipc::vector &targets); /** get placement ratios from node states in \a ctx context */ - void GetPlacementRatios(const std::vector &node_state, + void GetPlacementRatios(const lipc::vector &targets, const api::Context &ctx); }; diff --git a/src/dpe/random.cc b/src/dpe/random.cc index 913437007..9d04b1dc0 100644 --- a/src/dpe/random.cc +++ b/src/dpe/random.cc @@ -18,77 +18,10 @@ namespace hermes { -Status Random::AddSchema(std::multimap &ordered_cap, - size_t blob_size, PlacementSchema &schema) { - std::random_device rd; - std::mt19937 gen(rd()); - Status result; - - auto itlow = ordered_cap.lower_bound(blob_size); - if (itlow == ordered_cap.end()) { - result = DPE_RANDOM_FOUND_NO_TGT; - LOG(ERROR) << result.Msg(); - } else { - // distance from lower bound to the end - std::uniform_int_distribution<> - dst_dist(1, std::distance(itlow, ordered_cap.end())); - size_t dst_relative = dst_dist(gen); - std::advance(itlow, dst_relative-1); - ordered_cap.insert(std::pair((*itlow).first-blob_size, - (*itlow).second)); - - schema.push_back(std::make_pair(blob_size, (*itlow).second)); - ordered_cap.erase(itlow); - } - - return result; -} - -void Random::GetOrderedCapacities(const std::vector &node_state, - const std::vector &targets, - std::multimap &ordered_cap) { - for (size_t i = 0; i < node_state.size(); ++i) { - ordered_cap.insert(std::pair(node_state[i], targets[i])); - } -} - Status Random::Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, + const lipc::vector &targets, const api::Context &ctx, std::vector &output) { - Status result; - std::multimap ordered_cap; - - GetOrderedCapacities(node_state, targets, ordered_cap); - - for (size_t i {0}; i < blob_sizes.size(); ++i) { - PlacementSchema schema; - - // Split the blob - if (SplitBlob(blob_sizes[i])) { - // Construct the vector for the splitted blob - std::vector new_blob_size; - GetSplitSizes(blob_sizes[i], new_blob_size); - - for (size_t k {0}; k < new_blob_size.size(); ++k) { - result = AddSchema(ordered_cap, new_blob_size[k], schema); - - if (!result.Succeeded()) { - break; - } - } - } else { - // Blob size is less than 64KB or do not split - result = AddSchema(ordered_cap, blob_sizes[i], schema); - if (!result.Succeeded()) { - return result; - } - } - output.push_back(schema); - } - - return result; } } // namespace hermes diff --git a/src/dpe/random.h b/src/dpe/random.h index f41b41329..25def820e 100644 --- a/src/dpe/random.h +++ b/src/dpe/random.h @@ -21,24 +21,12 @@ namespace hermes { */ class Random : public DPE { public: - Random() : DPE(PlacementPolicy::kRandom) {} + Random() = default; ~Random() = default; Status Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, + const lipc::vector &targets, const api::Context &ctx, - std::vector &output); - - private: - /** - get the capacities of each \a node_state and \a targets and store them - into \a ordered_cap.*/ - void GetOrderedCapacities(const std::vector &node_state, - const std::vector &targets, - std::multimap &ordered_cap); - /** add placement schema */ - Status AddSchema(std::multimap &ordered_cap, size_t blob_size, - PlacementSchema &schema); + std::vector &output) override; }; } // namespace hermes diff --git a/src/dpe/round_robin.cc b/src/dpe/round_robin.cc index bebc9d558..21dd209a0 100644 --- a/src/dpe/round_robin.cc +++ b/src/dpe/round_robin.cc @@ -15,25 +15,10 @@ namespace hermes { -// Initialize RoundRobin devices -std::vector RoundRobin::devices_; - Status RoundRobin::Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, + const lipc::vector &targets, const api::Context &ctx, std::vector &output) { - Status result; - std::vector ns_local(node_state.begin(), node_state.end()); - bool split = ctx.rr_split; - - for (auto &blob_size : blob_sizes) { - for (auto &target : targets) { - - } - } - - return result; } diff --git a/src/dpe/round_robin.h b/src/dpe/round_robin.h index 04f062f5a..9bec740d6 100644 --- a/src/dpe/round_robin.h +++ b/src/dpe/round_robin.h @@ -23,20 +23,11 @@ using api::Status; /** Represents the state of a Round-Robin data placement strategy */ class RoundRobin : public DPE { - private: - static inline int current_device_index_{}; /**< The current device index */ - static std::vector devices_; /**< A list of device targets */ - std::mutex device_index_mutex_; /**< Protect index updates */ - public: - RoundRobin() : DPE(PlacementPolicy::kRoundRobin) { - device_index_mutex_.lock(); - } - ~RoundRobin() { device_index_mutex_.unlock(); } + RoundRobin() = default; Status Placement(const std::vector &blob_sizes, - const std::vector &node_state, - const std::vector &targets, + const lipc::vector &targets, const api::Context &ctx, std::vector &output); }; diff --git a/src/hermes_types.h b/src/hermes_types.h index 7c8dd4a30..db23e082d 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -80,7 +80,9 @@ typedef u16 DeviceID; /**< device id in unsigned 16-bit integer */ enum class TopologyType { Local, Neighborhood, - Global + Global, + + kCount }; /** Represents unique ID for BlobId, BucketId, and VBucketId */ diff --git a/src/io_clients/io_client_factory.h b/src/io_clients/io_client_factory.h index 5e446bf0b..af5adcca6 100644 --- a/src/io_clients/io_client_factory.h +++ b/src/io_clients/io_client_factory.h @@ -13,12 +13,12 @@ namespace hermes { /** - A class to represent Data Placement Engine Factory + A class to represent I/O Client Factory */ class IoClientFactory { public: /** - * Get the I/O api corresponding to a particular device type + * Get the I/O api implementation * */ static std::unique_ptr Get(IoInterface type) { switch (type) { diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 52d65901d..c376b4486 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -179,7 +179,7 @@ bool MetadataManager::LocalDestroyBucket(BucketId bkt_id) { * @RPC_CLASS_INSTANCE mdm * */ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, - lipc::charbuf &blob_name, + const lipc::charbuf &blob_name, Blob &data, lipc::vector &buffers) { /*lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 0b8a37d34..fa3758dec 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -155,7 +155,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BlobId LocalBucketPutBlob(BucketId bkt_id, lipc::charbuf &blob_name, + RPC BlobId LocalBucketPutBlob(BucketId bkt_id, const lipc::charbuf &blob_name, Blob &data, lipc::vector &buffers); /** @@ -301,6 +301,25 @@ class MetadataManager { target.rem_cap_ += offset; } + /** + * Update the capacity of the target device + * */ + RPC const lipc::vector& LocalGetTargetInfo() { + return targets_; + } + + /** + * Get the TargetInfo for neighborhood + * */ + lipc::vector GetNeighborhoodTargetInfo() { + } + + /** + * Get all TargetInfo in the system + * */ + lipc::vector GetGlobalTargetInfo() { + } + public: RPC_AUTOGEN_START BucketId GetOrCreateBucket(lipc::charbuf& bkt_name) { diff --git a/src/metadata_types.h b/src/metadata_types.h index f9e07b8fd..1c96730a6 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -18,7 +18,7 @@ using config::IoInterface; /** Represents the current status of a target */ struct TargetInfo { - TargetId id_; /**< unique Target ID */ + TargetId id_; /**< unique Target ID */ size_t max_cap_; /**< maximum capacity of the target */ size_t rem_cap_; /**< remaining capacity of the target */ @@ -31,6 +31,7 @@ struct TargetInfo { /** Represents an allocated fraction of a target */ struct BufferInfo { size_t off_; + size_t blob_off_; size_t size_; TargetId tid_; diff --git a/src/status.h b/src/status.h index 40edb7a68..12e2f1233 100644 --- a/src/status.h +++ b/src/status.h @@ -38,11 +38,15 @@ class Status { msg_ = other.msg_; } + const char* Msg() { + return msg_; + } + bool Success() { return code_ == 0; } - bool Failed() { + bool Fail() { return code_ != 0; } }; diff --git a/src/statuses.h b/src/statuses.h index 343a5b3f6..903fba219 100644 --- a/src/statuses.h +++ b/src/statuses.h @@ -13,7 +13,8 @@ using api::Status; const Status DPE_PLACEMENT_SCHEMA_EMPTY("Placement failed. Non-fatal."); const Status DPE_NO_SPACE("DPE has no remaining space."); - +const Status DPE_MIN_IO_TIME_NO_SOLUTION( + "DPE could not find solution for the minimize I/O time DPE"); } #endif // HERMES_SRC_STATUSES_H_ From da88c6a7fb8edb2880481d79b88ab063f9c6b7a7 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 23 Dec 2022 04:46:20 -0600 Subject: [PATCH 075/511] Enable Put again --- src/data_placement_engine_factory.h | 2 +- src/metadata_manager.cc | 14 ++++++-------- src/metadata_manager.h | 5 +++-- src/metadata_types.h | 19 +++++++++++++++++-- test/test_rpc.cc | 7 +++++++ 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/data_placement_engine_factory.h b/src/data_placement_engine_factory.h index 5ad5b01d6..054961af2 100644 --- a/src/data_placement_engine_factory.h +++ b/src/data_placement_engine_factory.h @@ -47,7 +47,7 @@ class DPEFactory { } case PlacementPolicy::kNone: default: { - // TODO(luke): @errorhandling not implemented + // TODO(llogan): @errorhandling not implemented LOG(FATAL) << "PlacementPolicy not implemented" << std::endl; return NULL; } diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index c376b4486..61d9acd4d 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -182,32 +182,30 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, const lipc::charbuf &blob_name, Blob &data, lipc::vector &buffers) { - /*lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); + lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); // Create unique ID for the Blob BlobId blob_id; blob_id.unique_ = header_->id_alloc_.fetch_add(1); blob_id.node_id_ = rpc_->node_id_; - if (blob_id_map_->try_emplace(blob_name, blob_id)) { + if (blob_id_map_->try_emplace(internal_blob_name, blob_id)) { BlobInfo info; - info.name_ = lipc::make_mptr( - CreateBlobName(bkt_id, blob_name)); + info.name_ = lipc::make_mptr(std::move(internal_blob_name)); info.buffers_ = lipc::make_mptr>( std::move(buffers)); - BlobInfoShmHeader hdr; info.shm_serialize(hdr); - // blob_map_->emplace(blob_id, hdr); + blob_map_->emplace(blob_id, std::move(hdr)); } else { auto iter = blob_map_->find(blob_id); BlobInfoShmHeader &hdr = (*iter).val_.get_ref(); BlobInfo info(hdr); *(info.buffers_) = std::move(buffers); info.shm_serialize(hdr); - (*iter).val_ = hdr; + (*iter).val_ = std::move(hdr); } - return blob_id;*/ + return blob_id; } /** diff --git a/src/metadata_manager.h b/src/metadata_manager.h index fa3758dec..a29c2092b 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -94,12 +94,13 @@ class MetadataManager { /** * Create a unique blob name using BucketId * */ - lipc::charbuf CreateBlobName(BucketId bkt_id, lipc::charbuf &blob_name) { + lipc::charbuf CreateBlobName(BucketId bkt_id, + const lipc::charbuf &blob_name) { lipc::charbuf new_name(sizeof(bkt_id) + blob_name.size()); size_t off = 0; memcpy(new_name.data_mutable() + off, &bkt_id, sizeof(BucketId)); off += sizeof(BucketId); - memcpy(blob_name.data_mutable() + off, blob_name.data(), blob_name.size()); + memcpy(new_name.data_mutable() + off, blob_name.data(), blob_name.size()); return new_name; } diff --git a/src/metadata_types.h b/src/metadata_types.h index 1c96730a6..bcc72774f 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -44,11 +44,26 @@ struct BufferInfo { /** Represents BlobInfo in shared memory */ struct BlobInfoShmHeader { BucketId bkt_id_; /**< The bucket containing the blob */ - lipc::ShmArchive> name_ar_; - lipc::ShmArchive>> buffers_ar_; + lipc::ShmArchive name_ar_; + lipc::ShmArchive> buffers_ar_; RwLock rwlock_; BlobInfoShmHeader() = default; + + BlobInfoShmHeader(BlobInfoShmHeader &&other) noexcept + : bkt_id_(std::move(other.bkt_id_)), name_ar_(std::move(other.name_ar_)), + buffers_ar_(std::move(other.buffers_ar_)), + rwlock_(std::move(other.rwlock_)) {} + + BlobInfoShmHeader& operator=(BlobInfoShmHeader &&other) { + if (this != &other) { + bkt_id_ = std::move(other.bkt_id_); + name_ar_ = std::move(other.name_ar_); + buffers_ar_ = std::move(other.buffers_ar_); + rwlock_ = std::move(other.rwlock_); + } + return *this; + } }; /** Blob metadata */ diff --git a/test/test_rpc.cc b/test/test_rpc.cc index ebd32409b..3f061f652 100644 --- a/test/test_rpc.cc +++ b/test/test_rpc.cc @@ -16,6 +16,7 @@ #include #include #include "hermes.h" +#include "bucket.h" namespace hapi = hermes::api; @@ -24,6 +25,12 @@ int main(int argc, char* argv[]) { auto hermes = hapi::Hermes::Create(hermes::HermesType::kClient); auto bkt = hermes->GetBucket("hello"); auto bkt2 = hermes->GetBucket("hello"); + + hermes::api::Context ctx; + hermes::BlobId blob_id; + hermes::Blob blob(nullptr, 1024); + bkt2->Put("0", std::move(blob), blob_id, ctx); + hermes->Finalize(); MPI_Finalize(); return 0; From 98c29e7c1e2c8418a7fbf1fb05aa6403b1128dfe Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 23 Dec 2022 11:44:37 -0600 Subject: [PATCH 076/511] Fix TargetInfo vector for DPE --- src/buffer_organizer.cc | 2 +- src/buffer_pool.cc | 6 +++--- src/config.h | 4 ++++ src/config_server.cc | 2 +- src/data_placement_engine.cc | 3 +++ src/data_placement_engine.h | 2 +- src/hermes_types.h | 8 ++++---- src/metadata_manager.cc | 14 +++++++++++--- src/metadata_manager.h | 12 ++++++++---- 9 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 39c1d6c9e..bc7355295 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -12,7 +12,7 @@ namespace hermes { RPC void BufferOrganizer::LocalPlaceBlobInBuffers( Blob &blob, lipc::vector &buffers) { for (auto &buffer_info : buffers) { - auto &dev_info = mdm_->devices_[buffer_info.tid_.GetDeviceId()]; + auto &dev_info = (*mdm_->devices_)[buffer_info.tid_.GetDeviceId()]; auto io_client = IoClientFactory::Get(dev_info.io_api_); bool ret = io_client->Write(dev_info, blob.data(), buffer_info.off_, buffer_info.size_); diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index b13a5a348..6d20ea692 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -11,9 +11,9 @@ namespace hermes { void BufferPoolManager::shm_init(MetadataManager *mdm) { mdm_ = mdm; target_allocs_.shm_init(nullptr); - target_allocs_.resize(mdm_->targets_.size()); - for (auto &target : mdm_->targets_) { - auto &dev_info = mdm_->devices_[target.id_.GetDeviceId()]; + target_allocs_.resize(mdm_->targets_->size()); + for (auto &target : (*mdm_->targets_)) { + auto &dev_info = (*mdm_->devices_)[target.id_.GetDeviceId()]; dev_info.mount_point_; } } diff --git a/src/config.h b/src/config.h index 8f0ad42b7..66b9d38cf 100644 --- a/src/config.h +++ b/src/config.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "data_structures.h" #include "hermes_types.h" @@ -140,6 +141,9 @@ static size_t ParseNumber(const std::string &num_text) { /** Returns size (bytes) */ static size_t ParseSize(const std::string &size_text) { size_t size = ParseNumber(size_text); + if (size_text == "inf") { + return std::numeric_limits::max(); + } std::string suffix = ParseNumberSuffix(size_text); if (suffix.size() == 0) { return size; diff --git a/src/config_server.cc b/src/config_server.cc index 4d745df88..8258775f9 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -22,7 +22,7 @@ namespace hermes::config { /** parse device information from YAML config */ void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { devices_.clear(); - for (auto device : yaml_conf["devices"]) { + for (auto device : yaml_conf) { DeviceInfo dev; auto dev_info = device.second; dev.mount_point_ = lipc::string(dev_info["mount_point"].as()); diff --git a/src/data_placement_engine.cc b/src/data_placement_engine.cc index 0ad46b789..187b3fc48 100644 --- a/src/data_placement_engine.cc +++ b/src/data_placement_engine.cc @@ -25,6 +25,9 @@ namespace hermes { +/** Constructor. */ +DPE::DPE() : mdm_(&HERMES->mdm_) {} + /** calculate data placement */ Status DPE::CalculatePlacement(const std::vector &blob_sizes, std::vector &output, diff --git a/src/data_placement_engine.h b/src/data_placement_engine.h index d45db0f18..9414c8a9a 100644 --- a/src/data_placement_engine.h +++ b/src/data_placement_engine.h @@ -36,7 +36,7 @@ class DPE { std::vector bandwidths; /**< a vector of bandwidths */ /** Constructor. */ - explicit DPE() {} + DPE(); /** Destructor. */ virtual ~DPE() = default; diff --git a/src/hermes_types.h b/src/hermes_types.h index db23e082d..9cc98191d 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -245,13 +245,13 @@ class PlacementPolicyConv { /** return enum value of \a policy */ static PlacementPolicy to_enum(const std::string &policy) { - if (policy.find("kRandom") != std::string::npos) { + if (policy.find("Random") != std::string::npos) { return PlacementPolicy::kRandom; - } else if (policy.find("kRoundRobin") != std::string::npos) { + } else if (policy.find("RoundRobin") != std::string::npos) { return PlacementPolicy::kRoundRobin; - } else if (policy.find("kMinimizeIoTime") != std::string::npos) { + } else if (policy.find("MinimizeIoTime") != std::string::npos) { return PlacementPolicy::kMinimizeIoTime; - } else if (policy.find("kNone") != std::string::npos) { + } else if (policy.find("None") != std::string::npos) { return PlacementPolicy::kNone; } return PlacementPolicy::kNone; diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 61d9acd4d..18096567a 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -25,13 +25,15 @@ void MetadataManager::shm_init(ServerConfig *config, vbkt_map_ = lipc::make_mptr(nullptr); // Create the DeviceInfo vector - devices_.shm_init(config->devices_); + devices_ = lipc::make_mptr>( + nullptr, HERMES->server_config_.devices_); + targets_ = lipc::make_mptr>(nullptr); // Create the TargetInfo vector - targets_.resize(devices_.size()); + targets_->reserve(devices_->size()); int dev_id = 0; for (auto &dev_info : config->devices_) { - targets_.emplace_back( + targets_->emplace_back( TargetId(rpc_->node_id_, dev_id, dev_id), dev_info.capacity_, dev_info.capacity_); @@ -53,6 +55,8 @@ void MetadataManager::shm_destroy() { blob_map_.shm_destroy(); bkt_map_.shm_destroy(); vbkt_map_.shm_destroy(); + targets_.shm_destroy(); + devices_.shm_destroy(); } /** @@ -65,6 +69,8 @@ void MetadataManager::shm_serialize() { blob_map_ >> header_->blob_map_ar_; bkt_map_ >> header_->bkt_map_ar_; vbkt_map_ >> header_->vbkt_map_ar_; + targets_ >> header_->targets_; + devices_ >> header_->devices_; } /** @@ -79,6 +85,8 @@ void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { blob_map_ << header_->blob_map_ar_; bkt_map_ << header_->bkt_map_ar_; vbkt_map_ << header_->vbkt_map_ar_; + targets_ << header_->targets_; + devices_ << header_->devices_; } /** diff --git a/src/metadata_manager.h b/src/metadata_manager.h index a29c2092b..80ba62af7 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -40,6 +40,10 @@ struct MetadataManagerShmHeader { lipc::ShmArchive> bkt_map_ar_; /// SHM representation of vbucket map lipc::ShmArchive> vbkt_map_ar_; + /// SHM representation of device vector + lipc::ShmArchive>> devices_; + /// SHM representation of target info vector + lipc::ShmArchive>> targets_; /// Used to create unique ids. Starts at 1. std::atomic id_alloc_; }; @@ -65,8 +69,8 @@ class MetadataManager { /** * Information about targets and devices * */ - lipc::vector devices_; - lipc::vector targets_; + lipc::mptr> devices_; + lipc::mptr> targets_; public: MetadataManager() = default; @@ -298,7 +302,7 @@ class MetadataManager { * Update the capacity of the target device * */ RPC void LocalUpdateTargetCapacity(TargetId tid, off64_t offset) { - auto &target = targets_[tid.GetIndex()]; + auto &target = (*targets_)[tid.GetIndex()]; target.rem_cap_ += offset; } @@ -306,7 +310,7 @@ class MetadataManager { * Update the capacity of the target device * */ RPC const lipc::vector& LocalGetTargetInfo() { - return targets_; + return (*targets_); } /** From 66d4686edd9e827f2c7113f31aa456bb78c3a5db Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 23 Dec 2022 18:58:19 -0600 Subject: [PATCH 077/511] Begin ram tier --- src/api/bucket.h | 2 +- src/api/hermes.cc | 18 +++++++++++++----- src/api/hermes.h | 3 ++- src/buffer_organizer.cc | 22 ++++++++++++++++++++++ src/buffer_organizer.h | 7 +++++-- src/buffer_pool.cc | 37 +++++++++++++++++++++++-------------- src/buffer_pool.h | 29 +++++++++++++++++++---------- src/data_placement_engine.h | 2 -- src/dpe/minimize_io_time.cc | 2 +- src/io_clients/io_client.h | 1 + src/io_clients/posix.h | 8 ++++++++ src/io_clients/ram.h | 22 ++++++++++++++++++++++ src/metadata_manager.cc | 6 +++++- src/metadata_types.h | 22 ++++++++++++++++------ src/rpc.cc | 2 +- src/status.h | 2 +- test/test_rpc.cc | 4 +++- 17 files changed, 143 insertions(+), 46 deletions(-) diff --git a/src/api/bucket.h b/src/api/bucket.h index ec3004bd7..cc9409f4d 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -14,7 +14,7 @@ namespace hermes::api { class Bucket { private: MetadataManager *mdm_; - BufferPoolManager *bpm_; + BufferPool *bpm_; BucketId id_; std::string name_; Context ctx_; diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 525c5915f..92eca2973 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -58,9 +58,11 @@ void Hermes::StopDaemon() { void Hermes::InitServer(std::string server_config_path) { LoadServerConfig(server_config_path); InitSharedMemory(); - mdm_.shm_init(&server_config_, &header_->mdm_); rpc_.InitServer(); rpc_.InitClient(); + mdm_.shm_init(&server_config_, &header_->mdm_); + bpm_.shm_init(&header_->bpm_); + borg_.shm_init(); } void Hermes::InitClient(std::string server_config_path, @@ -68,8 +70,10 @@ void Hermes::InitClient(std::string server_config_path, LoadServerConfig(server_config_path); LoadClientConfig(client_config_path); LoadSharedMemory(); - mdm_.shm_deserialize(&header_->mdm_); rpc_.InitClient(); + mdm_.shm_deserialize(&header_->mdm_); + bpm_.shm_deserialize(&header_->bpm_, &mdm_); + // borg_.shm_deserialize(&header_->borg_); } void Hermes::InitColocated(std::string server_config_path, @@ -77,8 +81,10 @@ void Hermes::InitColocated(std::string server_config_path, LoadServerConfig(server_config_path); LoadClientConfig(client_config_path); InitSharedMemory(); - mdm_.shm_init(&server_config_, &header_->mdm_); rpc_.InitColocated(); + mdm_.shm_init(&server_config_, &header_->mdm_); + bpm_.shm_init(&header_->bpm_); + borg_.shm_init(); } void Hermes::LoadServerConfig(std::string config_path) { @@ -118,9 +124,11 @@ void Hermes::LoadSharedMemory() { } void Hermes::FinalizeServer() { + // TODO(llogan): Fix the shared memory segfault // NOTE(llogan): rpc_.Finalize() is called internally by daemon in this case - mdm_.shm_destroy(); - LABSTOR_MEMORY_MANAGER->DestroyBackend(server_config_.shmem_name_); + // bpm_.shm_destroy(); + // mdm_.shm_destroy(); + // LABSTOR_MEMORY_MANAGER->DestroyBackend(server_config_.shmem_name_); } void Hermes::FinalizeClient() { diff --git a/src/api/hermes.h b/src/api/hermes.h index c1b02748e..7839ffe9b 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -27,6 +27,7 @@ class VBucket; * */ struct HermesShmHeader { MetadataManagerShmHeader mdm_; + BufferPoolShmHeader bpm_; }; /** @@ -39,7 +40,7 @@ class Hermes { ServerConfig server_config_; ClientConfig client_config_; MetadataManager mdm_; - BufferPoolManager bpm_; + BufferPool bpm_; BufferOrganizer borg_; COMM_TYPE comm_; RPC_TYPE rpc_; diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index bc7355295..2ebefdc81 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -5,9 +5,31 @@ #include "buffer_organizer.h" #include "metadata_manager.h" #include "io_clients/io_client_factory.h" +#include "hermes.h" namespace hermes { +/** + * Initialize the BORG + * REQUIRES mdm to be initialized already. + * */ +void BufferOrganizer::shm_init() { + mdm_ = &HERMES->mdm_; + for (auto &target : (*mdm_->targets_)) { + auto &dev_info = (*mdm_->devices_)[target.id_.GetDeviceId()]; + if (dev_info.mount_point_.size() == 0) { + dev_info.io_api_ = IoInterface::kRam; + } else { + dev_info.io_api_ = IoInterface::kPosix; + } + auto io_client = IoClientFactory::Get(dev_info.io_api_); + io_client->Init(dev_info); + } +} + +/** Finalize the BORG */ +void BufferOrganizer::shm_destroy() {} + /** Stores a blob into a set of buffers */ RPC void BufferOrganizer::LocalPlaceBlobInBuffers( Blob &blob, lipc::vector &buffers) { diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index bd309f1a7..5d88a6983 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -21,8 +21,11 @@ class BufferOrganizer { public: BufferOrganizer() = default; - /** Initialize the BORG */ - void shm_init(MetadataManager *mdm); + /** + * Initialize the BORG + * REQUIRES mdm to be initialized already. + * */ + void shm_init(); /** Finalize the BORG */ void shm_destroy(); diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 6d20ea692..8d6dba111 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -4,27 +4,36 @@ #include "buffer_pool.h" #include "metadata_manager.h" +#include "hermes.h" namespace hermes { -/** Initialize the BPM and its shared memory. */ -void BufferPoolManager::shm_init(MetadataManager *mdm) { - mdm_ = mdm; - target_allocs_.shm_init(nullptr); - target_allocs_.resize(mdm_->targets_->size()); - for (auto &target : (*mdm_->targets_)) { - auto &dev_info = (*mdm_->devices_)[target.id_.GetDeviceId()]; - dev_info.mount_point_; - } +/** + * Initialize the BPM and its shared memory. + * REQUIRES mdm to be initialized already. + * */ +void BufferPool::shm_init(BufferPoolShmHeader *header) { + mdm_ = &HERMES->mdm_; + borg_ = &HERMES->borg_; + target_allocs_ = lipc::make_mptr>(nullptr); + target_allocs_->resize(mdm_->targets_->size()); + shm_serialize(header); +} + +/** Destroy the BPM shared memory. */ +void BufferPool::shm_destroy() { + target_allocs_.shm_destroy(); } /** Store the BPM in shared memory */ -void BufferPoolManager::shm_serialize(BufferPoolManagerShmHeader *header) { +void BufferPool::shm_serialize(BufferPoolShmHeader *header) { target_allocs_ >> header->alloc_ar_; } /** Deserialize the BPM from shared memory */ -void BufferPoolManager::shm_deserialize(BufferPoolManagerShmHeader *header) { +void BufferPool::shm_deserialize(BufferPoolShmHeader *header, + MetadataManager *mdm) { + mdm_ = mdm; target_allocs_ << header->alloc_ar_; } @@ -34,14 +43,14 @@ void BufferPoolManager::shm_deserialize(BufferPoolManagerShmHeader *header) { * TODO(llogan): use better allocator policy * */ lipc::vector -BufferPoolManager::LocalAllocateAndSetBuffers(PlacementSchema &schema, +BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, Blob &blob) { lipc::vector buffers(nullptr); for (auto plcmnt : schema.plcmnts_) { if (plcmnt.tid_.GetNodeId() != mdm_->rpc_->node_id_) { continue; } - auto &alloc = target_allocs_[plcmnt.tid_.GetDeviceId()]; + auto &alloc = (*target_allocs_)[plcmnt.tid_.GetDeviceId()]; BufferInfo info; info.off_ = alloc.cur_off_; info.size_ = plcmnt.size_; @@ -59,7 +68,7 @@ BufferPoolManager::LocalAllocateAndSetBuffers(PlacementSchema &schema, * * TODO(llogan): actually implement * */ -bool BufferPoolManager::LocalReleaseBuffers(lipc::vector &buffers) { +bool BufferPool::LocalReleaseBuffers(lipc::vector &buffers) { return true; } diff --git a/src/buffer_pool.h b/src/buffer_pool.h index f5e7bc1f3..e889c7528 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -8,10 +8,11 @@ #include "hermes_types.h" #include "rpc.h" -class MetadataManager; - namespace hermes { +class MetadataManager; +class BufferOrganizer; + struct BufferPoolAllocator { std::atomic max_size_; std::atomic cur_off_; @@ -20,29 +21,37 @@ struct BufferPoolAllocator { /** * The shared-memory representation of the BufferPool * */ -struct BufferPoolManagerShmHeader { +struct BufferPoolShmHeader { lipc::ShmArchive> alloc_ar_; }; /** * Responsible for managing the buffering space of all node-local targets. * */ -class BufferPoolManager { +class BufferPool { private: MetadataManager *mdm_; - lipc::vector target_allocs_; /**< Per-target allocator */ + BufferOrganizer *borg_; + /** Per-target allocator */ + lipc::mptr> target_allocs_; public: - BufferPoolManager() = default; + BufferPool() = default; + + /** + * Initialize the BPM and its shared memory. + * REQUIRES mdm to be initialized already. + * */ + void shm_init(BufferPoolShmHeader *header); - /** Initialize the BPM and its shared memory. */ - void shm_init(MetadataManager *mdm); + /** Destroy the BPM shared memory. */ + void shm_destroy(); /** Store the BPM in shared memory */ - void shm_serialize(BufferPoolManagerShmHeader *header); + void shm_serialize(BufferPoolShmHeader *header); /** Deserialize the BPM from shared memory */ - void shm_deserialize(BufferPoolManagerShmHeader *header); + void shm_deserialize(BufferPoolShmHeader *header, MetadataManager *mdm); /** * Allocate buffers from the targets according to the schema diff --git a/src/data_placement_engine.h b/src/data_placement_engine.h index 9414c8a9a..0bab00138 100644 --- a/src/data_placement_engine.h +++ b/src/data_placement_engine.h @@ -33,8 +33,6 @@ class DPE { MetadataManager *mdm_; /**< A pointer to the MDM */ public: - std::vector bandwidths; /**< a vector of bandwidths */ - /** Constructor. */ DPE(); diff --git a/src/dpe/minimize_io_time.cc b/src/dpe/minimize_io_time.cc index 38ae78133..886b7a27a 100644 --- a/src/dpe/minimize_io_time.cc +++ b/src/dpe/minimize_io_time.cc @@ -80,7 +80,7 @@ Status MinimizeIoTime::Placement(const std::vector &blob_sizes, for (size_t i = 0; i < num_blobs; ++i) { for (size_t j = 0; j < num_targets; ++j) { lp.SetObjectiveCoeff(var.Get(i, j), - static_cast(blob_sizes[i])/bandwidths[j]); + static_cast(blob_sizes[i])/targets[j].bandwidth_); } } diff --git a/src/io_clients/io_client.h b/src/io_clients/io_client.h index e36653e11..10da02aa5 100644 --- a/src/io_clients/io_client.h +++ b/src/io_clients/io_client.h @@ -12,6 +12,7 @@ namespace hermes { class IoClient { public: + virtual bool Init(DeviceInfo &dev_info) = 0; virtual bool Write(DeviceInfo &dev_info, void *data, size_t off, size_t size) = 0; virtual bool Read(DeviceInfo &dev_info, void *data, diff --git a/src/io_clients/posix.h b/src/io_clients/posix.h index 5f87fa0a2..f6e66ea17 100644 --- a/src/io_clients/posix.h +++ b/src/io_clients/posix.h @@ -13,6 +13,14 @@ namespace hermes { class PosixIoClient : public IoClient { public: + bool Init(DeviceInfo &dev_info) override { + auto api = HERMES_POSIX_API; + int fd = api->open(dev_info.mount_point_.c_str(), O_TRUNC | O_CREAT, 0666); + if (fd < 0) { return false; } + api->close(fd); + return true; + } + bool Write(DeviceInfo &dev_info, void *data, size_t off, size_t size) override { auto api = HERMES_POSIX_API; diff --git a/src/io_clients/ram.h b/src/io_clients/ram.h index 134a61b09..6a954f3e8 100644 --- a/src/io_clients/ram.h +++ b/src/io_clients/ram.h @@ -5,4 +5,26 @@ #ifndef HERMES_SRC_IO_CLIENTS_RAM_H_ #define HERMES_SRC_IO_CLIENTS_RAM_H_ +#include "io_client.h" +#include "adapter/posix/real_api.h" +#include "adapter/posix/singleton_macros.h" + +namespace hermes { + +class RamIoClient : public IoClient { + public: + bool Init(DeviceInfo &dev_info) override { + } + + bool Write(DeviceInfo &dev_info, void *data, + size_t off, size_t size) override { + } + + bool Read(DeviceInfo &dev_info, void *data, + size_t off, size_t size) override { + } +}; + +} // namespace hermes + #endif // HERMES_SRC_IO_CLIENTS_RAM_H_ diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 18096567a..c82f22872 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -36,7 +36,9 @@ void MetadataManager::shm_init(ServerConfig *config, targets_->emplace_back( TargetId(rpc_->node_id_, dev_id, dev_id), dev_info.capacity_, - dev_info.capacity_); + dev_info.capacity_, + dev_info.bandwidth_, + dev_info.latency_); ++dev_id; } @@ -198,6 +200,7 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, blob_id.node_id_ = rpc_->node_id_; if (blob_id_map_->try_emplace(internal_blob_name, blob_id)) { BlobInfo info; + info.bkt_id_ = bkt_id; info.name_ = lipc::make_mptr(std::move(internal_blob_name)); info.buffers_ = lipc::make_mptr>( std::move(buffers)); @@ -205,6 +208,7 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, info.shm_serialize(hdr); blob_map_->emplace(blob_id, std::move(hdr)); } else { + blob_id = (*blob_id_map_)[internal_blob_name]; auto iter = blob_map_->find(blob_id); BlobInfoShmHeader &hdr = (*iter).val_.get_ref(); BlobInfo info(hdr); diff --git a/src/metadata_types.h b/src/metadata_types.h index bcc72774f..5190a6631 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -18,14 +18,18 @@ using config::IoInterface; /** Represents the current status of a target */ struct TargetInfo { - TargetId id_; /**< unique Target ID */ - size_t max_cap_; /**< maximum capacity of the target */ - size_t rem_cap_; /**< remaining capacity of the target */ + TargetId id_; /**< unique Target ID */ + size_t max_cap_; /**< maximum capacity of the target */ + size_t rem_cap_; /**< remaining capacity of the target */ + double bandwidth_; /**< the bandwidth of the device */ + double latency_; /**< the latency of the device */ TargetInfo() = default; - TargetInfo(TargetId id, size_t max_cap, size_t rem_cap) - : id_(id), max_cap_(max_cap), rem_cap_(rem_cap) {} + TargetInfo(TargetId id, size_t max_cap, size_t rem_cap, + double bandwidth, double latency) + : id_(id), max_cap_(max_cap), rem_cap_(rem_cap), + bandwidth_(bandwidth), latency_(latency) {} }; /** Represents an allocated fraction of a target */ @@ -50,10 +54,15 @@ struct BlobInfoShmHeader { BlobInfoShmHeader() = default; + BlobInfoShmHeader(const BlobInfoShmHeader &other) noexcept + : bkt_id_(other.bkt_id_), name_ar_(other.name_ar_), + buffers_ar_(other.buffers_ar_), + rwlock_() {} + BlobInfoShmHeader(BlobInfoShmHeader &&other) noexcept : bkt_id_(std::move(other.bkt_id_)), name_ar_(std::move(other.name_ar_)), buffers_ar_(std::move(other.buffers_ar_)), - rwlock_(std::move(other.rwlock_)) {} + rwlock_() {} BlobInfoShmHeader& operator=(BlobInfoShmHeader &&other) { if (this != &other) { @@ -82,6 +91,7 @@ struct BlobInfo { } void shm_serialize(BlobInfoShmHeader &ar) { + ar.bkt_id_ = bkt_id_; name_ >> ar.name_ar_; buffers_ >> ar.buffers_ar_; } diff --git a/src/rpc.cc b/src/rpc.cc index 220269c67..318eacfd6 100644 --- a/src/rpc.cc +++ b/src/rpc.cc @@ -20,7 +20,7 @@ void RpcContext::InitRpcContext() { } // Get all host info - hosts_.resize(hosts.size()); + hosts_.reserve(hosts.size()); for (const auto& name : hosts) { hosts_.emplace_back(name, _GetIpAddress(name)); } diff --git a/src/status.h b/src/status.h index 12e2f1233..0c0a986a1 100644 --- a/src/status.h +++ b/src/status.h @@ -26,7 +26,7 @@ class Status { const char *msg_; public: - Status() = default; + Status() : code_(0) {} explicit Status(const char *msg) : msg_(msg) { code_ = code_counter_; diff --git a/test/test_rpc.cc b/test/test_rpc.cc index 3f061f652..59abeec15 100644 --- a/test/test_rpc.cc +++ b/test/test_rpc.cc @@ -29,7 +29,9 @@ int main(int argc, char* argv[]) { hermes::api::Context ctx; hermes::BlobId blob_id; hermes::Blob blob(nullptr, 1024); - bkt2->Put("0", std::move(blob), blob_id, ctx); + for (size_t i = 0; i < 2; ++i) { + bkt2->Put("0", std::move(blob), blob_id, ctx); + } hermes->Finalize(); MPI_Finalize(); From 8aab4c6240182b4e2cff46b5bc85ca6e0e0fce46 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 26 Dec 2022 23:42:51 -0600 Subject: [PATCH 078/511] Ram tier executes successfully --- src/api/hermes.cc | 2 +- src/api/hermes.h | 1 + src/buffer_organizer.cc | 2 +- src/config_server.cc | 3 ++- src/config_server.h | 6 +++++- src/constants.h | 2 +- src/io_clients/io_client_factory.h | 4 +--- src/io_clients/posix.h | 6 ++++++ src/io_clients/ram.h | 16 ++++++++++++++++ src/status.h | 2 +- src/statuses.h | 2 ++ 11 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 92eca2973..63706ad3d 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -108,7 +108,7 @@ void Hermes::InitSharedMemory() { lipc::MemoryManager::kDefaultBackendSize, server_config_.shmem_name_); main_alloc_ = - mem_mngr->CreateAllocator(lipc::AllocatorType::kPageAllocator, + mem_mngr->CreateAllocator(lipc::AllocatorType::kMultiPageAllocator, server_config_.shmem_name_, main_alloc_id, sizeof(HermesShmHeader)); header_ = main_alloc_->GetCustomHeader(); diff --git a/src/api/hermes.h b/src/api/hermes.h index 7839ffe9b..dafb41342 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -26,6 +26,7 @@ class VBucket; * The Hermes shared-memory header * */ struct HermesShmHeader { + lipc::Pointer ram_tier_; MetadataManagerShmHeader mdm_; BufferPoolShmHeader bpm_; }; diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 2ebefdc81..149a4a6c3 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -17,7 +17,7 @@ void BufferOrganizer::shm_init() { mdm_ = &HERMES->mdm_; for (auto &target : (*mdm_->targets_)) { auto &dev_info = (*mdm_->devices_)[target.id_.GetDeviceId()]; - if (dev_info.mount_point_.size() == 0) { + if (dev_info.mount_dir_.size() == 0) { dev_info.io_api_ = IoInterface::kRam; } else { dev_info.io_api_ = IoInterface::kPosix; diff --git a/src/config_server.cc b/src/config_server.cc index 8258775f9..6c516e80f 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -25,7 +25,8 @@ void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { for (auto device : yaml_conf) { DeviceInfo dev; auto dev_info = device.second; - dev.mount_point_ = lipc::string(dev_info["mount_point"].as()); + dev.dev_name_ = lipc::string(device.first.as()); + dev.mount_dir_ = lipc::string(dev_info["mount_point"].as()); dev.capacity_ = ParseSize(dev_info["capacity"].as()); dev.bandwidth_ = diff --git a/src/config_server.h b/src/config_server.h index 755ec2785..aa3856417 100644 --- a/src/config_server.h +++ b/src/config_server.h @@ -21,13 +21,17 @@ enum class IoInterface { * Device information defined in server config * */ struct DeviceInfo { + /** The human-readable name of the device */ + lipc::string dev_name_; /** The I/O interface for the device */ IoInterface io_api_; /** The minimum transfer size of each device */ size_t block_size_; /** The unit of each slab, a multiple of the Device's block size */ lipc::vector slab_sizes_; - /** The mount point of a device */ + /** The directory the device is mounted on */ + lipc::string mount_dir_; + /** The file to create on the device */ lipc::string mount_point_; /** Device capacity (bytes) */ size_t capacity_; diff --git a/src/constants.h b/src/constants.h index f4ee2eb18..6da3b36e4 100644 --- a/src/constants.h +++ b/src/constants.h @@ -9,7 +9,7 @@ namespace hermes { -static const lipc::allocator_id_t main_alloc_id(0, 0); +static const lipc::allocator_id_t main_alloc_id(0, 1); static const char* kHermesServerConf = "HERMES_CONF"; static const char* kHermesClientConf = "HERMES_CLIENT_CONF"; diff --git a/src/io_clients/io_client_factory.h b/src/io_clients/io_client_factory.h index af5adcca6..836436f56 100644 --- a/src/io_clients/io_client_factory.h +++ b/src/io_clients/io_client_factory.h @@ -27,9 +27,7 @@ class IoClientFactory { } case IoInterface::kRam: default: { - // TODO(llogan): @errorhandling not implemented - LOG(FATAL) << "IoClient not implemented" << std::endl; - return NULL; + return std::make_unique(); } } } diff --git a/src/io_clients/posix.h b/src/io_clients/posix.h index f6e66ea17..670e08dd1 100644 --- a/src/io_clients/posix.h +++ b/src/io_clients/posix.h @@ -9,12 +9,18 @@ #include "adapter/posix/real_api.h" #include "adapter/posix/singleton_macros.h" +#include + +namespace stdfs = std::experimental::filesystem; + namespace hermes { class PosixIoClient : public IoClient { public: bool Init(DeviceInfo &dev_info) override { auto api = HERMES_POSIX_API; + dev_info.mount_point_ = dev_info.mount_dir_ + + "/" + "slab_" + dev_info.dev_name_; int fd = api->open(dev_info.mount_point_.c_str(), O_TRUNC | O_CREAT, 0666); if (fd < 0) { return false; } api->close(fd); diff --git a/src/io_clients/ram.h b/src/io_clients/ram.h index 6a954f3e8..284e3aeb9 100644 --- a/src/io_clients/ram.h +++ b/src/io_clients/ram.h @@ -8,20 +8,36 @@ #include "io_client.h" #include "adapter/posix/real_api.h" #include "adapter/posix/singleton_macros.h" +#include "hermes.h" namespace hermes { class RamIoClient : public IoClient { public: bool Init(DeviceInfo &dev_info) override { + auto &hermes_header = HERMES->header_; + auto &main_alloc = HERMES->main_alloc_; + auto &server_config = HERMES->server_config_; + hermes_header->ram_tier_ = main_alloc->Allocate(dev_info.capacity_); + if (hermes_header->ram_tier_.is_null()) { + LOG(FATAL) << BUFFER_POOL_OUT_OF_RAM.Msg() << std::endl; + } } bool Write(DeviceInfo &dev_info, void *data, size_t off, size_t size) override { + auto &hermes_header = HERMES->header_; + auto &main_alloc = HERMES->main_alloc_; + char *ram_ptr = main_alloc->Convert(hermes_header->ram_tier_); + memcpy(ram_ptr + off, data, size); } bool Read(DeviceInfo &dev_info, void *data, size_t off, size_t size) override { + auto &hermes_header = HERMES->header_; + auto &main_alloc = HERMES->main_alloc_; + char *ram_ptr = main_alloc->Convert(hermes_header->ram_tier_); + memcpy(data, ram_ptr + off, size); } }; diff --git a/src/status.h b/src/status.h index 0c0a986a1..23abe7f3f 100644 --- a/src/status.h +++ b/src/status.h @@ -38,7 +38,7 @@ class Status { msg_ = other.msg_; } - const char* Msg() { + const char* Msg() const { return msg_; } diff --git a/src/statuses.h b/src/statuses.h index 903fba219..c355865f3 100644 --- a/src/statuses.h +++ b/src/statuses.h @@ -15,6 +15,8 @@ const Status DPE_PLACEMENT_SCHEMA_EMPTY("Placement failed. Non-fatal."); const Status DPE_NO_SPACE("DPE has no remaining space."); const Status DPE_MIN_IO_TIME_NO_SOLUTION( "DPE could not find solution for the minimize I/O time DPE"); +const Status BUFFER_POOL_OUT_OF_RAM( + "Could not allocate the ram tier of storage in BPM"); } #endif // HERMES_SRC_STATUSES_H_ From c3e8dca6e90a8e650afeae30b0b736beec7e462a Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Tue, 27 Dec 2022 04:00:07 -0600 Subject: [PATCH 079/511] Bucket Put and Get --- src/api/bucket.cc | 5 ++- src/api/hermes.cc | 4 +-- src/buffer_organizer.cc | 54 +++++++++++++++++++++++++++----- src/buffer_organizer.h | 9 ++++-- src/buffer_pool.cc | 22 ++++++++----- src/buffer_pool.h | 2 +- src/io_clients/ram.h | 3 ++ src/metadata_manager.cc | 18 +++++++++++ src/metadata_manager.h | 15 +++++++++ src/metadata_types.h | 15 +++++---- src/rpc_thallium_serialization.h | 6 ++-- test/basic_test.h | 51 ++++++++++++++++++++++++++++++ test/main.cc | 42 +++++++++++++++++++++++++ test/test_rpc.cc | 7 +++++ test/verify_buffer.h | 21 +++++++++++++ 15 files changed, 245 insertions(+), 29 deletions(-) create mode 100644 test/basic_test.h create mode 100644 test/main.cc create mode 100644 test/verify_buffer.h diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 6be4ccd69..358189dbb 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -43,7 +43,8 @@ Status Bucket::Put(std::string blob_name, Blob blob, for (auto &schema : schemas) { // TODO(llogan): Use RPC if-else, not Local auto buffers = bpm_->LocalAllocateAndSetBuffers(schema, blob); - mdm_->LocalBucketPutBlob(id_, lipc::string(blob_name), blob, buffers); + blob_id = mdm_->LocalBucketPutBlob(id_, + lipc::string(blob_name), blob, buffers); } } @@ -52,6 +53,8 @@ Status Bucket::Put(std::string blob_name, Blob blob, * :WRAP-param: ctx -> ctx_ * */ Status Bucket::Get(BlobId blob_id, Blob &blob, Context &ctx) { + blob = mdm_->LocalBucketGetBlob(blob_id); + return Status(); } } // namespace hermes::api \ No newline at end of file diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 63706ad3d..bcdb231fd 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -72,8 +72,8 @@ void Hermes::InitClient(std::string server_config_path, LoadSharedMemory(); rpc_.InitClient(); mdm_.shm_deserialize(&header_->mdm_); - bpm_.shm_deserialize(&header_->bpm_, &mdm_); - // borg_.shm_deserialize(&header_->borg_); + bpm_.shm_deserialize(&header_->bpm_); + borg_.shm_deserialize(); } void Hermes::InitColocated(std::string server_config_path, diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 149a4a6c3..69a85afea 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -9,6 +9,14 @@ namespace hermes { +static size_t SumBufferBlobSizes(lipc::vector &buffers) { + size_t sum = 0; + for (auto &buffer : buffers) { + sum += buffer.blob_size_; + } + return sum; +} + /** * Initialize the BORG * REQUIRES mdm to be initialized already. @@ -30,14 +38,29 @@ void BufferOrganizer::shm_init() { /** Finalize the BORG */ void BufferOrganizer::shm_destroy() {} -/** Stores a blob into a set of buffers */ +/** Serialize the BORG into shared memory */ +void BufferOrganizer::shm_serialize() { +} + +/** Deserialize the BORG from shared memory */ +void BufferOrganizer::shm_deserialize() { + mdm_ = &HERMES->mdm_; +} + + /** Stores a blob into a set of buffers */ RPC void BufferOrganizer::LocalPlaceBlobInBuffers( Blob &blob, lipc::vector &buffers) { + size_t blob_off = 0; for (auto &buffer_info : buffers) { + if (buffer_info.tid_.GetNodeId() != mdm_->rpc_->node_id_) { + continue; + } auto &dev_info = (*mdm_->devices_)[buffer_info.tid_.GetDeviceId()]; auto io_client = IoClientFactory::Get(dev_info.io_api_); - bool ret = io_client->Write(dev_info, blob.data(), - buffer_info.off_, buffer_info.size_); + bool ret = io_client->Write(dev_info, blob.data() + blob_off, + buffer_info.t_off_, + buffer_info.blob_size_); + blob_off += buffer_info.blob_size_; if (!ret) { LOG(FATAL) << "Could not perform I/O in BORG" << std::endl; } @@ -45,13 +68,30 @@ RPC void BufferOrganizer::LocalPlaceBlobInBuffers( } /** Stores a blob into a set of buffers */ -RPC void LocalReadBlobFromBuffers(Blob &blob, - lipc::vector &buffers) { +RPC Blob BufferOrganizer::LocalReadBlobFromBuffers( + lipc::vector &buffers) { + Blob blob(nullptr, SumBufferBlobSizes(buffers)); + size_t blob_off = 0; + for (auto &buffer_info : buffers) { + if (buffer_info.tid_.GetNodeId() != mdm_->rpc_->node_id_) { + continue; + } + auto &dev_info = (*mdm_->devices_)[buffer_info.tid_.GetDeviceId()]; + auto io_client = IoClientFactory::Get(dev_info.io_api_); + bool ret = io_client->Read(dev_info, blob.data_mutable() + blob_off, + buffer_info.t_off_, + buffer_info.blob_size_); + blob_off += buffer_info.blob_size_; + if (!ret) { + LOG(FATAL) << "Could not perform I/O in BORG" << std::endl; + } + } + return std::move(blob); } /** Copies one buffer set into another buffer set */ -RPC void LocalCopyBuffers(lipc::vector &dst, - lipc::vector &src) { +RPC void BufferOrganizer::LocalCopyBuffers(lipc::vector &dst, + lipc::vector &src) { } } // namespace hermes \ No newline at end of file diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index 5d88a6983..fd7d59c3b 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -30,13 +30,18 @@ class BufferOrganizer { /** Finalize the BORG */ void shm_destroy(); + /** Serialize the BORG into shared memory */ + void shm_serialize(); + + /** Deserialize the BORG from shared memory */ + void shm_deserialize(); + /** Stores a blob into a set of buffers */ RPC void LocalPlaceBlobInBuffers(Blob &blob, lipc::vector &buffers); /** Stores a blob into a set of buffers */ - RPC void LocalReadBlobFromBuffers(Blob &blob, - lipc::vector &buffers); + RPC Blob LocalReadBlobFromBuffers(lipc::vector &buffers); /** Copies one buffer set into another buffer set */ RPC void LocalCopyBuffers(lipc::vector &dst, diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 8d6dba111..184619066 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -5,6 +5,7 @@ #include "buffer_pool.h" #include "metadata_manager.h" #include "hermes.h" +#include "buffer_organizer.h" namespace hermes { @@ -31,9 +32,9 @@ void BufferPool::shm_serialize(BufferPoolShmHeader *header) { } /** Deserialize the BPM from shared memory */ -void BufferPool::shm_deserialize(BufferPoolShmHeader *header, - MetadataManager *mdm) { - mdm_ = mdm; +void BufferPool::shm_deserialize(BufferPoolShmHeader *header) { + mdm_ = &HERMES->mdm_; + borg_ = &HERMES->borg_; target_allocs_ << header->alloc_ar_; } @@ -43,22 +44,27 @@ void BufferPool::shm_deserialize(BufferPoolShmHeader *header, * TODO(llogan): use better allocator policy * */ lipc::vector -BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, - Blob &blob) { +BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, Blob &blob) { lipc::vector buffers(nullptr); + size_t blob_off_ = 0; for (auto plcmnt : schema.plcmnts_) { if (plcmnt.tid_.GetNodeId() != mdm_->rpc_->node_id_) { + blob_off_ += plcmnt.size_; continue; } auto &alloc = (*target_allocs_)[plcmnt.tid_.GetDeviceId()]; BufferInfo info; - info.off_ = alloc.cur_off_; - info.size_ = plcmnt.size_; + info.t_off_ = alloc.cur_off_; + info.t_size_ = plcmnt.size_; + info.blob_off_ = blob_off_; + info.blob_size_ = plcmnt.size_; info.tid_ = plcmnt.tid_; alloc.cur_off_ += plcmnt.size_; buffers.emplace_back(info); + borg_->LocalPlaceBlobInBuffers(blob, buffers); mdm_->LocalUpdateTargetCapacity(info.tid_, - static_cast(info.size_)); + static_cast(info.t_size_)); + blob_off_ += plcmnt.size_; } return buffers; } diff --git a/src/buffer_pool.h b/src/buffer_pool.h index e889c7528..07762afef 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -51,7 +51,7 @@ class BufferPool { void shm_serialize(BufferPoolShmHeader *header); /** Deserialize the BPM from shared memory */ - void shm_deserialize(BufferPoolShmHeader *header, MetadataManager *mdm); + void shm_deserialize(BufferPoolShmHeader *header); /** * Allocate buffers from the targets according to the schema diff --git a/src/io_clients/ram.h b/src/io_clients/ram.h index 284e3aeb9..e7e74c310 100644 --- a/src/io_clients/ram.h +++ b/src/io_clients/ram.h @@ -22,6 +22,7 @@ class RamIoClient : public IoClient { if (hermes_header->ram_tier_.is_null()) { LOG(FATAL) << BUFFER_POOL_OUT_OF_RAM.Msg() << std::endl; } + return true; } bool Write(DeviceInfo &dev_info, void *data, @@ -30,6 +31,7 @@ class RamIoClient : public IoClient { auto &main_alloc = HERMES->main_alloc_; char *ram_ptr = main_alloc->Convert(hermes_header->ram_tier_); memcpy(ram_ptr + off, data, size); + return true; } bool Read(DeviceInfo &dev_info, void *data, @@ -38,6 +40,7 @@ class RamIoClient : public IoClient { auto &main_alloc = HERMES->main_alloc_; char *ram_ptr = main_alloc->Convert(hermes_header->ram_tier_); memcpy(data, ram_ptr + off, size); + return true; } }; diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index c82f22872..d2b2c2143 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -4,16 +4,19 @@ #include "hermes.h" #include "metadata_manager.h" +#include "buffer_organizer.h" namespace hermes { /** * Explicitly initialize the MetadataManager + * Doesn't require anything to be initialized. * */ void MetadataManager::shm_init(ServerConfig *config, MetadataManagerShmHeader *header) { header_ = header; rpc_ = &HERMES->rpc_; + borg_ = &HERMES->borg_; header_->id_alloc_ = 1; // Create the metadata maps @@ -81,6 +84,7 @@ void MetadataManager::shm_serialize() { void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { header_ = header; rpc_ = &HERMES->rpc_; + borg_ = &HERMES->borg_; blob_id_map_ << header_->blob_id_map_ar_; bkt_id_map_ << header_->bkt_id_map_ar_; vbkt_id_map_ << header_->vbkt_id_map_ar_; @@ -220,6 +224,19 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, return blob_id; } +/** + * Get \a blob_name blob from \a bkt_id bucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { + auto iter = blob_map_->find(blob_id); + BlobInfoShmHeader &hdr = (*iter).val_.get_ref(); + BlobInfo info(hdr); + return borg_->LocalReadBlobFromBuffers(*info.buffers_); +} + /** * Get \a blob_name blob from \a bkt_id bucket * @@ -228,6 +245,7 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, * */ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, lipc::charbuf &blob_name) { + lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); } /** diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 80ba62af7..57b0dea92 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -14,6 +14,9 @@ namespace hermes { +/** Forward declaration of borg */ +class BufferOrganizer; + /** * Type name simplification for the various map types * */ @@ -55,6 +58,7 @@ class MetadataManager { public: RPC_TYPE* rpc_; MetadataManagerShmHeader *header_; + BufferOrganizer *borg_; /** * The manual pointers representing the different map types. @@ -163,6 +167,17 @@ class MetadataManager { RPC BlobId LocalBucketPutBlob(BucketId bkt_id, const lipc::charbuf &blob_name, Blob &data, lipc::vector &buffers); + /** + * Get a blob from a bucket + * + * @param bkt_id id of the bucket + * @param blob_id id of the blob to get + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ + Blob LocalBucketGetBlob(BlobId blob_id); + /** * Get \a blob_name blob from \a bkt_id bucket * diff --git a/src/metadata_types.h b/src/metadata_types.h index 5190a6631..0dcbded19 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -34,15 +34,18 @@ struct TargetInfo { /** Represents an allocated fraction of a target */ struct BufferInfo { - size_t off_; - size_t blob_off_; - size_t size_; - TargetId tid_; + TargetId tid_; /**< The destination target */ + size_t t_off_; /**< Offset in the target */ + size_t t_size_; /**< Size in the target */ + size_t blob_off_; /**< Offset in the blob */ + size_t blob_size_; /**< The amount of the blob being placed */ BufferInfo() = default; - BufferInfo(size_t off, size_t size, TargetId tid) - : off_(off), size_(size), tid_(tid) {} + BufferInfo(TargetId tid, size_t t_off, size_t t_size, + size_t blob_off, size_t blob_size) + : tid_(tid), t_off_(t_off), t_size_(t_size), + blob_off_(blob_off), blob_size_(blob_size){} }; /** Represents BlobInfo in shared memory */ diff --git a/src/rpc_thallium_serialization.h b/src/rpc_thallium_serialization.h index 2ee8504b2..678bd4e83 100644 --- a/src/rpc_thallium_serialization.h +++ b/src/rpc_thallium_serialization.h @@ -82,9 +82,11 @@ void serialize(A &ar, TargetId &target_id) { */ template void serialize(A &ar, BufferInfo &info) { - ar &info.off_; - ar &info.size_; ar &info.tid_; + ar &info.t_off_; + ar &info.t_size_; + ar &info.blob_off_; + ar &info.blob_size_; } } // namespace hermes diff --git a/test/basic_test.h b/test/basic_test.h new file mode 100644 index 000000000..d6d0fb970 --- /dev/null +++ b/test/basic_test.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of LabStor + * + * LabStor 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 Lesser 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 + * . + */ + +#ifndef LABSTOR_TEST_UNIT_BASIC_TEST_H_ +#define LABSTOR_TEST_UNIT_BASIC_TEST_H_ + +#define CATCH_CONFIG_RUNNER +#include + +namespace cl = Catch::Clara; +cl::Parser define_options(); + +#include +#include + +static bool VerifyBuffer(char *ptr, size_t size, char nonce) { + for (size_t i = 0; i < size; ++i) { + if (ptr[i] != nonce) { + std::cout << (int)ptr[i] << std::endl; + return false; + } + } + return true; +} + +void MainPretest(); +void MainPosttest(); + +#endif // LABSTOR_TEST_UNIT_BASIC_TEST_H_ diff --git a/test/main.cc b/test/main.cc new file mode 100644 index 000000000..c48ca4d71 --- /dev/null +++ b/test/main.cc @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of LabStor + * + * LabStor 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 Lesser 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 + * . + */ + + +#include "basic_test.h" +#include + +int main(int argc, char **argv) { + int rc; + Catch::Session session; + auto cli = session.cli(); + session.cli(cli); + rc = session.applyCommandLine(argc, argv); + if (rc != 0) return rc; + MainPretest(); + rc = session.run(); + MainPosttest(); + if (rc != 0) return rc; + return rc; +} diff --git a/test/test_rpc.cc b/test/test_rpc.cc index 59abeec15..01a2eb58d 100644 --- a/test/test_rpc.cc +++ b/test/test_rpc.cc @@ -18,6 +18,8 @@ #include "hermes.h" #include "bucket.h" +#include "verify_buffer.h" + namespace hapi = hermes::api; int main(int argc, char* argv[]) { @@ -30,7 +32,12 @@ int main(int argc, char* argv[]) { hermes::BlobId blob_id; hermes::Blob blob(nullptr, 1024); for (size_t i = 0; i < 2; ++i) { + memset(blob.data_mutable(), 10, 1024); bkt2->Put("0", std::move(blob), blob_id, ctx); + hermes::Blob ret; + bkt->Get(blob_id, ret, ctx); + assert(ret.size() == 1024); + assert(VerifyBuffer(ret.data(), 1024, 10)); } hermes->Finalize(); diff --git a/test/verify_buffer.h b/test/verify_buffer.h new file mode 100644 index 000000000..7c0401a93 --- /dev/null +++ b/test/verify_buffer.h @@ -0,0 +1,21 @@ +// +// Created by lukemartinlogan on 12/27/22. +// + +#ifndef HERMES_TEST_VERIFY_BUFFER_H_ +#define HERMES_TEST_VERIFY_BUFFER_H_ + +#include +#include + +static bool VerifyBuffer(char *ptr, size_t size, char nonce) { + for (size_t i = 0; i < size; ++i) { + if (ptr[i] != nonce) { + std::cout << (int)ptr[i] << std::endl; + return false; + } + } + return true; +} + +#endif // HERMES_TEST_VERIFY_BUFFER_H_ From c6f1976f6b510ab45894438ebb4e449acee8d2aa Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Tue, 27 Dec 2022 23:34:11 -0600 Subject: [PATCH 080/511] Enable comparison between fixed-sized byte strings, which may contain null characters --- CMakeLists.txt | 6 +- benchmarks/CMakeLists.txt | 2 +- benchmarks/HermesVFD/README.md | 76 --- .../HermesVFD/hdf5-iotest_Hermes_VFD.csv | 11 - benchmarks/HermesVFD/hdf5_iotest.ini | 22 - .../HermesVFD/hermes.conf_4KB_128KB_example | 105 ---- benchmarks/borg_bench.cc | 515 ---------------- benchmarks/dpe_bench.cc | 169 ------ benchmarks/mdm_bench.cc | 253 -------- benchmarks/put_get_bench.cc | 74 +++ benchmarks/vpic_bench.cc | 560 ------------------ src/api/bucket.cc | 15 +- src/api/hermes.cc | 2 +- src/buffer_pool.cc | 4 +- src/metadata_manager.cc | 14 +- src/metadata_types.h | 31 + test/CMakeLists.txt | 2 +- test/test_put_get.cc | 76 +++ test/test_rpc.cc | 2 +- 19 files changed, 211 insertions(+), 1728 deletions(-) delete mode 100644 benchmarks/HermesVFD/README.md delete mode 100644 benchmarks/HermesVFD/hdf5-iotest_Hermes_VFD.csv delete mode 100644 benchmarks/HermesVFD/hdf5_iotest.ini delete mode 100644 benchmarks/HermesVFD/hermes.conf_4KB_128KB_example delete mode 100644 benchmarks/borg_bench.cc delete mode 100644 benchmarks/dpe_bench.cc delete mode 100644 benchmarks/mdm_bench.cc create mode 100644 benchmarks/put_get_bench.cc delete mode 100644 benchmarks/vpic_bench.cc create mode 100644 test/test_put_get.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e3a7afb2..2e50e821a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,10 +400,6 @@ if(HERMES_HAVE_GOTCHA) # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/gotcha_intercept) endif() -if(HERMES_ENABLE_WRAPPER) - # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/wrapper) -endif() - if(HERMES_BUILD_BUFFER_POOL_VISUALIZER AND SDL2_FOUND) # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/buffer_pool_visualizer) endif() @@ -459,7 +455,7 @@ endif() # Benchmarks #----------------------------------------------------------------------------- if(HERMES_BUILD_BENCHMARKS) - # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/benchmarks) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/benchmarks) endif() #----------------------------------------------------------------------------- diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index d7bde67c0..ffb042438 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -3,7 +3,7 @@ include_directories( ${PROJECT_SOURCE_DIR}/test ) -set(BENCHMARKS mdm_bench dpe_bench vpic_bench borg_bench) +set(BENCHMARKS put_get_bench) foreach(benchmark ${BENCHMARKS}) add_executable(${benchmark} ${benchmark}.cc) diff --git a/benchmarks/HermesVFD/README.md b/benchmarks/HermesVFD/README.md deleted file mode 100644 index e6918c971..000000000 --- a/benchmarks/HermesVFD/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# Demonstrate how to use Hermes with hdf5_iotest - -## Build Hermes - -Follow the instructions in the Hermes -[README](https://github.com/HDFGroup/hermes#hermes). Make sure to set the following options: -* `HERMES_ENABLE_VFD=ON` -* `HERMES_ENABLE_WRAPPER=ON` - -## Build hdf5-iotest - -### Dependencies - -* parallel HDF5 - -We use a fork of `hdf5-iotest` with a few modifications to make it compatible -with with the Hermes VFD. - -```bash -git clone https://github.com/jya-kmu/hdf5-iotest.git -cd hdf5-iotest -git checkout hermes-vfd -``` -We need two config files `hermes.yaml` and `hdf5_iotest.ini` to start `hdf5-iotest` with -Hermes buffering system. - -To create hermes.yaml configuration file for Hermes environment setup, user can start from -the provided example hermes.yaml (named `hermes.conf_4KB_128KB_example`) and modify it -to match different system setup and test purposes. For example, user can modify -`mount_points` and `swap_mount` in the config file according to the system configuration. -Once the file is ready, place it to top hdf5-iotest directory. - -User also needs the file `src/hdf5_iotest.ini` to start hdf5_iotest. For our test we -only modify the `split` option if to split metadata and data (`split = 1`) -or not (`split = 0`). An example `hdf5_iotest.ini` file is also provided in this -direcotry without splitting metadata and data. - -If the user choose not to split metadata and data by setting `split = 0`, the page -size is the same for metadata and data (if choosing hermes) and can be setup by function -`status = H5Pset_fapl_hermes(fapl, false, 1048576)` (@line 176) in file -`src/hdf5_iotest.c`. The last parameter in the function is the page size 1MiB in -this example. User can modify it for performance test. - -If the user choose to split metadata and data by setting `split = 1`, they -can use different VFD methods or same VFD method with different parameter -configuration for metadata and data. In the example of hdf5-iotest, function -`status = H5Pset_fapl_hermes(fapl, false, 1048576)` (@line 176) in file -`src/hdf5_iotest.c` will setup the page size for data. And default in this test -we choose HDF5 core VFD for metadata by HDF5 API -`status = H5Pset_fapl_core(fapl_m, (size_t)0, 0)` (@line 334), which will keep -the metadata in memory. As another option, user can choose Hermes VFD for -metadata with a smaller -page size by `status = H5Pset_fapl_hermes(fapl_m, false, 4096)` (@line 333) -instead of core VFD. - -We provide the performance results in hdf5-iotest_Hermes_VFD.csv for splitting and -not splitting metadata and data, and further using different methods for metadata -in the splitting case. - -## Before the run -Set up Herems environment variables by -```bash -export HERMES_CONF=/path/to/hermes.yaml -``` - -## Run -Run the test as -```bash -GLOG_minloglevel=2 /path/to/hdf5_iotest /path/to/hdf5_iotest.ini -``` - -## Run with Darshan -Darshan output can be generated by running the command -```bash -LD_PRELOAD=/path/to/libdarshan.so GLOG_minloglevel=2 /path/to/hdf5_iotest /path/to/hdf5_iotest.ini -``` diff --git a/benchmarks/HermesVFD/hdf5-iotest_Hermes_VFD.csv b/benchmarks/HermesVFD/hdf5-iotest_Hermes_VFD.csv deleted file mode 100644 index c33ebeba9..000000000 --- a/benchmarks/HermesVFD/hdf5-iotest_Hermes_VFD.csv +++ /dev/null @@ -1,11 +0,0 @@ -20 time steps,,,,,,,,,,,,,, -Baseline,posix,,,,,,,,,,,,, -,PFS,21024,21024,21024,21024,21024,21024,,,,,,, -,,,,,,,,,,,,,, -Hermes,buffer,1MB (not split),"1KB, 1MB","4KB, 1MB","8KB, 1MB","16KB, 1MB","core, 1MB",,128KB (not split),"1KB, 128KB","4KB, 128KB","8KB, 128KB","16KB, 128KB","core, 128KB" -random,NVMe,873,777,730,707,730,635,,570,731,625,600,586,519 -rr,,875,758,718,712,722,630,,556,716,611,589,585,515 -,,,,,,,,,,,,,, -Hermes,buffer,1MB (not split),"1KB, 1MB","4KB, 1MB","8KB, 1MB","16KB, 1MB","core, 1MB",,128KB (not split),"1KB, 128KB","4KB, 128KB","8KB, 128KB","16KB, 128KB","core, 128KB" -random,4 tiers,5374,4472,4054,4191,4627,3625,,3120,3152,3099,3196,3593,2572 -rr,,5325,4482,4083,4160,4621,3615,,3133,3053,3058,3173,3594,2557 diff --git a/benchmarks/HermesVFD/hdf5_iotest.ini b/benchmarks/HermesVFD/hdf5_iotest.ini deleted file mode 100644 index b5a4e95e9..000000000 --- a/benchmarks/HermesVFD/hdf5_iotest.ini +++ /dev/null @@ -1,22 +0,0 @@ -[DEFAULT] -version = 0 -steps = 20 -arrays = 500 -rows = 100 -columns = 200 -process-rows = 1 -process-columns = 1 -# [weak, strong] -scaling = weak -# align along increment [bytes] boundaries -alignment-increment = 1 -# minimum object size [bytes] to force alignment (0=all objects) -alignment-threshold = 0 -# minimum metadata block allocation size [bytes] -meta-block-size = 2048 -# [posix, core, mpi-io-uni, hermes] -single-process = hermes -# 1 indicates to use split file diriver, and 0 indicates not. -split = 0 -hdf5-file = hdf5_iotest.h5 -csv-file = hdf5_iotest.csv diff --git a/benchmarks/HermesVFD/hermes.conf_4KB_128KB_example b/benchmarks/HermesVFD/hermes.conf_4KB_128KB_example deleted file mode 100644 index 4b4b7bdb5..000000000 --- a/benchmarks/HermesVFD/hermes.conf_4KB_128KB_example +++ /dev/null @@ -1,105 +0,0 @@ -# Example Hermes configuration file - -# TODO(chogan): Allow specifying capacity values in bytes, KiB, or GiB. - -# The number of buffering tiers available. For example, RAM, NVMe, burst -# buffer, and parallel file system would be 4 tiers. -num_devices = 4; -# For now this should be the same as num_devices. -num_targets = 4; - -# The maximum buffering capacity in MiB of each device. -capacities_mb = {2876, 1024, 1536, 2048}; -# The size of the smallest available buffer in KiB. In general this should be -# the page size of your system for byte addressable storage, and the block size -# of the storage device for block addressable storage. -block_sizes_kb = {4, 4, 4, 4}; -# The number of size categories for each device. Here we say that each of our 4 -# devices should have 4 different sizes of buffers. -num_slabs = {2, 2, 2, 2}; - -# The number of blocks (the size of which is chosen in block_sizes_kb) that each -# device should contain for each slab (controlled by num_slabs). This allows for -# precise control of the distribution of buffer sizes. -slab_unit_sizes = { - {1, 32}, - {1, 32}, - {1, 32}, - {1, 32}, -}; - -# The percentage of buffering capacity per device to allocate for each slab. -# Each row should add up to 1. -desired_slab_percentages = { - {0.1, 0.9}, - {0.1, 0.9}, - {0.1, 0.9}, - {0.1, 0.9}, -}; - -# The maximum theoretical bandwidth (as advertised by the manufacturer) in -# MiB/sec. of each device. -bandwidths_mbps = {5000, 300, 150, 70}; -# The latency in microseconds of each device (as advertised by the manufacturer). -latencies_us = {15, 250000, 500000, 1000000}; - -# Hermes memory management. The following 4 values should add up to 1. -# The percentage of Hermes memory to reserve for RAM buffers. -buffer_pool_arena_percentage = 0.18; -# The percentage of Hermes memory to reserve for metadata. -metadata_arena_percentage = 0.71; -# The percentage of Hermes memory to reserve for short term storage. -transient_arena_percentage = 0.11; - -# The maximum number of buckets that can be created. -max_buckets_per_node = 16; -# The maximum number of virtual buckets that can be created. -max_vbuckets_per_node = 8; -# The interval in milliseconds at which to update the global system view. -system_view_state_update_interval_ms = 1000; - -# The mount point of each device. RAM should be the empty string. For block -# devices, this is the directory where Hermes will create buffering files. For -# object storage or cloud targets, this will be a url. -mount_points = {"", "./", "./", "./"}; -# The mount point of a PFS or object store for swap space, in the event that -# Hermes buffers become full. -swap_mount = "./"; -# The number of times the buffer organizer will attempt to place a blob from -# swap space into the hierarchy before giving up. -num_buffer_organizer_retries = 3; -# Base hostname for the RPC servers. -rpc_server_base_name = "localhost"; -# RPC server name suffix. This is appended to the the base name plus host -# number. -rpc_server_suffix = ""; -# The RPC protocol. This must come from the documentation of the specific RPC -# library in use. -rpc_protocol = "ofi+sockets"; -# RPC domain name for verbs transport. Blank for tcp. -rpc_domain = ""; -# Desired RPC port number. -rpc_port = 8080; -# Desired RPC port number for buffer organizer. -buffer_organizer_port = 8081; -# An inclusive range of the first and last server numbers. This is a convenience -# feature for generating long lists of server names. For example, if your -# servers are called server-1-40g, server-2-40g, server-3-40g, all the way to -# server-100-40g, then you would set rpc_server_base_name to 'server', -# rpc_server_suffix to '-40g', and rpc_host_number_range to {1, 100}. -# TODO(chogan): Support reading server names from file. -rpc_host_number_range = {}; -# The number of handler threads for each RPC server. -rpc_num_threads = 1; -# The shared memory prefix for the hermes shared memory segment. A user name -# will be automatically appended. -buffer_pool_shmem_name = "/hermes_buffer_pool_"; - -# Choose Random, RoundRobin, or MinimizeIoTime -default_placement_policy = "Random"; -#default_placement_policy = "RoundRobin"; -#default_placement_policy = "MinimizeIoTime"; - -# If true (1) the RoundRobin placement policy algorithm will split each Blob -# into a random number of smaller Blobs. -default_rr_split = 0; diff --git a/benchmarks/borg_bench.cc b/benchmarks/borg_bench.cc deleted file mode 100644 index d8cc211a8..000000000 --- a/benchmarks/borg_bench.cc +++ /dev/null @@ -1,515 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include - -#include - -#include "hermes.h" -#include "bucket.h" -#include "vbucket.h" -#include "metadata_management_internal.h" -#include "test_utils.h" - -namespace hapi = hermes::api; -using HermesPtr = std::shared_ptr; - -const int kDefaultIters = 2000; -const size_t kDefaultBlobSize = KILOBYTES(32); - -struct Options { - bool use_borg; - bool verify; - bool time_puts; - bool verbose; - bool debug; - bool write_only; - bool mixed; - long sleep_ms; - size_t blob_size; - int iters; - char *output_filename; -}; - -static void PrintUsage(char *program) { - fprintf(stderr, "Usage: %s [-bdmpvwx] [-f ]\n", program); - fprintf(stderr, " -b\n"); - fprintf(stderr, " Enable the BORG for the write-only case.\n"); - fprintf(stderr, " -d\n"); - fprintf(stderr, " If present, enable MPI breakpoint for debugging.\n"); - fprintf(stderr, " -f\n"); - fprintf(stderr, " The filename of the persisted data (for correctness" - " verification).\n"); - fprintf(stderr, " -i\n"); - fprintf(stderr, " Number of iterations (default: %d)\n", kDefaultIters); - fprintf(stderr, " -m\n"); - fprintf(stderr, " Run mixed workload.\n"); - fprintf(stderr, " -p\n"); - fprintf(stderr, " Get average for groups of puts.\n"); - fprintf(stderr, " -s\n"); - fprintf(stderr, " Sleep ms between each Put.\n"); - fprintf(stderr, " -v\n"); - fprintf(stderr, " Print verbose information.\n"); - fprintf(stderr, " -w\n"); - fprintf(stderr, " Run write only workload.\n"); - fprintf(stderr, " -x\n"); - fprintf(stderr, " If present, verify results at the end.\n"); - fprintf(stderr, " -z\n"); - fprintf(stderr, " Blob size in bytes (default: %zu).\n", kDefaultBlobSize); -} - -static Options HandleArgs(int argc, char **argv) { - Options result = {}; - result.iters = kDefaultIters; - result.blob_size = kDefaultBlobSize; - - int option = -1; - while ((option = getopt(argc, argv, "bdf:hi:mps:vxwz:")) != -1) { - switch (option) { - case 'h': { - PrintUsage(argv[0]); - exit(0); - } - case 'b': { - result.use_borg = true; - break; - } - case 'd': { - result.debug = true; - break; - } - case 'f': { - result.output_filename = optarg; - break; - } - case 'i': { - result.iters = strtol(optarg, NULL, 0); - break; - } - case 'm': { - result.mixed = true; - break; - } - case 'p': { - result.time_puts = true; - break; - } - case 's': { - result.sleep_ms = strtol(optarg, NULL, 0); - break; - } - case 'v': { - result.verbose = true; - break; - } - case 'x': { - result.verify = true; - break; - } - case 'w': { - result.write_only = true; - break; - } - case 'z': { - result.blob_size = strtoll(optarg, NULL, 0); - break; - } - default: { - PrintUsage(argv[0]); - exit(1); - } - } - } - - if (result.verify && !result.output_filename) { - fprintf(stderr, "Please supply filename via -f\n"); - exit(1); - } - if (optind < argc) { - fprintf(stderr, "non-option ARGV-elements: "); - while (optind < argc) { - fprintf(stderr, "%s ", argv[optind++]); - } - fprintf(stderr, "\n"); - } - return result; -} - -static double GetMPIAverage(double rank_seconds, int num_ranks, MPI_Comm comm) { - double total_secs = 0; - MPI_Reduce(&rank_seconds, &total_secs, 1, MPI_DOUBLE, MPI_SUM, 0, comm); - double result = total_secs / num_ranks; - - return result; -} - -static double GetBandwidth(double total_elapsed, double total_mb, MPI_Comm comm, - int ranks) { - double avg_total_seconds = GetMPIAverage(total_elapsed, ranks, comm); - double result = total_mb / avg_total_seconds; - - return result; -} - -static std::string MakeBlobName(int rank, int i) { - std::string result = std::to_string(rank) + "_" + std::to_string(i); - - return result; -} - -static void WriteOnlyWorkload(const Options &options) { - HermesPtr hermes = hapi::InitHermes(getenv("HERMES_CONF")); - - if (hermes->IsApplicationCore()) { - int rank = hermes->GetProcessRank(); - const int kNumRanks = hermes->GetNumProcesses(); - const size_t kTotalBytes = kNumRanks * options.blob_size * options.iters; - - hermes::testing::Timer timer; - hapi::Context ctx; - // Disable swapping of Blobs - ctx.disable_swap = true; - ctx.policy = hapi::PlacementPolicy::kMinimizeIoTime; - - std::string bkt_name = "BORG_" + std::to_string(rank); - hapi::VBucket vbkt(bkt_name, hermes); - hapi::Bucket bkt(bkt_name, hermes, ctx); - - hapi::WriteOnlyTrait trait; - if (options.use_borg) { - vbkt.Attach(&trait); - } - - // MinIoTime with retry - const int kReportFrequency = 30; - hermes::testing::Timer put_timer; - size_t failed_puts = 0; - size_t failed_links = 0; - size_t retries = 0; - for (int i = 0; i < options.iters; ++i) { - std::string blob_name = MakeBlobName(rank, i); - hapi::Blob blob(options.blob_size, i % 255); - - timer.resumeTime(); - put_timer.resumeTime(); - hapi::Status status; - int consecutive_fails = 0; - while (!((status = bkt.Put(blob_name, blob)).Succeeded())) { - retries++; - if (++consecutive_fails > 10) { - failed_puts++; - break; - } - } - - if (options.use_borg && consecutive_fails <= 10) { - hapi::Status link_status = vbkt.Link(blob_name, bkt_name); - if (!link_status.Succeeded()) { - failed_links++; - } - } - - if (options.sleep_ms > 0 && i > 0 && i % kReportFrequency == 0) { - std::this_thread::sleep_for( - std::chrono::milliseconds(options.sleep_ms)); - } - - put_timer.pauseTime(); - timer.pauseTime(); - - if (options.time_puts && i > 0 && i % kReportFrequency == 0) { - Assert(kNumRanks == 1); - double total_mb = - (options.blob_size * kReportFrequency) / 1024.0 / 1024.0; - - std::cout << i << ", " << total_mb / put_timer.getElapsedTime() << "\n"; - } - hermes->AppBarrier(); - } - - Assert(failed_puts == 0); - if (options.verbose) { - std::cout << "Rank " << rank << " failed puts: " << failed_puts << "\n"; - std::cout << "Rank " << rank << " failed links: " << failed_links << "\n"; - std::cout << "Rank " << rank << " Put retries: " << retries << "\n"; - } - - hermes->AppBarrier(); - if (!hermes->IsFirstRankOnNode()) { - vbkt.Release(); - bkt.Release(); - } - - hermes->AppBarrier(); - if (hermes->IsFirstRankOnNode()) { - vbkt.Destroy(); - if (options.verify) { - hapi::VBucket file_vbucket(options.output_filename, hermes); - auto offset_map = std::unordered_map(); - - for (int i = 0; i < kNumRanks; ++i) { - for (int j = 0; j < options.iters; ++j) { - std::string blob_name = MakeBlobName(i, j); - file_vbucket.Link(blob_name, bkt_name, ctx); - const size_t kBytesPerRank = options.iters * options.blob_size; - size_t offset = (i * kBytesPerRank) + (j * options.blob_size); - offset_map.emplace(blob_name, offset); - } - } - bool flush_synchronously = true; - hapi::PersistTrait persist_trait(options.output_filename, offset_map, - flush_synchronously); - if (options.verbose) { - std::cout << "Flushing buffers...\n"; - } - file_vbucket.Attach(&persist_trait); - - file_vbucket.Destroy(); - } - bkt.Destroy(); - } - - hermes->AppBarrier(); - - MPI_Comm *comm = (MPI_Comm *)hermes->GetAppCommunicator(); - double total_mb = kTotalBytes / 1024.0 / 1024.0; - double bandwidth = GetBandwidth(timer.getElapsedTime(), total_mb, *comm, - kNumRanks); - - if (hermes->IsFirstRankOnNode()) { - std::cout << bandwidth << "," << kNumRanks << "," << options.use_borg - << "," << options.sleep_ms << "\n"; - } - } - - hermes->Finalize(); -} - -static void OptimizeReads(Options &options) { - HermesPtr hermes = hapi::InitHermes(getenv("HERMES_CONF")); - if (options.sleep_ms == 0) { - options.sleep_ms = 3000; - } - - if (hermes->IsApplicationCore()) { - // Optimize reads - // Fill hierarchy - // Delete all RAM Blobs - // BORG moves BB Blobs to RAM - // Read all BB Blobs at RAM BW - - using namespace hermes; // NOLINT(*) - - int rank = hermes->GetProcessRank(); - const int kNumRanks = hermes->GetNumProcesses(); - // const size_t kTotalBytes = kNumRanks * options.blob_size * options.iters; - MetadataManager *mdm = GetMetadataManagerFromContext(&hermes->context_); - std::vector targets(mdm->node_targets.length); - - for (u16 i = 0; i < mdm->node_targets.length; ++i) { - targets[i] = {1, i, i}; - } - - GlobalSystemViewState *gsvs = GetGlobalSystemViewState(&hermes->context_); - f32 ram_min_threshold = gsvs->bo_capacity_thresholds[0].min; - f32 nvme_min_threshold = gsvs->bo_capacity_thresholds[1].min; - - std::vector capacities = - GetRemainingTargetCapacities(&hermes->context_, &hermes->rpc_, targets); - - // See how many blobs we can fit in each Target - std::vector blobs_per_target(capacities.size()); - for (size_t i = 0; i < blobs_per_target.size(); ++i) { - blobs_per_target[i] = capacities[i] / options.blob_size; - } - - hermes::testing::Timer timer; - hapi::Context ctx; - // Disable swapping of Blobs - ctx.disable_swap = true; - ctx.policy = hapi::PlacementPolicy::kMinimizeIoTime; - - std::string bkt_name = __func__ + std::to_string(rank); - hapi::Bucket bkt(bkt_name, hermes, ctx); - - // MinIoTime with retry - hermes::testing::Timer put_timer; - size_t failed_puts = 0; - size_t retries = 0; - - // Fill hierarchy - for (size_t target_idx = 0; target_idx < blobs_per_target.size(); - ++target_idx) { - for (int i = 0; i < blobs_per_target[target_idx]; ++i) { - std::string blob_name = (std::to_string(rank) + "_" - + std::to_string(target_idx) + "_" - + std::to_string(i)); - hapi::Blob blob(options.blob_size, i % 255); - - hapi::Status status; - int consecutive_fails = 0; - - while (!((status = bkt.Put(blob_name, blob)).Succeeded())) { - retries++; - if (++consecutive_fails > 10) { - failed_puts++; - break; - } - } - } - hermes->AppBarrier(); - } - - Assert(failed_puts == 0); - if (options.verbose) { - std::cout << "Rank " << rank << " failed puts: " << failed_puts << "\n"; - std::cout << "Rank " << rank << " Put retries: " << retries << "\n"; - } - - // Delete all RAM and NVMe Blobs - for (size_t j = 0; j < blobs_per_target.size() - 1; ++j) { - for (int i = 0; i < blobs_per_target[j]; ++i) { - std::string blob_name = (std::to_string(rank) + "_" - + std::to_string(j) + "_" - + std::to_string(i)); - Assert(bkt.DeleteBlob(blob_name).Succeeded()); - } - } - - // Give the BORG time to move BB Blobs to RAM and NVMe - std::this_thread::sleep_for(std::chrono::milliseconds(options.sleep_ms)); - - // Read all BB Blobs at RAM and NVMe BW - const int kBbIndex = 2; - - int blobs_to_read = blobs_per_target[kBbIndex]; - if (ram_min_threshold > 0) { - blobs_to_read = (ram_min_threshold * blobs_per_target[0] + - nvme_min_threshold * blobs_per_target[1]); - } - int stopping_index = blobs_per_target[kBbIndex] - blobs_to_read; - for (int i = blobs_per_target[kBbIndex] - 1; i > stopping_index; --i) { - std::string blob_name = (std::to_string(rank) + "_" - + std::to_string(kBbIndex) + "_" - + std::to_string(i)); - - hapi::Blob blob(options.blob_size); - timer.resumeTime(); - Assert(bkt.Get(blob_name, blob) == options.blob_size); - timer.pauseTime(); - - // Verify - hapi::Blob expected_blob(options.blob_size, i % 255); - Assert(blob == expected_blob); - } - - if (!hermes->IsFirstRankOnNode()) { - bkt.Release(); - } - hermes->AppBarrier(); - if (hermes->IsFirstRankOnNode()) { - bkt.Destroy(); - } - hermes->AppBarrier(); - - MPI_Comm *comm = (MPI_Comm *)hermes->GetAppCommunicator(); - size_t bytes_read = blobs_per_target[kBbIndex] * options.blob_size; - double total_mb = bytes_read / 1024.0 / 1024.0; - double bandwidth = GetBandwidth(timer.getElapsedTime(), total_mb, *comm, - kNumRanks); - - if (hermes->IsFirstRankOnNode()) { - std::cout << bandwidth << "," << kNumRanks << "," << options.use_borg - << "," << options.sleep_ms << "\n"; - } - } - - hermes->Finalize(); -} - -static void Verify(const Options &options) { - int my_rank; - int comm_size; - MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); - MPI_Comm_size(MPI_COMM_WORLD, &comm_size); - - const size_t kAppCores = comm_size - 1; - const size_t kTotalBytes = kAppCores * options.iters * options.blob_size; - if (my_rank == 0) { - std::vector data(kTotalBytes); - - if (options.verbose) { - std::cout << "Verifying data\n"; - } - - FILE *f = fopen(options.output_filename, "r"); - Assert(f); - Assert(fseek(f, 0L, SEEK_END) == 0); - size_t file_size = ftell(f); - Assert(file_size == kTotalBytes); - Assert(fseek(f, 0L, SEEK_SET) == 0); - size_t result = fread(data.data(), kTotalBytes, 1, f); - Assert(result == 1); - - for (size_t rank = 0; rank < kAppCores; ++rank) { - for (int iter = 0; iter < options.iters; ++iter) { - for (size_t byte = 0; byte < options.blob_size; ++byte) { - Assert(data[(rank * options.iters * options.blob_size) + - (iter * options.blob_size) + byte] == iter % 255); - } - } - } - } -} - -static void DebugBreak() { - int gdb_iii = 0; - char gdb_DEBUG_hostname[256]; - gethostname(gdb_DEBUG_hostname, sizeof(gdb_DEBUG_hostname)); - printf("PID %d on %s ready for attach\n", getpid(), gdb_DEBUG_hostname); - fflush(stdout); - while (0 == gdb_iii) - sleep(5); -} - -int main(int argc, char *argv[]) { - Options options = HandleArgs(argc, argv); - - int mpi_threads_provided; - MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &mpi_threads_provided); - if (mpi_threads_provided < MPI_THREAD_MULTIPLE) { - fprintf(stderr, "Didn't receive appropriate MPI threading specification\n"); - return 1; - } - - if (options.debug) { - DebugBreak(); - } - - if (options.write_only) { - WriteOnlyWorkload(options); - } - if (options.mixed) { - OptimizeReads(options); - } - if (options.verify) { - Verify(options); - } - - MPI_Finalize(); - - return 0; -} diff --git a/benchmarks/dpe_bench.cc b/benchmarks/dpe_bench.cc deleted file mode 100644 index 08037d4ae..000000000 --- a/benchmarks/dpe_bench.cc +++ /dev/null @@ -1,169 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include -#include - -#include "hermes.h" -#include "utils.h" -#include "test_utils.h" -#include "data_placement_engine_factory.h" - -/* example usage: ./bin/dpe_bench -m -s 4096 */ - -using namespace hermes; // NOLINT(*) -using std::chrono::time_point; -const auto now = std::chrono::high_resolution_clock::now; - -const u64 dpe_total_targets = 10; -const size_t dpe_total_num_blobs = 10; -const size_t dpe_total_blob_size = GIGABYTES(10); -const size_t kDefaultBlobSize = KILOBYTES(4); - -void PrintUsage(char *program) { - fprintf(stderr, "Usage %s [-r]\n", program); - fprintf(stderr, " -m\n"); - fprintf(stderr, " Use Random policy (default).\n"); - fprintf(stderr, " -n\n"); - fprintf(stderr, " Use RoundRobin policy.\n"); - fprintf(stderr, " -o\n"); - fprintf(stderr, " Use MinimizeIoTime policy.\n"); - fprintf(stderr, " -r\n"); - fprintf(stderr, " Chooese blob size range.\n"); - fprintf(stderr, " s/S: Small blob range (0, 64KB].\n"); - fprintf(stderr, " m/M: Medium blob range (64KB, 1MB].\n"); - fprintf(stderr, " l/L: Large blob range (1MB, 4MB].\n"); - fprintf(stderr, " x/X: Xlarge blob range (4MB, 64MB].\n"); - fprintf(stderr, " h/H: Huge blob size is 1GB.\n"); - fprintf(stderr, " -s\n"); - fprintf(stderr, " Specify exact blob size.\n"); - fprintf(stderr, " Blob size option: 4KB, 64KB, 1MB, 4MB, 64MB.\n"); -} - -int main(int argc, char **argv) { - api::PlacementPolicy policy {api::PlacementPolicy::kRandom}; - bool fixed_total_num_blobs {true}, fixed_total_blob_size {false}; - int option = -1; - char *rvalue = NULL; - size_t each_blob_size = kDefaultBlobSize; - size_t total_placed_size; - double dpe_seconds; - api::Status result; - - while ((option = getopt(argc, argv, "mnor:s:")) != -1) { - switch (option) { - case 'm': - policy = api::PlacementPolicy::kRandom; - break; - case 'n': - policy = api::PlacementPolicy::kRoundRobin; - break; - case 'o': - policy = api::PlacementPolicy::kMinimizeIoTime; - break; - case 'r': - fixed_total_blob_size = true; - if (fixed_total_num_blobs) - fixed_total_num_blobs = false; - rvalue = optarg; - break; - case 's': - fixed_total_num_blobs = true; - each_blob_size = atoi(optarg); - break; - default: - PrintUsage(argv[0]); - policy = api::PlacementPolicy::kRandom; - fixed_total_blob_size = true; - each_blob_size = kDefaultBlobSize; - std::cout << "Using Random policy for data placement engine.\n" - << "Using fixed number of blobs of size 4KB for test.\n\n"; - } - } - - if (fixed_total_num_blobs && fixed_total_blob_size) { - std::cout << "DPE benchmark uses fixed total blob size\n" - << "or fixed total number of blbs.\n" - << "Use default fixed total number of blbs now\n\n"; - } - - std::vector blob_sizes; - if (fixed_total_blob_size) { - testing::BlobSizeRange blob_range; - - if (rvalue[0] == 's' || rvalue[0] == 'S') { - blob_range = testing::BlobSizeRange::kSmall; - } else if (rvalue[0] == 'm' || rvalue[0] == 'M') { - blob_range = testing::BlobSizeRange::kMedium; - } else if (rvalue[0] == 'l' || rvalue[0] == 'L') { - blob_range = testing::BlobSizeRange::kLarge; - } else if (rvalue[0] == 'x' || rvalue[0] == 'X') { - blob_range = testing::BlobSizeRange::kXLarge; - } else if (rvalue[0] == 'h' || rvalue[0] == 'H') { - blob_range = testing::BlobSizeRange::kHuge; - } else { - blob_range = testing::BlobSizeRange::kSmall; - std::cout << "No blob range is setup.\n" - << "Choose small blob size range (0, 64KB] to test.\n\n"; - } - - blob_sizes = testing::GenFixedTotalBlobSize(dpe_total_blob_size, - blob_range); - total_placed_size = dpe_total_blob_size; - } else { - blob_sizes.resize(dpe_total_blob_size); - fill(blob_sizes.begin(), blob_sizes.end(), each_blob_size); - total_placed_size = each_blob_size * dpe_total_num_blobs; - } - - testing::TargetViewState tgt_state = - testing::InitDeviceState(dpe_total_targets); - - assert(tgt_state.num_devices == dpe_total_targets); - - std::vector output_tmp, schemas; - std::vector targets = - testing::GetDefaultTargets(tgt_state.num_devices); - - api::Context ctx; - ctx.policy = policy; - std::cout << "DPE benchmark uses " << - api::PlacementPolicyConv::str(policy) << " placement.\n\n"; - time_point start_tm = now(); - auto dpe = DPEFactory().Get(policy); - dpe->bandwidths = tgt_state.bandwidth; - result = dpe->Placement(blob_sizes, tgt_state.bytes_available, - targets, ctx, output_tmp); - time_point end_tm = now(); - dpe_seconds = std::chrono::duration(end_tm - start_tm).count(); - - u64 placed_size {0}; - for (auto schema : output_tmp) { - placed_size += testing::UpdateDeviceState(schema, tgt_state); - } - Assert(placed_size == total_placed_size); - - // Aggregate placement schemas from the same target - if (result.Succeeded()) { - for (auto it = output_tmp.begin(); it != output_tmp.end(); ++it) { - PlacementSchema schema = AggregateBlobSchema((*it)); - assert(schema.size() > 0); - schemas.push_back(schema); - } - } - - std::cout << "Total DPE time: " << dpe_seconds << '\n'; - - return 0; -} diff --git a/benchmarks/mdm_bench.cc b/benchmarks/mdm_bench.cc deleted file mode 100644 index 6c9ab49f3..000000000 --- a/benchmarks/mdm_bench.cc +++ /dev/null @@ -1,253 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include - -#include - -#include - -#include "hermes.h" -#include "utils.h" -#include "metadata_management_internal.h" - -namespace hapi = hermes::api; -using std::chrono::time_point; -const auto now = std::chrono::high_resolution_clock::now; -const int kNumRequests = 512; -constexpr int sizeof_id = sizeof(hermes::BufferID); - -struct Options { - bool bench_local; - bool bench_remote; - bool bench_server_scalability; - char *config_file; -}; - -double GetAvgSeconds(time_point start, - time_point end, - hapi::Hermes *hermes, MPI_Comm comm) { - double local_seconds = std::chrono::duration(end - start).count(); - double total_seconds = 0; - MPI_Reduce(&local_seconds, &total_seconds, 1, MPI_DOUBLE, MPI_SUM, 0, comm); - double avg_seconds = total_seconds / hermes->GetNumProcesses(); - - return avg_seconds; -} - -void Run(int target_node, int rank, int comm_size, int num_requests, - MPI_Comm comm, hapi::Hermes *hermes) { - for (hermes::u32 num_bytes = 8; - num_bytes <= KILOBYTES(4); - num_bytes *= 2) { - int num_ids = num_bytes / sizeof_id; - - std::vector buffer_ids(num_ids); - for (int i = 0; i < num_ids; ++i) { - hermes::BufferID id = {}; - id.bits.node_id = target_node; - id.bits.header_index = i; - buffer_ids[i] = id; - } - - hermes::u32 id_list_offset = - hermes::AllocateBufferIdList(&hermes->context_, &hermes->rpc_, - target_node, buffer_ids); - - MPI_Barrier(comm); - - hermes::BlobId blob_id = {}; - blob_id.bits.node_id = target_node; - blob_id.bits.buffer_ids_offset = id_list_offset; - - time_point start_get = now(); - for (int j = 0; j < num_requests; ++j) { - std::vector ids = - hermes::GetBufferIdList(&hermes->context_, &hermes->rpc_, blob_id); - } - time_point end_get = now(); - MPI_Barrier(comm); - - FreeBufferIdList(&hermes->context_, &hermes->rpc_, blob_id); - - // TODO(chogan): Time 'put' and 'delete' once they are optimized. For now - // they are too slow so we just time 'get'. - double avg_get_seconds = GetAvgSeconds(start_get, end_get, hermes, comm); - - if (rank == 0) { - printf("Hermes,%d,%d,%d,%f\n", comm_size, hermes->comm_.num_nodes, - (int)num_bytes, num_requests / avg_get_seconds); - } - } -} - -void BenchLocal() { - hermes::Config config = {}; - hermes::InitDefaultConfig(&config); - config.capacities[0] = GIGABYTES(2); - config.arena_percentages[hermes::kArenaType_BufferPool] = 0.15; - config.arena_percentages[hermes::kArenaType_MetaData] = 0.74; - - std::shared_ptr hermes = hermes::InitHermes(&config); - - if (hermes->IsApplicationCore()) { - int app_rank = hermes->GetProcessRank(); - int app_size = hermes->GetNumProcesses(); - int target_node = hermes->rpc_.node_id; - - MPI_Comm *comm = (MPI_Comm *)hermes->GetAppCommunicator(); - Run(target_node, app_rank, app_size, kNumRequests, *comm, hermes.get()); - hermes->AppBarrier(); - } else { - // Hermes core. No user code. - } - hermes->Finalize(); -} - -void BenchRemote(const char *config_file) { - std::shared_ptr hermes = hapi::InitHermes(config_file); - - if (hermes->IsApplicationCore()) { - int app_rank = hermes->GetProcessRank(); - - MPI_Comm *app_comm = (MPI_Comm *)hermes->GetAppCommunicator(); - - // NOTE(chogan): Create a communicator for app ranks not on node 1 so that - // all requests are remote. - MPI_Comm client_comm; - MPI_Comm_split(*app_comm, hermes->rpc_.node_id != 1, app_rank, - &client_comm); - int client_comm_size; - int client_rank; - MPI_Comm_size(client_comm, &client_comm_size); - MPI_Comm_rank(client_comm, &client_rank); - - if (hermes->rpc_.node_id != 1) { - const int kTargetNode = 1; - Run(kTargetNode, client_rank, client_comm_size, kNumRequests, client_comm, - hermes.get()); - } - hermes->AppBarrier(); - } else { - // Hermes core. No user code here. - } - - hermes->Finalize(); -} - -void BenchServerScalability(const char *config_file) { - std::shared_ptr hermes = hapi::InitHermes(config_file); - - if (hermes->IsApplicationCore()) { - int app_rank = hermes->GetProcessRank(); - int app_size = hermes->GetNumProcesses(); - int num_nodes = hermes->comm_.num_nodes; - // NOTE(chogan): A node_id of 0 is the NULL node, so we add 1. - int target_node = (app_rank % num_nodes) + 1; - - if (app_rank == 0) { - printf("Library,Clients,Servers,BytesTransferred,Ops/sec\n"); - } - - MPI_Comm *comm = (MPI_Comm *)hermes->GetAppCommunicator(); - Run(target_node, app_rank, app_size, kNumRequests, *comm, hermes.get()); - hermes->AppBarrier(); - } else { - // Hermes core. No user code here. - } - - hermes->Finalize(); -} - -void PrintUsage(char *program) { - fprintf(stderr, "Usage: %s -[rsx] [-f config_file]\n", program); - fprintf(stderr, " -f\n"); - fprintf(stderr, " Name of configuration file.\n"); - fprintf(stderr, " -r\n"); - fprintf(stderr, " Bench remote operations only.\n"); - fprintf(stderr, " -s\n"); - fprintf(stderr, " Bench local performance on a single node.\n"); - fprintf(stderr, " -x\n"); - fprintf(stderr, " Bench server scalability.\n"); -} - -Options HandleArgs(int argc, char **argv) { - Options result = {}; - int option = -1; - - while ((option = getopt(argc, argv, "f:rsx")) != -1) { - switch (option) { - case 'f': { - result.config_file = optarg; - break; - } - case 'r': { - result.bench_remote = true; - break; - } - case 's': { - result.bench_local = true; - break; - } - case 'x': { - result.bench_server_scalability = true; - break; - } - default: - PrintUsage(argv[0]); - exit(1); - } - } - - if ((result.bench_remote || result.bench_server_scalability) && - !result.config_file) { - fprintf(stderr, "Remote configuration option -r requires a config file name" - "with the -f option.\n"); - exit(1); - } - - if (optind < argc) { - fprintf(stderr, "non-option ARGV-elements: "); - while (optind < argc) { - fprintf(stderr, "%s ", argv[optind++]); - } - fprintf(stderr, "\n"); - } - - return result; -} - -int main(int argc, char **argv) { - Options opts = HandleArgs(argc, argv); - - int mpi_threads_provided; - MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &mpi_threads_provided); - if (mpi_threads_provided < MPI_THREAD_MULTIPLE) { - fprintf(stderr, "Didn't receive appropriate MPI threading specification\n"); - return 1; - } - - if (opts.bench_local) { - BenchLocal(); - } - if (opts.bench_remote) { - BenchRemote(opts.config_file); - } - if (opts.bench_server_scalability) { - BenchServerScalability(opts.config_file); - } - - MPI_Finalize(); - - return 0; -} diff --git a/benchmarks/put_get_bench.cc b/benchmarks/put_get_bench.cc new file mode 100644 index 000000000..92ebc5f0e --- /dev/null +++ b/benchmarks/put_get_bench.cc @@ -0,0 +1,74 @@ +// +// Created by lukemartinlogan on 12/27/22. +// + +#include +#include +#include +#include "hermes.h" +#include "bucket.h" + +namespace hapi = hermes::api; +using Timer = labstor::HighResMonotonicTimer; + +void GatherTimes(Timer &t) { + MPI_Barrier(MPI_COMM_WORLD); + int nprocs, rank; + MPI_Comm_size(MPI_COMM_WORLD, &nprocs); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + double time = t.GetSec(), max; + MPI_Reduce(&time, &max, + 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); + if (rank == 0) { + std::cout << "Time (sec): " << max << std::endl; + } +} + +void PutTest(hapi::Hermes *hermes, + int rank, int blobs_per_rank, size_t blob_size) { + Timer t; + t.Resume(); + auto bkt = hermes->GetBucket("hello"); + hermes::api::Context ctx; + hermes::BlobId blob_id; + hermes::Blob blob(nullptr, blob_size); + for (size_t i = 0; i < blobs_per_rank; ++i) { + size_t blob_name_int = rank * blobs_per_rank + i; + std::string name = std::to_string(blob_name_int); + bkt->Put(name, std::move(blob), blob_id, ctx); + } + t.Pause(); + GatherTimes(t); +} + +void GetTest(hapi::Hermes *hermes, + int rank, int blobs_per_rank, size_t blob_size) { + Timer t; + t.Resume(); + auto bkt = hermes->GetBucket("hello"); + hermes::api::Context ctx; + hermes::BlobId blob_id; + hermes::Blob blob(nullptr, blob_size); + for (size_t i = 0; i < blobs_per_rank; ++i) { + size_t blob_name_int = rank * blobs_per_rank + i; + std::string name = std::to_string(blob_name_int); + hermes::Blob ret; + bkt->GetBlobId(name, blob_id, ctx); + bkt->Get(blob_id, ret, ctx); + } + t.Pause(); + GatherTimes(t); +} + +int main(int argc, char **argv) { + int rank; + MPI_Init(&argc, &argv); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + auto hermes = hapi::Hermes::Create(hermes::HermesType::kClient); + int blobs_per_rank = 1024; + size_t blob_size = KILOBYTES(64); + PutTest(hermes, rank, blobs_per_rank, blob_size); + GetTest(hermes, rank, blobs_per_rank, blob_size); + hermes->Finalize(); + MPI_Finalize(); +} \ No newline at end of file diff --git a/benchmarks/vpic_bench.cc b/benchmarks/vpic_bench.cc deleted file mode 100644 index b83a04969..000000000 --- a/benchmarks/vpic_bench.cc +++ /dev/null @@ -1,560 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "hermes.h" -#include "bucket.h" -#include "test_utils.h" - -namespace hapi = hermes::api; -using u8 = hermes::u8; -using std::chrono::duration; -const auto now = std::chrono::high_resolution_clock::now; - -const int kXdim = 64; - -const int kDefaultSleepSeconds = 0; -const size_t kDefaultDataSizeMB = 8; -const size_t kDefaultIoSizeMB = kDefaultDataSizeMB; -const char *kDefaultOutputPath = "./"; -const int kDefaultIterations = 1; -const char *kDefaultDpePolicy = "none"; -const bool kDefaultSharedBucket = true; -const bool kDefaultDoPosixIo = true; -const bool kDefaultDirectIo = false; -const bool kDefaultSync = false; -const bool kDefaultVerifyResults = false; - -struct Options { - size_t data_size_mb; - size_t io_size_mb; - int num_iterations; - int sleep_seconds; - std::string output_path; - std::string dpe_policy; - bool shared_bucket; - bool do_posix_io; - bool direct_io; - bool sync; - bool verify_results; -}; - -struct Timing { - double fopen_time; - double fwrite_time; - double fclose_time; - double compute_time; - double total_time; -}; - -void GetDefaultOptions(Options *options) { - options->sleep_seconds = kDefaultSleepSeconds; - options->data_size_mb = kDefaultDataSizeMB; - options->io_size_mb = kDefaultIoSizeMB; - options->output_path = kDefaultOutputPath; - options->num_iterations = kDefaultIterations; - options->dpe_policy = kDefaultDpePolicy; - options->shared_bucket = kDefaultSharedBucket; - options->do_posix_io = kDefaultDoPosixIo; - options->direct_io = kDefaultDirectIo; - options->sync = kDefaultSync; - options->verify_results = kDefaultVerifyResults; -} - -#define HERMES_BOOL_OPTION(var) (var) ? "true" : "false" - -void PrintUsage(char *program) { - fprintf(stderr, "Usage: %s [-bhiopx] \n", program); - fprintf(stderr, " -a (default %d)\n", kDefaultSleepSeconds); - fprintf(stderr, " The number of seconds to sleep between each loop\n" - " iteration to simulate computation.\n"); - fprintf(stderr, " -c \n"); - fprintf(stderr, " Path to a Hermes configuration file.\n"); - fprintf(stderr, " -d (default %s)\n", HERMES_BOOL_OPTION(kDefaultDirectIo)); - fprintf(stderr, " Boolean flag. Do POSIX I/O with O_DIRECT.\n"); - fprintf(stderr, " -f (default %s)\n", HERMES_BOOL_OPTION(kDefaultSync)); - fprintf(stderr, " Boolean flag. fflush and fsync after every write\n"); - fprintf(stderr, " -h\n"); - fprintf(stderr, " Print help\n"); - fprintf(stderr, " -i (default %d)\n", kDefaultIterations); - fprintf(stderr, " The number of times to run the VPIC I/O kernel.\n"); - fprintf(stderr, " The number of nodes (only required when -x is used)\n"); - fprintf(stderr, " -o (default %s)\n", kDefaultOutputPath); - fprintf(stderr, " The path to an output file, which will be called\n" - " 'vpic_.out\n"); - fprintf(stderr, " -p (default %zu)\n", kDefaultDataSizeMB); - fprintf(stderr, " The size of particle data in MiB for each variable.\n"); - fprintf(stderr, " -s (default %s)\n", - HERMES_BOOL_OPTION(kDefaultSharedBucket)); - fprintf(stderr, " Boolean flag. Whether to share a single Bucket or \n" - " give each rank its own Bucket\n"); - fprintf(stderr, " -t (default is the value of -p)\n"); - fprintf(stderr, " The size of each I/O. Must be a multiple of the total\n" - " data_size_mb (-p). I/O will be done in a loop with\n" - " io_size_mb/data_size_mb iterations\n"); - fprintf(stderr, " -v (default %s)\n", - HERMES_BOOL_OPTION(kDefaultVerifyResults)); - fprintf(stderr, " Boolean flag. If enabled, read the written results\n" - " and verify that they match what's expected.\n"); - fprintf(stderr, " -x (default %s)\n", HERMES_BOOL_OPTION(kDefaultDoPosixIo)); - fprintf(stderr, " Boolean flag. If enabled, POSIX I/O is performed\n" - " instead of going through Hermes.\n"); -} - -Options HandleArgs(int argc, char **argv) { - Options result = {}; - GetDefaultOptions(&result); - - bool io_size_provided = false; - int option = -1; - - while ((option = getopt(argc, argv, "a:dfhi:o:p:st:vx")) != -1) { - switch (option) { - case 'a': { - result.sleep_seconds = atoi(optarg); - break; - } - case 'd': { - result.direct_io = true; - break; - } - case 'f': { - result.sync = true; - break; - } - case 'h': { - PrintUsage(argv[0]); - exit(0); - } - case 'i': { - result.num_iterations = atoi(optarg); - break; - } - case 'o': { - result.output_path = optarg; - break; - } - case 'p': { - result.data_size_mb = (size_t)std::stoull(optarg); - break; - } - case 's': { - result.shared_bucket = false; - break; - } - case 't': { - result.io_size_mb = (size_t)std::stoull(optarg); - io_size_provided = true; - break; - } - case 'v': { - result.verify_results = true; - break; - } - case 'x': { - result.do_posix_io = false; - break; - } - default: { - PrintUsage(argv[0]); - exit(1); - } - } - } - - if (optind < argc) { - fprintf(stderr, "non-option ARGV-elements: "); - while (optind < argc) { - fprintf(stderr, "%s ", argv[optind++]); - } - fprintf(stderr, "\n"); - } - - if (!io_size_provided) { - result.io_size_mb = result.data_size_mb; - } - - if (MEGABYTES(result.data_size_mb) % MEGABYTES(result.io_size_mb) != 0) { - fprintf(stderr, - "io_size_mb (-t) must be a multiple of data_size_mb (-p)\n"); - exit(1); - } - - return result; -} - -static inline double uniform_random_number() { - return (((double)rand())/((double)(RAND_MAX))); -} - -static void DoFwrite(void *data, size_t size, FILE *f) { - size_t bytes_written = fwrite(data, 1, size, f); - CHECK_EQ(bytes_written, size); -} - -static void DoWrite(float *data, size_t size, int fd) { - ssize_t bytes_written = write(fd, data, size); - CHECK_EQ(bytes_written, size); -} - -#if 0 -static void InitParticles(const int x_dim, const int y_dim, const int z_dim, - std::vector &id1, std::vector &id2, - std::vector &x, std::vector &y, - std::vector &z, std::vector &px, - std::vector &py, std::vector &pz) { - size_t num_particles = id1.size(); - - std::iota(id1.begin(), id1.end(), 0); - - for (size_t i = 0; i < num_particles; ++i) { - id2[i] = id1[i] * 2; - } - - std::generate(x.begin(), x.end(), [&x_dim]() { - return uniform_random_number() * x_dim; - }); - - std::generate(y.begin(), y.end(), [&y_dim]() { - return uniform_random_number() * y_dim; - }); - - for (size_t i = 0; i < num_particles; ++i) { - z[i] = ((double)id1[i] / num_particles) * z_dim; - } - - std::generate(px.begin(), px.end(), [&x_dim]() { - return uniform_random_number() * x_dim; - }); - - std::generate(py.begin(), py.end(), [&y_dim]() { - return uniform_random_number() * y_dim; - }); - - for (size_t i = 0; i < num_particles; ++i) { - pz[i] = ((double)id2[i] / num_particles) * z_dim; - } -} -#endif - -double GetMPIAverage(double rank_seconds, int num_ranks, MPI_Comm comm) { - double total_secs = 0; - MPI_Reduce(&rank_seconds, &total_secs, 1, MPI_DOUBLE, MPI_SUM, 0, comm); - double result = total_secs / num_ranks; - - return result; -} - -double GetMPIAverage(double rank_seconds, int num_ranks, MPI_Comm *comm) { - double result = GetMPIAverage(rank_seconds, num_ranks, *comm); - - return result; -} - -#if 0 -double GetBandwidth(const Options &options, double total_elapsed, - MPI_Comm comm) { - double avg_total_seconds = GetMPIAverage(total_elapsed, 8, comm); - double total_mb = - options.data_size_mb * kDefaultNumVariables * options.num_iterations; - double result = total_mb / avg_total_seconds; - - return result; -} - -void RunHermesBench(Options &options, float *data) { - double bandwidth = 0; - std::shared_ptr hermes = nullptr; - - if (options.config_path.size() != 0) { - hermes = hapi::InitHermes(options.config_path.c_str()); - } else { - hermes::Config config = {}; - hermes::InitDefaultConfig(&config); - config.num_devices = 1; - config.num_targets = 1; - config.capacities[0] = 128 * 1024 * 1024; - config.system_view_state_update_interval_ms = 500; - - hermes = hermes::InitHermes(&config); - } - - if (hermes->IsApplicationCore()) { - int my_rank = hermes->GetProcessRank(); - MPI_Comm *comm = (MPI_Comm *)hermes->GetAppCommunicator(); - options.num_nodes = hermes->rpc_.num_nodes; - - std::string bucket_name = "vpic_"; - - if (options.shared_bucket) { - bucket_name += "shared"; - } else { - bucket_name += std::to_string(my_rank); - } - - std::string blob_name = "data_" + std::to_string(my_rank); - size_t total_bytes = MEGABYTES(options.data_size_mb); - - constexpr int kNumPolicies = 3; - - const std::array policies = { - hapi::PlacementPolicy::kRandom, - hapi::PlacementPolicy::kRoundRobin, - hapi::PlacementPolicy::kMinimizeIoTime - }; - - const std::array policy_strings = { - "random", - "round_robin", - "minimize_io_time" - }; - - for (int p = 0; p < kNumPolicies; ++p) { - hermes::testing::Timer timer; - hapi::Context ctx; - ctx.policy = policies[p]; - options.dpe_policy = policy_strings[p]; - - hapi::Bucket bucket(bucket_name, hermes, ctx); - - hermes->AppBarrier(); - - for (int i = 0; i < options.num_iterations; ++i) { - timer.resumeTime(); - CHECK(bucket.Put(blob_name, (u8*)data, total_bytes).Succeeded()); - timer.pauseTime(); - - // NOTE(chogan): Simulate computation and let SystemViewState update - std::this_thread::sleep_for(std::chrono::duration(500)); - - // TODO(chogan): Investigate crash when these barriers aren't here - hermes->AppBarrier(); - CHECK(bucket.DeleteBlob(blob_name).Succeeded()); - hermes->AppBarrier(); - } - - hermes->AppBarrier(); - - if (options.shared_bucket) { - if (my_rank != 0) { - bucket.Release(); - } - hermes->AppBarrier(); - if (my_rank == 0) { - bucket.Destroy(); - } - } else { - // TODO(chogan): Investigate whey refcount is sometimes > 1 - bucket.Destroy(); - } - - bandwidth = GetBandwidth(options, timer.getElapsedTime(), *comm); - - if (my_rank == 0) { - std::string buffering = "hermes"; - PrintResults(options, bandwidth, buffering); - } - hermes->AppBarrier(); - } - } else { - // Hermes core. No user code. - } - - hermes->Finalize(); -} -#endif - -void PrintResults(const Options &options, const Timing &timing, - double bandwidth) { - double compute_percentage = timing.compute_time / timing.total_time; - printf("%zu,%zu,%f,%f,%f,%f,%f,%f,%f\n", options.data_size_mb, - options.io_size_mb, timing.fopen_time, timing.fwrite_time, - timing.fclose_time, timing.total_time, timing.compute_time, - bandwidth, compute_percentage); -} - -std::string GetOutputPath(const std::string &output_path, int rank) { - std::string output_file = "vpic_posix_" + std::to_string(rank) + ".out"; - int last_char_index = output_path.size() > 0 ? output_path.size() - 1 : 0; - std::string maybe_slash = output_path[last_char_index] == '/' ? "" : "/"; - std::string result = output_path + maybe_slash + output_file; - - return result; -} - -Timing RunPosixBench(Options &options, float *x, int rank) { - Timing result = {}; - - hermes::testing::Timer fopen_timer; - hermes::testing::Timer fwrite_timer; - hermes::testing::Timer fclose_timer; - hermes::testing::Timer compute_timer; - hermes::testing::Timer timer; - - for (int i = 0; i < options.num_iterations; ++i) { - std::string output_path = GetOutputPath(options.output_path, rank); - - if (options.direct_io) { - fopen_timer.resumeTime(); - int fd = open(output_path.c_str(), - O_WRONLY | O_CREAT | O_TRUNC | O_DIRECT | O_SYNC, - S_IRUSR | S_IWUSR); - fopen_timer.pauseTime(); - MPI_Barrier(MPI_COMM_WORLD); - - CHECK_GT(fd, 0); - fwrite_timer.resumeTime(); - DoWrite(x, MEGABYTES(options.data_size_mb), fd); - fwrite_timer.pauseTime(); - MPI_Barrier(MPI_COMM_WORLD); - - fclose_timer.resumeTime(); - CHECK_EQ(close(fd), 0); - fclose_timer.pauseTime(); - MPI_Barrier(MPI_COMM_WORLD); - } else { - fopen_timer.resumeTime(); - FILE *f = fopen(output_path.c_str(), "w"); - fopen_timer.pauseTime(); - CHECK(f); - MPI_Barrier(MPI_COMM_WORLD); - - size_t num_ios = options.data_size_mb / options.io_size_mb; - size_t byte_offset = 0; - size_t byte_increment = MEGABYTES(options.data_size_mb) / num_ios; - - for (size_t iter = 0; iter < num_ios; ++iter) { - auto sleep_seconds = std::chrono::seconds(options.sleep_seconds); - compute_timer.resumeTime(); - std::this_thread::sleep_for(sleep_seconds); - compute_timer.pauseTime(); - - fwrite_timer.resumeTime(); - void *write_start = (hermes::u8 *)x + byte_offset; - DoFwrite(write_start, byte_increment, f); - - if (options.sync) { - CHECK_EQ(fflush(f), 0); - CHECK_EQ(fsync(fileno(f)), 0); - } - fwrite_timer.pauseTime(); - byte_offset += byte_increment; - MPI_Barrier(MPI_COMM_WORLD); - } - - fclose_timer.resumeTime(); - CHECK_EQ(fclose(f), 0); - fclose_timer.pauseTime(); - MPI_Barrier(MPI_COMM_WORLD); - } - } - - result.fopen_time = fopen_timer.getElapsedTime(); - result.fwrite_time = fwrite_timer.getElapsedTime(); - result.fclose_time = fclose_timer.getElapsedTime(); - result.compute_time = compute_timer.getElapsedTime(); - result.total_time = timer.getElapsedTime(); - - return result; -} - -void CheckResults(float *data, size_t num_elements, - const std::string &results_base, int rank) { - std::string results_path = GetOutputPath(results_base, rank); - - FILE *f = fopen(results_path.c_str(), "r"); - CHECK(f); - - std::vector read_data(num_elements); - size_t num_bytes = num_elements * sizeof(float); - size_t bytes_read = fread(read_data.data(), 1, num_bytes, f); - Assert(bytes_read == num_bytes); - - for (size_t i = 0; i < num_elements; ++i) { - Assert(data[i] == read_data[i]); - } - - CHECK_EQ(fclose(f), 0); -} - -int main(int argc, char* argv[]) { - Options options = HandleArgs(argc, argv); - - MPI_Init(&argc, &argv); - - int rank = 0; - int comm_size = 0; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &comm_size); - - size_t num_elements = MEGABYTES(options.data_size_mb) / sizeof(float); - const int kSectorSize = 512; - float *data = (float *)aligned_alloc(kSectorSize, - num_elements * sizeof(float)); - - for (size_t i = 0; i < num_elements; ++i) { - data[i] = uniform_random_number() * kXdim; - } - - Timing local_results = {}; - - if (options.do_posix_io) { - hermes::testing::Timer timer; - timer.resumeTime(); - local_results = RunPosixBench(options, data, rank); - local_results.total_time = timer.pauseTime(); - } else { - // RunHermesBench(options, data); - } - - if (options.verify_results) { - CheckResults(data, num_elements, options.output_path, rank); - } - - Timing combined_results = {}; - MPI_Reduce(&local_results.total_time, &combined_results.total_time, 1, - MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); - MPI_Reduce(&local_results.fwrite_time, &combined_results.fwrite_time, 1, - MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); - MPI_Reduce(&local_results.fopen_time, &combined_results.fopen_time, 1, - MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); - MPI_Reduce(&local_results.fclose_time, &combined_results.fclose_time, 1, - MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); - MPI_Reduce(&local_results.compute_time, &combined_results.compute_time, 1, - MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); - - if (rank == 0) { - double total_mb = options.data_size_mb * options.num_iterations * comm_size; - double bandwidth_mbps = total_mb / combined_results.total_time; - PrintResults(options, combined_results, bandwidth_mbps); - } - - free(data); - - MPI_Finalize(); - - return 0; -} diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 358189dbb..ed7b1bc77 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -28,6 +28,17 @@ void Bucket::Rename(std::string new_bkt_name) { void Bucket::Destroy(std::string blob_name) { } +/** + * Get the id of a blob from the blob name + * */ +Status Bucket::GetBlobId(std::string blob_name, + BlobId &blob_id, Context &ctx) { + lipc::string blob_name_l(blob_name); + blob_id = mdm_->GetBlobId(GetId(), blob_name_l); + return Status(); +} + + /** * Put \a blob_id Blob into the bucket * */ @@ -43,8 +54,8 @@ Status Bucket::Put(std::string blob_name, Blob blob, for (auto &schema : schemas) { // TODO(llogan): Use RPC if-else, not Local auto buffers = bpm_->LocalAllocateAndSetBuffers(schema, blob); - blob_id = mdm_->LocalBucketPutBlob(id_, - lipc::string(blob_name), blob, buffers); + blob_id = mdm_->LocalBucketPutBlob(id_, lipc::string(blob_name), + blob, buffers); } } diff --git a/src/api/hermes.cc b/src/api/hermes.cc index bcdb231fd..dd34e29ee 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -108,7 +108,7 @@ void Hermes::InitSharedMemory() { lipc::MemoryManager::kDefaultBackendSize, server_config_.shmem_name_); main_alloc_ = - mem_mngr->CreateAllocator(lipc::AllocatorType::kMultiPageAllocator, + mem_mngr->CreateAllocator(lipc::AllocatorType::kStackAllocator, server_config_.shmem_name_, main_alloc_id, sizeof(HermesShmHeader)); header_ = main_alloc_->GetCustomHeader(); diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 184619066..18101254b 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -55,18 +55,18 @@ BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, Blob &blob) { auto &alloc = (*target_allocs_)[plcmnt.tid_.GetDeviceId()]; BufferInfo info; info.t_off_ = alloc.cur_off_; + alloc.cur_off_ += plcmnt.size_; // NOTE(llogan): allocate emulation info.t_size_ = plcmnt.size_; info.blob_off_ = blob_off_; info.blob_size_ = plcmnt.size_; info.tid_ = plcmnt.tid_; - alloc.cur_off_ += plcmnt.size_; buffers.emplace_back(info); borg_->LocalPlaceBlobInBuffers(blob, buffers); mdm_->LocalUpdateTargetCapacity(info.tid_, static_cast(info.t_size_)); blob_off_ += plcmnt.size_; } - return buffers; + return std::move(buffers); } /** diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index d2b2c2143..250385284 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -206,8 +206,8 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, BlobInfo info; info.bkt_id_ = bkt_id; info.name_ = lipc::make_mptr(std::move(internal_blob_name)); - info.buffers_ = lipc::make_mptr>( - std::move(buffers)); + info.buffers_ = lipc::make_mptr>(buffers); + auto &buffers = *info.buffers_; BlobInfoShmHeader hdr; info.shm_serialize(hdr); blob_map_->emplace(blob_id, std::move(hdr)); @@ -216,7 +216,7 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, auto iter = blob_map_->find(blob_id); BlobInfoShmHeader &hdr = (*iter).val_.get_ref(); BlobInfo info(hdr); - *(info.buffers_) = std::move(buffers); + *(info.buffers_) = buffers; info.shm_serialize(hdr); (*iter).val_ = std::move(hdr); } @@ -234,7 +234,8 @@ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { auto iter = blob_map_->find(blob_id); BlobInfoShmHeader &hdr = (*iter).val_.get_ref(); BlobInfo info(hdr); - return borg_->LocalReadBlobFromBuffers(*info.buffers_); + auto &buffers = *info.buffers_; + return borg_->LocalReadBlobFromBuffers(buffers); } /** @@ -246,6 +247,11 @@ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, lipc::charbuf &blob_name) { lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); + auto iter = blob_id_map_->find(internal_blob_name); + if (iter == blob_id_map_->end()) { + return BlobId::GetNull(); + } + return (*iter).val_; } /** diff --git a/src/metadata_types.h b/src/metadata_types.h index 0dcbded19..53e009fea 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -46,6 +46,35 @@ struct BufferInfo { size_t blob_off, size_t blob_size) : tid_(tid), t_off_(t_off), t_size_(t_size), blob_off_(blob_off), blob_size_(blob_size){} + + /** Copy constructor */ + BufferInfo(const BufferInfo &other) { + Copy(other); + } + + /** Move constructor */ + BufferInfo(BufferInfo &&other) { + Copy(other); + } + + /** Copy assignment */ + BufferInfo& operator=(const BufferInfo &other) { + Copy(other); + } + + /** Move assignment */ + BufferInfo& operator=(BufferInfo &&other) { + Copy(other); + } + + /** Performs move/copy */ + void Copy(const BufferInfo &other) { + tid_ = other.tid_; + t_off_ = other.t_off_; + t_size_ = other.t_size_; + blob_off_ = other.blob_off_; + blob_size_ = other.blob_size_; + } }; /** Represents BlobInfo in shared memory */ @@ -80,6 +109,7 @@ struct BlobInfoShmHeader { /** Blob metadata */ struct BlobInfo { + public: /// The bucket containing the blob BucketId bkt_id_; /// The name of the blob @@ -100,6 +130,7 @@ struct BlobInfo { } void shm_deserialize(BlobInfoShmHeader &ar) { + bkt_id_ = ar.bkt_id_; name_ << ar.name_ar_; buffers_ << ar.buffers_ar_; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bc90c2948..99bfedb93 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,7 +11,7 @@ include_directories( #------------------------------------------------------------------------------ # API tests #------------------------------------------------------------------------------ -set(API_TESTS test_rpc) +set(API_TESTS test_rpc test_put_get) foreach(program ${API_TESTS}) add_executable(${program} ${program}.cc) diff --git a/test/test_put_get.cc b/test/test_put_get.cc new file mode 100644 index 000000000..b4bc16a0f --- /dev/null +++ b/test/test_put_get.cc @@ -0,0 +1,76 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include + +#include +#include +#include "hermes.h" +#include "bucket.h" + +#include "verify_buffer.h" + +namespace hapi = hermes::api; + +void TestManyPuts(hapi::Hermes *hermes) { + auto bkt = hermes->GetBucket("hello"); + int num_blobs = 16; + size_t blob_size = KILOBYTES(1); + hermes::api::Context ctx; + hermes::BlobId blob_id; + + for (size_t i = 0; i < num_blobs; ++i) { + hermes::Blob blob(nullptr, blob_size); + std::string name = std::to_string(i); + char nonce = i % 256; + memset(blob.data_mutable(), nonce, blob_size); + bkt->Put(name, std::move(blob), blob_id, ctx); + } + + for (size_t i = 0; i < num_blobs; ++i) { + std::string name = std::to_string(i); + char nonce = i % 256; + hermes::Blob blob; + bkt->GetBlobId(name, blob_id, ctx); + bkt->Get(blob_id, blob, ctx); + assert(blob.size() == blob_size); + assert(VerifyBuffer(blob.data(), blob_size, nonce)); + } +} + +void TestBlobOverride(hapi::Hermes *hermes) { + auto bkt = hermes->GetBucket("hello"); + auto bkt2 = hermes->GetBucket("hello"); + hermes::api::Context ctx; + hermes::BlobId blob_id; + hermes::Blob blob(nullptr, 1024); + for (size_t i = 0; i < 1024; ++i) { + memset(blob.data_mutable(), 10, 1024); + bkt2->Put("0", std::move(blob), blob_id, ctx); + hermes::Blob ret; + bkt->Get(blob_id, ret, ctx); + assert(ret.size() == 1024); + assert(VerifyBuffer(ret.data(), 1024, 10)); + } +} + +int main(int argc, char* argv[]) { + MPI_Init(&argc, &argv); + auto hermes = hapi::Hermes::Create(hermes::HermesType::kClient); + + TestManyPuts(hermes); + + hermes->Finalize(); + MPI_Finalize(); + return 0; +} \ No newline at end of file diff --git a/test/test_rpc.cc b/test/test_rpc.cc index 01a2eb58d..23be02e20 100644 --- a/test/test_rpc.cc +++ b/test/test_rpc.cc @@ -31,7 +31,7 @@ int main(int argc, char* argv[]) { hermes::api::Context ctx; hermes::BlobId blob_id; hermes::Blob blob(nullptr, 1024); - for (size_t i = 0; i < 2; ++i) { + for (size_t i = 0; i < 1024; ++i) { memset(blob.data_mutable(), 10, 1024); bkt2->Put("0", std::move(blob), blob_id, ctx); hermes::Blob ret; From 58fa950e165c467ca22d6e294512702557b806ef Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 28 Dec 2022 00:53:17 -0600 Subject: [PATCH 081/511] Fix a few default values in Hermes config --- config/hermes_server_default.yaml | 8 ++++---- src/config.h | 2 +- src/config_server.cc | 5 +++++ src/config_server_default.h | 26 +++++++++++++------------- src/io_clients/posix.h | 1 + test/test_put_get.cc | 4 ++-- 6 files changed, 26 insertions(+), 20 deletions(-) diff --git a/config/hermes_server_default.yaml b/config/hermes_server_default.yaml index 3f8b968bb..32d757a9d 100644 --- a/config/hermes_server_default.yaml +++ b/config/hermes_server_default.yaml @@ -34,7 +34,7 @@ devices: # For each device, indicate '1' if it is shared among nodes (e.g., burst # buffers), or '0' if it is per node (e.g., local NVMe). - is_shared_device: 0 + is_shared_device: false # For each device, the minimum and maximum percent capacity threshold at which # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause @@ -54,7 +54,7 @@ devices: slab_units: [ 1, 4, 16, 32 ] bandwidth: 1GBps latency: 600us - is_shared_device: 0 + is_shared_device: false borg_capacity_thresh: [ 0.0, 1.0 ] ssd: @@ -64,7 +64,7 @@ devices: slab_units: [ 1, 4, 16, 32 ] bandwidth: 500MBps latency: 1200us - is_shared_device: 0 + is_shared_device: false borg_capacity_thresh: [ 0.0, 1.0 ] pfs: @@ -74,7 +74,7 @@ devices: slab_units: [ 1, 4, 16, 32 ] bandwidth: 100MBps # Per-device bandwidth latency: 200ms - is_shared_device: 0 + is_shared_device: true borg_capacity_thresh: [ 0.0, 1.0 ] ### Define properties of RPCs diff --git a/src/config.h b/src/config.h index 66b9d38cf..83a9de58d 100644 --- a/src/config.h +++ b/src/config.h @@ -147,7 +147,7 @@ static size_t ParseSize(const std::string &size_text) { std::string suffix = ParseNumberSuffix(size_text); if (suffix.size() == 0) { return size; - } else if (suffix[0] == 'k' || suffix[0] == 'k') { + } else if (suffix[0] == 'k' || suffix[0] == 'K') { return KILOBYTES(size); } else if (suffix[0] == 'm' || suffix[0] == 'M') { return MEGABYTES(size); diff --git a/src/config_server.cc b/src/config_server.cc index 6c516e80f..265a81416 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -27,6 +27,11 @@ void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { auto dev_info = device.second; dev.dev_name_ = lipc::string(device.first.as()); dev.mount_dir_ = lipc::string(dev_info["mount_point"].as()); + dev.borg_min_thresh_ = dev_info["borg_capacity_thresh"][0].as(); + dev.borg_max_thresh_ = dev_info["borg_capacity_thresh"][1].as(); + dev.is_shared_ = dev_info["is_shared_device"].as(); + dev.block_size_ = + ParseSize(dev_info["block_size"].as()); dev.capacity_ = ParseSize(dev_info["capacity"].as()); dev.bandwidth_ = diff --git a/src/config_server_default.h b/src/config_server_default.h index e85d88b00..1e054a364 100644 --- a/src/config_server_default.h +++ b/src/config_server_default.h @@ -37,15 +37,15 @@ const char* kServerDefaultConfigStr = "\n" " # For each device, indicate \'1\' if it is shared among nodes (e.g., burst\n" " # buffers), or \'0\' if it is per node (e.g., local NVMe).\n" -" is_shared_device: 0\n" -"\n" -" # For each device, the minimum and maximum percent capacity threshold at which\n" -" # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause\n" -" # the BufferOrganizer to move data to lower devices, making more room in faster\n" -" # devices (ideal for write-heavy workloads). Conversely, increasing the minimum\n" -" # threshold will cause data to be moved from slower devices into faster devices\n" -" # (ideal for read-heavy workloads). For example, a maximum capacity threshold of\n" -" # 0.8 would have the effect of always keeping 20% of the device\'s space free for\n" +" is_shared_device: false\n" +"\n" +" # For each device, the minimum and maximum percent capacity threshold at which\n" +" # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause\n" +" # the BufferOrganizer to move data to lower devices, making more room in faster\n" +" # devices (ideal for write-heavy workloads). Conversely, increasing the minimum\n" +" # threshold will cause data to be moved from slower devices into faster devices\n" +" # (ideal for read-heavy workloads). For example, a maximum capacity threshold of\n" +" # 0.8 would have the effect of always keeping 20% of the device\'s space free for\n" " # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure\n" " # that the device is always at least 30% occupied.\n" " borg_capacity_thresh: [0.0, 1.0]\n" @@ -57,7 +57,7 @@ const char* kServerDefaultConfigStr = " slab_units: [ 1, 4, 16, 32 ]\n" " bandwidth: 1GBps\n" " latency: 600us\n" -" is_shared_device: 0\n" +" is_shared_device: false\n" " borg_capacity_thresh: [ 0.0, 1.0 ]\n" "\n" " ssd:\n" @@ -67,7 +67,7 @@ const char* kServerDefaultConfigStr = " slab_units: [ 1, 4, 16, 32 ]\n" " bandwidth: 500MBps\n" " latency: 1200us\n" -" is_shared_device: 0\n" +" is_shared_device: false\n" " borg_capacity_thresh: [ 0.0, 1.0 ]\n" "\n" " pfs:\n" @@ -77,10 +77,10 @@ const char* kServerDefaultConfigStr = " slab_units: [ 1, 4, 16, 32 ]\n" " bandwidth: 100MBps # Per-device bandwidth\n" " latency: 200ms\n" -" is_shared_device: 0\n" +" is_shared_device: true\n" " borg_capacity_thresh: [ 0.0, 1.0 ]\n" "\n" -"### Define the network communication protocol\n" +"### Define properties of RPCs\n" "rpc:\n" " # A path to a file containing a list of server names, 1 per line. If your\n" " # servers are named according to a pattern (e.g., server-1, server-2, etc.),\n" diff --git a/src/io_clients/posix.h b/src/io_clients/posix.h index 670e08dd1..07e4b053c 100644 --- a/src/io_clients/posix.h +++ b/src/io_clients/posix.h @@ -30,6 +30,7 @@ class PosixIoClient : public IoClient { bool Write(DeviceInfo &dev_info, void *data, size_t off, size_t size) override { auto api = HERMES_POSIX_API; + std::string str = dev_info.mount_point_.str(); int fd = api->open(dev_info.mount_point_.c_str(), O_RDWR); if (fd < 0) { return false; } size_t count = api->pwrite(fd, data, size, off); diff --git a/test/test_put_get.cc b/test/test_put_get.cc index b4bc16a0f..64d27def9 100644 --- a/test/test_put_get.cc +++ b/test/test_put_get.cc @@ -24,8 +24,8 @@ namespace hapi = hermes::api; void TestManyPuts(hapi::Hermes *hermes) { auto bkt = hermes->GetBucket("hello"); - int num_blobs = 16; - size_t blob_size = KILOBYTES(1); + int num_blobs = 1; + size_t blob_size = MEGABYTES(150); hermes::api::Context ctx; hermes::BlobId blob_id; From 7827748d6177d428e5d01a9d7e3e862758b7e665 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Tue, 3 Jan 2023 02:16:54 -0600 Subject: [PATCH 082/511] Data structures compiling --- benchmarks/put_get_bench.cc | 4 +- src/buffer_organizer.cc | 34 +++++---- src/buffer_pool.cc | 7 +- src/config_server.cc | 17 +++-- src/config_server.h | 69 ++++++++++++++++-- src/data_structures.h | 15 ++++ src/dpe/minimize_io_time.cc | 15 ++-- src/io_clients/posix.h | 1 + src/io_clients/ram.h | 5 +- src/metadata_manager.cc | 60 +++++++--------- src/metadata_manager.h | 8 +-- src/metadata_types.h | 140 ++++++++++++++++++++++++++++++------ src/statuses.h | 1 + test/test_put_get.cc | 4 +- test/test_rpc.cc | 2 +- 15 files changed, 275 insertions(+), 107 deletions(-) diff --git a/benchmarks/put_get_bench.cc b/benchmarks/put_get_bench.cc index 92ebc5f0e..a2b2f04ee 100644 --- a/benchmarks/put_get_bench.cc +++ b/benchmarks/put_get_bench.cc @@ -31,7 +31,7 @@ void PutTest(hapi::Hermes *hermes, auto bkt = hermes->GetBucket("hello"); hermes::api::Context ctx; hermes::BlobId blob_id; - hermes::Blob blob(nullptr, blob_size); + hermes::Blob blob(blob_size); for (size_t i = 0; i < blobs_per_rank; ++i) { size_t blob_name_int = rank * blobs_per_rank + i; std::string name = std::to_string(blob_name_int); @@ -48,7 +48,7 @@ void GetTest(hapi::Hermes *hermes, auto bkt = hermes->GetBucket("hello"); hermes::api::Context ctx; hermes::BlobId blob_id; - hermes::Blob blob(nullptr, blob_size); + hermes::Blob blob(blob_size); for (size_t i = 0; i < blobs_per_rank; ++i) { size_t blob_name_int = rank * blobs_per_rank + i; std::string name = std::to_string(blob_name_int); diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 69a85afea..645546588 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -11,8 +11,8 @@ namespace hermes { static size_t SumBufferBlobSizes(lipc::vector &buffers) { size_t sum = 0; - for (auto &buffer : buffers) { - sum += buffer.blob_size_; + for (lipc::Ref buffer_ref : buffers) { + sum += (*buffer_ref).blob_size_; } return sum; } @@ -23,14 +23,15 @@ static size_t SumBufferBlobSizes(lipc::vector &buffers) { * */ void BufferOrganizer::shm_init() { mdm_ = &HERMES->mdm_; - for (auto &target : (*mdm_->targets_)) { - auto &dev_info = (*mdm_->devices_)[target.id_.GetDeviceId()]; + for (lipc::Ref target_ref : (*mdm_->targets_)) { + auto &target = *target_ref; + DeviceInfo &dev_info = *(*mdm_->devices_)[target.id_.GetDeviceId()]; if (dev_info.mount_dir_.size() == 0) { - dev_info.io_api_ = IoInterface::kRam; + dev_info.header_->io_api_ = IoInterface::kRam; } else { - dev_info.io_api_ = IoInterface::kPosix; + dev_info.header_->io_api_ = IoInterface::kPosix; } - auto io_client = IoClientFactory::Get(dev_info.io_api_); + auto io_client = IoClientFactory::Get(dev_info.header_->io_api_); io_client->Init(dev_info); } } @@ -47,16 +48,17 @@ void BufferOrganizer::shm_deserialize() { mdm_ = &HERMES->mdm_; } - /** Stores a blob into a set of buffers */ +/** Stores a blob into a set of buffers */ RPC void BufferOrganizer::LocalPlaceBlobInBuffers( Blob &blob, lipc::vector &buffers) { size_t blob_off = 0; - for (auto &buffer_info : buffers) { + for (lipc::Ref buffer_info_ref : buffers) { + BufferInfo &buffer_info = *buffer_info_ref; if (buffer_info.tid_.GetNodeId() != mdm_->rpc_->node_id_) { continue; } - auto &dev_info = (*mdm_->devices_)[buffer_info.tid_.GetDeviceId()]; - auto io_client = IoClientFactory::Get(dev_info.io_api_); + DeviceInfo &dev_info = *(*mdm_->devices_)[buffer_info.tid_.GetDeviceId()]; + auto io_client = IoClientFactory::Get(dev_info.header_->io_api_); bool ret = io_client->Write(dev_info, blob.data() + blob_off, buffer_info.t_off_, buffer_info.blob_size_); @@ -70,14 +72,16 @@ RPC void BufferOrganizer::LocalPlaceBlobInBuffers( /** Stores a blob into a set of buffers */ RPC Blob BufferOrganizer::LocalReadBlobFromBuffers( lipc::vector &buffers) { - Blob blob(nullptr, SumBufferBlobSizes(buffers)); + Blob blob(SumBufferBlobSizes(buffers)); size_t blob_off = 0; - for (auto &buffer_info : buffers) { + for (lipc::Ref buffer_info_ref : buffers) { + BufferInfo &buffer_info = *buffer_info_ref; if (buffer_info.tid_.GetNodeId() != mdm_->rpc_->node_id_) { continue; } - auto &dev_info = (*mdm_->devices_)[buffer_info.tid_.GetDeviceId()]; - auto io_client = IoClientFactory::Get(dev_info.io_api_); + auto dev_info_ref = (*mdm_->devices_)[buffer_info.tid_.GetDeviceId()]; + DeviceInfo &dev_info = *dev_info_ref; + auto io_client = IoClientFactory::Get(dev_info.header_->io_api_); bool ret = io_client->Read(dev_info, blob.data_mutable() + blob_off, buffer_info.t_off_, buffer_info.blob_size_); diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 18101254b..3129e81a1 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -16,7 +16,8 @@ namespace hermes { void BufferPool::shm_init(BufferPoolShmHeader *header) { mdm_ = &HERMES->mdm_; borg_ = &HERMES->borg_; - target_allocs_ = lipc::make_mptr>(nullptr); + target_allocs_ = lipc::make_mptr>( + HERMES->main_alloc_); target_allocs_->resize(mdm_->targets_->size()); shm_serialize(header); } @@ -45,14 +46,14 @@ void BufferPool::shm_deserialize(BufferPoolShmHeader *header) { * */ lipc::vector BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, Blob &blob) { - lipc::vector buffers(nullptr); + lipc::vector buffers(HERMES->main_alloc_); size_t blob_off_ = 0; for (auto plcmnt : schema.plcmnts_) { if (plcmnt.tid_.GetNodeId() != mdm_->rpc_->node_id_) { blob_off_ += plcmnt.size_; continue; } - auto &alloc = (*target_allocs_)[plcmnt.tid_.GetDeviceId()]; + BufferPoolAllocator &alloc = *(*target_allocs_)[plcmnt.tid_.GetDeviceId()]; BufferInfo info; info.t_off_ = alloc.cur_off_; alloc.cur_off_ += plcmnt.size_; // NOTE(llogan): allocate emulation diff --git a/src/config_server.cc b/src/config_server.cc index 265a81416..afb97ba90 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -27,16 +27,19 @@ void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { auto dev_info = device.second; dev.dev_name_ = lipc::string(device.first.as()); dev.mount_dir_ = lipc::string(dev_info["mount_point"].as()); - dev.borg_min_thresh_ = dev_info["borg_capacity_thresh"][0].as(); - dev.borg_max_thresh_ = dev_info["borg_capacity_thresh"][1].as(); - dev.is_shared_ = dev_info["is_shared_device"].as(); - dev.block_size_ = + dev.header_->borg_min_thresh_ = + dev_info["borg_capacity_thresh"][0].as(); + dev.header_->borg_max_thresh_ = + dev_info["borg_capacity_thresh"][1].as(); + dev.header_->is_shared_ = + dev_info["is_shared_device"].as(); + dev.header_->block_size_ = ParseSize(dev_info["block_size"].as()); - dev.capacity_ = + dev.header_->capacity_ = ParseSize(dev_info["capacity"].as()); - dev.bandwidth_ = + dev.header_->bandwidth_ = ParseSize(dev_info["bandwidth"].as()); - dev.latency_ = + dev.header_->latency_ = ParseLatency(dev_info["latency"].as()); ParseVector>( dev_info["slab_sizes"], dev.slab_sizes_); diff --git a/src/config_server.h b/src/config_server.h index aa3856417..0dafa42fc 100644 --- a/src/config_server.h +++ b/src/config_server.h @@ -17,22 +17,27 @@ enum class IoInterface { kPosix }; + +/** Forward declaration of DeviceInfo */ +class DeviceInfo; + /** - * Device information defined in server config + * DeviceInfo shared-memory representation * */ -struct DeviceInfo { +template<> +struct ShmHeader : public lipc::ShmBaseHeader { /** The human-readable name of the device */ - lipc::string dev_name_; + lipc::ShmArchive dev_name_; /** The I/O interface for the device */ IoInterface io_api_; /** The minimum transfer size of each device */ size_t block_size_; /** The unit of each slab, a multiple of the Device's block size */ - lipc::vector slab_sizes_; + lipc::ShmArchive> slab_sizes_; /** The directory the device is mounted on */ - lipc::string mount_dir_; + lipc::ShmArchive mount_dir_; /** The file to create on the device */ - lipc::string mount_point_; + lipc::ShmArchive mount_point_; /** Device capacity (bytes) */ size_t capacity_; /** Bandwidth of a device (MBps) */ @@ -45,6 +50,58 @@ struct DeviceInfo { f32 borg_min_thresh_, borg_max_thresh_; }; +/** + * Device information defined in server config + * */ +struct DeviceInfo : public SHM_CONTAINER(DeviceInfo) { + SHM_CONTAINER_TEMPLATE(DeviceInfo, DeviceInfo) + + /** The human-readable name of the device */ + lipc::string dev_name_; + /** The unit of each slab, a multiple of the Device's block size */ + lipc::vector slab_sizes_; + /** The directory the device is mounted on */ + lipc::string mount_dir_; + /** The file to create on the device */ + lipc::string mount_point_; + + void shm_init_main(lipc::ShmArchive *ar, + lipc::Allocator *alloc) { + shm_init_header(ar, alloc); + } + + void shm_destroy(bool destroy_header = true) { + dev_name_.SetDestructable(); + slab_sizes_.SetDestructable(); + mount_dir_.SetDestructable(); + mount_point_.SetDestructable(); + } + + void shm_serialize(lipc::ShmArchive &ar) const { + shm_serialize_header(ar.header_ptr_); + dev_name_ >> header_->dev_name_; + slab_sizes_ >> header_->slab_sizes_; + mount_dir_ >> header_->mount_dir_; + mount_point_ >> header_->mount_point_; + } + + void shm_deserialize(const lipc::ShmArchive &ar) { + shm_deserialize_header(ar.header_ptr_); + dev_name_ << header_->dev_name_; + slab_sizes_ << header_->slab_sizes_; + mount_dir_ << header_->mount_dir_; + mount_point_ << header_->mount_point_; + } + + void WeakMove(DeviceInfo &other) { + throw NOT_IMPLEMENTED; + } + + void StrongCopy(const DeviceInfo &other) { + throw NOT_IMPLEMENTED; + } +}; + /** * RPC information defined in server config * */ diff --git a/src/data_structures.h b/src/data_structures.h index dc989f579..8c8901d1e 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -23,4 +23,19 @@ using labstor::Mutex; #include #include +namespace hermes { +template +struct ShmHeader; +} // namespace hermes + +namespace hermes::api { +template +struct ShmHeader; +} // namespace hermes::api + +namespace hermes::config { +template +struct ShmHeader; +} // namespace hermes::config + #endif // HERMES_SRC_DATA_STRUCTURES_H_ diff --git a/src/dpe/minimize_io_time.cc b/src/dpe/minimize_io_time.cc index 886b7a27a..085933c88 100644 --- a/src/dpe/minimize_io_time.cc +++ b/src/dpe/minimize_io_time.cc @@ -61,8 +61,8 @@ Status MinimizeIoTime::Placement(const std::vector &blob_sizes, // Constraint #2: Capacity constraints for (size_t j = 0; j < num_targets; ++j) { double rem_cap_thresh = - static_cast(targets[j].rem_cap_) * (1 - minimum_remaining_capacity); - double est_rem_cap = capacity_change_threshold * targets[j].rem_cap_; + static_cast((*targets[j]).rem_cap_) * (1 - minimum_remaining_capacity); + double est_rem_cap = capacity_change_threshold * (*targets[j]).rem_cap_; double max_capacity = std::max({rem_cap_thresh, est_rem_cap}); if (max_capacity > 0) { lp.AddConstraint("rem_cap_", GLP_DB, 0.0, max_capacity); @@ -80,7 +80,8 @@ Status MinimizeIoTime::Placement(const std::vector &blob_sizes, for (size_t i = 0; i < num_blobs; ++i) { for (size_t j = 0; j < num_targets; ++j) { lp.SetObjectiveCoeff(var.Get(i, j), - static_cast(blob_sizes[i])/targets[j].bandwidth_); + static_cast(blob_sizes[i])/ + (*targets[j]).bandwidth_); } } @@ -120,7 +121,7 @@ Status MinimizeIoTime::Placement(const std::vector &blob_sizes, for (size_t j = 0; j < num_targets; ++j) { size_t io_to_target = vars_bytes[j]; if (io_to_target != 0) { - schema.AddSubPlacement(io_to_target, targets[j].id_); + schema.AddSubPlacement(io_to_target, (*targets[j]).id_); } } output.emplace_back(std::move(schema)); @@ -135,7 +136,7 @@ void MinimizeIoTime::PlaceBytes(size_t j, ssize_t bytes, PlaceBytes(j+1, bytes, vars_bytes, targets); return; } - ssize_t node_cap = static_cast(targets[j].rem_cap_); + ssize_t node_cap = static_cast((*targets[j]).rem_cap_); ssize_t req_bytes = static_cast(vars_bytes[j]); req_bytes += bytes; ssize_t io_diff = req_bytes - node_cap; @@ -159,12 +160,12 @@ void MinimizeIoTime::GetPlacementRatios(const lipc::vector &targets, // Total number of bytes remaining across all targets size_t total_bytes = 0; for (auto iter = targets.cbegin(); iter != targets.cend(); ++iter) { - total_bytes += (*iter).rem_cap_; + total_bytes += (**iter).rem_cap_; } double total = static_cast(total_bytes); // Get percentage of total capacity each target has for (size_t j = 0; j < targets.size() - 1; ++j) { - double target_cap = static_cast(targets[j].rem_cap_); + double target_cap = static_cast((*targets[j]).rem_cap_); double placement_ratio = target_cap / total; placement_ratios_.emplace_back(placement_ratio); } diff --git a/src/io_clients/posix.h b/src/io_clients/posix.h index 07e4b053c..39fed7b80 100644 --- a/src/io_clients/posix.h +++ b/src/io_clients/posix.h @@ -21,6 +21,7 @@ class PosixIoClient : public IoClient { auto api = HERMES_POSIX_API; dev_info.mount_point_ = dev_info.mount_dir_ + "/" + "slab_" + dev_info.dev_name_; + dev_info.mount_point_ >> dev_info.header_->mount_point_; int fd = api->open(dev_info.mount_point_.c_str(), O_TRUNC | O_CREAT, 0666); if (fd < 0) { return false; } api->close(fd); diff --git a/src/io_clients/ram.h b/src/io_clients/ram.h index e7e74c310..8ecb470a8 100644 --- a/src/io_clients/ram.h +++ b/src/io_clients/ram.h @@ -18,8 +18,9 @@ class RamIoClient : public IoClient { auto &hermes_header = HERMES->header_; auto &main_alloc = HERMES->main_alloc_; auto &server_config = HERMES->server_config_; - hermes_header->ram_tier_ = main_alloc->Allocate(dev_info.capacity_); - if (hermes_header->ram_tier_.is_null()) { + hermes_header->ram_tier_ = main_alloc-> + Allocate(dev_info.header_->capacity_); + if (hermes_header->ram_tier_.IsNull()) { LOG(FATAL) << BUFFER_POOL_OUT_OF_RAM.Msg() << std::endl; } return true; diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 250385284..bef2e70e6 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -20,17 +20,17 @@ void MetadataManager::shm_init(ServerConfig *config, header_->id_alloc_ = 1; // Create the metadata maps - blob_id_map_ = lipc::make_mptr(nullptr); - bkt_id_map_ = lipc::make_mptr(nullptr); - vbkt_id_map_ = lipc::make_mptr(nullptr); - blob_map_ = lipc::make_mptr(nullptr); - bkt_map_ = lipc::make_mptr(nullptr); - vbkt_map_ = lipc::make_mptr(nullptr); + blob_id_map_ = lipc::make_mptr(); + bkt_id_map_ = lipc::make_mptr(); + vbkt_id_map_ = lipc::make_mptr(); + blob_map_ = lipc::make_mptr(); + bkt_map_ = lipc::make_mptr(); + vbkt_map_ = lipc::make_mptr(); // Create the DeviceInfo vector devices_ = lipc::make_mptr>( - nullptr, HERMES->server_config_.devices_); - targets_ = lipc::make_mptr>(nullptr); + HERMES->server_config_.devices_); + targets_ = lipc::make_mptr>(); // Create the TargetInfo vector targets_->reserve(devices_->size()); @@ -38,10 +38,10 @@ void MetadataManager::shm_init(ServerConfig *config, for (auto &dev_info : config->devices_) { targets_->emplace_back( TargetId(rpc_->node_id_, dev_id, dev_id), - dev_info.capacity_, - dev_info.capacity_, - dev_info.bandwidth_, - dev_info.latency_); + dev_info.header_->capacity_, + dev_info.header_->capacity_, + dev_info.header_->bandwidth_, + dev_info.header_->latency_); ++dev_id; } @@ -109,17 +109,16 @@ BucketId MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { // Emplace bucket if it does not already exist if (bkt_id_map_->try_emplace(bkt_name, bkt_id)) { - BucketInfo info; + BucketInfo info(HERMES->main_alloc_); info.name_ = lipc::make_mptr(bkt_name); - BucketInfoShmHeader hdr; - info.name_ >> hdr.name_ar_; - bkt_map_->emplace(bkt_id, hdr); + info.name_ >> info.header_->name_ar_; + bkt_map_->emplace(bkt_id, info); } else { auto iter = bkt_id_map_->find(bkt_name); if (iter == bkt_id_map_->end()) { return BucketId::GetNull(); } - bkt_id = (*iter).val_; + bkt_id = *(*iter).val_; } return bkt_id; @@ -132,12 +131,11 @@ BucketId MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { * @RPC_CLASS_INSTANCE mdm * */ BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { - BucketId bkt_id; auto iter = bkt_id_map_->find(bkt_name); if (iter == bkt_id_map_->end()) { return BucketId::GetNull(); } - bkt_id = (*iter).val_; + BucketId bkt_id = *(*iter).val_; return bkt_id; } @@ -154,9 +152,8 @@ bool MetadataManager::LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id) { return false; } // Get the blob info - BlobInfoShmHeader &hdr = (*iter).val_.get_ref(); - BlobInfo info(hdr); - return info.bkt_id_ == bkt_id; + BlobInfo &blob_info = *(*iter).val_; + return blob_info.bkt_id_ == bkt_id; } /** @@ -207,18 +204,12 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, info.bkt_id_ = bkt_id; info.name_ = lipc::make_mptr(std::move(internal_blob_name)); info.buffers_ = lipc::make_mptr>(buffers); - auto &buffers = *info.buffers_; - BlobInfoShmHeader hdr; - info.shm_serialize(hdr); - blob_map_->emplace(blob_id, std::move(hdr)); + blob_map_->emplace(blob_id, info); } else { - blob_id = (*blob_id_map_)[internal_blob_name]; + blob_id = *(*blob_id_map_)[internal_blob_name]; auto iter = blob_map_->find(blob_id); - BlobInfoShmHeader &hdr = (*iter).val_.get_ref(); - BlobInfo info(hdr); + BlobInfo info(*(*iter).val_); *(info.buffers_) = buffers; - info.shm_serialize(hdr); - (*iter).val_ = std::move(hdr); } return blob_id; @@ -232,9 +223,8 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, * */ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { auto iter = blob_map_->find(blob_id); - BlobInfoShmHeader &hdr = (*iter).val_.get_ref(); - BlobInfo info(hdr); - auto &buffers = *info.buffers_; + BlobInfo &info = *(*iter).val_; + lipc::vector &buffers = *info.buffers_; return borg_->LocalReadBlobFromBuffers(buffers); } @@ -251,7 +241,7 @@ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, if (iter == blob_id_map_->end()) { return BlobId::GetNull(); } - return (*iter).val_; + return *(*iter).val_; } /** diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 57b0dea92..c7db45465 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -23,9 +23,9 @@ class BufferOrganizer; typedef lipc::unordered_map BLOB_ID_MAP_T; typedef lipc::unordered_map BKT_ID_MAP_T; typedef lipc::unordered_map VBKT_ID_MAP_T; -typedef lipc::unordered_map BLOB_MAP_T; -typedef lipc::unordered_map BKT_MAP_T; -typedef lipc::unordered_map VBKT_MAP_T; +typedef lipc::unordered_map BLOB_MAP_T; +typedef lipc::unordered_map BKT_MAP_T; +typedef lipc::unordered_map VBKT_MAP_T; /** * The SHM representation of the MetadataManager @@ -317,7 +317,7 @@ class MetadataManager { * Update the capacity of the target device * */ RPC void LocalUpdateTargetCapacity(TargetId tid, off64_t offset) { - auto &target = (*targets_)[tid.GetIndex()]; + TargetInfo &target = *(*targets_)[tid.GetIndex()]; target.rem_cap_ += offset; } diff --git a/src/metadata_types.h b/src/metadata_types.h index 53e009fea..f122cac58 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -11,6 +11,9 @@ namespace hermes { using api::Blob; +struct BucketInfo; /** Forward declaration of BucketInfo */ +struct BlobInfo; /** Forward declaration of BlobInfo */ +struct VBucketInfo; /** Forward declaration of VBucketInfo */ /** Device information required by other processes */ using config::DeviceInfo; @@ -65,6 +68,7 @@ struct BufferInfo { /** Move assignment */ BufferInfo& operator=(BufferInfo &&other) { Copy(other); + return *this; } /** Performs move/copy */ @@ -78,25 +82,26 @@ struct BufferInfo { }; /** Represents BlobInfo in shared memory */ -struct BlobInfoShmHeader { +template<> +struct ShmHeader : public lipc::ShmBaseHeader { BucketId bkt_id_; /**< The bucket containing the blob */ lipc::ShmArchive name_ar_; lipc::ShmArchive> buffers_ar_; RwLock rwlock_; - BlobInfoShmHeader() = default; + ShmHeader() = default; - BlobInfoShmHeader(const BlobInfoShmHeader &other) noexcept + ShmHeader(const ShmHeader &other) noexcept : bkt_id_(other.bkt_id_), name_ar_(other.name_ar_), buffers_ar_(other.buffers_ar_), rwlock_() {} - BlobInfoShmHeader(BlobInfoShmHeader &&other) noexcept + ShmHeader(ShmHeader &&other) noexcept : bkt_id_(std::move(other.bkt_id_)), name_ar_(std::move(other.name_ar_)), buffers_ar_(std::move(other.buffers_ar_)), rwlock_() {} - BlobInfoShmHeader& operator=(BlobInfoShmHeader &&other) { + ShmHeader& operator=(ShmHeader &&other) { if (this != &other) { bkt_id_ = std::move(other.bkt_id_); name_ar_ = std::move(other.name_ar_); @@ -108,7 +113,10 @@ struct BlobInfoShmHeader { }; /** Blob metadata */ -struct BlobInfo { +struct BlobInfo : public SHM_CONTAINER(BlobInfo){ + public: + SHM_CONTAINER_TEMPLATE(BlobInfo, BlobInfo); + public: /// The bucket containing the blob BucketId bkt_id_; @@ -119,43 +127,129 @@ struct BlobInfo { BlobInfo() = default; - BlobInfo(BlobInfoShmHeader &ar) { - shm_deserialize(ar); + void shm_init_main(lipc::ShmArchive *ar, + lipc::Allocator *alloc) { + shm_init_header(ar, alloc); } - void shm_serialize(BlobInfoShmHeader &ar) { - ar.bkt_id_ = bkt_id_; - name_ >> ar.name_ar_; - buffers_ >> ar.buffers_ar_; + void shm_destroy(bool destroy_header = true) { + SHM_DESTROY_DATA_START + SHM_DESTROY_DATA_END + SHM_DESTROY_END } - void shm_deserialize(BlobInfoShmHeader &ar) { - bkt_id_ = ar.bkt_id_; - name_ << ar.name_ar_; - buffers_ << ar.buffers_ar_; + void shm_serialize(lipc::ShmArchive &ar) const { + shm_serialize_header(ar.header_ptr_); + header_->bkt_id_ = bkt_id_; + name_ >> header_->name_ar_; + buffers_ >> header_->buffers_ar_; + } + + void shm_deserialize(const lipc::ShmArchive &ar) { + shm_deserialize_header(ar.header_ptr_); + bkt_id_ = header_->bkt_id_; + name_ << header_->name_ar_; + buffers_ << header_->buffers_ar_; + } + + void WeakMove(BlobInfo &other) { + throw NOT_IMPLEMENTED; + } + + void StrongCopy(const BlobInfo &other) { + throw NOT_IMPLEMENTED; } }; + /** Represents BucketInfo in shared memory */ -struct BucketInfoShmHeader { - lipc::ShmArchive> name_ar_; +template<> +struct ShmHeader : public lipc::ShmBaseHeader { + lipc::ShmArchive name_ar_; }; /** Metadata for a Bucket */ -struct BucketInfo { +struct BucketInfo : public SHM_CONTAINER(BucketInfo) { + public: + SHM_CONTAINER_TEMPLATE(BucketInfo, BucketInfo); + + public: lipc::mptr name_; + + public: + BucketInfo() = default; + + void shm_init_main(lipc::ShmArchive *ar, + lipc::Allocator *alloc) { + shm_init_header(ar, alloc); + } + + void shm_destroy(bool destroy_header = true) { + SHM_DESTROY_DATA_START + SHM_DESTROY_DATA_END + SHM_DESTROY_END + } + + void shm_serialize(lipc::ShmArchive &ar) const { + shm_serialize_header(ar.header_ptr_); + } + + void shm_deserialize(const lipc::ShmArchive &ar) { + shm_deserialize_header(ar.header_ptr_); + } + + void WeakMove(BucketInfo &other) { + throw NOT_IMPLEMENTED; + } + + void StrongCopy(const BucketInfo &other) { + throw NOT_IMPLEMENTED; + } }; /** Represents a VBucket in shared memory */ -struct VBucketInfoShmHeader { - lipc::ShmArchive>> name_; - lipc::ShmArchive>> blobs_; +template<> +struct ShmHeader : public lipc::ShmBaseHeader { + lipc::ShmArchive> name_; + lipc::ShmArchive> blobs_; }; /** Metadata for a VBucket */ -struct VBucketInfo { +struct VBucketInfo : public SHM_CONTAINER(VBucketInfo) { + public: + SHM_CONTAINER_TEMPLATE(VBucketInfo, VBucketInfo); + + public: lipc::mptr> name_; lipc::mptr> blobs_; + + public: + void shm_init_main(lipc::ShmArchive *ar, + lipc::Allocator *alloc) { + shm_init_header(ar, alloc); + } + + void shm_destroy(bool destroy_header = true) { + SHM_DESTROY_DATA_START + SHM_DESTROY_DATA_END + SHM_DESTROY_END + } + + void shm_serialize(lipc::ShmArchive &ar) const { + shm_serialize_header(ar.header_ptr_); + } + + void shm_deserialize(const lipc::ShmArchive &ar) { + shm_deserialize_header(ar.header_ptr_); + } + + void WeakMove(VBucketInfo &other) { + throw NOT_IMPLEMENTED; + } + + void StrongCopy(const VBucketInfo &other) { + throw NOT_IMPLEMENTED; + } }; } // namespace hermes diff --git a/src/statuses.h b/src/statuses.h index c355865f3..233e58b25 100644 --- a/src/statuses.h +++ b/src/statuses.h @@ -11,6 +11,7 @@ namespace hermes { using api::Status; +const Status NOT_IMPLEMENTED("The function was not implemented"); const Status DPE_PLACEMENT_SCHEMA_EMPTY("Placement failed. Non-fatal."); const Status DPE_NO_SPACE("DPE has no remaining space."); const Status DPE_MIN_IO_TIME_NO_SOLUTION( diff --git a/test/test_put_get.cc b/test/test_put_get.cc index 64d27def9..8cb90548c 100644 --- a/test/test_put_get.cc +++ b/test/test_put_get.cc @@ -30,7 +30,7 @@ void TestManyPuts(hapi::Hermes *hermes) { hermes::BlobId blob_id; for (size_t i = 0; i < num_blobs; ++i) { - hermes::Blob blob(nullptr, blob_size); + hermes::Blob blob(blob_size); std::string name = std::to_string(i); char nonce = i % 256; memset(blob.data_mutable(), nonce, blob_size); @@ -53,7 +53,7 @@ void TestBlobOverride(hapi::Hermes *hermes) { auto bkt2 = hermes->GetBucket("hello"); hermes::api::Context ctx; hermes::BlobId blob_id; - hermes::Blob blob(nullptr, 1024); + hermes::Blob blob(1024); for (size_t i = 0; i < 1024; ++i) { memset(blob.data_mutable(), 10, 1024); bkt2->Put("0", std::move(blob), blob_id, ctx); diff --git a/test/test_rpc.cc b/test/test_rpc.cc index 23be02e20..4f61683c0 100644 --- a/test/test_rpc.cc +++ b/test/test_rpc.cc @@ -30,7 +30,7 @@ int main(int argc, char* argv[]) { hermes::api::Context ctx; hermes::BlobId blob_id; - hermes::Blob blob(nullptr, 1024); + hermes::Blob blob(1024); for (size_t i = 0; i < 1024; ++i) { memset(blob.data_mutable(), 10, 1024); bkt2->Put("0", std::move(blob), blob_id, ctx); From da6e83d1373ebac100872056f18eb416e07e3596 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 4 Jan 2023 05:01:32 -0600 Subject: [PATCH 083/511] Use catch2 for test cases --- CMakeLists.txt | 11 +++++ benchmarks/put_get_bench.cc | 12 ++--- src/api/hermes.h | 2 + src/buffer_organizer.cc | 55 +++++++++++---------- src/buffer_pool.cc | 9 ++-- src/config.h | 10 +++- src/config_server.cc | 12 +++-- src/config_server.h | 46 ++++++++++++------ src/io_clients/posix.h | 13 +++-- src/metadata_manager.cc | 25 +++++----- src/metadata_types.h | 95 ++++++++++++++++++++++++++++++++----- test/CMakeLists.txt | 4 +- test/main_mpi.cc | 44 +++++++++++++++++ test/test_put_get.cc | 23 +++++---- test/test_rpc.cc | 29 ++++------- test/verify_buffer.h | 21 -------- 16 files changed, 269 insertions(+), 142 deletions(-) create mode 100644 test/main_mpi.cc delete mode 100644 test/verify_buffer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e50e821a..f295f6cdc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,17 @@ endif() project(HERMES) +#------------------------------------------------------------------------------ +# Compiler optimization +#------------------------------------------------------------------------------ +message(${CMAKE_BUILD_TYPE}) +if (CMAKE_BUILD_TYPE STREQUAL "Release") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O1") + message("This IS a release build") +else() + message("This is NOT a release build") +endif() + #------------------------------------------------------------------------------ # Version information #------------------------------------------------------------------------------ diff --git a/benchmarks/put_get_bench.cc b/benchmarks/put_get_bench.cc index a2b2f04ee..66839df5b 100644 --- a/benchmarks/put_get_bench.cc +++ b/benchmarks/put_get_bench.cc @@ -11,7 +11,7 @@ namespace hapi = hermes::api; using Timer = labstor::HighResMonotonicTimer; -void GatherTimes(Timer &t) { +void GatherTimes(std::string test_name, Timer &t) { MPI_Barrier(MPI_COMM_WORLD); int nprocs, rank; MPI_Comm_size(MPI_COMM_WORLD, &nprocs); @@ -20,35 +20,35 @@ void GatherTimes(Timer &t) { MPI_Reduce(&time, &max, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); if (rank == 0) { - std::cout << "Time (sec): " << max << std::endl; + std::cout << test_name << ": Time (sec): " << max << std::endl; } } void PutTest(hapi::Hermes *hermes, int rank, int blobs_per_rank, size_t blob_size) { Timer t; - t.Resume(); auto bkt = hermes->GetBucket("hello"); hermes::api::Context ctx; hermes::BlobId blob_id; hermes::Blob blob(blob_size); + t.Resume(); for (size_t i = 0; i < blobs_per_rank; ++i) { size_t blob_name_int = rank * blobs_per_rank + i; std::string name = std::to_string(blob_name_int); bkt->Put(name, std::move(blob), blob_id, ctx); } t.Pause(); - GatherTimes(t); + GatherTimes("Put", t); } void GetTest(hapi::Hermes *hermes, int rank, int blobs_per_rank, size_t blob_size) { Timer t; - t.Resume(); auto bkt = hermes->GetBucket("hello"); hermes::api::Context ctx; hermes::BlobId blob_id; hermes::Blob blob(blob_size); + t.Resume(); for (size_t i = 0; i < blobs_per_rank; ++i) { size_t blob_name_int = rank * blobs_per_rank + i; std::string name = std::to_string(blob_name_int); @@ -57,7 +57,7 @@ void GetTest(hapi::Hermes *hermes, bkt->Get(blob_id, ret, ctx); } t.Pause(); - GatherTimes(t); + GatherTimes("Get", t); } int main(int argc, char **argv) { diff --git a/src/api/hermes.h b/src/api/hermes.h index dafb41342..d1d1101dc 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -50,6 +50,8 @@ class Hermes { public: Hermes() = default; + ~Hermes() = default; + static Hermes* Create(HermesType mode = HermesType::kClient, std::string server_config_path = "", std::string client_config_path = "") { diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 645546588..830ca1a00 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -23,16 +23,16 @@ static size_t SumBufferBlobSizes(lipc::vector &buffers) { * */ void BufferOrganizer::shm_init() { mdm_ = &HERMES->mdm_; - for (lipc::Ref target_ref : (*mdm_->targets_)) { - auto &target = *target_ref; - DeviceInfo &dev_info = *(*mdm_->devices_)[target.id_.GetDeviceId()]; - if (dev_info.mount_dir_.size() == 0) { - dev_info.header_->io_api_ = IoInterface::kRam; + for (lipc::Ref target : (*mdm_->targets_)) { + lipc::Ref dev_info = + (*mdm_->devices_)[target->id_.GetDeviceId()]; + if (dev_info->mount_dir_->size() == 0) { + dev_info->header_->io_api_ = IoInterface::kRam; } else { - dev_info.header_->io_api_ = IoInterface::kPosix; + dev_info->header_->io_api_ = IoInterface::kPosix; } - auto io_client = IoClientFactory::Get(dev_info.header_->io_api_); - io_client->Init(dev_info); + auto io_client = IoClientFactory::Get(dev_info->header_->io_api_); + io_client->Init(*dev_info); } } @@ -52,17 +52,17 @@ void BufferOrganizer::shm_deserialize() { RPC void BufferOrganizer::LocalPlaceBlobInBuffers( Blob &blob, lipc::vector &buffers) { size_t blob_off = 0; - for (lipc::Ref buffer_info_ref : buffers) { - BufferInfo &buffer_info = *buffer_info_ref; - if (buffer_info.tid_.GetNodeId() != mdm_->rpc_->node_id_) { + for (lipc::Ref buffer_info : buffers) { + if (buffer_info->tid_.GetNodeId() != mdm_->rpc_->node_id_) { continue; } - DeviceInfo &dev_info = *(*mdm_->devices_)[buffer_info.tid_.GetDeviceId()]; - auto io_client = IoClientFactory::Get(dev_info.header_->io_api_); - bool ret = io_client->Write(dev_info, blob.data() + blob_off, - buffer_info.t_off_, - buffer_info.blob_size_); - blob_off += buffer_info.blob_size_; + lipc::Ref dev_info = + (*mdm_->devices_)[buffer_info->tid_.GetDeviceId()]; + auto io_client = IoClientFactory::Get(dev_info->header_->io_api_); + bool ret = io_client->Write(*dev_info, blob.data() + blob_off, + buffer_info->t_off_, + buffer_info->blob_size_); + blob_off += buffer_info->blob_size_; if (!ret) { LOG(FATAL) << "Could not perform I/O in BORG" << std::endl; } @@ -74,23 +74,22 @@ RPC Blob BufferOrganizer::LocalReadBlobFromBuffers( lipc::vector &buffers) { Blob blob(SumBufferBlobSizes(buffers)); size_t blob_off = 0; - for (lipc::Ref buffer_info_ref : buffers) { - BufferInfo &buffer_info = *buffer_info_ref; - if (buffer_info.tid_.GetNodeId() != mdm_->rpc_->node_id_) { + for (lipc::Ref buffer_info : buffers) { + if (buffer_info->tid_.GetNodeId() != mdm_->rpc_->node_id_) { continue; } - auto dev_info_ref = (*mdm_->devices_)[buffer_info.tid_.GetDeviceId()]; - DeviceInfo &dev_info = *dev_info_ref; - auto io_client = IoClientFactory::Get(dev_info.header_->io_api_); - bool ret = io_client->Read(dev_info, blob.data_mutable() + blob_off, - buffer_info.t_off_, - buffer_info.blob_size_); - blob_off += buffer_info.blob_size_; + lipc::Ref dev_info = + (*mdm_->devices_)[buffer_info->tid_.GetDeviceId()]; + auto io_client = IoClientFactory::Get(dev_info->header_->io_api_); + bool ret = io_client->Read(*dev_info, blob.data_mutable() + blob_off, + buffer_info->t_off_, + buffer_info->blob_size_); + blob_off += buffer_info->blob_size_; if (!ret) { LOG(FATAL) << "Could not perform I/O in BORG" << std::endl; } } - return std::move(blob); + return blob; } /** Copies one buffer set into another buffer set */ diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 3129e81a1..566c47d1c 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -53,10 +53,11 @@ BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, Blob &blob) { blob_off_ += plcmnt.size_; continue; } - BufferPoolAllocator &alloc = *(*target_allocs_)[plcmnt.tid_.GetDeviceId()]; + lipc::Ref alloc = + (*target_allocs_)[plcmnt.tid_.GetDeviceId()]; BufferInfo info; - info.t_off_ = alloc.cur_off_; - alloc.cur_off_ += plcmnt.size_; // NOTE(llogan): allocate emulation + info.t_off_ = alloc->cur_off_; + alloc->cur_off_ += plcmnt.size_; // NOTE(llogan): allocate emulation info.t_size_ = plcmnt.size_; info.blob_off_ = blob_off_; info.blob_size_ = plcmnt.size_; @@ -64,7 +65,7 @@ BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, Blob &blob) { buffers.emplace_back(info); borg_->LocalPlaceBlobInBuffers(blob, buffers); mdm_->LocalUpdateTargetCapacity(info.tid_, - static_cast(info.t_size_)); + -static_cast(info.t_size_)); blob_off_ += plcmnt.size_; } return std::move(buffers); diff --git a/src/config.h b/src/config.h index 83a9de58d..989ce5e95 100644 --- a/src/config.h +++ b/src/config.h @@ -76,8 +76,14 @@ static void PrintExpectedAndFail(const std::string &expected, u32 line_number = /** parse \a list_node vector from configuration file in YAML */ template> static void ParseVector(YAML::Node list_node, VEC_TYPE &list) { - for (auto val_node : list_node) { - list.emplace_back(val_node.as()); + if constexpr(IS_SHM_SMART_POINTER(VEC_TYPE)) { + for (auto val_node : list_node) { + list->emplace_back(val_node.as()); + } + } else { + for (auto val_node : list_node) { + list.emplace_back(val_node.as()); + } } } diff --git a/src/config_server.cc b/src/config_server.cc index afb97ba90..c2a377d44 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -23,10 +23,12 @@ namespace hermes::config { void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { devices_.clear(); for (auto device : yaml_conf) { - DeviceInfo dev; + DeviceInfo dev(SHM_ALLOCATOR_NULL); auto dev_info = device.second; - dev.dev_name_ = lipc::string(device.first.as()); - dev.mount_dir_ = lipc::string(dev_info["mount_point"].as()); + (*dev.dev_name_) = lipc::string( + device.first.as()); + (*dev.mount_dir_) = lipc::string( + dev_info["mount_point"].as()); dev.header_->borg_min_thresh_ = dev_info["borg_capacity_thresh"][0].as(); dev.header_->borg_max_thresh_ = @@ -42,8 +44,8 @@ void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { dev.header_->latency_ = ParseLatency(dev_info["latency"].as()); ParseVector>( - dev_info["slab_sizes"], dev.slab_sizes_); - devices_.emplace_back(dev); + dev_info["slab_sizes"], *dev.slab_sizes_); + devices_.emplace_back(std::move(dev)); } } diff --git a/src/config_server.h b/src/config_server.h index 0dafa42fc..421ea045a 100644 --- a/src/config_server.h +++ b/src/config_server.h @@ -9,6 +9,8 @@ namespace hermes::config { +class DeviceInfo; /** Forward declaration of DeviceInfo */ + /** * The type of interface the device exposes * */ @@ -17,10 +19,6 @@ enum class IoInterface { kPosix }; - -/** Forward declaration of DeviceInfo */ -class DeviceInfo; - /** * DeviceInfo shared-memory representation * */ @@ -57,24 +55,32 @@ struct DeviceInfo : public SHM_CONTAINER(DeviceInfo) { SHM_CONTAINER_TEMPLATE(DeviceInfo, DeviceInfo) /** The human-readable name of the device */ - lipc::string dev_name_; + lipc::mptr dev_name_; /** The unit of each slab, a multiple of the Device's block size */ - lipc::vector slab_sizes_; + lipc::mptr> slab_sizes_; /** The directory the device is mounted on */ - lipc::string mount_dir_; + lipc::mptr mount_dir_; /** The file to create on the device */ - lipc::string mount_point_; + lipc::mptr mount_point_; void shm_init_main(lipc::ShmArchive *ar, lipc::Allocator *alloc) { shm_init_header(ar, alloc); + dev_name_.shm_init(alloc); + slab_sizes_.shm_init(alloc); + mount_dir_.shm_init(alloc); + mount_point_.shm_init(alloc); + shm_serialize(ar_); } void shm_destroy(bool destroy_header = true) { - dev_name_.SetDestructable(); - slab_sizes_.SetDestructable(); - mount_dir_.SetDestructable(); - mount_point_.SetDestructable(); + SHM_DESTROY_DATA_START + dev_name_.shm_destroy(); + slab_sizes_.shm_destroy(); + mount_dir_.shm_destroy(); + mount_point_.shm_destroy(); + SHM_DESTROY_DATA_END + SHM_DESTROY_END } void shm_serialize(lipc::ShmArchive &ar) const { @@ -94,11 +100,23 @@ struct DeviceInfo : public SHM_CONTAINER(DeviceInfo) { } void WeakMove(DeviceInfo &other) { - throw NOT_IMPLEMENTED; + SHM_WEAK_MOVE_START(SHM_WEAK_MOVE_DEFAULT(DeviceInfo)) + (*header_) = (*other.header_); + (*dev_name_) = lipc::Move(*other.dev_name_); + (*slab_sizes_) = lipc::Move(*other.slab_sizes_); + (*mount_dir_) = lipc::Move(*other.mount_dir_); + (*mount_point_) = lipc::Move(*other.mount_point_); + SHM_WEAK_MOVE_END() } void StrongCopy(const DeviceInfo &other) { - throw NOT_IMPLEMENTED; + SHM_STRONG_COPY_START(SHM_STRONG_COPY_DEFAULT(DeviceInfo)) + (*header_) = (*other.header_); + (*dev_name_) = lipc::Copy(*other.dev_name_); + (*slab_sizes_) = lipc::Copy(*other.slab_sizes_); + (*mount_dir_) = lipc::Copy(*other.mount_dir_); + (*mount_point_) = lipc::Copy(*other.mount_point_); + SHM_STRONG_COPY_END() } }; diff --git a/src/io_clients/posix.h b/src/io_clients/posix.h index 39fed7b80..58935be8f 100644 --- a/src/io_clients/posix.h +++ b/src/io_clients/posix.h @@ -19,10 +19,10 @@ class PosixIoClient : public IoClient { public: bool Init(DeviceInfo &dev_info) override { auto api = HERMES_POSIX_API; - dev_info.mount_point_ = dev_info.mount_dir_ + - "/" + "slab_" + dev_info.dev_name_; - dev_info.mount_point_ >> dev_info.header_->mount_point_; - int fd = api->open(dev_info.mount_point_.c_str(), O_TRUNC | O_CREAT, 0666); + (*dev_info.mount_point_) = (*dev_info.mount_dir_) + + "/" + "slab_" + (*dev_info.dev_name_); + int fd = api->open((*dev_info.mount_point_).c_str(), + O_TRUNC | O_CREAT, 0666); if (fd < 0) { return false; } api->close(fd); return true; @@ -31,8 +31,7 @@ class PosixIoClient : public IoClient { bool Write(DeviceInfo &dev_info, void *data, size_t off, size_t size) override { auto api = HERMES_POSIX_API; - std::string str = dev_info.mount_point_.str(); - int fd = api->open(dev_info.mount_point_.c_str(), O_RDWR); + int fd = api->open((*dev_info.mount_point_).c_str(), O_RDWR); if (fd < 0) { return false; } size_t count = api->pwrite(fd, data, size, off); api->close(fd); @@ -42,7 +41,7 @@ class PosixIoClient : public IoClient { bool Read(DeviceInfo &dev_info, void *data, size_t off, size_t size) override { auto api = HERMES_POSIX_API; - int fd = api->open(dev_info.mount_point_.c_str(), O_RDWR); + int fd = api->open((*dev_info.mount_point_).c_str(), O_RDWR); if (fd < 0) { return false; } size_t count = api->pread(fd, data, size, off); api->close(fd); diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index bef2e70e6..561c82164 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -29,7 +29,7 @@ void MetadataManager::shm_init(ServerConfig *config, // Create the DeviceInfo vector devices_ = lipc::make_mptr>( - HERMES->server_config_.devices_); + HERMES->main_alloc_, HERMES->server_config_.devices_); targets_ = lipc::make_mptr>(); // Create the TargetInfo vector @@ -110,9 +110,8 @@ BucketId MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { // Emplace bucket if it does not already exist if (bkt_id_map_->try_emplace(bkt_name, bkt_id)) { BucketInfo info(HERMES->main_alloc_); - info.name_ = lipc::make_mptr(bkt_name); - info.name_ >> info.header_->name_ar_; - bkt_map_->emplace(bkt_id, info); + (*info.name_) = bkt_name; + bkt_map_->emplace(bkt_id, std::move(info)); } else { auto iter = bkt_id_map_->find(bkt_name); if (iter == bkt_id_map_->end()) { @@ -200,16 +199,16 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, blob_id.unique_ = header_->id_alloc_.fetch_add(1); blob_id.node_id_ = rpc_->node_id_; if (blob_id_map_->try_emplace(internal_blob_name, blob_id)) { - BlobInfo info; - info.bkt_id_ = bkt_id; - info.name_ = lipc::make_mptr(std::move(internal_blob_name)); - info.buffers_ = lipc::make_mptr>(buffers); - blob_map_->emplace(blob_id, info); + BlobInfo blob_info(HERMES->main_alloc_); + blob_info.bkt_id_ = bkt_id; + (*blob_info.name_) = std::move(internal_blob_name); + (*blob_info.buffers_) = std::move(buffers); + blob_map_->emplace(blob_id, std::move(blob_info)); } else { blob_id = *(*blob_id_map_)[internal_blob_name]; auto iter = blob_map_->find(blob_id); - BlobInfo info(*(*iter).val_); - *(info.buffers_) = buffers; + lipc::Ref blob_info = (*iter).val_; + (*blob_info->buffers_) = std::move(buffers); } return blob_id; @@ -223,8 +222,8 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, * */ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { auto iter = blob_map_->find(blob_id); - BlobInfo &info = *(*iter).val_; - lipc::vector &buffers = *info.buffers_; + lipc::Ref blob_info = (*iter).val_; + lipc::vector &buffers = (*blob_info->buffers_); return borg_->LocalReadBlobFromBuffers(buffers); } diff --git a/src/metadata_types.h b/src/metadata_types.h index f122cac58..2b88740b6 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -63,6 +63,7 @@ struct BufferInfo { /** Copy assignment */ BufferInfo& operator=(const BufferInfo &other) { Copy(other); + return *this; } /** Move assignment */ @@ -89,24 +90,37 @@ struct ShmHeader : public lipc::ShmBaseHeader { lipc::ShmArchive> buffers_ar_; RwLock rwlock_; + /** Default constructor */ ShmHeader() = default; + /** Copy constructor */ ShmHeader(const ShmHeader &other) noexcept : bkt_id_(other.bkt_id_), name_ar_(other.name_ar_), buffers_ar_(other.buffers_ar_), rwlock_() {} + /** Move constructor */ ShmHeader(ShmHeader &&other) noexcept : bkt_id_(std::move(other.bkt_id_)), name_ar_(std::move(other.name_ar_)), buffers_ar_(std::move(other.buffers_ar_)), rwlock_() {} + /** Copy assignment */ + ShmHeader& operator=(const ShmHeader &other) { + if (this != &other) { + bkt_id_ = other.bkt_id_; + name_ar_ = other.name_ar_; + buffers_ar_ = other.buffers_ar_; + } + return *this; + } + + /** Move assignment */ ShmHeader& operator=(ShmHeader &&other) { if (this != &other) { bkt_id_ = std::move(other.bkt_id_); name_ar_ = std::move(other.name_ar_); buffers_ar_ = std::move(other.buffers_ar_); - rwlock_ = std::move(other.rwlock_); } return *this; } @@ -125,19 +139,28 @@ struct BlobInfo : public SHM_CONTAINER(BlobInfo){ /// The BufferInfo vector lipc::mptr> buffers_; + /** Default constructor. Does nothing. */ BlobInfo() = default; + /** Initialize the data structure */ void shm_init_main(lipc::ShmArchive *ar, lipc::Allocator *alloc) { shm_init_header(ar, alloc); + name_.shm_init(alloc); + buffers_.shm_init(alloc); + shm_serialize(ar_); } + /** Destroy all allocated data */ void shm_destroy(bool destroy_header = true) { SHM_DESTROY_DATA_START + name_.shm_destroy(); + buffers_.shm_destroy(); SHM_DESTROY_DATA_END SHM_DESTROY_END } + /** Serialize into \a ShmArchive */ void shm_serialize(lipc::ShmArchive &ar) const { shm_serialize_header(ar.header_ptr_); header_->bkt_id_ = bkt_id_; @@ -145,23 +168,35 @@ struct BlobInfo : public SHM_CONTAINER(BlobInfo){ buffers_ >> header_->buffers_ar_; } + /** Deserialize from \a ShmArchive */ void shm_deserialize(const lipc::ShmArchive &ar) { - shm_deserialize_header(ar.header_ptr_); + if(!shm_deserialize_header(ar.header_ptr_)) { return; } bkt_id_ = header_->bkt_id_; name_ << header_->name_ar_; buffers_ << header_->buffers_ar_; } + /** Move pointers into another BlobInfo */ void WeakMove(BlobInfo &other) { - throw NOT_IMPLEMENTED; + SHM_WEAK_MOVE_START(SHM_WEAK_MOVE_DEFAULT(BlobInfo)) + (*header_) = (*other.header_); + bkt_id_ = other.bkt_id_; + (*name_) = lipc::Move(*other.name_); + (*buffers_) = lipc::Move(*other.buffers_); + SHM_WEAK_MOVE_END() } + /** Deep copy data into another BlobInfo */ void StrongCopy(const BlobInfo &other) { - throw NOT_IMPLEMENTED; + SHM_STRONG_COPY_START(SHM_STRONG_COPY_DEFAULT(BlobInfo)) + (*header_) = (*other.header_); + bkt_id_ = other.bkt_id_; + (*name_) = lipc::Copy(*other.name_); + (*buffers_) = lipc::Copy(*other.buffers_); + SHM_STRONG_COPY_END() } }; - /** Represents BucketInfo in shared memory */ template<> struct ShmHeader : public lipc::ShmBaseHeader { @@ -174,36 +209,54 @@ struct BucketInfo : public SHM_CONTAINER(BucketInfo) { SHM_CONTAINER_TEMPLATE(BucketInfo, BucketInfo); public: + /** The name of the bucket */ lipc::mptr name_; public: + /** Default constructor */ BucketInfo() = default; + /** Initialize the data structure */ void shm_init_main(lipc::ShmArchive *ar, lipc::Allocator *alloc) { shm_init_header(ar, alloc); + name_.shm_init(alloc); } + /** Destroy all allocated data */ void shm_destroy(bool destroy_header = true) { SHM_DESTROY_DATA_START + name_.shm_destroy(); SHM_DESTROY_DATA_END SHM_DESTROY_END } + /** Serialize into \a ShmArchive */ void shm_serialize(lipc::ShmArchive &ar) const { shm_serialize_header(ar.header_ptr_); + name_ >> header_->name_ar_; } + /** Deserialize from \a ShmArchive */ void shm_deserialize(const lipc::ShmArchive &ar) { - shm_deserialize_header(ar.header_ptr_); + if(!shm_deserialize_header(ar.header_ptr_)) { return; } + name_ << header_->name_ar_; } void WeakMove(BucketInfo &other) { - throw NOT_IMPLEMENTED; + SHM_WEAK_MOVE_START(SHM_WEAK_MOVE_DEFAULT(BucketInfo)) + (*header_) = (*other.header_); + (*name_) = lipc::Move(*other.name_); + shm_serialize(ar_); + SHM_WEAK_MOVE_END() } void StrongCopy(const BucketInfo &other) { - throw NOT_IMPLEMENTED; + SHM_STRONG_COPY_START(SHM_STRONG_COPY_DEFAULT(BucketInfo)) + (*header_) = (*other.header_); + (*name_) = lipc::Copy(*other.name_); + shm_serialize(ar_); + SHM_STRONG_COPY_END() } }; @@ -224,31 +277,51 @@ struct VBucketInfo : public SHM_CONTAINER(VBucketInfo) { lipc::mptr> blobs_; public: + VBucketInfo() = default; + void shm_init_main(lipc::ShmArchive *ar, lipc::Allocator *alloc) { shm_init_header(ar, alloc); + name_.shm_init(alloc); + blobs_.shm_init(alloc_); } void shm_destroy(bool destroy_header = true) { SHM_DESTROY_DATA_START + name_.shm_destroy(); + blobs_.shm_destroy(); SHM_DESTROY_DATA_END SHM_DESTROY_END } void shm_serialize(lipc::ShmArchive &ar) const { shm_serialize_header(ar.header_ptr_); + name_ >> header_->name_; + blobs_ >> header_->blobs_; } void shm_deserialize(const lipc::ShmArchive &ar) { - shm_deserialize_header(ar.header_ptr_); + if(!shm_deserialize_header(ar.header_ptr_)) { return; } + name_ << header_->name_; + blobs_ << header_->blobs_; } void WeakMove(VBucketInfo &other) { - throw NOT_IMPLEMENTED; + SHM_WEAK_MOVE_START(SHM_WEAK_MOVE_DEFAULT(VBucketInfo)) + (*header_) = (*other.header_); + (*name_) = lipc::Move(*other.name_); + (*blobs_) = lipc::Move(*other.blobs_); + shm_serialize(ar_); + SHM_WEAK_MOVE_END() } void StrongCopy(const VBucketInfo &other) { - throw NOT_IMPLEMENTED; + SHM_STRONG_COPY_START(SHM_STRONG_COPY_DEFAULT(VBucketInfo)) + (*header_) = (*other.header_); + (*name_) = lipc::Copy(*other.name_); + (*blobs_) = lipc::Copy(*other.blobs_); + shm_serialize(ar_); + SHM_STRONG_COPY_END() } }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 99bfedb93..f08262799 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -14,9 +14,9 @@ include_directories( set(API_TESTS test_rpc test_put_get) foreach(program ${API_TESTS}) - add_executable(${program} ${program}.cc) + add_executable(${program} ${program}.cc main_mpi.cc) target_link_libraries(${program} ${LIBRT} hermes MPI::MPI_CXX - $<$:thallium> glog::glog) + $<$:thallium> glog::glog Catch2::Catch2) add_test(NAME "Test${program}" COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2 "${CMAKE_BINARY_DIR}/bin/${program}") diff --git a/test/main_mpi.cc b/test/main_mpi.cc new file mode 100644 index 000000000..9f0da40e7 --- /dev/null +++ b/test/main_mpi.cc @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of LabStor + * + * LabStor 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 Lesser 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 + * . + */ + + +#include "basic_test.h" +#include + +int main(int argc, char **argv) { + int rc; + MPI_Init(&argc, &argv); + Catch::Session session; + auto cli = session.cli(); + session.cli(cli); + rc = session.applyCommandLine(argc, argv); + if (rc != 0) return rc; + MainPretest(); + rc = session.run(); + MainPosttest(); + if (rc != 0) return rc; + MPI_Finalize(); + return rc; +} diff --git a/test/test_put_get.cc b/test/test_put_get.cc index 8cb90548c..078b3bd66 100644 --- a/test/test_put_get.cc +++ b/test/test_put_get.cc @@ -18,10 +18,18 @@ #include "hermes.h" #include "bucket.h" -#include "verify_buffer.h" +#include "basic_test.h" namespace hapi = hermes::api; +void MainPretest() { + hapi::Hermes::Create(hermes::HermesType::kClient); +} + +void MainPosttest() { + HERMES->Finalize(); +} + void TestManyPuts(hapi::Hermes *hermes) { auto bkt = hermes->GetBucket("hello"); int num_blobs = 1; @@ -64,13 +72,10 @@ void TestBlobOverride(hapi::Hermes *hermes) { } } -int main(int argc, char* argv[]) { - MPI_Init(&argc, &argv); - auto hermes = hapi::Hermes::Create(hermes::HermesType::kClient); - - TestManyPuts(hermes); +TEST_CASE("TestManyPuts") { + TestManyPuts(HERMES); +} - hermes->Finalize(); - MPI_Finalize(); - return 0; +TEST_CASE("TestBlobOverride") { + TestBlobOverride(HERMES); } \ No newline at end of file diff --git a/test/test_rpc.cc b/test/test_rpc.cc index 4f61683c0..228fcbe61 100644 --- a/test/test_rpc.cc +++ b/test/test_rpc.cc @@ -18,29 +18,18 @@ #include "hermes.h" #include "bucket.h" -#include "verify_buffer.h" +#include "basic_test.h" namespace hapi = hermes::api; -int main(int argc, char* argv[]) { - MPI_Init(&argc, &argv); - auto hermes = hapi::Hermes::Create(hermes::HermesType::kClient); - auto bkt = hermes->GetBucket("hello"); - auto bkt2 = hermes->GetBucket("hello"); +void MainPretest() { + hapi::Hermes::Create(hermes::HermesType::kClient); +} - hermes::api::Context ctx; - hermes::BlobId blob_id; - hermes::Blob blob(1024); - for (size_t i = 0; i < 1024; ++i) { - memset(blob.data_mutable(), 10, 1024); - bkt2->Put("0", std::move(blob), blob_id, ctx); - hermes::Blob ret; - bkt->Get(blob_id, ret, ctx); - assert(ret.size() == 1024); - assert(VerifyBuffer(ret.data(), 1024, 10)); - } +void MainPosttest() { + HERMES->Finalize(); +} - hermes->Finalize(); - MPI_Finalize(); - return 0; +TEST_CASE("TestRpc") { + HERMES->Finalize(); } \ No newline at end of file diff --git a/test/verify_buffer.h b/test/verify_buffer.h deleted file mode 100644 index 7c0401a93..000000000 --- a/test/verify_buffer.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// Created by lukemartinlogan on 12/27/22. -// - -#ifndef HERMES_TEST_VERIFY_BUFFER_H_ -#define HERMES_TEST_VERIFY_BUFFER_H_ - -#include -#include - -static bool VerifyBuffer(char *ptr, size_t size, char nonce) { - for (size_t i = 0; i < size; ++i) { - if (ptr[i] != nonce) { - std::cout << (int)ptr[i] << std::endl; - return false; - } - } - return true; -} - -#endif // HERMES_TEST_VERIFY_BUFFER_H_ From ff1e3539556f6feb6cab3f0d27b13f3878897674 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 5 Jan 2023 09:09:12 -0600 Subject: [PATCH 084/511] Fill in more VBucket APIs --- src/api/bucket.cc | 13 +- src/api/vbucket.cc | 59 +++- src/api/vbucket.h | 55 +++- src/metadata_manager.cc | 353 +++++++++++++---------- src/metadata_manager.h | 301 +------------------ src/metadata_types.h | 4 +- src/rpc_thallium_defs.cc | 132 --------- test/CMakeLists.txt | 5 +- test/{test_put_get.cc => test_bucket.cc} | 8 +- test/test_vbucket.cc | 31 ++ 10 files changed, 366 insertions(+), 595 deletions(-) rename test/{test_put_get.cc => test_bucket.cc} (92%) create mode 100644 test/test_vbucket.cc diff --git a/src/api/bucket.cc b/src/api/bucket.cc index ed7b1bc77..18d0cb1b2 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -13,13 +13,17 @@ namespace hermes::api { Bucket::Bucket(std::string name, Context &ctx) : mdm_(&HERMES->mdm_), bpm_(&HERMES->bpm_) { lipc::string lname(name); - id_ = mdm_->GetOrCreateBucket(lname); + // TODO(llogan): rpcify + id_ = mdm_->LocalGetOrCreateBucket(lname); } /** * Rename this bucket * */ void Bucket::Rename(std::string new_bkt_name) { + lipc::string lname(new_bkt_name); + // TODO(llogan): rpcify + mdm_->LocalRenameBucket(id_, lname); } /** @@ -34,7 +38,8 @@ void Bucket::Destroy(std::string blob_name) { Status Bucket::GetBlobId(std::string blob_name, BlobId &blob_id, Context &ctx) { lipc::string blob_name_l(blob_name); - blob_id = mdm_->GetBlobId(GetId(), blob_name_l); + // TODO(llogan): rpcify + blob_id = mdm_->LocalGetBlobId(GetId(), blob_name_l); return Status(); } @@ -52,11 +57,13 @@ Status Bucket::Put(std::string blob_name, Blob blob, // Allocate buffers for the blob & enqueue placement for (auto &schema : schemas) { - // TODO(llogan): Use RPC if-else, not Local + // TODO(llogan): rpcify auto buffers = bpm_->LocalAllocateAndSetBuffers(schema, blob); blob_id = mdm_->LocalBucketPutBlob(id_, lipc::string(blob_name), blob, buffers); } + + return Status(); } /** diff --git a/src/api/vbucket.cc b/src/api/vbucket.cc index 693d85d9a..9c85fee46 100644 --- a/src/api/vbucket.cc +++ b/src/api/vbucket.cc @@ -6,7 +6,64 @@ namespace hermes::api { -VBucket::VBucket(std::string name, Context &ctx) { +/** + * Either gets or creates a VBucket. + * + * @param name the name of the vbucket + * @param ctx any additional information + * */ +VBucket::VBucket(std::string name, Context &ctx) : mdm_(&HERMES->mdm_) { + lipc::string lname(name); + // TODO(llogan): rpcify + id_ = mdm_->LocalGetOrCreateVBucket(lname); +} + +/** + * Rename a VBucket. + * + * @param name the name of the new vbucket + * */ +void VBucket::Rename(std::string name) { + lipc::string lname(name); + mdm_->LocalRenameVBucket(id_, lname); +} + +/** + * Associate a blob in a VBucket. + * + * @param blob_id the ID of the blob to associate + * @param ctx any additional information + * @return status + * */ +Status VBucket::Link(BlobId blob_id, Context &ctx) { + mdm_->LocalVBucketLinkBlob(id_, blob_id); + return Status(); +} + +/** + * Unlink a blob from a VBucket. + * + * @param blob_id the ID of a blob + * @param ctx any additional information + * */ +Status VBucket::Unlink(BlobId blob_id, Context &ctx) { + mdm_->LocalVBucketUnlinkBlob(id_, blob_id); + return Status(); +} + +/** + * Destroys a VBucket and its contents + * */ +Status VBucket::Destroy() { + mdm_->LocalDestroyVBucket(id_); + return Status(); +} + +/** + * Check if \a blob_id blob is linked in the VBucket + * */ +bool VBucket::ContainsBlob(BlobId blob_id) { + return mdm_->LocalVBucketContainsBlob(id_, blob_id); } } // namespace hermes::api \ No newline at end of file diff --git a/src/api/vbucket.h b/src/api/vbucket.h index 7023af0cb..da62d7b57 100644 --- a/src/api/vbucket.h +++ b/src/api/vbucket.h @@ -12,30 +12,59 @@ namespace hermes::api { class VBucket { + private: + MetadataManager *mdm_; + VBucketId id_; + public: + /** + * Either gets or creates a VBucket. + * + * @param name the name of the vbucket + * @param ctx any additional information + * */ VBucket(std::string name, Context &ctx); - /*void Link(std::string bucket_name, - std::string blob_name, Context ctx = Context()); - - void Link(std::shared_ptr &bucket, - std::string blob_name, Context ctx = Context()); + /** + * Rename a VBucket. + * + * @param name the name of the new vbucket + * */ + void Rename(std::string name); - void Unlink(std::string bucket_name, - std::string blob_name, Context ctx = Context()); + /** + * Associate a blob in a VBucket. + * + * @param blob_id the ID of the blob to associate + * @param ctx any additional information + * @return status + * */ + Status Link(BlobId blob_id, Context &ctx); - void Unlink(std::shared_ptr &bucket, - std::string blob_name, Context ctx = Context()); + /** + * Unlink a blob from a VBucket. + * + * @param blob_id the ID of a blob + * @param ctx any additional information + * */ + Status Unlink(BlobId blob_id, Context &ctx); + /** + * Destroys a VBucket and its contents + * */ Status Destroy(); - bool ContainsBlob(std::string bucket_name, std::string blob_name); - - size_t Get(); + /** + * Check if \a blob_id blob is linked in the VBucket + * */ + bool ContainsBlob(BlobId blob_id); + /** + * Create + attach a trait to the VBucket. + * */ template void Attach(Args ...args) { - }*/ + } }; } // namespace hermes::api diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 561c82164..c51990d80 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -96,11 +96,11 @@ void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { } /** - * Get or create a bucket with \a bkt_name bucket name - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Get or create a bucket with \a bkt_name bucket name + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ BucketId MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { // Create unique ID for the Bucket BucketId bkt_id; @@ -124,11 +124,11 @@ BucketId MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { } /** - * Get the BucketId with \a bkt_name bucket name - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Get the BucketId with \a bkt_name bucket name + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { auto iter = bkt_id_map_->find(bkt_name); if (iter == bkt_id_map_->end()) { @@ -139,12 +139,12 @@ BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { } /** - * Check whether or not \a bkt_id bucket contains - * \a blob_id blob - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Check whether or not \a bkt_id bucket contains + * \a blob_id blob + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ bool MetadataManager::LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id) { auto iter = blob_map_->find(blob_id); if (iter == blob_map_->end()) { @@ -156,38 +156,46 @@ bool MetadataManager::LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id) { } /** - * Rename \a bkt_id bucket to \a new_bkt_name new name - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Rename \a bkt_id bucket to \a new_bkt_name new name + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ bool MetadataManager::LocalRenameBucket(BucketId bkt_id, lipc::charbuf &new_bkt_name) { + auto iter = bkt_map_->find(bkt_id); + if (iter == bkt_map_->end()) { + return true; + } + lipc::Ref bkt_info = (*iter).val_; + lipc::string &old_bkt_name = *bkt_info->name_; + bkt_id_map_->emplace(new_bkt_name, bkt_id); + bkt_id_map_->erase(old_bkt_name); return true; } - /** - * Destroy \a bkt_id bucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Destroy \a bkt_id bucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ bool MetadataManager::LocalDestroyBucket(BucketId bkt_id) { + bkt_map_->erase(bkt_id); + return true; } - /** - * Put a blob in a bucket - * - * @param bkt_id id of the bucket - * @param blob_name semantic blob name - * @param data the data being placed - * @param buffers the buffers to place data in - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Put a blob in a bucket + * + * @param bkt_id id of the bucket + * @param blob_name semantic blob name + * @param data the data being placed + * @param buffers the buffers to place data in + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, const lipc::charbuf &blob_name, Blob &data, @@ -215,11 +223,11 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, } /** - * Get \a blob_name blob from \a bkt_id bucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Get \a blob_name blob from \a bkt_id bucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { auto iter = blob_map_->find(blob_id); lipc::Ref blob_info = (*iter).val_; @@ -228,11 +236,11 @@ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { } /** - * Get \a blob_name blob from \a bkt_id bucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Get \a blob_name blob from \a bkt_id bucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, lipc::charbuf &blob_name) { lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); @@ -244,148 +252,193 @@ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, } /** - * Change \a blob_id blob's buffers to \the buffers - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ -bool MetadataManager::LocalSetBlobBuffers(BlobId blob_id, - lipc::vector &buffers) { -} - -/** - * Get \a blob_id blob's buffers - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Get \a blob_id blob's buffers + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ lipc::vector MetadataManager::LocalGetBlobBuffers(BlobId blob_id) { + auto iter = blob_map_->find(blob_id); + if (iter == blob_map_->end()) { + return lipc::vector(); + } + lipc::Ref blob_info = (*iter).val_; + return (*blob_info->buffers_); } /** - * Rename \a blob_id blob to \a new_blob_name new blob name - * in \a bkt_id bucket. - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Rename \a blob_id blob to \a new_blob_name new blob name + * in \a bkt_id bucket. + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ bool MetadataManager::LocalRenameBlob(BucketId bkt_id, BlobId blob_id, lipc::charbuf &new_blob_name) { + auto iter = (*blob_map_).find(blob_id); + if (iter == blob_map_->end()) { + return true; + } + lipc::Ref blob_info = (*iter).val_; + lipc::charbuf &old_blob_name = (*blob_info->name_); + lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, new_blob_name); + blob_id_map_->erase(old_blob_name); + blob_id_map_->emplace(internal_blob_name, blob_id); + return true; } /** - * Destroy \a blob_id blob in \a bkt_id bucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Destroy \a blob_id blob in \a bkt_id bucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ bool MetadataManager::LocalDestroyBlob(BucketId bkt_id, - lipc::charbuf &blob_name) { + BlobId blob_id) { + (void)bkt_id; + auto iter = (*blob_map_).find(blob_id); + if (iter == blob_map_->end()) { + return true; + } + lipc::Ref blob_info = (*iter).val_; + lipc::charbuf &blob_name = (*blob_info->name_); + blob_id_map_->erase(blob_name); + blob_map_->erase(blob_id); + return true; } /** - * Acquire \a blob_id blob's write lock - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ -bool MetadataManager::LocalWriteLockBlob(BlobId blob_id) { -} + * Get or create \a vbkt_name VBucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +VBucketId MetadataManager::LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name) { + // Create unique ID for the Bucket + VBucketId vbkt_id; + vbkt_id.unique_ = header_->id_alloc_.fetch_add(1); + vbkt_id.node_id_ = rpc_->node_id_; -/** - * Release \a blob_id blob's write lock - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ -bool MetadataManager::LocalWriteUnlockBlob(BlobId blob_id) { -} + // Emplace bucket if it does not already exist + if (vbkt_id_map_->try_emplace(vbkt_name, vbkt_id)) { + VBucketInfo info(HERMES->main_alloc_); + (*info.name_) = vbkt_name; + vbkt_map_->emplace(vbkt_id, std::move(info)); + } else { + auto iter = vbkt_id_map_->find(vbkt_name); + if (iter == vbkt_id_map_->end()) { + return VBucketId::GetNull(); + } + vbkt_id = *(*iter).val_; + } -/** - * Acquire \a blob_id blob's read lock - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ -bool MetadataManager::LocalReadLockBlob(BlobId blob_id) { -} + return vbkt_id; -/** - * Release \a blob_id blob's read lock - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ -bool MetadataManager::LocalReadUnlockBlob(BlobId blob_id) { } /** - * Get or create \a vbkt_name VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ -VBucketId MetadataManager::LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name) { + * Get the VBucketId of \a vbkt_name VBucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +VBucketId MetadataManager::LocalGetVBucketId(lipc::charbuf &vbkt_name) { + auto iter = vbkt_id_map_->find(vbkt_name); + if (iter == vbkt_id_map_->end()) { + return VBucketId::GetNull(); + } + VBucketId vbkt_id = *(*iter).val_; + return vbkt_id; } /** - * Get the VBucketId of \a vbkt_name VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ -VBucketId MetadataManager::LocalGetVBucketId(lipc::charbuf &vbkt_name) { + * Link \a vbkt_id VBucketId + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalVBucketLinkBlob(VBucketId vbkt_id, + BlobId blob_id) { + auto iter = vbkt_map_->find(vbkt_id); + if (iter == vbkt_map_->end()) { + return true; + } + lipc::Ref vbkt_info = (*iter).val_; + vbkt_info->blobs_->emplace(blob_id, blob_id); + return true; } /** - * Link \a vbkt_id VBucketId - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ -VBucketId MetadataManager::LocalVBucketLinkBlob(VBucketId vbkt_id, - BucketId bkt_id, - lipc::charbuf &blob_name) { + * Unlink \a blob_name Blob of \a bkt_id Bucket + * from \a vbkt_id VBucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +bool MetadataManager::LocalVBucketUnlinkBlob(VBucketId vbkt_id, + BlobId blob_id) { + auto iter = vbkt_map_->find(vbkt_id); + if (iter == vbkt_map_->end()) { + return true; + } + lipc::Ref vbkt_info = (*iter).val_; + vbkt_info->blobs_->erase(blob_id); + return true; } /** - * Unlink \a blob_name Blob of \a bkt_id Bucket - * from \a vbkt_id VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ -VBucketId MetadataManager::LocalVBucketUnlinkBlob(VBucketId vbkt_id, - BucketId bkt_id, - lipc::charbuf &blob_name) { + * Get the linked blobs from \a vbkt_id VBucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +std::list MetadataManager::LocalVBucketGetLinks(VBucketId vbkt_id) { + // TODO(llogan) + return {}; } /** - * Get the linked blobs from \a vbkt_id VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ -std::list MetadataManager::LocalVBucketGetLinks(VBucketId vbkt_id) { + * Whether \a vbkt_id VBucket contains \a blob_id blob + * */ +bool MetadataManager::LocalVBucketContainsBlob(VBucketId vbkt_id, + BlobId blob_id) { + auto iter = vbkt_map_->find(vbkt_id); + if (iter == vbkt_map_->end()) { + return true; + } + lipc::Ref vbkt_info = (*iter).val_; + auto link_iter = vbkt_info->blobs_->find(blob_id); + return link_iter != vbkt_info->blobs_->end(); } /** - * Rename \a vbkt_id VBucket to \a new_vbkt_name name - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Rename \a vbkt_id VBucket to \a new_vbkt_name name + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ bool MetadataManager::LocalRenameVBucket(VBucketId vbkt_id, lipc::charbuf &new_vbkt_name) { + auto iter = vbkt_map_->find(vbkt_id); + if (iter == vbkt_map_->end()) { + return true; + } + lipc::Ref vbkt_info = (*iter).val_; + lipc::string &old_bkt_name = *vbkt_info->name_; + vbkt_id_map_->emplace(new_vbkt_name, vbkt_id); + vbkt_id_map_->erase(old_bkt_name); + return true; } /** - * Destroy \a vbkt_id VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ + * Destroy \a vbkt_id VBucket + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ bool MetadataManager::LocalDestroyVBucket(VBucketId vbkt_id) { + vbkt_map_->erase(vbkt_id); + return true; } } // namespace hermes \ No newline at end of file diff --git a/src/metadata_manager.h b/src/metadata_manager.h index c7db45465..8aa926f83 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -143,7 +143,8 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalRenameBucket(BucketId bkt_id, lipc::charbuf &new_bkt_name); + RPC bool LocalRenameBucket(BucketId bkt_id, + lipc::charbuf &new_bkt_name); /** * Destroy \a bkt_id bucket @@ -186,15 +187,6 @@ class MetadataManager { * */ RPC BlobId LocalGetBlobId(BucketId bkt_id, lipc::charbuf &blob_name); - /** - * Change \a blob_id blob's buffers to \the buffers - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ - RPC bool LocalSetBlobBuffers(BlobId blob_id, - lipc::vector &buffers); - /** * Get \a blob_id blob's buffers * @@ -219,39 +211,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalDestroyBlob(BucketId bkt_id, lipc::charbuf &blob_name); - - /** - * Acquire \a blob_id blob's write lock - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ - RPC bool LocalWriteLockBlob(BlobId blob_id); - - /** - * Release \a blob_id blob's write lock - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ - RPC bool LocalWriteUnlockBlob(BlobId blob_id); - - /** - * Acquire \a blob_id blob's read lock - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ - RPC bool LocalReadLockBlob(BlobId blob_id); - - /** - * Release \a blob_id blob's read lock - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ - RPC bool LocalReadUnlockBlob(BlobId blob_id); + RPC bool LocalDestroyBlob(BucketId bkt_id, BlobId blob_id); /** * Get or create \a vbkt_name VBucket @@ -275,8 +235,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC VBucketId LocalVBucketLinkBlob(VBucketId vbkt_id, BucketId bkt_id, - lipc::charbuf &blob_name); + RPC bool LocalVBucketLinkBlob(VBucketId vbkt_id, BlobId blob_id); /** * Unlink \a blob_name Blob of \a bkt_id Bucket @@ -285,8 +244,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC VBucketId LocalVBucketUnlinkBlob(VBucketId vbkt_id, BucketId bkt_id, - lipc::charbuf &blob_name); + RPC bool LocalVBucketUnlinkBlob(VBucketId vbkt_id, BlobId blob_id); /** * Get the linked blobs from \a vbkt_id VBucket @@ -296,6 +254,11 @@ class MetadataManager { * */ RPC std::list LocalVBucketGetLinks(VBucketId vbkt_id); + /** + * Whether \a vbkt_id VBucket contains \a blob_id blob + * */ + RPC bool LocalVBucketContainsBlob(VBucketId vbkt_id, BlobId blob_id); + /** * Rename \a vbkt_id VBucket to \a new_vbkt_name name * @@ -332,258 +295,18 @@ class MetadataManager { * Get the TargetInfo for neighborhood * */ lipc::vector GetNeighborhoodTargetInfo() { + return {}; } /** * Get all TargetInfo in the system * */ lipc::vector GetGlobalTargetInfo() { + return {}; } public: RPC_AUTOGEN_START - BucketId GetOrCreateBucket(lipc::charbuf& bkt_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetOrCreateBucket( - bkt_name); - } else { - return rpc_->Call( - target_node, "GetOrCreateBucket", - bkt_name); - } - } - BucketId GetBucketId(lipc::charbuf& bkt_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetBucketId( - bkt_name); - } else { - return rpc_->Call( - target_node, "GetBucketId", - bkt_name); - } - } - bool BucketContainsBlob(BucketId bkt_id, BlobId blob_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalBucketContainsBlob( - bkt_id, blob_id); - } else { - return rpc_->Call( - target_node, "BucketContainsBlob", - bkt_id, blob_id); - } - } - bool RenameBucket(BucketId bkt_id, lipc::charbuf& new_bkt_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalRenameBucket( - bkt_id, new_bkt_name); - } else { - return rpc_->Call( - target_node, "RenameBucket", - bkt_id, new_bkt_name); - } - } - bool DestroyBucket(BucketId bkt_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalDestroyBucket( - bkt_id); - } else { - return rpc_->Call( - target_node, "DestroyBucket", - bkt_id); - } - } - BlobId BucketPutBlob(BucketId bkt_id, lipc::charbuf& blob_name, Blob& data, lipc::vector& buffers) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalBucketPutBlob( - bkt_id, blob_name, data, buffers); - } else { - return rpc_->Call( - target_node, "BucketPutBlob", - bkt_id, blob_name, data, buffers); - } - } - BlobId GetBlobId(BucketId bkt_id, lipc::charbuf& blob_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetBlobId( - bkt_id, blob_name); - } else { - return rpc_->Call( - target_node, "GetBlobId", - bkt_id, blob_name); - } - } - bool SetBlobBuffers(BlobId blob_id, lipc::vector& buffers) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalSetBlobBuffers( - blob_id, buffers); - } else { - return rpc_->Call( - target_node, "SetBlobBuffers", - blob_id, buffers); - } - } - lipc::vector GetBlobBuffers(BlobId blob_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetBlobBuffers( - blob_id); - } else { - return rpc_->Call>( - target_node, "GetBlobBuffers", - blob_id); - } - } - bool RenameBlob(BucketId bkt_id, BlobId blob_id, lipc::charbuf& new_blob_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalRenameBlob( - bkt_id, blob_id, new_blob_name); - } else { - return rpc_->Call( - target_node, "RenameBlob", - bkt_id, blob_id, new_blob_name); - } - } - bool DestroyBlob(BucketId bkt_id, lipc::charbuf& blob_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalDestroyBlob( - bkt_id, blob_name); - } else { - return rpc_->Call( - target_node, "DestroyBlob", - bkt_id, blob_name); - } - } - bool WriteLockBlob(BlobId blob_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalWriteLockBlob( - blob_id); - } else { - return rpc_->Call( - target_node, "WriteLockBlob", - blob_id); - } - } - bool WriteUnlockBlob(BlobId blob_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalWriteUnlockBlob( - blob_id); - } else { - return rpc_->Call( - target_node, "WriteUnlockBlob", - blob_id); - } - } - bool ReadLockBlob(BlobId blob_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalReadLockBlob( - blob_id); - } else { - return rpc_->Call( - target_node, "ReadLockBlob", - blob_id); - } - } - bool ReadUnlockBlob(BlobId blob_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalReadUnlockBlob( - blob_id); - } else { - return rpc_->Call( - target_node, "ReadUnlockBlob", - blob_id); - } - } - VBucketId GetOrCreateVBucket(lipc::charbuf& vbkt_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetOrCreateVBucket( - vbkt_name); - } else { - return rpc_->Call( - target_node, "GetOrCreateVBucket", - vbkt_name); - } - } - VBucketId GetVBucketId(lipc::charbuf& vbkt_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalGetVBucketId( - vbkt_name); - } else { - return rpc_->Call( - target_node, "GetVBucketId", - vbkt_name); - } - } - VBucketId VBucketLinkBlob(VBucketId vbkt_id, BucketId bkt_id, lipc::charbuf& blob_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalVBucketLinkBlob( - vbkt_id, bkt_id, blob_name); - } else { - return rpc_->Call( - target_node, "VBucketLinkBlob", - vbkt_id, bkt_id, blob_name); - } - } - VBucketId VBucketUnlinkBlob(VBucketId vbkt_id, BucketId bkt_id, lipc::charbuf& blob_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalVBucketUnlinkBlob( - vbkt_id, bkt_id, blob_name); - } else { - return rpc_->Call( - target_node, "VBucketUnlinkBlob", - vbkt_id, bkt_id, blob_name); - } - } - std::list VBucketGetLinks(VBucketId vbkt_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalVBucketGetLinks( - vbkt_id); - } else { - return rpc_->Call>( - target_node, "VBucketGetLinks", - vbkt_id); - } - } - bool RenameVBucket(VBucketId vbkt_id, lipc::charbuf& new_vbkt_name) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalRenameVBucket( - vbkt_id, new_vbkt_name); - } else { - return rpc_->Call( - target_node, "RenameVBucket", - vbkt_id, new_vbkt_name); - } - } - bool DestroyVBucket(VBucketId vbkt_id) { - u32 target_node = rpc_->node_id_; - if (target_node == rpc_->node_id_) { - return LocalDestroyVBucket( - vbkt_id); - } else { - return rpc_->Call( - target_node, "DestroyVBucket", - vbkt_id); - } - } RPC_AUTOGEN_END }; diff --git a/src/metadata_types.h b/src/metadata_types.h index 2b88740b6..49af057c8 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -263,7 +263,7 @@ struct BucketInfo : public SHM_CONTAINER(BucketInfo) { /** Represents a VBucket in shared memory */ template<> struct ShmHeader : public lipc::ShmBaseHeader { - lipc::ShmArchive> name_; + lipc::ShmArchive name_; lipc::ShmArchive> blobs_; }; @@ -273,7 +273,7 @@ struct VBucketInfo : public SHM_CONTAINER(VBucketInfo) { SHM_CONTAINER_TEMPLATE(VBucketInfo, VBucketInfo); public: - lipc::mptr> name_; + lipc::mptr name_; lipc::mptr> blobs_; public: diff --git a/src/rpc_thallium_defs.cc b/src/rpc_thallium_defs.cc index 5594c4d7a..00ef5027d 100644 --- a/src/rpc_thallium_defs.cc +++ b/src/rpc_thallium_defs.cc @@ -17,138 +17,6 @@ void ThalliumRpc::DefineRpcs() { RPC_CLASS_INSTANCE_DEFS_END RPC_AUTOGEN_START - auto remote_get_or_create_bucket = - [mdm](const request &req, lipc::charbuf& bkt_name) { - auto result = mdm->LocalGetOrCreateBucket(bkt_name); - req.respond(result); - }; - server_engine_->define("GetOrCreateBucket", remote_get_or_create_bucket); - auto remote_get_bucket_id = - [mdm](const request &req, lipc::charbuf& bkt_name) { - auto result = mdm->LocalGetBucketId(bkt_name); - req.respond(result); - }; - server_engine_->define("GetBucketId", remote_get_bucket_id); - auto remote_bucket_contains_blob = - [mdm](const request &req, BucketId bkt_id, BlobId blob_id) { - auto result = mdm->LocalBucketContainsBlob(bkt_id, blob_id); - req.respond(result); - }; - server_engine_->define("BucketContainsBlob", remote_bucket_contains_blob); - auto remote_rename_bucket = - [mdm](const request &req, BucketId bkt_id, lipc::charbuf& new_bkt_name) { - auto result = mdm->LocalRenameBucket(bkt_id, new_bkt_name); - req.respond(result); - }; - server_engine_->define("RenameBucket", remote_rename_bucket); - auto remote_destroy_bucket = - [mdm](const request &req, BucketId bkt_id) { - auto result = mdm->LocalDestroyBucket(bkt_id); - req.respond(result); - }; - server_engine_->define("DestroyBucket", remote_destroy_bucket); - auto remote_bucket_put_blob = - [mdm](const request &req, BucketId bkt_id, lipc::charbuf& blob_name, Blob& data, lipc::vector& buffers) { - auto result = mdm->LocalBucketPutBlob(bkt_id, blob_name, data, buffers); - req.respond(result); - }; - server_engine_->define("BucketPutBlob", remote_bucket_put_blob); - auto remote_get_blob_id = - [mdm](const request &req, BucketId bkt_id, lipc::charbuf& blob_name) { - auto result = mdm->LocalGetBlobId(bkt_id, blob_name); - req.respond(result); - }; - server_engine_->define("GetBlobId", remote_get_blob_id); - auto remote_set_blob_buffers = - [mdm](const request &req, BlobId blob_id, lipc::vector& buffers) { - auto result = mdm->LocalSetBlobBuffers(blob_id, buffers); - req.respond(result); - }; - server_engine_->define("SetBlobBuffers", remote_set_blob_buffers); - auto remote_get_blob_buffers = - [mdm](const request &req, BlobId blob_id) { - auto result = mdm->LocalGetBlobBuffers(blob_id); - req.respond(std::ref(result)); - }; - server_engine_->define("GetBlobBuffers", remote_get_blob_buffers); - auto remote_rename_blob = - [mdm](const request &req, BucketId bkt_id, BlobId blob_id, lipc::charbuf& new_blob_name) { - auto result = mdm->LocalRenameBlob(bkt_id, blob_id, new_blob_name); - req.respond(result); - }; - server_engine_->define("RenameBlob", remote_rename_blob); - auto remote_destroy_blob = - [mdm](const request &req, BucketId bkt_id, lipc::charbuf& blob_name) { - auto result = mdm->LocalDestroyBlob(bkt_id, blob_name); - req.respond(result); - }; - server_engine_->define("DestroyBlob", remote_destroy_blob); - auto remote_write_lock_blob = - [mdm](const request &req, BlobId blob_id) { - auto result = mdm->LocalWriteLockBlob(blob_id); - req.respond(result); - }; - server_engine_->define("WriteLockBlob", remote_write_lock_blob); - auto remote_write_unlock_blob = - [mdm](const request &req, BlobId blob_id) { - auto result = mdm->LocalWriteUnlockBlob(blob_id); - req.respond(result); - }; - server_engine_->define("WriteUnlockBlob", remote_write_unlock_blob); - auto remote_read_lock_blob = - [mdm](const request &req, BlobId blob_id) { - auto result = mdm->LocalReadLockBlob(blob_id); - req.respond(result); - }; - server_engine_->define("ReadLockBlob", remote_read_lock_blob); - auto remote_read_unlock_blob = - [mdm](const request &req, BlobId blob_id) { - auto result = mdm->LocalReadUnlockBlob(blob_id); - req.respond(result); - }; - server_engine_->define("ReadUnlockBlob", remote_read_unlock_blob); - auto remote_get_or_create_v_bucket = - [mdm](const request &req, lipc::charbuf& vbkt_name) { - auto result = mdm->LocalGetOrCreateVBucket(vbkt_name); - req.respond(result); - }; - server_engine_->define("GetOrCreateVBucket", remote_get_or_create_v_bucket); - auto remote_get_v_bucket_id = - [mdm](const request &req, lipc::charbuf& vbkt_name) { - auto result = mdm->LocalGetVBucketId(vbkt_name); - req.respond(result); - }; - server_engine_->define("GetVBucketId", remote_get_v_bucket_id); - auto remote_v_bucket_link_blob = - [mdm](const request &req, VBucketId vbkt_id, BucketId bkt_id, lipc::charbuf& blob_name) { - auto result = mdm->LocalVBucketLinkBlob(vbkt_id, bkt_id, blob_name); - req.respond(result); - }; - server_engine_->define("VBucketLinkBlob", remote_v_bucket_link_blob); - auto remote_v_bucket_unlink_blob = - [mdm](const request &req, VBucketId vbkt_id, BucketId bkt_id, lipc::charbuf& blob_name) { - auto result = mdm->LocalVBucketUnlinkBlob(vbkt_id, bkt_id, blob_name); - req.respond(result); - }; - server_engine_->define("VBucketUnlinkBlob", remote_v_bucket_unlink_blob); - auto remote_v_bucket_get_links = - [mdm](const request &req, VBucketId vbkt_id) { - auto result = mdm->LocalVBucketGetLinks(vbkt_id); - req.respond(result); - }; - server_engine_->define("VBucketGetLinks", remote_v_bucket_get_links); - auto remote_rename_v_bucket = - [mdm](const request &req, VBucketId vbkt_id, lipc::charbuf& new_vbkt_name) { - auto result = mdm->LocalRenameVBucket(vbkt_id, new_vbkt_name); - req.respond(result); - }; - server_engine_->define("RenameVBucket", remote_rename_v_bucket); - auto remote_destroy_v_bucket = - [mdm](const request &req, VBucketId vbkt_id) { - auto result = mdm->LocalDestroyVBucket(vbkt_id); - req.respond(result); - }; - server_engine_->define("DestroyVBucket", remote_destroy_v_bucket); RPC_AUTOGEN_END } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f08262799..ae15ab0a4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,7 +11,10 @@ include_directories( #------------------------------------------------------------------------------ # API tests #------------------------------------------------------------------------------ -set(API_TESTS test_rpc test_put_get) +set(API_TESTS + test_rpc + test_put_get + test_vbucket) foreach(program ${API_TESTS}) add_executable(${program} ${program}.cc main_mpi.cc) diff --git a/test/test_put_get.cc b/test/test_bucket.cc similarity index 92% rename from test/test_put_get.cc rename to test/test_bucket.cc index 078b3bd66..63228418f 100644 --- a/test/test_put_get.cc +++ b/test/test_bucket.cc @@ -51,8 +51,8 @@ void TestManyPuts(hapi::Hermes *hermes) { hermes::Blob blob; bkt->GetBlobId(name, blob_id, ctx); bkt->Get(blob_id, blob, ctx); - assert(blob.size() == blob_size); - assert(VerifyBuffer(blob.data(), blob_size, nonce)); + REQUIRE(blob.size() == blob_size); + REQUIRE(VerifyBuffer(blob.data(), blob_size, nonce)); } } @@ -67,8 +67,8 @@ void TestBlobOverride(hapi::Hermes *hermes) { bkt2->Put("0", std::move(blob), blob_id, ctx); hermes::Blob ret; bkt->Get(blob_id, ret, ctx); - assert(ret.size() == 1024); - assert(VerifyBuffer(ret.data(), 1024, 10)); + REQUIRE(ret.size() == 1024); + REQUIRE(VerifyBuffer(ret.data(), 1024, 10)); } } diff --git a/test/test_vbucket.cc b/test/test_vbucket.cc new file mode 100644 index 000000000..bb53babe1 --- /dev/null +++ b/test/test_vbucket.cc @@ -0,0 +1,31 @@ +// +// Created by lukemartinlogan on 1/5/23. +// + +#include +#include + +#include +#include +#include "hermes.h" +#include "bucket.h" +#include "vbucket.h" + +#include "basic_test.h" + +namespace hapi = hermes::api; + +void TestVBucketCreateDestroy(hapi::Hermes *hermes) { + auto bkt = hermes->GetBucket("hello"); + auto vbkt = hermes->GetVBucket("hello"); + hermes::api::Context ctx; + + hapi::Blob blob(1024); + hermes::BlobId blob_id; + bkt->Put("0", blob, blob_id, ctx); + vbkt->Link(blob_id, ctx); +} + +TEST_CASE("TestVBucketCreate") { + TestVBucketCreateDestroy(HERMES); +} \ No newline at end of file From 37a76d466e1639bc2451f910b33ba2bc6dd18449 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sat, 7 Jan 2023 05:46:12 -0600 Subject: [PATCH 085/511] Basic tests of all bucket stuff --- src/api/bucket.cc | 34 +++++++++++++++---- src/api/bucket.h | 32 +++++++++++++++-- src/api/hermes.cc | 5 ++- src/metadata_types.h | 1 + test/CMakeLists.txt | 2 +- test/test_bucket.cc | 81 ++++++++++++++++++++++++++++++++++++++++++++ test/test_vbucket.cc | 8 +++++ 7 files changed, 149 insertions(+), 14 deletions(-) diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 18d0cb1b2..0af3485c8 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -7,13 +7,16 @@ namespace hermes::api { +/////////////////////////// +////// Bucket Operations +////////////////////////// + /** * Either initialize or fetch the bucket. * */ Bucket::Bucket(std::string name, Context &ctx) : mdm_(&HERMES->mdm_), bpm_(&HERMES->bpm_) { lipc::string lname(name); - // TODO(llogan): rpcify id_ = mdm_->LocalGetOrCreateBucket(lname); } @@ -22,24 +25,26 @@ Bucket::Bucket(std::string name, Context &ctx) * */ void Bucket::Rename(std::string new_bkt_name) { lipc::string lname(new_bkt_name); - // TODO(llogan): rpcify mdm_->LocalRenameBucket(id_, lname); } /** * Destroys this bucket along with all its contents. * */ -void Bucket::Destroy(std::string blob_name) { +void Bucket::Destroy() { } +/////////////////////// +////// Blob Operations +/////////////////////// + /** * Get the id of a blob from the blob name * */ Status Bucket::GetBlobId(std::string blob_name, BlobId &blob_id, Context &ctx) { - lipc::string blob_name_l(blob_name); - // TODO(llogan): rpcify - blob_id = mdm_->LocalGetBlobId(GetId(), blob_name_l); + lipc::string lblob_name(blob_name); + blob_id = mdm_->LocalGetBlobId(GetId(), lblob_name); return Status(); } @@ -68,11 +73,26 @@ Status Bucket::Put(std::string blob_name, Blob blob, /** * Get \a blob_id Blob from the bucket - * :WRAP-param: ctx -> ctx_ * */ Status Bucket::Get(BlobId blob_id, Blob &blob, Context &ctx) { blob = mdm_->LocalBucketGetBlob(blob_id); return Status(); } +/** + * Rename \a blob_id blob to \a new_blob_name new name + * */ +void Bucket::RenameBlob(BlobId blob_id, + std::string new_blob_name, Context &ctx) { + lipc::string lnew_blob_name(new_blob_name); + mdm_->LocalRenameBlob(id_, blob_id, lnew_blob_name); +} + +/** + * Delete \a blob_id blob + * */ +void Bucket::DestroyBlob(BlobId blob_id, Context &ctx) { + mdm_->LocalDestroyBlob(id_, blob_id); +} + } // namespace hermes::api \ No newline at end of file diff --git a/src/api/bucket.h b/src/api/bucket.h index cc9409f4d..7f516532e 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -19,7 +19,9 @@ class Bucket { std::string name_; Context ctx_; - /* Bucket operations */ + /////////////////////////// + ////// Bucket Operations + ////////////////////////// public: /** @@ -54,14 +56,28 @@ class Bucket { /** * Destroys this bucket along with all its contents. * */ - void Destroy(std::string blob_name); + void Destroy(); + /** + * Check if this bucket is valid + * */ + bool IsNull() { + return id_.IsNull(); + } - /* Blob operations */ + + /////////////////////// + ////// Blob Operations + /////////////////////// public: /** * Get the id of a blob from the blob name + * + * @param blob_name the name of the blob + * @param blob_id (output) the returned blob_id + * @param ctx any additional information + * @return The Status of the operation * */ Status GetBlobId(std::string blob_name, BlobId &blob_id, Context &ctx); @@ -79,6 +95,16 @@ class Bucket { * */ Status Get(BlobId blob_id, Blob &blob, Context &ctx); + /** + * Rename \a blob_id blob to \a new_blob_name new name + * */ + void RenameBlob(BlobId blob_id, std::string new_blob_name, Context &ctx); + + /** + * Delete \a blob_id blob + * */ + void DestroyBlob(BlobId blob_id, Context &ctx); + public: RPC_AUTOGEN_START RPC_AUTOGEN_END diff --git a/src/api/hermes.cc b/src/api/hermes.cc index dd34e29ee..a37b0d678 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -126,9 +126,8 @@ void Hermes::LoadSharedMemory() { void Hermes::FinalizeServer() { // TODO(llogan): Fix the shared memory segfault // NOTE(llogan): rpc_.Finalize() is called internally by daemon in this case - // bpm_.shm_destroy(); - // mdm_.shm_destroy(); - // LABSTOR_MEMORY_MANAGER->DestroyBackend(server_config_.shmem_name_); + bpm_.shm_destroy(); + mdm_.shm_destroy(); } void Hermes::FinalizeClient() { diff --git a/src/metadata_types.h b/src/metadata_types.h index 49af057c8..383e4454b 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -201,6 +201,7 @@ struct BlobInfo : public SHM_CONTAINER(BlobInfo){ template<> struct ShmHeader : public lipc::ShmBaseHeader { lipc::ShmArchive name_ar_; + size_t num_blobs_; }; /** Metadata for a Bucket */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ae15ab0a4..e4b833c93 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -13,7 +13,7 @@ include_directories( #------------------------------------------------------------------------------ set(API_TESTS test_rpc - test_put_get + test_bucket test_vbucket) foreach(program ${API_TESTS}) diff --git a/test/test_bucket.cc b/test/test_bucket.cc index 63228418f..a015969dc 100644 --- a/test/test_bucket.cc +++ b/test/test_bucket.cc @@ -72,10 +72,91 @@ void TestBlobOverride(hapi::Hermes *hermes) { } } +void TestBucketRename(hapi::Hermes *hermes) { + auto bkt = hermes->GetBucket("hello"); + bkt->Rename("hello2"); + auto bkt1 = hermes->GetBucket("hello"); + auto bkt2 = hermes->GetBucket("hello2"); + + REQUIRE(!bkt2->IsNull()); + REQUIRE(bkt1->GetId() != bkt2->GetId()); + REQUIRE(bkt->GetId() == bkt2->GetId()); +} + +void TestBucketDestroy(hapi::Hermes *hermes) { + auto bkt = hermes->GetBucket("hello"); + int num_blobs = 1; + size_t blob_size = MEGABYTES(150); + hermes::api::Context ctx; + hermes::BlobId blob_id; + + for (size_t i = 0; i < num_blobs; ++i) { + hermes::Blob blob(blob_size); + std::string name = std::to_string(i); + char nonce = i % 256; + memset(blob.data_mutable(), nonce, blob_size); + bkt->Put(name, std::move(blob), blob_id, ctx); + } + + bkt->Destroy(); +} + +void TestBlobRename(hapi::Hermes *hermes) { + auto bkt = hermes->GetBucket("hello"); + hapi::Blob blob(1024); + hermes::BlobId blob_id; + hapi::Context ctx; + bkt->Put("0", blob, blob_id, ctx); + bkt->RenameBlob(blob_id, "1", ctx); + + { + hermes::BlobId blob_get_id; + bkt->GetBlobId("0", blob_get_id, ctx); + REQUIRE(blob_get_id.IsNull()); + } + + { + hermes::BlobId blob_get_id; + bkt->GetBlobId("1", blob_get_id, ctx); + REQUIRE(!blob_get_id.IsNull()); + REQUIRE(blob_get_id == blob_id); + } +} + +void TestBlobDestroy(hapi::Hermes *hermes) { + auto bkt = hermes->GetBucket("hello"); + hapi::Blob blob(1024); + hermes::BlobId blob_id; + hapi::Context ctx; + bkt->Put("0", blob, blob_id, ctx); + bkt->DestroyBlob(blob_id, ctx); + { + hermes::BlobId blob_id_get; + bkt->GetBlobId("0", blob_id_get, ctx); + REQUIRE(blob_id_get.IsNull()); + } +} + TEST_CASE("TestManyPuts") { TestManyPuts(HERMES); } TEST_CASE("TestBlobOverride") { TestBlobOverride(HERMES); +} + +TEST_CASE("TestBucketRename") { + TestBucketRename(HERMES); +} + +TEST_CASE("TestBucketDestroy") { + TestBucketDestroy(HERMES); +} + +TEST_CASE("TestBlobRename") { + TestBlobRename(HERMES); +} + +TEST_CASE("TestBlobDestroy") { + TestBlobDestroy(HERMES); } \ No newline at end of file diff --git a/test/test_vbucket.cc b/test/test_vbucket.cc index bb53babe1..b6b25136f 100644 --- a/test/test_vbucket.cc +++ b/test/test_vbucket.cc @@ -15,6 +15,14 @@ namespace hapi = hermes::api; +void MainPretest() { + hapi::Hermes::Create(hermes::HermesType::kClient); +} + +void MainPosttest() { + HERMES->Finalize(); +} + void TestVBucketCreateDestroy(hapi::Hermes *hermes) { auto bkt = hermes->GetBucket("hello"); auto vbkt = hermes->GetVBucket("hello"); From 5ceaf7ad1b7b027f26b5d1169d076f6f812dc4cb Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 19 Jan 2023 09:00:21 -0600 Subject: [PATCH 086/511] Copy-paste from hermes_old --- adapter/filesystem/filesystem.cc | 392 ++++++++++ adapter/filesystem/filesystem.h | 452 +++++++++++ adapter/posix/posix.cc | 72 +- adapter/stdio/CMakeLists.txt | 49 ++ adapter/stdio/fs_api.cc | 102 +++ adapter/stdio/fs_api.h | 64 ++ adapter/stdio/real_api.h | 300 ++++++++ adapter/stdio/stdio.cc | 565 ++++++++++++++ adapter/utils.h | 10 + adapter/vfd/CMakeLists.txt | 189 +++++ adapter/vfd/H5FDhermes.c | 1173 +++++++++++++++++++++++++++++ adapter/vfd/H5FDhermes.h | 60 ++ adapter/vfd/H5FDhermes_err.h | 199 +++++ adapter/vfd/README.md | 102 +++ benchmarks/put_get_bench.cc | 35 +- config/hermes_server_default.yaml | 2 +- src/io_clients/posix.h | 12 +- src/metadata_manager.cc | 12 +- src/prefetcher.cc | 225 ++++++ src/prefetcher.h | 264 +++++++ src/prefetcher_factory.h | 48 ++ src/prefetchers/apriori.cc | 13 + src/prefetchers/apriori.h | 28 + src/prefetchers/sequential.cc | 145 ++++ src/prefetchers/sequential.h | 52 ++ test/test_vbucket.cc | 1 + 26 files changed, 4489 insertions(+), 77 deletions(-) create mode 100644 adapter/filesystem/filesystem.cc create mode 100644 adapter/filesystem/filesystem.h create mode 100644 adapter/stdio/CMakeLists.txt create mode 100644 adapter/stdio/fs_api.cc create mode 100644 adapter/stdio/fs_api.h create mode 100644 adapter/stdio/real_api.h create mode 100644 adapter/stdio/stdio.cc create mode 100644 adapter/utils.h create mode 100644 adapter/vfd/CMakeLists.txt create mode 100644 adapter/vfd/H5FDhermes.c create mode 100644 adapter/vfd/H5FDhermes.h create mode 100644 adapter/vfd/H5FDhermes_err.h create mode 100644 adapter/vfd/README.md create mode 100644 src/prefetcher.cc create mode 100644 src/prefetcher.h create mode 100644 src/prefetcher_factory.h create mode 100644 src/prefetchers/apriori.cc create mode 100644 src/prefetchers/apriori.h create mode 100644 src/prefetchers/sequential.cc create mode 100644 src/prefetchers/sequential.h diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc new file mode 100644 index 000000000..eee3ff841 --- /dev/null +++ b/adapter/filesystem/filesystem.cc @@ -0,0 +1,392 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "filesystem.h" +#include "constants.h" +#include "singleton.h" +#include "metadata_manager.h" +#include "vbucket.h" + +#include +#include + +namespace stdfs = std::experimental::filesystem; + +namespace hermes::adapter::fs { + +File Filesystem::Open(AdapterStat &stat, const std::string &path) { + File f = _RealOpen(stat, path); + if (!f.status_) { return f; } + Open(stat, f, path); + return f; +} + +void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { + _InitFile(f); + auto mdm = HERMES_FILESYSTEM_ADAPTER_METADTA_MANAGER; + stat.bkt_id_ = HERMES->GetBucket(path); + LOG(INFO) << "File not opened before by adapter" << std::endl; + _OpenInitStats(f, stat); + mdm->Create(f, stat); +} + +void Filesystem::_PutWithFallback(AdapterStat &stat, + const std::string &blob_name, + const std::string &filename, + hapi::Blob blob, + size_t offset, + IoStatus &io_status, IoOptions &opts) { + hapi::Context ctx; + hermes::BlobId blob_id; + hapi::Status put_status = stat.bkt_id_->Put(blob_name, blob, blob_id, ctx); + if (put_status.Fail()) { + if (opts.with_fallback_) { + LOG(WARNING) << "Failed to Put Blob " << blob_name << " to Bucket " + << filename << ". Falling back to posix I/O." << std::endl; + _RealWrite(filename, offset, size, data, io_status, opts); + } + } +} + +size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, + size_t off, size_t total_size, + IoStatus &io_status, IoOptions opts) { + (void) f; + std::shared_ptr &bkt = stat.st_bkid; + std::string filename = bkt->GetName(); + LOG(INFO) << "Write called for filename: " << filename << " on offset: " + << off << " and size: " << total_size << std::endl; + + size_t ret; + auto mdm = Singleton::GetInstance(); + BlobPlacements mapping; + auto mapper = MapperFactory().Get(kMapperType); + mapper->map(off, total_size, mapping); + size_t data_offset = 0; + + for (const auto &p : mapping) { + BlobPlacementIter wi(f, stat, filename, p, bkt, io_status, opts); + wi.blob_name_ = wi.p_.CreateBlobName(); + wi.blob_exists_ = wi.bkt_->ContainsBlob(wi.blob_name_); + wi.blob_start_ = p.page_ * kPageSize; + wi.mem_ptr_ = (u8 *)ptr + data_offset; + data_offset += p.blob_size_; + } + off_t f_offset = off + data_offset; + if (opts.seek_) { stat.st_ptr = f_offset; } + stat.st_size = std::max(stat.st_size, static_cast(f_offset)); + + struct timespec ts; + timespec_get(&ts, TIME_UTC); + stat.st_mtim = ts; + stat.st_ctim = ts; + + ret = data_offset; + _IoStats(data_offset, io_status, opts); + return ret; +} + +HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, + size_t off, size_t total_size, size_t req_id, + IoStatus &io_status, IoOptions opts) { + (void) io_status; + LOG(INFO) << "Starting an asynchronous write" << std::endl; + auto pool = + Singleton::GetInstance(kNumThreads); + HermesRequest *hreq = new HermesRequest(); + auto lambda = + [](Filesystem *fs, File &f, AdapterStat &stat, const void *ptr, + size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { + return fs->Write(f, stat, ptr, off, total_size, io_status, opts); + }; + auto func = std::bind(lambda, this, f, stat, ptr, off, + total_size, hreq->io_status, opts); + hreq->return_future = pool->run(func); + auto mdm = Singleton::GetInstance(); + mdm->request_map.emplace(req_id, hreq); + return hreq; +} + +HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, + size_t off, size_t total_size, size_t req_id, + IoStatus &io_status, IoOptions opts) { + (void) io_status; + auto pool = + Singleton::GetInstance(kNumThreads); + HermesRequest *hreq = new HermesRequest(); + auto lambda = + [](Filesystem *fs, File &f, AdapterStat &stat, void *ptr, + size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { + return fs->Read(f, stat, ptr, off, total_size, io_status, opts); + }; + auto func = std::bind(lambda, this, f, stat, + ptr, off, total_size, hreq->io_status, opts); + hreq->return_future = pool->run(func); + auto mdm = Singleton::GetInstance(); + mdm->request_map.emplace(req_id, hreq); + return hreq; +} + +size_t Filesystem::Wait(uint64_t req_id) { + auto mdm = Singleton::GetInstance(); + auto req_iter = mdm->request_map.find(req_id); + if (req_iter == mdm->request_map.end()) { + return 0; + } + HermesRequest *req = (*req_iter).second; + size_t ret = req->return_future.get(); + delete req; + return ret; +} + +void Filesystem::Wait(std::vector &req_ids, + std::vector &ret) { + for (auto &req_id : req_ids) { + ret.emplace_back(Wait(req_id)); + } +} + +off_t Filesystem::Seek(File &f, AdapterStat &stat, + SeekMode whence, off_t offset) { + if (stat.is_append_) { + LOG(INFO) + << "File pointer not updating as file was opened in append mode." + << std::endl; + return -1; + } + auto mdm = Singleton::GetInstance(); + switch (whence) { + case SeekMode::kSet: { + stat.st_ptr_ = offset; + break; + } + case SeekMode::kCurrent: { + stat.st_ptr_ += offset; + break; + } + case SeekMode::kEnd: { + stat.st_ptr_ = stat.st_size + offset; + break; + } + default: { + // TODO(hari): throw not implemented error. + } + } + mdm->Update(f, stat); + return stat.st_ptr_; +} + +off_t Filesystem::Tell(File &f, AdapterStat &stat) { + (void) f; + return stat.st_ptr_; +} + +int Filesystem::Sync(File &f, AdapterStat &stat) { +} + +int Filesystem::Close(File &f, AdapterStat &stat, bool destroy) { +} + + +/** + * Variants of Read and Write which do not take an offset as + * input. + * */ + +size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, + size_t total_size, IoStatus &io_status, + IoOptions opts) { + off_t off = Tell(f, stat); + return Write(f, stat, ptr, off, total_size, io_status, opts); +} + +size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, + size_t total_size, + IoStatus &io_status, IoOptions opts) { + off_t off = Tell(f, stat); + return Read(f, stat, ptr, off, total_size, io_status, opts); +} + +HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, + size_t total_size, size_t req_id, + IoStatus &io_status, IoOptions opts) { + off_t off = Tell(f, stat); + return AWrite(f, stat, ptr, off, total_size, req_id, io_status, opts); +} + +HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, + size_t total_size, size_t req_id, + IoStatus &io_status, IoOptions opts) { + off_t off = Tell(f, stat); + return ARead(f, stat, ptr, off, total_size, req_id, io_status, opts); +} + + +/** + * Variants of the above functions which retrieve the AdapterStat + * data structure internally. + * */ + +size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, + size_t total_size, + IoStatus &io_status, IoOptions opts) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return 0; + } + stat_exists = true; + return Write(f, stat, ptr, total_size, io_status, opts); +} + +size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, + size_t total_size, + IoStatus &io_status, IoOptions opts) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return 0; + } + stat_exists = true; + return Read(f, stat, ptr, total_size, io_status, opts); +} + +size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, + size_t off, size_t total_size, + IoStatus &io_status, IoOptions opts) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return 0; + } + stat_exists = true; + opts.seek_ = false; + return Write(f, stat, ptr, off, total_size, io_status, opts); +} + +size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, + size_t off, size_t total_size, + IoStatus &io_status, IoOptions opts) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return 0; + } + stat_exists = true; + opts.seek_ = false; + return Read(f, stat, ptr, off, total_size, io_status, opts); +} + +HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, + size_t total_size, size_t req_id, + IoStatus &io_status, IoOptions opts) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return 0; + } + stat_exists = true; + return AWrite(f, stat, ptr, total_size, req_id, io_status, opts); +} + +HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, + size_t total_size, size_t req_id, + IoStatus &io_status, IoOptions opts) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return 0; + } + stat_exists = true; + return ARead(f, stat, ptr, total_size, req_id, io_status, opts); +} + +HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, + size_t off, size_t total_size, size_t req_id, + IoStatus &io_status, IoOptions opts) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return 0; + } + stat_exists = true; + opts.seek_ = false; + return AWrite(f, stat, ptr, off, total_size, req_id, io_status, opts); +} + +HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, + size_t off, size_t total_size, size_t req_id, + IoStatus &io_status, IoOptions opts) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return 0; + } + stat_exists = true; + opts.seek_ = false; + return ARead(f, stat, ptr, off, total_size, req_id, io_status, opts); +} + +off_t Filesystem::Seek(File &f, bool &stat_exists, + SeekMode whence, off_t offset) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Seek(f, stat, whence, offset); +} + +off_t Filesystem::Tell(File &f, bool &stat_exists) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Tell(f, stat); +} + +int Filesystem::Sync(File &f, bool &stat_exists) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Sync(f, stat); +} + +int Filesystem::Close(File &f, bool &stat_exists, bool destroy) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Close(f, stat, destroy); +} + +} // namespace hermes::adapter::fs diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h new file mode 100644 index 000000000..439f939cb --- /dev/null +++ b/adapter/filesystem/filesystem.h @@ -0,0 +1,452 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_H_ +#define HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace hapi = hermes::api; + +namespace hermes::adapter::fs { + +enum class SeekMode { + kNone = -1, + kSet = SEEK_SET, + kCurrent = SEEK_CUR, + kEnd = SEEK_END +}; + +/** + A structure to represent adapter stat. +*/ +struct AdapterStat { + std::shared_ptr bkt_id_; /**< bucket associated with the file */ + /** VBucket for persisting data asynchronously. */ + std::shared_ptr vbkt_id_; + int flags_; /**< open() flags for POSIX */ + mode_t st_mode_; /**< protection */ + off64_t st_ptr_; /**< Current ptr of FILE */ + timespec st_atim_; /**< time of last access */ + timespec st_mtim_; /**< time of last modification */ + timespec st_ctim_; /**< time of last status change */ + std::string mode_str_; /**< mode used for fopen() */ + + bool is_append_; /**< File is in append mode */ + int amode_; /**< access mode */ + MPI_Info info_; /**< Info object (handle) */ + MPI_Comm comm_; /**< Communicator for the file.*/ + bool atomicity_; /**< Consistency semantics for data-access */ + + AdapterStat() + : bkt_id_(), + vbkt_id_(), + flags_(0), + st_mode_(), + st_ptr_(0), + st_atim_(), + st_mtim_(), + st_ctim_(), + is_append_(false), + amode_(0), + comm_(MPI_COMM_SELF), + atomicity_(false) {} + + /** compare \a a BLOB and \a b BLOB.*/ + static bool CompareBlobs(const std::string &a, const std::string &b) { + return std::stol(a) < std::stol(b); + } +}; + +/** + A structure to represent file +*/ +struct File { + int fd_; /**< file descriptor */ + FILE *fh_; /**< file handler */ + MPI_File mpi_fh_; /**< MPI file handler */ + + dev_t st_dev; /**< device */ + ino_t st_ino; /**< inode */ + bool status_; /**< status */ + int mpi_status_; /**< MPI status */ + + /** default file constructor */ + File() + : fd_(-1), + fh_(nullptr), + mpi_fh_(nullptr), + st_dev(-1), + st_ino(-1), + status_(true), + mpi_status_(MPI_SUCCESS) {} + + /** file constructor that copies \a old file */ + File(const File &old) { Copy(old); } + + /** file assignment operator that copies \a old file */ + File &operator=(const File &old) { + Copy(old); + return *this; + } + + /** copy \a old file */ + void Copy(const File &old) { + fd_ = old.fd_; + fh_ = old.fh_; + mpi_fh_ = old.mpi_fh_; + st_dev = old.st_dev; + st_ino = old.st_ino; + status_ = old.status_; + } + + /** file comparison operator */ + bool operator==(const File &old) const { + return (st_dev == old.st_dev) && (st_ino == old.st_ino) && + (mpi_fh_ == old.mpi_fh_); + } + + /** return hash value of this class */ + std::size_t hash() const { + std::size_t result; + std::size_t h1 = std::hash{}(st_dev); + std::size_t h2 = std::hash{}(st_ino); + std::size_t h3 = std::hash{}(mpi_fh_); + result = h1 ^ h2 ^ h3; + return result; + } +}; + +/** + A structure to represent IO options +*/ +struct IoOptions { + PlacementPolicy dpe_; /**< data placement policy */ + bool coordinate_; /**< use coordinate? */ + bool seek_; /**< use seek? */ + bool with_fallback_; /**< use fallback? */ + MPI_Datatype mpi_type_; /**< MPI data type */ + int count_; /**< option count */ + IoOptions() + : dpe_(PlacementPolicy::kNone), + coordinate_(true), + seek_(true), + with_fallback_(true), + mpi_type_(MPI_CHAR), + count_(0) {} + + /** return options with \a dpe parallel data placement engine */ + static IoOptions WithParallelDpe(PlacementPolicy dpe) { + IoOptions opts; + opts.dpe_ = dpe; + opts.coordinate_ = true; + return opts; + } + + /** return direct IO options by setting placement policy to none */ + static IoOptions DirectIo(IoOptions &cur_opts) { + IoOptions opts(cur_opts); + opts.seek_ = false; + opts.dpe_ = PlacementPolicy::kNone; + opts.with_fallback_ = true; + return opts; + } + + /** return IO options with \a mpi_type MPI data type */ + static IoOptions DataType(MPI_Datatype mpi_type, bool seek = true) { + IoOptions opts; + opts.mpi_type_ = mpi_type; + opts.seek_ = seek; + return opts; + } + + /** + * Ensure that I/O goes only to Hermes, and does not fall back to PFS. + * + * @param orig_opts The original options to modify + * */ + static IoOptions PlaceInHermes(IoOptions &orig_opts) { + IoOptions opts(orig_opts); + opts.seek_ = false; + opts.with_fallback_ = false; + return opts; + } +}; + +/** + A structure to represent IO status +*/ +struct IoStatus { + int mpi_ret_; /**< MPI return value */ + MPI_Status mpi_status_; /**< MPI status */ + MPI_Status *mpi_status_ptr_; /**< MPI status pointer */ + + IoStatus() : mpi_ret_(MPI_SUCCESS), mpi_status_ptr_(&mpi_status_) {} +}; + +/** + A structure to represent Hermes request +*/ +struct HermesRequest { + std::future return_future; /**< future result of async op. */ + IoStatus io_status; /**< IO status */ +}; + +/** + A structure to represent BLOB placement iterator +*/ +struct BlobPlacementIter { + File &f_; /**< file */ + AdapterStat &stat_; /**< adapter stat */ + const std::string &filename_; /**< file name */ + const BlobPlacement &p_; /**< BLOB placement */ + std::shared_ptr &bkt_; /**< bucket*/ + IoStatus &io_status_; /**< IO status */ + IoOptions &opts_; /**< IO options */ + + std::string blob_name_; /**< BLOB name */ + u8 *mem_ptr_; /**< pointer to memory */ + size_t blob_start_; /**< BLOB start */ + hapi::Context ctx_; /**< context */ + hapi::Blob blob_; /**< BLOB */ + int rank_; /**< MPI rank */ + int nprocs_; /**< number of processes */ + bool blob_exists_; /**< Does BLOB exist? */ + + /** iterate \a p BLOB placement */ + explicit BlobPlacementIter(File &f, AdapterStat &stat, + const std::string &filename, + const BlobPlacement &p, + std::shared_ptr &bkt, + IoStatus &io_status, IoOptions &opts) + : f_(f), + stat_(stat), + filename_(filename), + p_(p), + bkt_(bkt), + io_status_(io_status), + opts_(opts) {} +}; + +/** + A class to represent file system +*/ +class Filesystem { + public: + /** open \a path */ + File Open(AdapterStat &stat, const std::string &path); + /** open \a f File in \a path*/ + void Open(AdapterStat &stat, File &f, const std::string &path); + /** write */ + size_t Write(File &f, AdapterStat &stat, const void *ptr, size_t off, + size_t total_size, IoStatus &io_status, + IoOptions opts = IoOptions()); + /** read */ + size_t Read(File &f, AdapterStat &stat, void *ptr, size_t off, + size_t total_size, IoStatus &io_status, + IoOptions opts = IoOptions()); + /** write asynchronously */ + HermesRequest *AWrite(File &f, AdapterStat &stat, const void *ptr, size_t off, + size_t total_size, size_t req_id, IoStatus &io_status, + IoOptions opts = IoOptions()); + /** read asynchronously */ + HermesRequest *ARead(File &f, AdapterStat &stat, void *ptr, size_t off, + size_t total_size, size_t req_id, IoStatus &io_status, + IoOptions opts = IoOptions()); + /** wait for \a req_id request ID */ + size_t Wait(uint64_t req_id); + /** wait for request IDs in \a req_id vector */ + void Wait(std::vector &req_id, std::vector &ret); + /** seek */ + off_t Seek(File &f, AdapterStat &stat, SeekMode whence, off_t offset); + /** tell */ + off_t Tell(File &f, AdapterStat &stat); + /** sync */ + int Sync(File &f, AdapterStat &stat); + /** close */ + int Close(File &f, AdapterStat &stat, bool destroy = true); + + /* + * APIs used internally + * */ + + private: + /** coordinated put */ + void _CoordinatedPut(BlobPlacementIter &wi); + /** uncoordinated put */ + void _UncoordinatedPut(BlobPlacementIter &wi); + /** write to a new aligned buffer */ + void _WriteToNewAligned(BlobPlacementIter &write_iter); + /** write to a new unaligned buffer */ + void _WriteToNewUnaligned(BlobPlacementIter &write_iter); + /** write to an existing aligned buffer */ + void _WriteToExistingAligned(BlobPlacementIter &write_iter); + /** write to an existing unaligned buffer */ + void _WriteToExistingUnaligned(BlobPlacementIter &write_iter); + /** put with fallback */ + void _PutWithFallback(AdapterStat &stat, const std::string &blob_name, + const std::string &filename, u8 *data, size_t size, + size_t offset, IoStatus &io_status_, IoOptions &opts); + /** read existing contained buffer */ + size_t _ReadExistingContained(BlobPlacementIter &read_iter); + /** read existing partial buffer */ + size_t _ReadExistingPartial(BlobPlacementIter &read_iter); + /** read new buffer */ + size_t _ReadNew(BlobPlacementIter &read_iter); + + void _OpenInitStatsInternal(AdapterStat &stat, bool bucket_exists) { + // TODO(llogan): This isn't really parallel-safe. + /** + * Here we assume that the file size can only be growing. + * If the bucket already exists and has content not already in + * the file (e.g., when using ADAPTER_MODE=SCRATCH), we should + * use the size of the bucket instead. + * + * There are other concerns with what happens during multi-tenancy. + * What happens if one process is opening a file, while another + * process is adding content? The mechanics here aren't + * well-defined. + * */ + if (bucket_exists) { + size_t orig = stat.st_size; + size_t bkt_size = stat.st_bkid->GetTotalBlobSize(); + stat.st_size = std::max(bkt_size, orig); + LOG(INFO) << "Since bucket exists, should reset its size to: " + << bkt_size << " or " << orig + << ", winner: " << stat.st_size << std::endl; + } + if (stat.is_append) { + stat.st_ptr = stat.st_size; + } + } + + /* + * The APIs to overload + */ + public: + /** initialize file */ + virtual void _InitFile(File &f) = 0; + + private: + /** open initial status */ + virtual void _OpenInitStats(File &f, AdapterStat &stat) = 0; + /** real open */ + virtual File _RealOpen(AdapterStat &stat, const std::string &path) = 0; + /** real write */ + virtual size_t _RealWrite(const std::string &filename, off_t offset, + size_t size, const u8 *data_ptr, + IoStatus &io_status, IoOptions &opts) = 0; + /** real read */ + virtual size_t _RealRead(const std::string &filename, off_t offset, + size_t size, u8 *data_ptr, IoStatus &io_status, + IoOptions &opts) = 0; + /** io status */ + virtual void _IoStats(size_t count, IoStatus &io_status, IoOptions &opts) { + (void)count; + (void)io_status; + (void)opts; + } + /** real sync */ + virtual int _RealSync(File &f) = 0; + /** real close */ + virtual int _RealClose(File &f) = 0; + + /* + * I/O APIs which seek based on the internal AdapterStat st_ptr, + * instead of taking an offset as input. + */ + + public: + /** write */ + size_t Write(File &f, AdapterStat &stat, const void *ptr, size_t total_size, + IoStatus &io_status, IoOptions opts); + /** read */ + size_t Read(File &f, AdapterStat &stat, void *ptr, size_t total_size, + IoStatus &io_status, IoOptions opts); + /** write asynchronously */ + HermesRequest *AWrite(File &f, AdapterStat &stat, const void *ptr, + size_t total_size, size_t req_id, IoStatus &io_status, + IoOptions opts); + /** read asynchronously */ + HermesRequest *ARead(File &f, AdapterStat &stat, void *ptr, size_t total_size, + size_t req_id, IoStatus &io_status, IoOptions opts); + + /* + * Locates the AdapterStat data structure internally, and + * call the underlying APIs which take AdapterStat as input. + */ + + public: + /** write */ + size_t Write(File &f, bool &stat_exists, const void *ptr, size_t total_size, + IoStatus &io_status, IoOptions opts = IoOptions()); + /** read */ + size_t Read(File &f, bool &stat_exists, void *ptr, size_t total_size, + IoStatus &io_status, IoOptions opts = IoOptions()); + /** write \a off offset */ + size_t Write(File &f, bool &stat_exists, const void *ptr, size_t off, + size_t total_size, IoStatus &io_status, + IoOptions opts = IoOptions()); + /** read \a off offset */ + size_t Read(File &f, bool &stat_exists, void *ptr, size_t off, + size_t total_size, IoStatus &io_status, + IoOptions opts = IoOptions()); + /** write asynchronously */ + HermesRequest *AWrite(File &f, bool &stat_exists, const void *ptr, + size_t total_size, size_t req_id, IoStatus &io_status, + IoOptions opts); + /** read asynchronously */ + HermesRequest *ARead(File &f, bool &stat_exists, void *ptr, size_t total_size, + size_t req_id, IoStatus &io_status, IoOptions opts); + /** write \a off offset asynchronously */ + HermesRequest *AWrite(File &f, bool &stat_exists, const void *ptr, size_t off, + size_t total_size, size_t req_id, IoStatus &io_status, + IoOptions opts); + /** read \a off offset asynchronously */ + HermesRequest *ARead(File &f, bool &stat_exists, void *ptr, size_t off, + size_t total_size, size_t req_id, IoStatus &io_status, + IoOptions opts); + /** seek */ + off_t Seek(File &f, bool &stat_exists, SeekMode whence, off_t offset); + /** tell */ + off_t Tell(File &f, bool &stat_exists); + /** sync */ + int Sync(File &f, bool &stat_exists); + /** close */ + int Close(File &f, bool &stat_exists, bool destroy = true); +}; + +} // namespace hermes::adapter::fs + +namespace std { +/** + A structure to represent hash +*/ +template <> +struct hash { + /** hash creator functor */ + std::size_t operator()(const hermes::adapter::fs::File &key) const { + return key.hash(); + } +}; +} // namespace std + +#endif // HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_H_ diff --git a/adapter/posix/posix.cc b/adapter/posix/posix.cc index b76a497f2..272e1dda8 100644 --- a/adapter/posix/posix.cc +++ b/adapter/posix/posix.cc @@ -17,61 +17,25 @@ bool posix_intercepted = true; #include #include #include +#include -#include "interceptor.cc" - -#include "interceptor.h" #include "singleton.h" - +#include "utils.h" #include "posix/real_api.h" -#include "posix/fs_api.h" - -#ifndef O_TMPFILE -#define O_TMPFILE 0 -#endif -using hermes::adapter::WeaklyCanonical; -using hermes::adapter::posix::API; -using hermes::adapter::posix::PosixFS; using hermes::Singleton; -using hermes::adapter::fs::MetadataManager; -using hermes::adapter::fs::SeekMode; namespace hapi = hermes::api; namespace stdfs = std::experimental::filesystem; -using hermes::u8; extern "C" { -/** - * MPI - */ -int HERMES_DECL(MPI_Init)(int *argc, char ***argv) { - auto real_api = Singleton::GetInstance(); - int status = real_api->MPI_Init(argc, argv); - if (status == 0) { - LOG(INFO) << "MPI Init intercepted." << std::endl; - auto mdm = hermes::Singleton::GetInstance(); - mdm->InitializeHermes(true); - } - return status; -} - -int HERMES_DECL(MPI_Finalize)(void) { - auto real_api = Singleton::GetInstance(); - LOG(INFO) << "MPI Finalize intercepted." << std::endl; - auto mdm = hermes::Singleton::GetInstance(); - mdm->FinalizeHermes(); - int status = real_api->MPI_Finalize(); - return status; -} - /** * POSIX */ int HERMES_DECL(open)(const char *path, int flags, ...) { int mode = 0; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (flags & O_CREAT || flags & O_TMPFILE) { va_list arg; @@ -95,7 +59,7 @@ int HERMES_DECL(open)(const char *path, int flags, ...) { int HERMES_DECL(open64)(const char *path, int flags, ...) { int mode = 0; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (flags & O_CREAT) { va_list arg; @@ -118,7 +82,7 @@ int HERMES_DECL(open64)(const char *path, int flags, ...) { } int HERMES_DECL(__open_2)(const char *path, int oflag) { - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(path)) { LOG(INFO) << "Intercept __open_2 for filename: " << path @@ -133,7 +97,7 @@ int HERMES_DECL(__open_2)(const char *path, int oflag) { int HERMES_DECL(creat)(const char *path, mode_t mode) { std::string path_str(path); - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(path)) { LOG(INFO) << "Intercept creat for filename: " << path @@ -148,7 +112,7 @@ int HERMES_DECL(creat)(const char *path, mode_t mode) { int HERMES_DECL(creat64)(const char *path, mode_t mode) { std::string path_str(path); - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(path)) { LOG(INFO) << "Intercept creat64 for filename: " << path @@ -163,7 +127,7 @@ int HERMES_DECL(creat64)(const char *path, mode_t mode) { ssize_t HERMES_DECL(read)(int fd, void *buf, size_t count) { bool stat_exists; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(fd)) { LOG(INFO) << "Intercept read." << std::endl; @@ -176,7 +140,7 @@ ssize_t HERMES_DECL(read)(int fd, void *buf, size_t count) { ssize_t HERMES_DECL(write)(int fd, const void *buf, size_t count) { bool stat_exists; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(fd)) { LOG(INFO) << "Intercept write." << std::endl; @@ -189,7 +153,7 @@ ssize_t HERMES_DECL(write)(int fd, const void *buf, size_t count) { ssize_t HERMES_DECL(pread)(int fd, void *buf, size_t count, off_t offset) { bool stat_exists; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(fd)) { LOG(INFO) << "Intercept pread." << std::endl; @@ -203,7 +167,7 @@ ssize_t HERMES_DECL(pread)(int fd, void *buf, size_t count, off_t offset) { ssize_t HERMES_DECL(pwrite)(int fd, const void *buf, size_t count, off_t offset) { bool stat_exists; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; @@ -216,7 +180,7 @@ ssize_t HERMES_DECL(pwrite)(int fd, const void *buf, size_t count, ssize_t HERMES_DECL(pread64)(int fd, void *buf, size_t count, off64_t offset) { bool stat_exists; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; @@ -230,7 +194,7 @@ ssize_t HERMES_DECL(pread64)(int fd, void *buf, size_t count, off64_t offset) { ssize_t HERMES_DECL(pwrite64)(int fd, const void *buf, size_t count, off64_t offset) { bool stat_exists; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; @@ -243,7 +207,7 @@ ssize_t HERMES_DECL(pwrite64)(int fd, const void *buf, size_t count, off_t HERMES_DECL(lseek)(int fd, off_t offset, int whence) { bool stat_exists; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); @@ -257,7 +221,7 @@ off_t HERMES_DECL(lseek)(int fd, off_t offset, int whence) { off64_t HERMES_DECL(lseek64)(int fd, off64_t offset, int whence) { bool stat_exists; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); @@ -271,7 +235,7 @@ off64_t HERMES_DECL(lseek64)(int fd, off64_t offset, int whence) { int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { int result = 0; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); @@ -309,7 +273,7 @@ int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { int HERMES_DECL(fsync)(int fd) { bool stat_exists; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); @@ -321,7 +285,7 @@ int HERMES_DECL(fsync)(int fd) { int HERMES_DECL(close)(int fd) { bool stat_exists; - auto real_api = Singleton::GetInstance(); + auto real_api = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); if (hermes::adapter::IsTracked(fd)) { LOG(INFO) << "Intercept close(" << std::to_string(fd) << ")"; diff --git a/adapter/stdio/CMakeLists.txt b/adapter/stdio/CMakeLists.txt new file mode 100644 index 000000000..fb34ba472 --- /dev/null +++ b/adapter/stdio/CMakeLists.txt @@ -0,0 +1,49 @@ +project(StdioAdapter VERSION ${HERMES_PACKAGE_VERSION}) +include_directories(${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +# STDIO src code. We only include stdio.cc as it includes other cc to reduce compilation time. +set(STDIO_ADAPTER_SRC stdio.cc) + +set(HERMES_STDIO_ADAPTER_DIR ${HERMES_ADAPTER_DIR}/stdio) + +# Only stdio.h is the public adapter. +set(STDIO_ADAPTER_PUBLIC_HEADER + ${HERMES_STDIO_ADAPTER_DIR}/real_api.h + ${HERMES_STDIO_ADAPTER_DIR}/fs_api.h) + +# Add library hermes_stdio +add_library(hermes_stdio_backend ${CMAKE_CURRENT_SOURCE_DIR}/fs_api.cc) +add_dependencies(hermes_stdio_backend hermes) +target_link_libraries(hermes_stdio_backend hermes MPI::MPI_CXX glog::glog stdc++fs dl) + +add_library(hermes_stdio SHARED ${STDIO_ADAPTER_PUBLIC_HEADER} ${STDIO_ADAPTER_SRC}) +add_dependencies(hermes_stdio hermes_stdio_backend) +target_link_libraries(hermes_stdio hermes_stdio_backend) + +#----------------------------------------------------------------------------- +# Add Target(s) to CMake Install +#----------------------------------------------------------------------------- +install( + TARGETS + hermes_stdio_backend + EXPORT + ${HERMES_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} +) +install( + TARGETS + hermes_stdio + EXPORT + ${HERMES_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} +) +#----------------------------------------------------------------------------- +# Add Target(s) to Coverage +#----------------------------------------------------------------------------- +if(HERMES_ENABLE_COVERAGE) + set_coverage_flags(hermes_stdio) +endif() diff --git a/adapter/stdio/fs_api.cc b/adapter/stdio/fs_api.cc new file mode 100644 index 000000000..855bc6ad7 --- /dev/null +++ b/adapter/stdio/fs_api.cc @@ -0,0 +1,102 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include "real_api.h" +#include "fs_api.h" +#include + +namespace hermes::adapter::stdio { + +File StdioFS::_RealOpen(AdapterStat &stat, const std::string &path) { + File f; + f.fh_ = real_api->fopen(path.c_str(), stat.mode_str.c_str()); + if (f.fh_ == nullptr) { + f.status_ = false; + } + _InitFile(f); + return f; +} + +void StdioFS::_InitFile(File &f) { + struct stat st; + if (f.fh_ == nullptr) { + f.fd_ = -1; + return; + } + f.fd_ = fileno(f.fh_); + posix_api->__fxstat(_STAT_VER, f.fd_, &st); + f.st_dev = st.st_dev; + f.st_ino = st.st_ino; +} + +void StdioFS::_OpenInitStats(File &f, AdapterStat &stat) { + struct stat st; + posix_api->__fxstat(_STAT_VER, f.fd_, &st); + stat.st_mode = st.st_mode; + stat.st_uid = st.st_uid; + stat.st_gid = st.st_gid; + stat.st_size = st.st_size; + stat.st_blksize = st.st_blksize; + stat.st_atim = st.st_atim; + stat.st_mtim = st.st_mtim; + stat.st_ctim = st.st_ctim; + if (stat.mode_str.find('a') != std::string::npos) { + stat.is_append = true; + } +} + +size_t StdioFS::_RealWrite(const std::string &filename, off_t offset, + size_t size, const u8 *data_ptr, + IoStatus &io_status, IoOptions &opts) { + (void) opts; (void) io_status; + LOG(INFO) << "Writing to file: " << filename + << " offset: " << offset + << " size:" << size << "." + << " file_size:" << stdfs::file_size(filename) << std::endl; + FILE *fh = real_api->fopen(filename.c_str(), "r+"); + if (fh == nullptr) { return 0; } + real_api->fseek(fh, offset, SEEK_SET); + flock(fileno(fh), LOCK_EX); + size_t write_size = real_api->fwrite(data_ptr, sizeof(char), size, fh); + flock(fileno(fh), LOCK_UN); + real_api->fclose(fh); + return write_size; +} + +size_t StdioFS::_RealRead(const std::string &filename, off_t offset, + size_t size, u8 *data_ptr, + IoStatus &io_status, IoOptions &opts) { + (void) opts; (void) io_status; + LOG(INFO) << "Read called for filename from destination: " << filename + << " on offset: " << offset + << " and size: " << size << "." + << " file_size:" << stdfs::file_size(filename) << std::endl; + FILE *fh = real_api->fopen(filename.c_str(), "r"); + if (fh == nullptr) { return 0; } + real_api->fseek(fh, offset, SEEK_SET); + flock(fileno(fh), LOCK_SH); + size_t read_size = real_api->fread(data_ptr, sizeof(char), size, fh); + flock(fileno(fh), LOCK_UN); + real_api->fclose(fh); + return read_size; +} + +int StdioFS::_RealSync(File &f) { + return real_api->fflush(f.fh_); +} + +int StdioFS::_RealClose(File &f) { + return real_api->fclose(f.fh_); +} + +} // namespace hermes::adapter::stdio diff --git a/adapter/stdio/fs_api.h b/adapter/stdio/fs_api.h new file mode 100644 index 000000000..a10f3f418 --- /dev/null +++ b/adapter/stdio/fs_api.h @@ -0,0 +1,64 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_ADAPTER_STDIO_NATIVE_H_ +#define HERMES_ADAPTER_STDIO_NATIVE_H_ + +#include + +#include "filesystem/filesystem.cc" +#include "filesystem/filesystem.h" +#include "filesystem/metadata_manager.cc" +#include "filesystem/metadata_manager.h" +#include "posix/real_api.h" +#include "real_api.h" + +using hermes::Singleton; +using hermes::adapter::fs::AdapterStat; +using hermes::adapter::fs::File; +using hermes::adapter::fs::IoOptions; +using hermes::adapter::fs::IoStatus; +using hermes::adapter::stdio::API; + +namespace hermes::adapter::stdio { +/** + A class to represent standard IO file system +*/ +class StdioFS : public hermes::adapter::fs::Filesystem { + private: + API *real_api; /**< pointer to real APIs */ + hermes::adapter::posix::API *posix_api; /**< pointer to POSIX APIs */ + + public: + StdioFS() { + real_api = Singleton::GetInstance(); + posix_api = Singleton::GetInstance(); + } + ~StdioFS() = default; + + void _InitFile(File &f) override; + + private: + void _OpenInitStats(File &f, AdapterStat &stat) override; + File _RealOpen(AdapterStat &stat, const std::string &path) override; + size_t _RealWrite(const std::string &filename, off_t offset, size_t size, + const u8 *data_ptr, IoStatus &io_status, + IoOptions &opts) override; + size_t _RealRead(const std::string &filename, off_t offset, size_t size, + u8 *data_ptr, IoStatus &io_status, IoOptions &opts) override; + int _RealSync(File &f) override; + int _RealClose(File &f) override; +}; + +} // namespace hermes::adapter::stdio + +#endif // HERMES_ADAPTER_STDIO_NATIVE_H_ diff --git a/adapter/stdio/real_api.h b/adapter/stdio/real_api.h new file mode 100644 index 000000000..7fceff47e --- /dev/null +++ b/adapter/stdio/real_api.h @@ -0,0 +1,300 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_ADAPTER_STDIO_H +#define HERMES_ADAPTER_STDIO_H +#include +#include +#include +#include +#include +#include "interceptor.h" +#include "filesystem/filesystem.h" +#include "filesystem/metadata_manager.h" + +#define REQUIRE_API(api_name) \ + if (api_name == nullptr) { \ + LOG(FATAL) << "HERMES Adapter failed to map symbol: " \ + #api_name << std::endl; \ + std::exit(1); \ + } + +extern "C" { +typedef int (*MPI_Init_t)(int * argc, char *** argv); +typedef int (*MPI_Finalize_t)( void); +typedef FILE * (*fopen_t)(const char * path, const char * mode); +typedef FILE * (*fopen64_t)(const char * path, const char * mode); +typedef FILE * (*fdopen_t)(int fd, const char * mode); +typedef FILE * (*freopen_t)(const char * path, const char * mode, FILE * stream); +typedef FILE * (*freopen64_t)(const char * path, const char * mode, FILE * stream); +typedef int (*fflush_t)(FILE * fp); +typedef int (*fclose_t)(FILE * fp); +typedef size_t (*fwrite_t)(const void * ptr, size_t size, size_t nmemb, FILE * fp); +typedef int (*fputc_t)(int c, FILE * fp); +typedef int (*fgetpos_t)(FILE * fp, fpos_t * pos); +typedef int (*fgetpos64_t)(FILE * fp, fpos64_t * pos); +typedef int (*putc_t)(int c, FILE * fp); +typedef int (*putw_t)(int w, FILE * fp); +typedef int (*fputs_t)(const char * s, FILE * stream); +typedef size_t (*fread_t)(void * ptr, size_t size, size_t nmemb, FILE * stream); +typedef int (*fgetc_t)(FILE * stream); +typedef int (*getc_t)(FILE * stream); +typedef int (*getw_t)(FILE * stream); +typedef char * (*fgets_t)(char * s, int size, FILE * stream); +typedef void (*rewind_t)(FILE * stream); +typedef int (*fseek_t)(FILE * stream, long offset, int whence); +typedef int (*fseeko_t)(FILE * stream, off_t offset, int whence); +typedef int (*fseeko64_t)(FILE * stream, off64_t offset, int whence); +typedef int (*fsetpos_t)(FILE * stream, const fpos_t * pos); +typedef int (*fsetpos64_t)(FILE * stream, const fpos64_t * pos); +typedef long int (*ftell_t)(FILE * fp); +} + +namespace hermes::adapter::stdio { + +/** Pointers to the real stdio API */ +class API { + public: + /** MPI_Init */ + MPI_Init_t MPI_Init = nullptr; + /** MPI_Finalize */ + MPI_Finalize_t MPI_Finalize = nullptr; + /** fopen */ + fopen_t fopen = nullptr; + /** fopen64 */ + fopen64_t fopen64 = nullptr; + /** fdopen */ + fdopen_t fdopen = nullptr; + /** freopen */ + freopen_t freopen = nullptr; + /** freopen64 */ + freopen64_t freopen64 = nullptr; + /** fflush */ + fflush_t fflush = nullptr; + /** fclose */ + fclose_t fclose = nullptr; + /** fwrite */ + fwrite_t fwrite = nullptr; + /** fputc */ + fputc_t fputc = nullptr; + /** fgetpos */ + fgetpos_t fgetpos = nullptr; + /** fgetpos64 */ + fgetpos64_t fgetpos64 = nullptr; + /** putc */ + putc_t putc = nullptr; + /** putw */ + putw_t putw = nullptr; + /** fputs */ + fputs_t fputs = nullptr; + /** fread */ + fread_t fread = nullptr; + /** fgetc */ + fgetc_t fgetc = nullptr; + /** getc */ + getc_t getc = nullptr; + /** getw */ + getw_t getw = nullptr; + /** fgets */ + fgets_t fgets = nullptr; + /** rewind */ + rewind_t rewind = nullptr; + /** fseek */ + fseek_t fseek = nullptr; + /** fseeko */ + fseeko_t fseeko = nullptr; + /** fseeko64 */ + fseeko64_t fseeko64 = nullptr; + /** fsetpos */ + fsetpos_t fsetpos = nullptr; + /** fsetpos64 */ + fsetpos64_t fsetpos64 = nullptr; + /** ftell */ + ftell_t ftell = nullptr; + + API() { + void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, "stdio_intercepted"); + if (is_intercepted) { + MPI_Init = (MPI_Init_t)dlsym(RTLD_NEXT, "MPI_Init"); + } else { + MPI_Init = (MPI_Init_t)dlsym(RTLD_DEFAULT, "MPI_Init"); + } + REQUIRE_API(MPI_Init) + if (is_intercepted) { + MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_NEXT, "MPI_Finalize"); + } else { + MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_DEFAULT, "MPI_Finalize"); + } + REQUIRE_API(MPI_Finalize) + if (is_intercepted) { + fopen = (fopen_t)dlsym(RTLD_NEXT, "fopen"); + } else { + fopen = (fopen_t)dlsym(RTLD_DEFAULT, "fopen"); + } + REQUIRE_API(fopen) + if (is_intercepted) { + fopen64 = (fopen64_t)dlsym(RTLD_NEXT, "fopen64"); + } else { + fopen64 = (fopen64_t)dlsym(RTLD_DEFAULT, "fopen64"); + } + REQUIRE_API(fopen64) + if (is_intercepted) { + fdopen = (fdopen_t)dlsym(RTLD_NEXT, "fdopen"); + } else { + fdopen = (fdopen_t)dlsym(RTLD_DEFAULT, "fdopen"); + } + REQUIRE_API(fdopen) + if (is_intercepted) { + freopen = (freopen_t)dlsym(RTLD_NEXT, "freopen"); + } else { + freopen = (freopen_t)dlsym(RTLD_DEFAULT, "freopen"); + } + REQUIRE_API(freopen) + if (is_intercepted) { + freopen64 = (freopen64_t)dlsym(RTLD_NEXT, "freopen64"); + } else { + freopen64 = (freopen64_t)dlsym(RTLD_DEFAULT, "freopen64"); + } + REQUIRE_API(freopen64) + if (is_intercepted) { + fflush = (fflush_t)dlsym(RTLD_NEXT, "fflush"); + } else { + fflush = (fflush_t)dlsym(RTLD_DEFAULT, "fflush"); + } + REQUIRE_API(fflush) + if (is_intercepted) { + fclose = (fclose_t)dlsym(RTLD_NEXT, "fclose"); + } else { + fclose = (fclose_t)dlsym(RTLD_DEFAULT, "fclose"); + } + REQUIRE_API(fclose) + if (is_intercepted) { + fwrite = (fwrite_t)dlsym(RTLD_NEXT, "fwrite"); + } else { + fwrite = (fwrite_t)dlsym(RTLD_DEFAULT, "fwrite"); + } + REQUIRE_API(fwrite) + if (is_intercepted) { + fputc = (fputc_t)dlsym(RTLD_NEXT, "fputc"); + } else { + fputc = (fputc_t)dlsym(RTLD_DEFAULT, "fputc"); + } + REQUIRE_API(fputc) + if (is_intercepted) { + fgetpos = (fgetpos_t)dlsym(RTLD_NEXT, "fgetpos"); + } else { + fgetpos = (fgetpos_t)dlsym(RTLD_DEFAULT, "fgetpos"); + } + REQUIRE_API(fgetpos) + if (is_intercepted) { + fgetpos64 = (fgetpos64_t)dlsym(RTLD_NEXT, "fgetpos64"); + } else { + fgetpos64 = (fgetpos64_t)dlsym(RTLD_DEFAULT, "fgetpos64"); + } + REQUIRE_API(fgetpos64) + if (is_intercepted) { + putc = (putc_t)dlsym(RTLD_NEXT, "putc"); + } else { + putc = (putc_t)dlsym(RTLD_DEFAULT, "putc"); + } + REQUIRE_API(putc) + if (is_intercepted) { + putw = (putw_t)dlsym(RTLD_NEXT, "putw"); + } else { + putw = (putw_t)dlsym(RTLD_DEFAULT, "putw"); + } + REQUIRE_API(putw) + if (is_intercepted) { + fputs = (fputs_t)dlsym(RTLD_NEXT, "fputs"); + } else { + fputs = (fputs_t)dlsym(RTLD_DEFAULT, "fputs"); + } + REQUIRE_API(fputs) + if (is_intercepted) { + fread = (fread_t)dlsym(RTLD_NEXT, "fread"); + } else { + fread = (fread_t)dlsym(RTLD_DEFAULT, "fread"); + } + REQUIRE_API(fread) + if (is_intercepted) { + fgetc = (fgetc_t)dlsym(RTLD_NEXT, "fgetc"); + } else { + fgetc = (fgetc_t)dlsym(RTLD_DEFAULT, "fgetc"); + } + REQUIRE_API(fgetc) + if (is_intercepted) { + getc = (getc_t)dlsym(RTLD_NEXT, "getc"); + } else { + getc = (getc_t)dlsym(RTLD_DEFAULT, "getc"); + } + REQUIRE_API(getc) + if (is_intercepted) { + getw = (getw_t)dlsym(RTLD_NEXT, "getw"); + } else { + getw = (getw_t)dlsym(RTLD_DEFAULT, "getw"); + } + REQUIRE_API(getw) + if (is_intercepted) { + fgets = (fgets_t)dlsym(RTLD_NEXT, "fgets"); + } else { + fgets = (fgets_t)dlsym(RTLD_DEFAULT, "fgets"); + } + REQUIRE_API(fgets) + if (is_intercepted) { + rewind = (rewind_t)dlsym(RTLD_NEXT, "rewind"); + } else { + rewind = (rewind_t)dlsym(RTLD_DEFAULT, "rewind"); + } + REQUIRE_API(rewind) + if (is_intercepted) { + fseek = (fseek_t)dlsym(RTLD_NEXT, "fseek"); + } else { + fseek = (fseek_t)dlsym(RTLD_DEFAULT, "fseek"); + } + REQUIRE_API(fseek) + if (is_intercepted) { + fseeko = (fseeko_t)dlsym(RTLD_NEXT, "fseeko"); + } else { + fseeko = (fseeko_t)dlsym(RTLD_DEFAULT, "fseeko"); + } + REQUIRE_API(fseeko) + if (is_intercepted) { + fseeko64 = (fseeko64_t)dlsym(RTLD_NEXT, "fseeko64"); + } else { + fseeko64 = (fseeko64_t)dlsym(RTLD_DEFAULT, "fseeko64"); + } + REQUIRE_API(fseeko64) + if (is_intercepted) { + fsetpos = (fsetpos_t)dlsym(RTLD_NEXT, "fsetpos"); + } else { + fsetpos = (fsetpos_t)dlsym(RTLD_DEFAULT, "fsetpos"); + } + REQUIRE_API(fsetpos) + if (is_intercepted) { + fsetpos64 = (fsetpos64_t)dlsym(RTLD_NEXT, "fsetpos64"); + } else { + fsetpos64 = (fsetpos64_t)dlsym(RTLD_DEFAULT, "fsetpos64"); + } + REQUIRE_API(fsetpos64) + if (is_intercepted) { + ftell = (ftell_t)dlsym(RTLD_NEXT, "ftell"); + } else { + ftell = (ftell_t)dlsym(RTLD_DEFAULT, "ftell"); + } + REQUIRE_API(ftell) + } +}; +} // namespace hermes::adapter::stdio + +#undef REQUIRE_API + +#endif // HERMES_ADAPTER_STDIO_H diff --git a/adapter/stdio/stdio.cc b/adapter/stdio/stdio.cc new file mode 100644 index 000000000..4805cd5e4 --- /dev/null +++ b/adapter/stdio/stdio.cc @@ -0,0 +1,565 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +bool stdio_intercepted = true; + +#include +#include + +#include "interceptor.cc" +#include +#include "stdio/real_api.h" +#include "stdio/fs_api.h" + +using hermes::adapter::WeaklyCanonical; +using hermes::adapter::stdio::API; +using hermes::adapter::stdio::StdioFS; +using hermes::Singleton; +using hermes::adapter::fs::MetadataManager; +using hermes::adapter::fs::SeekMode; + +namespace hapi = hermes::api; +namespace stdfs = std::experimental::filesystem; +using hermes::u8; +using hermes::u64; + +namespace hapi = hermes::api; +namespace stdfs = std::experimental::filesystem; + +extern "C" { + +/** + * MPI + */ +int HERMES_DECL(MPI_Init)(int *argc, char ***argv) { + auto real_api = Singleton::GetInstance(); + int status = real_api->MPI_Init(argc, argv); + if (status == 0) { + auto mdm = Singleton::GetInstance(); + mdm->InitializeHermes(true); + LOG(INFO) << "MPI Init intercepted." << std::endl; + } + return status; +} + +int HERMES_DECL(MPI_Finalize)(void) { + LOG(INFO) << "MPI Finalize intercepted." << std::endl; + auto real_api = Singleton::GetInstance(); + auto mdm = Singleton::GetInstance(); + mdm->FinalizeHermes(); + int status = real_api->MPI_Finalize(); + return status; +} + +/** + * STDIO + */ + +FILE *reopen_internal(const std::string &user_path, const char *mode, + FILE *stream) { + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + auto mdm = Singleton::GetInstance(); + FILE *ret; + ret = real_api->freopen(user_path.c_str(), mode, stream); + if (!ret) { + return ret; + } + + File f; + f.fh_ = ret; + fs_api->_InitFile(f); + std::string path_str = WeaklyCanonical(user_path).string(); + LOG(INFO) << "Reopen file for filename " << path_str << " in mode " << mode + << std::endl; + auto existing = mdm->Find(f); + if (!existing.second) { + LOG(INFO) << "File not opened before by adapter" << std::endl; + return nullptr; + } else { + LOG(INFO) << "File opened before by adapter" << std::endl; + struct timespec ts; + timespec_get(&ts, TIME_UTC); + existing.first.st_atim = ts; + existing.first.st_ctim = ts; + mdm->Update(f, existing.first); + } + return ret; +} + +FILE *HERMES_DECL(fopen)(const char *path, const char *mode) { + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(path)) { + LOG(INFO) << "Intercepting fopen(" << path << ", " << mode << ")\n"; + AdapterStat stat; + stat.mode_str = mode; + return fs_api->Open(stat, path).fh_; + } else { + return real_api->fopen(path, mode); + } +} + +FILE *HERMES_DECL(fopen64)(const char *path, const char *mode) { + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(path)) { + LOG(INFO) << "Intercepting fopen64(" << path << ", " << mode << ")\n"; + AdapterStat stat; + stat.mode_str = mode; + return fs_api->Open(stat, path).fh_; + } else { + return real_api->fopen64(path, mode); + } +} + +FILE *HERMES_DECL(fdopen)(int fd, const char *mode) { + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + FILE *ret = real_api->fdopen(fd, mode); + if (ret && hermes::adapter::IsTracked(ret)) { + LOG(INFO) << "Intercepting fdopen(" << fd << ", " << mode << ")\n"; + std::string path_str = hermes::adapter::GetFilenameFromFD(fd); + File f; + f.fh_ = ret; + fs_api->_InitFile(f); + AdapterStat stat; + stat.mode_str = mode; + fs_api->Open(stat, f, path_str); + } + return ret; +} + +FILE *HERMES_DECL(freopen)(const char *path, const char *mode, FILE *stream) { + auto real_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(path)) { + LOG(INFO) << "Intercepting freopen(" << path << ", " << mode << ", " + << stream << ")\n"; + return reopen_internal(path, mode, stream); + } + return real_api->freopen(path, mode, stream); +} + +FILE *HERMES_DECL(freopen64)(const char *path, const char *mode, FILE *stream) { + auto real_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(path)) { + LOG(INFO) << "Intercepting freopen64(" << path << ", " << mode << ", " + << stream << ")\n"; + return reopen_internal(path, mode, stream); + } + return real_api->freopen64(path, mode, stream); +} + +int HERMES_DECL(fflush)(FILE *fp) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (fp && hermes::adapter::IsTracked(fp)) { + File f; + f.fh_ = fp; + fs_api->_InitFile(f); + return fs_api->Sync(f, stat_exists); + } + return real_api->fflush(fp); +} + +int HERMES_DECL(fclose)(FILE *fp) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(fp)) { + LOG(INFO) << "Intercepting fclose(" << fp << ")\n"; + File f; + f.fh_ = fp; + fs_api->_InitFile(f); + int ret = fs_api->Close(f, stat_exists); + if (stat_exists) return ret; + } + return real_api->fclose(fp); +} + +size_t HERMES_DECL(fwrite)(const void *ptr, size_t size, size_t nmemb, + FILE *fp) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(fp)) { + LOG(INFO) << "Intercepting fwrite(" << ptr << ", " << size << ", " << nmemb + << ", " << fp << ")\n"; + File f; + f.fh_ = fp; + fs_api->_InitFile(f); + IoStatus io_status; + size_t ret = fs_api->Write(f, stat_exists, ptr, size * nmemb, io_status); + if (stat_exists) { + return ret; + } + } + return real_api->fwrite(ptr, size, nmemb, fp); +} + +int HERMES_DECL(fputc)(int c, FILE *fp) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(fp)) { + LOG(INFO) << "Intercepting fputc(" << c << ", " << fp << ")\n"; + File f; + f.fh_ = fp; + fs_api->_InitFile(f); + IoStatus io_status; + fs_api->Write(f, stat_exists, &c, 1, io_status); + if (stat_exists) { + return c; + } + } + return real_api->fputc(c, fp); +} + +int HERMES_DECL(fgetpos)(FILE *fp, fpos_t *pos) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(fp) && pos) { + File f; + f.fh_ = fp; + fs_api->_InitFile(f); + LOG(INFO) << "Intercept fgetpos." << std::endl; + // TODO(chogan): @portability In the GNU C Library, fpos_t is an opaque + // data structure that contains internal data to represent file offset and + // conversion state information. In other systems, it might have a + // different internal representation. This will need to change to support + // other compilers. + pos->__pos = fs_api->Tell(f, stat_exists); + if (stat_exists) { + return 0; + } + } + return real_api->fgetpos(fp, pos); +} + +int HERMES_DECL(fgetpos64)(FILE *fp, fpos64_t *pos) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(fp) && pos) { + File f; + f.fh_ = fp; + fs_api->_InitFile(f); + LOG(INFO) << "Intercept fgetpos64." << std::endl; + // TODO(chogan): @portability In the GNU C Library, fpos_t is an opaque + // data structure that contains internal data to represent file offset and + // conversion state information. In other systems, it might have a + // different internal representation. This will need to change to support + // other compilers. + pos->__pos = fs_api->Tell(f, stat_exists); + if (stat_exists) { + return 0; + } + } + return real_api->fgetpos64(fp, pos); +} + +int HERMES_DECL(putc)(int c, FILE *fp) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(fp)) { + File f; + f.fh_ = fp; + fs_api->_InitFile(f); + IoStatus io_status; + LOG(INFO) << "Intercept putc." << std::endl; + fs_api->Write(f, stat_exists, &c, 1, io_status); + if (stat_exists) { + return c; + } + } + return real_api->fputc(c, fp); +} + +int HERMES_DECL(putw)(int w, FILE *fp) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(fp)) { + LOG(INFO) << "Intercept putw." << std::endl; + File f; + f.fh_ = fp; + fs_api->_InitFile(f); + IoStatus io_status; + int ret = fs_api->Write(f, stat_exists, &w, sizeof(w), io_status); + if (ret == sizeof(w)) { + return 0; + } else { + return EOF; + } + } + return real_api->putw(w, fp); +} + +int HERMES_DECL(fputs)(const char *s, FILE *stream) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(stream)) { + LOG(INFO) << "Intercept fputs." << std::endl; + File f; + f.fh_ = stream; + fs_api->_InitFile(f); + IoStatus io_status; + int ret = fs_api->Write(f, stat_exists, s, strlen(s), io_status); + if (stat_exists) { + return ret; + } + } + return real_api->fputs(s, stream); +} + +size_t HERMES_DECL(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(stream)) { + LOG(INFO) << "Intercept fread with size: " << size << "." << std::endl; + File f; + f.fh_ = stream; + fs_api->_InitFile(f); + IoStatus io_status; + size_t ret = fs_api->Read(f, stat_exists, ptr, size * nmemb, io_status); + if (stat_exists) { + return ret; + } + } + return real_api->fread(ptr, size, nmemb, stream); +} + +int HERMES_DECL(fgetc)(FILE *stream) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(stream)) { + LOG(INFO) << "Intercept fgetc." << std::endl; + File f; + f.fh_ = stream; + fs_api->_InitFile(f); + IoStatus io_status; + u8 value; + fs_api->Read(f, stat_exists, &value, sizeof(u8), io_status); + if (stat_exists) { + return value; + } + } + return real_api->fgetc(stream); +} + +int HERMES_DECL(getc)(FILE *stream) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(stream)) { + LOG(INFO) << "Intercept getc." << std::endl; + File f; + f.fh_ = stream; + fs_api->_InitFile(f); + IoStatus io_status; + u8 value; + fs_api->Read(f, stat_exists, &value, sizeof(u8), io_status); + if (stat_exists) { + return value; + } + } + return real_api->getc(stream); +} + +int HERMES_DECL(getw)(FILE *stream) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(stream)) { + LOG(INFO) << "Intercept getw." << std::endl; + File f; + f.fh_ = stream; + fs_api->_InitFile(f); + IoStatus io_status; + int value; + fs_api->Read(f, stat_exists, &value, sizeof(int), io_status); + if (stat_exists) { + return value; + } + } + return real_api->getc(stream); +} + +char *HERMES_DECL(fgets)(char *s, int size, FILE *stream) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(stream)) { + LOG(INFO) << "Intercept fgets." << std::endl; + File f; + f.fh_ = stream; + fs_api->_InitFile(f); + IoStatus io_status; + size_t read_size = size - 1; + size_t ret_size = fs_api->Read(f, stat_exists, s, read_size, io_status); + if (ret_size < read_size) { + /* FILE ended */ + read_size = ret_size; + } + /* Check if \0 or \n in s.*/ + size_t copy_pos = 0; + for (size_t i = 0; i < read_size; ++i) { + if (s[i] == '\0' || s[i] == '\n') { + copy_pos = i; + break; + } + } + if (copy_pos > 0) { + /* \n and \0 was found. */ + s[copy_pos + 1] = '\0'; + } else { + s[read_size] = '\0'; + } + if (stat_exists) return s; + } + return real_api->fgets(s, size, stream); +} + +void HERMES_DECL(rewind)(FILE *stream) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(stream)) { + LOG(INFO) << "Intercept rewind." << std::endl; + File f; + f.fh_ = stream; + fs_api->_InitFile(f); + fs_api->Seek(f, stat_exists, SeekMode::kSet, 0); + if (stat_exists) { + return; + } + } + real_api->rewind(stream); +} + +int HERMES_DECL(fseek)(FILE *stream, long offset, int whence) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(stream)) { + LOG(INFO) << "Intercept fseek offset:" << offset << " whence:" << whence + << "." << std::endl; + File f; + f.fh_ = stream; + fs_api->_InitFile(f); + off_t ret = + fs_api->Seek(f, stat_exists, static_cast(whence), offset); + if (stat_exists && ret > 0) { + return 0; + } + } + return real_api->fseek(stream, offset, whence); +} + +int HERMES_DECL(fseeko)(FILE *stream, off_t offset, int whence) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(stream)) { + LOG(INFO) << "Intercept fseeko offset:" << offset << " whence:" << whence + << "." << std::endl; + File f; + f.fh_ = stream; + fs_api->_InitFile(f); + off_t ret = + fs_api->Seek(f, stat_exists, static_cast(whence), offset); + if (stat_exists && ret > 0) { + return 0; + } + } + return real_api->fseeko(stream, offset, whence); +} + +int HERMES_DECL(fseeko64)(FILE *stream, off64_t offset, int whence) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(stream)) { + LOG(INFO) << "Intercept fseeko offset:" << offset << " whence:" << whence + << "." << std::endl; + File f; + f.fh_ = stream; + fs_api->_InitFile(f); + off_t ret = + fs_api->Seek(f, stat_exists, static_cast(whence), offset); + if (stat_exists && ret > 0) { + return 0; + } + } + return real_api->fseeko64(stream, offset, whence); +} + +int HERMES_DECL(fsetpos)(FILE *stream, const fpos_t *pos) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + off_t offset = pos->__pos; + if (hermes::adapter::IsTracked(stream)) { + LOG(INFO) << "Intercept fsetpos offset:" << offset << "." << std::endl; + File f; + f.fh_ = stream; + fs_api->_InitFile(f); + off_t ret = fs_api->Seek(f, stat_exists, SeekMode::kSet, offset); + if (stat_exists && ret > 0) { + return 0; + } + } + return real_api->fsetpos(stream, pos); +} + +int HERMES_DECL(fsetpos64)(FILE *stream, const fpos64_t *pos) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + off_t offset = pos->__pos; + if (hermes::adapter::IsTracked(stream)) { + LOG(INFO) << "Intercept fsetpos64 offset:" << offset << "." << std::endl; + File f; + f.fh_ = stream; + fs_api->_InitFile(f); + off_t ret = fs_api->Seek(f, stat_exists, SeekMode::kSet, offset); + if (stat_exists && ret > 0) { + return 0; + } + } + return real_api->fsetpos64(stream, pos); +} + +long int HERMES_DECL(ftell)(FILE *fp) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(fp)) { + LOG(INFO) << "Intercept ftell." << std::endl; + File f; + f.fh_ = fp; + fs_api->_InitFile(f); + off_t ret = fs_api->Tell(f, stat_exists); + if (stat_exists) { + return ret; + } + } + return real_api->ftell(fp); +} + +} // extern C diff --git a/adapter/utils.h b/adapter/utils.h new file mode 100644 index 000000000..3db768b93 --- /dev/null +++ b/adapter/utils.h @@ -0,0 +1,10 @@ +// +// Created by lukemartinlogan on 1/19/23. +// + +#ifndef HERMES_ADAPTER_UTILS_H_ +#define HERMES_ADAPTER_UTILS_H_ + +#define HERMES_DECL + +#endif // HERMES_ADAPTER_UTILS_H_ diff --git a/adapter/vfd/CMakeLists.txt b/adapter/vfd/CMakeLists.txt new file mode 100644 index 000000000..cae8406c7 --- /dev/null +++ b/adapter/vfd/CMakeLists.txt @@ -0,0 +1,189 @@ +# CMakeLists files in this project can +# refer to the root source directory of the project as ${HDF5_HERMES_SOURCE_DIR} and +# to the root binary directory of the project as ${HDF5_HERMES_BINARY_DIR}. + +project(HDF5_HERMES_VFD) + +#------------------------------------------------------------------------------ +# Version information +#------------------------------------------------------------------------------ +set(HDF5_HERMES_VFD_VERSION_MAJOR ${HERMES_VERSION_MAJOR}) +set(HDF5_HERMES_VFD_VERSION_MINOR ${HERMES_VERSION_MINOR}) +set(HDF5_HERMES_VFD_VERSION_PATCH ${HERMES_VERSION_PATCH}) +set(HDF5_HERMES_VFD_PACKAGE "hdf5_hermes_vfd") +set(HDF5_HERMES_VFD_PACKAGE_NAME "HDF5_HERMES_VFD") +set(HDF5_HERMES_VFD_PACKAGE_VERSION "${HDF5_HERMES_VFD_VERSION_MAJOR}.${HDF5_HERMES_VFD_VERSION_MINOR}.${HDF5_HERMES_VFD_VERSION_PATCH}") +set(HDF5_HERMES_VFD_PACKAGE_VERSION_MAJOR "${HDF5_HERMES_VFD_VERSION_MAJOR}.${HDF5_HERMES_VFD_VERSION_MINOR}") +set(HDF5_HERMES_VFD_PACKAGE_VERSION_MINOR "${HDF5_HERMES_VFD_VERSION_PATCH}") +set(HDF5_HERMES_VFD_PACKAGE_STRING "${HDF5_HERMES_VFD_PACKAGE_NAME} ${HDF5_HERMES_VFD_PACKAGE_VERSION}") +set(HDF5_HERMES_VFD_PACKAGE_TARNAME "${HDF5_HERMES_VFD_PACKAGE}") + +# Dynamically loaded VFDs must be shared libraries +set(HDF5_HERMES_VFD_LIBTYPE SHARED) + +#----------------------------------------------------------------------------- +# Targets built within this project are exported at Install time for use +# by other projects. +#----------------------------------------------------------------------------- +if(NOT HDF5_HERMES_VFD_EXPORTED_TARGETS) + set(HDF5_HERMES_VFD_EXPORTED_TARGETS "${HDF5_HERMES_VFD_PACKAGE}-targets") +endif() + +set(HDF5_HERMES_VFD_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/H5FDhermes.h + ${CMAKE_CURRENT_SOURCE_DIR}/H5FDhermes.c + ) + +add_library(hdf5_hermes_vfd ${HDF5_HERMES_VFD_SRCS}) +set_target_properties(hdf5_hermes_vfd PROPERTIES LIBRARY_OUTPUT_DIRECTORY + ${HERMES_VFD_LIBRARY_DIR} +) +target_include_directories(hdf5_hermes_vfd PRIVATE ${CMAKE_SOURCE_DIR}/wrapper) +target_include_directories(hdf5_hermes_vfd + SYSTEM PUBLIC ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} +) + +target_link_libraries(hdf5_hermes_vfd + hermes_wrapper + MPI::MPI_C + ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES} +) + +set(HDF5_HERMES_VFD_EXPORTED_LIBS hdf5_hermes_vfd ${HDF5_HERMES_VFD_EXPORTED_LIBS} PARENT_SCOPE) + +#----------------------------------------------------------------------------- +# Specify project header files to be installed +#----------------------------------------------------------------------------- +set(HDF5_HERMES_VFD_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/H5FDhermes.h +) + +#----------------------------------------------------------------------------- +# Add file(s) to CMake Install +#----------------------------------------------------------------------------- +install( + FILES + ${HDF5_HERMES_VFD_HEADERS} + DESTINATION + ${HERMES_INSTALL_INCLUDE_DIR} + COMPONENT + headers +) + +#----------------------------------------------------------------------------- +# Add Target(s) to CMake Install +#----------------------------------------------------------------------------- +install( + TARGETS + hdf5_hermes_vfd + EXPORT + ${HDF5_HERMES_VFD_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR}/${HERMES_VFD_DIR_NAME} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR}/${HERMES_VFD_DIR_NAME} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} +) + +#----------------------------------------------------------------------------- +# Add Target(s) to CMake Install for import into other projects +#----------------------------------------------------------------------------- +install( + EXPORT + ${HDF5_HERMES_VFD_EXPORTED_TARGETS} + DESTINATION + ${HERMES_INSTALL_DATA_DIR}/cmake/hdf5_hermes_vfd + FILE + ${HDF5_HERMES_VFD_EXPORTED_TARGETS}.cmake +) + +#----------------------------------------------------------------------------- +# Export all exported targets to the build tree for use by parent project + +if(NOT HDF5_HERMES_VFD_EXTERNALLY_CONFIGURED) + export( + TARGETS + ${HDF5_HERMES_VFD_EXPORTED_LIBS} + FILE + ${HDF5_HERMES_VFD_EXPORTED_TARGETS}.cmake + ) +endif() + +#------------------------------------------------------------------------------ +# Set variables for parent scope +#------------------------------------------------------------------------------ + +# Pkg-config configuration +if(CMAKE_BUILD_TYPE) + string(TOLOWER ${CMAKE_BUILD_TYPE} lower_cmake_build_type) +endif() + +# Hermes VFD package dependencies +foreach(pkg_dep ${HDF5_HERMES_VFD_EXT_PKG_DEPENDENCIES}) + set(HDF5_HERMES_VFD_PKG_DEPENDENCIES ${HDF5_HERMES_VFD_PKG_DEPENDENCIES} ${pkg_dep}) +endforeach() +set(HDF5_HERMES_VFD_PKG_DEPENDENCIES ${HDF5_HERMES_VFD_PKG_DEPENDENCIES} PARENT_SCOPE) + +# Hermes VFD private library dependencies +foreach(exported_lib ${HDF5_HERMES_VFD_EXPORTED_LIBS}) + if(lower_cmake_build_type MATCHES "debug") + get_target_property(HDF5_HERMES_VFD_LIBRARY ${exported_lib} DEBUG_OUTPUT_NAME) + else() + get_target_property(HDF5_HERMES_VFD_LIBRARY ${exported_lib} RELEASE_OUTPUT_NAME) + endif() + set(HDF5_HERMES_VFD_LIBRARIES "${HDF5_HERMES_VFD_LIBRARIES} -l${HDF5_HERMES_VFD_LIBRARY}") +endforeach() +set(HDF5_HERMES_VFD_LIBRARIES ${HDF5_HERMES_VFD_LIBRARIES} PARENT_SCOPE) +# Hermes VFD external library dependencies +# Need to generate -lib if not already passed +set(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES + ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES} + ${HDF5_HERMES_VFD_EXT_PKG_LIB_DEPENDENCIES} + PARENT_SCOPE +) +foreach(lib_dep ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES}) + # get library name + get_filename_component(lib_name ${lib_dep} NAME_WE) + if(lib_name MATCHES "^-l") + # lib_name found is -lxxx + set(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST} ${lib_name}) + else() + # lib_name is /path/to/lib so get library path and name + get_filename_component(lib_path ${lib_dep} PATH) + string(REGEX REPLACE "^lib" "" lib_name ${lib_name}) + set(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST} -L${lib_path} -l${lib_name}) + endif() +endforeach() +if(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST) + list(REMOVE_DUPLICATES HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST) +endif() +foreach(lib_dep ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST}) + set(HDF5_HERMES_VFD_LIB_DEPENDENCIES "${HDF5_HERMES_VFD_LIB_DEPENDENCIES} ${lib_dep}") +endforeach() +set(HDF5_HERMES_VFD_LIB_DEPENDENCIES ${HDF5_HERMES_VFD_LIB_DEPENDENCIES} PARENT_SCOPE) + +# External include dependencies +set(HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES + ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} + ${HDF5_HERMES_VFD_EXT_PKG_INCLUDE_DEPENDENCIES} + PARENT_SCOPE +) +if(HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES) + list(REMOVE_DUPLICATES HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES) +endif() +foreach(inc_dep ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES}) + set(HDF5_HERMES_VFD_INCLUDE_DEPENDENCIES "${HDF5_HERMES_VFD_INCLUDE_DEPENDENCIES} -I${inc_dep}") +endforeach() +set(HDF5_HERMES_VFD_INCLUDE_DEPENDENCIES ${HDF5_HERMES_VFD_INCLUDE_DEPENDENCIES} PARENT_SCOPE) + +set(HDF5_HERMES_VFD_INCLUDES_BUILD_TIME + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} + PARENT_SCOPE +) + +set(HDF5_HERMES_VFD_INCLUDES_INSTALL_TIME + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} + PARENT_SCOPE +) diff --git a/adapter/vfd/H5FDhermes.c b/adapter/vfd/H5FDhermes.c new file mode 100644 index 000000000..09ca87094 --- /dev/null +++ b/adapter/vfd/H5FDhermes.c @@ -0,0 +1,1173 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Kimmy Mu + * March 2021 + * + * Purpose: The hermes file driver using only the HDF5 public API + * and buffer datasets in Hermes buffering systems with + * multiple storage tiers. + */ +#ifndef _GNU_SOURCE + #define _GNU_SOURCE +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* HDF5 header for dynamic plugin loading */ +#include "H5PLextern.h" + +#include "H5FDhermes.h" /* Hermes file driver */ +#include "H5FDhermes_err.h" /* error handling */ + +/* Necessary hermes headers */ +#include "hermes_wrapper.h" + +#define H5FD_HERMES (H5FD_hermes_init()) + +/* HDF5 doesn't currently have a driver init callback. Use + * macro to initialize driver if loaded as a plugin. + */ +#define H5FD_HERMES_INIT \ + do { \ + if (H5FD_HERMES_g < 0) \ + H5FD_HERMES_g = H5FD_HERMES; \ + } while (0) + +/* The driver identification number, initialized at runtime */ +static hid_t H5FD_HERMES_g = H5I_INVALID_HID; + +/* Identifiers for HDF5's error API */ +hid_t H5FDhermes_err_stack_g = H5I_INVALID_HID; +hid_t H5FDhermes_err_class_g = H5I_INVALID_HID; + +/* Whether Hermes is initialized */ +static htri_t hermes_initialized = FAIL; +static hbool_t mpi_is_initialized = FALSE; + +/* File operations */ +#define OP_UNKNOWN 0 +#define OP_READ 1 +#define OP_WRITE 2 + +/* POSIX I/O mode used as the third parameter to open/_open + * when creating a new file (O_CREAT is set). */ +#if defined(H5_HAVE_WIN32_API) +#define H5FD_HERMES_POSIX_CREATE_MODE_RW (_S_IREAD | _S_IWRITE) +#else +#define H5FD_HERMES_POSIX_CREATE_MODE_RW 0666 +#endif + +/* Define length of blob name, which is converted from page index */ +#define LEN_BLOB_NAME 10 + +#define BIT_SIZE_OF_UNSIGNED (sizeof(uint)*8) + +/* kHermesConf env variable is used to define path to kHermesConf in adapters. + * This is used for initialization of Hermes. */ +const char *kHermesConf = "HERMES_CONF"; + +/* The description of bit representation of blobs in Hermes buffering system. */ +typedef struct bitv_t { + uint *blobs; + size_t capacity; + size_t end_pos; +} bitv_t; + +/* The description of a file/bucket belonging to this driver. */ +typedef struct H5FD_hermes_t { + H5FD_t pub; /* public stuff, must be first */ + haddr_t eoa; /* end of allocated region */ + haddr_t eof; /* end of file; current file size */ + haddr_t pos; /* current file I/O position */ + int op; /* last operation */ + hbool_t persistence; /* write to file name on close */ + int fd; /* the filesystem file descriptor */ + size_t buf_size; + char *bktname; /* Copy of file name from open operation */ + BucketClass *bkt_handle; + int ref_count; + unsigned char *page_buf; + bitv_t blob_in_bucket; + unsigned flags; /* The flags passed from H5Fcreate/H5Fopen */ +} H5FD_hermes_t; + +/* Driver-specific file access properties */ +typedef struct H5FD_hermes_fapl_t { + hbool_t persistence; /* write to file name on flush */ + size_t page_size; /* page size */ +} H5FD_hermes_fapl_t; + +/* + * These macros check for overflow of various quantities. These macros + * assume that HDoff_t is signed and haddr_t and size_t are unsigned. + * + * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t' + * is too large to be represented by the second argument + * of the file seek function. + * + * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too + * large to be represented by the `size_t' type. + * + * REGION_OVERFLOW: Checks whether an address and size pair describe data + * which can be addressed entirely by the second + * argument of the file seek function. + */ +#define MAXADDR (((haddr_t)1 << (8 * sizeof(off_t) - 1)) - 1) +#define ADDR_OVERFLOW(A) (HADDR_UNDEF == (A) || ((A) & ~(haddr_t)MAXADDR)) +#define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR) +#define REGION_OVERFLOW(A, Z) \ + (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || HADDR_UNDEF == (A) + (Z) || \ + (off_t)((A) + (Z)) < (off_t)(A)) + +/* Prototypes */ +static herr_t H5FD__hermes_term(void); +static herr_t H5FD__hermes_fapl_free(void *_fa); +static H5FD_t *H5FD__hermes_open(const char *name, unsigned flags, + hid_t fapl_id, haddr_t maxaddr); +static herr_t H5FD__hermes_close(H5FD_t *_file); +static int H5FD__hermes_cmp(const H5FD_t *_f1, const H5FD_t *_f2); +static herr_t H5FD__hermes_query(const H5FD_t *_f1, unsigned long *flags); +static haddr_t H5FD__hermes_get_eoa(const H5FD_t *_file, H5FD_mem_t type); +static herr_t H5FD__hermes_set_eoa(H5FD_t *_file, H5FD_mem_t type, + haddr_t addr); +static haddr_t H5FD__hermes_get_eof(const H5FD_t *_file, H5FD_mem_t type); +static herr_t H5FD__hermes_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, + haddr_t addr, size_t size, void *buf); +static herr_t H5FD__hermes_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, + haddr_t addr, size_t size, const void *buf); + +static const H5FD_class_t H5FD_hermes_g = { + H5FD_HERMES_VALUE, /* value */ + H5FD_HERMES_NAME, /* name */ + MAXADDR, /* maxaddr */ + H5F_CLOSE_STRONG, /* fc_degree */ + H5FD__hermes_term, /* terminate */ + NULL, /* sb_size */ + NULL, /* sb_encode */ + NULL, /* sb_decode */ + sizeof(H5FD_hermes_fapl_t),/* fapl_size */ + NULL, /* fapl_get */ + NULL, /* fapl_copy */ + H5FD__hermes_fapl_free, /* fapl_free */ + 0, /* dxpl_size */ + NULL, /* dxpl_copy */ + NULL, /* dxpl_free */ + H5FD__hermes_open, /* open */ + H5FD__hermes_close, /* close */ + H5FD__hermes_cmp, /* cmp */ + H5FD__hermes_query, /* query */ + NULL, /* get_type_map */ + NULL, /* alloc */ + NULL, /* free */ + H5FD__hermes_get_eoa, /* get_eoa */ + H5FD__hermes_set_eoa, /* set_eoa */ + H5FD__hermes_get_eof, /* get_eof */ + NULL, /* get_handle */ + H5FD__hermes_read, /* read */ + H5FD__hermes_write, /* write */ + NULL, /* flush */ + NULL, /* truncate */ + NULL, /* lock */ + NULL, /* unlock */ + NULL, /* del */ + NULL, /* ctl */ + H5FD_FLMAP_DICHOTOMY /* fl_map */ +}; + +/* Check if the blob at POS is set */ +static bool check_blob(bitv_t *bits, size_t bit_pos) { + bool result = false; + + if (bit_pos >= bits->capacity) + return false; + + size_t unit_pos = bit_pos / BIT_SIZE_OF_UNSIGNED; + size_t blob_pos_in_unit = bit_pos % BIT_SIZE_OF_UNSIGNED; + result = bits->blobs[unit_pos] & (1 << blob_pos_in_unit); + + return result; +} + +/* Set the bit at POS and reallocate 2*capacity for blobs as needed */ +static void set_blob(bitv_t *bits, size_t bit_pos) { + if (bit_pos >= bits->capacity) { + size_t current_units = bits->capacity/BIT_SIZE_OF_UNSIGNED; + size_t need_units = bit_pos/BIT_SIZE_OF_UNSIGNED + 1; + bits->capacity = need_units * BIT_SIZE_OF_UNSIGNED * 2; + bits->blobs = realloc(bits->blobs, bits->capacity); + memset(&bits->blobs[current_units], 0, + sizeof(uint)*(need_units*2-current_units+1)); + } + + size_t unit_pos = bit_pos / BIT_SIZE_OF_UNSIGNED; + size_t blob_pos_in_unit = bit_pos % BIT_SIZE_OF_UNSIGNED; + bits->blobs[unit_pos] |= 1 << blob_pos_in_unit; + if (bit_pos > bits->end_pos) + bits->end_pos = bit_pos; +} + +/** Returns true if @p page_index is the last page in the file. */ +bool H5FD__hermes_is_last_page(H5FD_hermes_t *file, size_t page_index) { + size_t total_pages = (size_t)ceil(file->eof / (float)file->buf_size); + size_t last_page_index = total_pages > 0 ? total_pages - 1 : 0; + bool ret_value = page_index == last_page_index; + + return ret_value; +} + +/** Returns the size of page @page_index. This is only different from + * H5FD_hermes_t::buf_size if it's the last page in the file. */ +size_t H5FD__hermes_get_gap_size(H5FD_hermes_t *file, size_t page_index) { + size_t ret_value = file->buf_size; + if (H5FD__hermes_is_last_page(file, page_index)) { + ret_value = file->eof - (page_index * file->buf_size); + } + + return ret_value; +} + +/** + * If the Hermes VFD recieves a partial page update to an existing file, we + * first need to fill the page with exising data from the file with a read + * before the Blob can be buffered. We refer to these partial pages as "gaps." + */ +herr_t H5FD__hermes_read_gap(H5FD_hermes_t *file, size_t seek_offset, + unsigned char *read_ptr, size_t read_size) { + herr_t ret_value = SUCCEED; + + if (!(file->flags & H5F_ACC_CREAT || file->flags & H5F_ACC_TRUNC || + file->flags & H5F_ACC_EXCL)) { + if (file->fd > -1) { + if (flock(file->fd, LOCK_SH) == -1) { + H5FD_HERMES_SYS_GOTO_ERROR(H5E_IO, H5E_CANTLOCKFILE, FAIL, + file->bktname); + } + + ssize_t bytes_read = pread(file->fd, read_ptr, read_size, seek_offset); + if (bytes_read == -1 || + ((size_t)bytes_read != read_size && bytes_read != 0)) { + H5FD_HERMES_SYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, file->bktname); + } + + if (flock(file->fd, LOCK_UN) == -1) { + H5FD_HERMES_SYS_GOTO_ERROR(H5E_IO, H5E_CANTUNLOCKFILE, FAIL, + file->bktname); + } + } + } + +done: + H5FD_HERMES_FUNC_LEAVE; +} + +/*------------------------------------------------------------------------- + * Function: H5FD_hermes_init + * + * Purpose: Initialize this driver by registering the driver with the + * library. + * + * Return: Success: The driver ID for the hermes driver + * Failure: H5I_INVALID_HID + * + *------------------------------------------------------------------------- + */ +hid_t +H5FD_hermes_init(void) { + hid_t ret_value = H5I_INVALID_HID; /* Return value */ + + /* Initialize error reporting */ + if ((H5FDhermes_err_stack_g = H5Ecreate_stack()) < 0) + H5FD_HERMES_GOTO_ERROR(H5E_VFL, H5E_CANTINIT, H5I_INVALID_HID, + "can't create HDF5 error stack"); + if ((H5FDhermes_err_class_g = H5Eregister_class(H5FD_HERMES_ERR_CLS_NAME, + H5FD_HERMES_ERR_LIB_NAME, + H5FD_HERMES_ERR_VER)) < 0) + H5FD_HERMES_GOTO_ERROR(H5E_VFL, H5E_CANTINIT, H5I_INVALID_HID, + "can't register error class with HDF5 error API"); + + if (H5I_VFL != H5Iget_type(H5FD_HERMES_g)) + H5FD_HERMES_g = H5FDregister(&H5FD_hermes_g); + + /* Set return value */ + ret_value = H5FD_HERMES_g; + +done: + H5FD_HERMES_FUNC_LEAVE; +} /* end H5FD_hermes_init() */ + +/*--------------------------------------------------------------------------- + * Function: H5FD__hermes_term + * + * Purpose: Shut down the VFD + * + * Returns: SUCCEED (Can't fail) + * + *--------------------------------------------------------------------------- + */ +static herr_t +H5FD__hermes_term(void) { + herr_t ret_value = SUCCEED; + + /* Unregister from HDF5 error API */ + if (H5FDhermes_err_class_g >= 0) { + if (H5Eunregister_class(H5FDhermes_err_class_g) < 0) + H5FD_HERMES_GOTO_ERROR( + H5E_VFL, H5E_CLOSEERROR, FAIL, + "can't unregister error class from HDF5 error API"); + + /* Print the current error stack before destroying it */ + PRINT_ERROR_STACK; + + /* Destroy the error stack */ + if (H5Eclose_stack(H5FDhermes_err_stack_g) < 0) { + H5FD_HERMES_GOTO_ERROR(H5E_VFL, H5E_CLOSEERROR, FAIL, + "can't close HDF5 error stack"); + PRINT_ERROR_STACK; + } /* end if */ + + H5FDhermes_err_stack_g = H5I_INVALID_HID; + H5FDhermes_err_class_g = H5I_INVALID_HID; + } + + /* Reset VFL ID */ + H5FD_HERMES_g = H5I_INVALID_HID; + +done: + H5FD_HERMES_FUNC_LEAVE_API; +} /* end H5FD__hermes_term() */ + +/*------------------------------------------------------------------------- + * Function: H5Pset_fapl_hermes + * + * Purpose: Modify the file access property list to use the H5FD_HERMES + * driver defined in this source file. There are no driver + * specific properties. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pset_fapl_hermes(hid_t fapl_id, hbool_t persistence, size_t page_size) { + H5FD_hermes_fapl_t fa; /* Hermes VFD info */ + herr_t ret_value = SUCCEED; /* Return value */ + + /* Check argument */ + if (H5I_GENPROP_LST != H5Iget_type(fapl_id) || + TRUE != H5Pisa_class(fapl_id, H5P_FILE_ACCESS)) { + H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, + "not a file access property list"); + } + + /* Set VFD info values */ + memset(&fa, 0, sizeof(H5FD_hermes_fapl_t)); + fa.persistence = persistence; + fa.page_size = page_size; + + /* Set the property values & the driver for the FAPL */ + if (H5Pset_driver(fapl_id, H5FD_HERMES, &fa) < 0) { + H5FD_HERMES_GOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, + "can't set Hermes VFD as driver"); + } + +done: + H5FD_HERMES_FUNC_LEAVE_API; +} /* end H5Pset_fapl_hermes() */ + +/*------------------------------------------------------------------------- + * Function: H5FD__hermes_fapl_free + * + * Purpose: Frees the family-specific file access properties. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t H5FD__hermes_fapl_free(void *_fa) { + H5FD_hermes_fapl_t *fa = (H5FD_hermes_fapl_t *)_fa; + herr_t ret_value = SUCCEED; /* Return value */ + + free(fa); + + H5FD_HERMES_FUNC_LEAVE; +} + +/*------------------------------------------------------------------------- + * Function: H5FD__hermes_open + * + * Purpose: Create and/or opens a bucket in Hermes. + * + * Return: Success: A pointer to a new bucket data structure. + * Failure: NULL + * + *------------------------------------------------------------------------- + */ +static H5FD_t * +H5FD__hermes_open(const char *name, unsigned flags, hid_t fapl_id, + haddr_t maxaddr) { + H5FD_hermes_t *file = NULL; /* hermes VFD info */ + int fd = -1; /* File descriptor */ + int o_flags = 0; /* Flags for open() call */ + struct stat sb = {0}; + const H5FD_hermes_fapl_t *fa = NULL; + H5FD_hermes_fapl_t new_fa = {0}; + char *hermes_config = NULL; + H5FD_t *ret_value = NULL; /* Return value */ + + /* Sanity check on file offsets */ + assert(sizeof(off_t) >= sizeof(size_t)); + + H5FD_HERMES_INIT; + + /* Check arguments */ + if (!name || !*name) + H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name"); + if (0 == maxaddr || HADDR_UNDEF == maxaddr) + H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr"); + if (ADDR_OVERFLOW(maxaddr)) + H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr"); + + /* Get the driver specific information */ + H5E_BEGIN_TRY { + fa = H5Pget_driver_info(fapl_id); + } + H5E_END_TRY; + if (!fa || (H5P_FILE_ACCESS_DEFAULT == fapl_id)) { + ssize_t config_str_len = 0; + char config_str_buf[128]; + if ((config_str_len = + H5Pget_driver_config_str(fapl_id, config_str_buf, 128)) < 0) { + printf("H5Pget_driver_config_str() error\n"); + } + char *saveptr = NULL; + char* token = strtok_r(config_str_buf, " ", &saveptr); + if (!strcmp(token, "true") || !strcmp(token, "TRUE") || + !strcmp(token, "True")) { + new_fa.persistence = true; + } + token = strtok_r(0, " ", &saveptr); + sscanf(token, "%zu", &(new_fa.page_size)); + fa = &new_fa; + } + + /* Initialize Hermes */ + if ((H5OPEN hermes_initialized) == FAIL) { + hermes_config = getenv(kHermesConf); + if (HermesInitHermes(hermes_config) < 0) { + H5FD_HERMES_GOTO_ERROR(H5E_SYM, H5E_UNINITIALIZED, NULL, + "Hermes initialization failed"); + } else { + hermes_initialized = TRUE; + } + } + + bool creating_file = false; + + /* Build the open flags */ + o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY; + if (H5F_ACC_TRUNC & flags) { + o_flags |= O_TRUNC; + } + if (H5F_ACC_CREAT & flags) { + o_flags |= O_CREAT; + creating_file = true; + } + if (H5F_ACC_EXCL & flags) { + o_flags |= O_EXCL; + } + + if (fa->persistence || !creating_file) { + // NOTE(chogan): We're either in persistent mode, or we're in scratch mode + // and dealing with an existing file. + if ((fd = open(name, o_flags, H5FD_HERMES_POSIX_CREATE_MODE_RW)) < 0) { + int myerrno = errno; + H5FD_HERMES_GOTO_ERROR( + H5E_FILE, H5E_CANTOPENFILE, NULL, + "unable to open file: name = '%s', errno = %d, error message = '%s'," + "flags = %x, o_flags = %x", name, myerrno, strerror(myerrno), flags, + (unsigned)o_flags); + } + + if (__fxstat(_STAT_VER, fd, &sb) < 0) { + H5FD_HERMES_SYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, + "unable to fstat file"); + } + } + + /* Create the new file struct */ + if (NULL == (file = calloc(1, sizeof(H5FD_hermes_t)))) { + H5FD_HERMES_GOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, + "unable to allocate file struct"); + } + + if (name && *name) { + file->bktname = strdup(name); + } + + file->persistence = fa->persistence; + file->fd = fd; + file->bkt_handle = HermesBucketCreate(name); + file->page_buf = malloc(fa->page_size); + file->buf_size = fa->page_size; + file->ref_count = 1; + file->op = OP_UNKNOWN; + file->blob_in_bucket.capacity = BIT_SIZE_OF_UNSIGNED; + file->blob_in_bucket.blobs = (uint *)calloc(1, sizeof(uint)); + file->blob_in_bucket.end_pos = 0; + file->flags = flags; + file->eof = (haddr_t)sb.st_size; + + /* Set return value */ + ret_value = (H5FD_t *)file; + +done: + if (NULL == ret_value) { + if (fd >= 0) + close(fd); + if (file) { + if (file->bkt_handle) { + HermesBucketDestroy(file->bkt_handle); + } + free(file->blob_in_bucket.blobs); + free(file->bktname); + free(file->page_buf); + free(file); + } + } /* end if */ + + H5FD_HERMES_FUNC_LEAVE_API; +} /* end H5FD__hermes_open() */ + +/*------------------------------------------------------------------------- + * Function: H5FD__hermes_close + * + * Purpose: Closes an HDF5 file. + * + * Return: Success: SUCCEED + * Failure: FAIL, file not closed. + * + *------------------------------------------------------------------------- + */ +static herr_t H5FD__hermes_close(H5FD_t *_file) { + H5FD_hermes_t *file = (H5FD_hermes_t *)_file; + size_t blob_size = file->buf_size; + size_t i; + herr_t ret_value = SUCCEED; /* Return value */ + + /* Sanity check */ + assert(file); + + if (file->persistence) { + if (file->op == OP_WRITE) { + /* TODO: if there is user blobk, the logic is not working, + including offset, but not 0 */ + for (i = 0; i <= file->blob_in_bucket.end_pos; i++) { + /* Check if this blob exists */ + bool blob_exists = check_blob(&file->blob_in_bucket, i); + if (!blob_exists) + continue; + + char i_blob[LEN_BLOB_NAME]; + snprintf(i_blob, sizeof(i_blob), "%zu\n", i); + HermesBucketGet(file->bkt_handle, i_blob, blob_size, file->page_buf); + + bool is_last_page = H5FD__hermes_is_last_page(file, i); + size_t bytes_to_write = blob_size; + + if (is_last_page) { + size_t bytes_in_last_page = file->eof - (i * blob_size); + bytes_to_write = bytes_in_last_page; + } + + ssize_t bytes_written = pwrite(file->fd, file->page_buf, bytes_to_write, + i * blob_size); + assert(bytes_written == bytes_to_write); + } + } + if (close(file->fd) < 0) + H5FD_HERMES_SYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, + "unable to close file"); + } + + if (file->ref_count == 1) { + HermesBucketDestroy(file->bkt_handle); + } else { + HermesBucketClose(file->bkt_handle); + } + + /* Release the file info */ + free(file->blob_in_bucket.blobs); + free(file->page_buf); + free(file->bktname); + free(file); + +done: + H5FD_HERMES_FUNC_LEAVE_API; +} /* end H5FD__hermes_close() */ + +/*------------------------------------------------------------------------- + * Function: H5FD__hermes_cmp + * + * Purpose: Compares two buckets belonging to this driver using an + * arbitrary (but consistent) ordering. + * + * Return: Success: A value like strcmp() + * Failure: never fails (arguments were checked by the + * caller). + * + *------------------------------------------------------------------------- + */ +static int H5FD__hermes_cmp(const H5FD_t *_f1, const H5FD_t *_f2) { + const H5FD_hermes_t *f1 = (const H5FD_hermes_t *)_f1; + const H5FD_hermes_t *f2 = (const H5FD_hermes_t *)_f2; + int ret_value = 0; + + ret_value = strcmp(f1->bktname, f2->bktname); + + H5FD_HERMES_FUNC_LEAVE; +} /* end H5FD__hermes_cmp() */ + +/*------------------------------------------------------------------------- + * Function: H5FD__hermes_query + * + * Purpose: Set the flags that this VFL driver is capable of supporting. + * (listed in H5FDpublic.h) + * + * Return: SUCCEED (Can't fail) + * + *------------------------------------------------------------------------- + */ +static herr_t H5FD__hermes_query(const H5FD_t *_file, + unsigned long *flags /* out */) { + /* Set the VFL feature flags that this driver supports */ + /* Notice: the Mirror VFD Writer currently uses only the hermes driver as + * the underying driver -- as such, the Mirror VFD implementation copies + * these feature flags as its own. Any modifications made here must be + * reflected in H5FDmirror.c + * -- JOS 2020-01-13 + */ + herr_t ret_value = SUCCEED; + + if (flags) { + *flags = 0; + } /* end if */ + + H5FD_HERMES_FUNC_LEAVE; +} /* end H5FD__hermes_query() */ + +/*------------------------------------------------------------------------- + * Function: H5FD__hermes_get_eoa + * + * Purpose: Gets the end-of-address marker for the file. The EOA marker + * is the first address past the last byte allocated in the + * format address space. + * + * Return: The end-of-address marker. + * + *------------------------------------------------------------------------- + */ +static haddr_t H5FD__hermes_get_eoa(const H5FD_t *_file, + H5FD_mem_t H5_ATTR_UNUSED type) { + haddr_t ret_value = HADDR_UNDEF; + + const H5FD_hermes_t *file = (const H5FD_hermes_t *)_file; + + ret_value = file->eoa; + + H5FD_HERMES_FUNC_LEAVE; +} /* end H5FD__hermes_get_eoa() */ + +/*------------------------------------------------------------------------- + * Function: H5FD__hermes_set_eoa + * + * Purpose: Set the end-of-address marker for the file. This function is + * called shortly after an existing HDF5 file is opened in order + * to tell the driver where the end of the HDF5 data is located. + * + * Return: SUCCEED (Can't fail) + * + *------------------------------------------------------------------------- + */ +static herr_t H5FD__hermes_set_eoa(H5FD_t *_file, + H5FD_mem_t H5_ATTR_UNUSED type, + haddr_t addr) { + herr_t ret_value = SUCCEED; + + H5FD_hermes_t *file = (H5FD_hermes_t *)_file; + + file->eoa = addr; + + H5FD_HERMES_FUNC_LEAVE; +} /* end H5FD__hermes_set_eoa() */ + +/*------------------------------------------------------------------------- + * Function: H5FD__hermes_get_eof + * + * Purpose: Returns the end-of-file marker, which is the greater of + * either the filesystem end-of-file or the HDF5 end-of-address + * markers. + * + * Return: End of file address, the first address past the end of the + * "file", either the filesystem file or the HDF5 file. + * + *------------------------------------------------------------------------- + */ +static haddr_t H5FD__hermes_get_eof(const H5FD_t *_file, + H5FD_mem_t H5_ATTR_UNUSED type) { + haddr_t ret_value = HADDR_UNDEF; + + const H5FD_hermes_t *file = (const H5FD_hermes_t *)_file; + + ret_value = file->eof; + + H5FD_HERMES_FUNC_LEAVE; +} /* end H5FD__hermes_get_eof() */ + +/*------------------------------------------------------------------------- + * Function: H5FD__hermes_read + * + * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR + * into buffer BUF according to data transfer properties in + * DXPL_ID. Determine the number of file pages affected by this + * call from ADDR and SIZE. Utilize transfer buffer PAGE_BUF to + * read the data from Blobs. Exercise care for the first and last + * pages to prevent overwriting existing data. + * + * Return: Success: SUCCEED. Result is stored in caller-supplied + * buffer BUF. + * Failure: FAIL, Contents of buffer BUF are undefined. + * + *------------------------------------------------------------------------- + */ +static herr_t H5FD__hermes_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, + hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, + size_t size, void *buf /*out*/) { + H5FD_hermes_t *file = (H5FD_hermes_t *)_file; + size_t num_pages; /* Number of pages of transfer buffer */ + size_t start_page_index; /* First page index of tranfer buffer */ + size_t end_page_index; /* End page index of tranfer buffer */ + size_t transfer_size = 0; + size_t blob_size = file->buf_size; + size_t k; + haddr_t addr_end = addr+size-1; + herr_t ret_value = SUCCEED; /* Return value */ + + assert(file && file->pub.cls); + assert(buf); + + /* Check for overflow conditions */ + if (HADDR_UNDEF == addr) { + H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "addr undefined, addr = %llu", + (unsigned long long)addr); + } + if (REGION_OVERFLOW(addr, size)) { + H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, + "addr overflow, addr = %llu", + (unsigned long long)addr); + } + if (NULL == file->page_buf) { + H5FD_HERMES_GOTO_ERROR(H5E_INTERNAL, H5E_UNINITIALIZED, FAIL, + "transfer buffer not initialized"); + } + + /* Check easy cases */ + if (0 == size) + return 0; + if ((haddr_t)addr >= file->eof) { + memset(buf, 0, size); + return 0; + } + + start_page_index = addr/blob_size; + end_page_index = addr_end/blob_size; + num_pages = end_page_index - start_page_index + 1; + + for (k = start_page_index; k <= end_page_index; ++k) { + size_t bytes_in; + char k_blob[LEN_BLOB_NAME]; + snprintf(k_blob, sizeof(k_blob), "%zu\n", k); + /* Check if this blob exists */ + bool blob_exists = check_blob(&file->blob_in_bucket, k); + + /* Check if addr is in the range of (k*blob_size, (k+1)*blob_size) */ + /* NOTE: The range does NOT include the start address of page k, + but includes the end address of page k */ + if (addr > k*blob_size && addr < (k+1)*blob_size) { + /* Calculate the starting address of transfer buffer update within page + * k */ + size_t offset = addr - k*blob_size; + assert(offset > 0); + + if (addr_end <= (k+1)*blob_size-1) + bytes_in = size; + else + bytes_in = (k+1)*blob_size-addr; + + if (!blob_exists) { + size_t bytes_copy; + if (file->eof < (k+1)*blob_size-1) + bytes_copy = file->eof-k*blob_size; + else + bytes_copy = blob_size; + + size_t bytes_read = pread(file->fd, file->page_buf, bytes_copy, + k*blob_size); + if (bytes_read != bytes_copy) + H5FD_HERMES_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "pread failed"); + memcpy(buf, file->page_buf+offset, bytes_in); + + /* Write Blob k to Hermes buffering system */ + HermesBucketPut(file->bkt_handle, k_blob, file->page_buf, blob_size); + set_blob(&file->blob_in_bucket, k); + } else { + /* Read blob back to transfer buffer */ + HermesBucketGet(file->bkt_handle, k_blob, blob_size, file->page_buf); + + memcpy(buf, file->page_buf+offset, bytes_in); + } + transfer_size += bytes_in; + /* Check if addr_end is in the range of [k*blob_size, + * (k+1)*blob_size-1) */ + /* NOTE: The range includes the start address of page k, + but does NOT include the end address of page k */ + } else if (addr_end >= k*blob_size && addr_end < (k+1)*blob_size-1) { + bytes_in = addr_end-k*blob_size+1; + if (!blob_exists) { + size_t bytes_copy; + if (file->eof < (k+1)*blob_size-1) + bytes_copy = file->eof-k*blob_size; + else + bytes_copy = blob_size; + + ssize_t bytes_read = pread(file->fd, file->page_buf, bytes_copy, + k*blob_size); + if (bytes_read != bytes_copy) + H5FD_HERMES_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "pread failed"); + + memcpy((char *)buf + transfer_size, file->page_buf, bytes_in); + + /* Write Blob k to Hermes buffering system */ + HermesBucketPut(file->bkt_handle, k_blob, file->page_buf, blob_size); + set_blob(&file->blob_in_bucket, k); + } else { + /* Read blob back to transfer buffer */ + HermesBucketGet(file->bkt_handle, k_blob, blob_size, file->page_buf); + + /* Update transfer buffer */ + memcpy((char *)buf + transfer_size, file->page_buf, bytes_in); + } + transfer_size += bytes_in; + /* Page/Blob k is within the range of (addr, addr+size) */ + /* addr <= k*blob_size && addr_end >= (k+1)*blob_size-1 */ + } else { + if (!blob_exists) { + ssize_t bytes_read = pread(file->fd, (char *)buf + transfer_size, + blob_size, addr+transfer_size); + if (bytes_read != blob_size) + H5FD_HERMES_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "pread failed"); + + /* Write Blob k to Hermes buffering system */ + HermesBucketPut(file->bkt_handle, k_blob, (char *)buf + transfer_size, + blob_size); + set_blob(&file->blob_in_bucket, k); + } else { + /* Read blob back directly */ + HermesBucketGet(file->bkt_handle, k_blob, blob_size, + (char *)buf + transfer_size); + } + transfer_size += blob_size; + } + } + + /* Update current position */ + file->pos = addr+size; + file->op = OP_READ; + +done: + if (ret_value < 0) { + /* Reset last file I/O information */ + file->pos = HADDR_UNDEF; + file->op = OP_UNKNOWN; + } /* end if */ + + H5FD_HERMES_FUNC_LEAVE_API; +} /* end H5FD__hermes_read() */ + +/*------------------------------------------------------------------------- + * Function: H5FD__hermes_write + * + * Purpose: Writes SIZE bytes of data contained in buffer BUF to Hermes + * buffering system according to data transfer properties in + * DXPL_ID. Determine the number of file pages affected by this + * call from ADDR and SIZE. Utilize transfer buffer PAGE_BUF to + * put the data into Blobs. Exercise care for the first and last + * pages to prevent overwriting existing data. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t H5FD__hermes_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, + hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, + size_t size, const void *buf) { + H5FD_hermes_t *file = (H5FD_hermes_t *)_file; + size_t start_page_index; /* First page index of tranfer buffer */ + size_t end_page_index; /* End page index of tranfer buffer */ + size_t transfer_size = 0; + size_t blob_size = file->buf_size; + size_t k; + haddr_t addr_end = addr+size-1; + herr_t ret_value = SUCCEED; /* Return value */ + + assert(file && file->pub.cls); + assert(buf); + + /* Check for overflow conditions */ + if (HADDR_UNDEF == addr) { + H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "addr undefined, addr = %llu", + (unsigned long long)addr); + } + if (REGION_OVERFLOW(addr, size)) { + H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, + "addr overflow, addr = %llu, size = %llu", + (unsigned long long)addr, (unsigned long long)size); + } + if (NULL == file->page_buf) { + H5FD_HERMES_GOTO_ERROR(H5E_INTERNAL, H5E_UNINITIALIZED, FAIL, + "transfer buffer not initialized"); + } + start_page_index = addr/blob_size; + end_page_index = addr_end/blob_size; + + for (k = start_page_index; k <= end_page_index; ++k) { + char k_blob[LEN_BLOB_NAME]; + snprintf(k_blob, sizeof(k_blob), "%zu\n", k); + bool blob_exists = check_blob(&file->blob_in_bucket, k); + size_t page_start = k * blob_size; + size_t next_page_start = (k + 1) * blob_size; + + /* Check if addr is in the range of (page_start, next_page_start) */ + /* NOTE: The range does NOT include the start address of page k, + but includes the end address of page k */ + if (addr > page_start && addr < next_page_start) { + size_t page_offset = addr - page_start; + size_t page_write_size; + + if (addr_end < next_page_start) { + /* addr + size is within the same page (only one page) */ + page_write_size = size; + } else { + /* More than one page. Only copy until the end of this page. */ + page_write_size = next_page_start - addr; + } + + /* Fill transfer buffer with existing data, if any. */ + if (blob_exists) { + HermesBucketGet(file->bkt_handle, k_blob, blob_size, file->page_buf); + } else { + /* Populate this page from the original file */ + size_t gap_size = H5FD__hermes_get_gap_size(file, k); + herr_t status = H5FD__hermes_read_gap(file, page_start, file->page_buf, + gap_size); + if (status != SUCCEED) { + H5FD_HERMES_GOTO_DONE(FAIL); + } + } + + memcpy(file->page_buf + page_offset, (char *)buf + transfer_size, + page_write_size); + transfer_size += page_write_size; + + /* Write Blob k to Hermes. */ + HermesBucketPut(file->bkt_handle, k_blob, file->page_buf, blob_size); + set_blob(&file->blob_in_bucket, k); + } else if (addr_end >= page_start && addr_end < next_page_start - 1) { + /* NOTE: The range includes the start address of page k, but does NOT + include the end address of page k */ + + /* Read blob back */ + if (blob_exists) { + HermesBucketGet(file->bkt_handle, k_blob, blob_size, file->page_buf); + } else { + /* Populate this page from the original file */ + size_t gap_size = H5FD__hermes_get_gap_size(file, k); + herr_t status = H5FD__hermes_read_gap(file, page_start, file->page_buf, + gap_size); + if (status != SUCCEED) { + H5FD_HERMES_GOTO_DONE(FAIL); + } + } + + /* Update transfer buffer */ + memcpy(file->page_buf, (char *)buf + transfer_size, + addr_end-page_start + 1); + transfer_size += addr_end-page_start + 1; + /* Write Blob k to Hermes. */ + HermesBucketPut(file->bkt_handle, k_blob, file->page_buf, blob_size); + set_blob(&file->blob_in_bucket, k); + } else if (addr <= page_start && addr_end >= next_page_start-1) { + /* The write spans this page entirely */ + /* Write Blob k to Hermes buffering system */ + HermesBucketPut(file->bkt_handle, k_blob, (char *)buf + transfer_size, + blob_size); + set_blob(&(file->blob_in_bucket), k); + transfer_size += blob_size; + } + } + + /* Update current position and eof */ + file->pos = addr+size; + file->op = OP_WRITE; + if (file->pos > file->eof) + file->eof = file->pos; + +done: + if (ret_value < 0) { + /* Reset last file I/O information */ + file->pos = HADDR_UNDEF; + file->op = OP_UNKNOWN; + } /* end if */ + + H5FD_HERMES_FUNC_LEAVE_API; +} /* end H5FD__hermes_write() */ + +/* + * Stub routines for dynamic plugin loading + */ +H5PL_type_t +H5PLget_plugin_type(void) { + return H5PL_TYPE_VFD; +} + +const void* +H5PLget_plugin_info(void) { + return &H5FD_hermes_g; +} + +/* NOTE(chogan): Question: Why do we intercept initialization and termination of + * HDF5 and MPI? Answer: We have to handle several possible cases in order to + * get the initialization and finalization order of Hermes correct. First, the + * HDF5 application using the Hermes VFD can be either an MPI application or a + * serial application. If it's a serial application, we simply initialize Hermes + * before initializing the HDF5 library by intercepting H5_init_library. See + * https://github.com/HDFGroup/hermes/issues/385 for an explanation of why we + * need to initialize Hermes before HDF5. + * + * If we're dealing with an MPI application, then there are two possibilities: + * the app called MPI_Init before any HDF5 calls, or it made at least one HDF5 + * call before calling MPI_Init. If HDF5 was called first, then we have to + * initialize MPI ourselves and then intercept the app's call to MPI_Init to + * ensure MPI_Init is not called twice. + * + * For finalization, there are two cases to handle: 1) The application called + * MPI_Finalize(). In this case we need to intercept MPI_Finalize and shut down + * Hermes before MPI is finalized because Hermes finalization requires MPI. 2) + * If the app is serial, we need to call MPI_Finalize ourselves, so we intercept + * H5_term_library().*/ + +herr_t H5_init_library() { + herr_t ret_value = SUCCEED; + + if (mpi_is_initialized == FALSE) { + int status = PMPI_Init(NULL, NULL); + if (status != MPI_SUCCESS) { + // NOTE(chogan): We can't use the HDF5 error reporting functions here + // because HDF5 isn't initialized yet. + fprintf(stderr, "Hermes VFD: can't initialize MPI\n"); + ret_value = FAIL; + } else { + mpi_is_initialized = TRUE; + } + } + + if (ret_value == SUCCEED) { + if (hermes_initialized == FAIL) { + char *hermes_config = getenv(kHermesConf); + int status = HermesInitHermes(hermes_config); + if (status == 0) { + hermes_initialized = TRUE; + } else { + fprintf(stderr, "Hermes VFD: can't initialize Hermes\n"); + ret_value = FAIL; + } + } + + if (hermes_initialized == TRUE) { + MAP_OR_FAIL(H5_init_library); + ret_value = real_H5_init_library_(); + } + } + + return ret_value; +} + +herr_t H5_term_library() { + MAP_OR_FAIL(H5_term_library); + herr_t ret_value = real_H5_term_library_(); + + if (hermes_initialized == TRUE) { + HermesFinalize(); + hermes_initialized = FALSE; + } + + if (mpi_is_initialized) { + MPI_Finalize(); + mpi_is_initialized = FALSE; + } + + return ret_value; +} + +/** Only Initialize MPI if it hasn't already been initialized. */ +int MPI_Init(int *argc, char ***argv) { + int status = MPI_SUCCESS; + if (mpi_is_initialized == FALSE) { + int status = PMPI_Init(argc, argv); + if (status == MPI_SUCCESS) { + mpi_is_initialized = TRUE; + } + } + + return status; +} + +int MPI_Finalize() { + MAP_OR_FAIL(H5_term_library); + real_H5_term_library_(); + + if (hermes_initialized == TRUE) { + HermesFinalize(); + hermes_initialized = FALSE; + } + + int status = PMPI_Finalize(); + if (status == MPI_SUCCESS) { + mpi_is_initialized = FALSE; + } + + return status; +} diff --git a/adapter/vfd/H5FDhermes.h b/adapter/vfd/H5FDhermes.h new file mode 100644 index 000000000..fb347273a --- /dev/null +++ b/adapter/vfd/H5FDhermes.h @@ -0,0 +1,60 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Kimmy Mu + * April 2021 + * + * Purpose: The public header file for the Hermes driver. + */ +#ifndef H5FDhermes_H +#define H5FDhermes_H + +#include +#include +#include + +#define H5FD_HERMES_NAME "hermes" +#define H5FD_HERMES_VALUE ((H5FD_class_value_t)(513)) + +#define HERMES_FORWARD_DECL(func_, ret_, args_) \ + typedef ret_(*real_t_##func_##_) args_; \ + ret_(*real_##func_##_) args_ = NULL; + +#define MAP_OR_FAIL(func_) \ + if (!(real_##func_##_)) { \ + real_##func_##_ = (real_t_##func_##_)dlsym(RTLD_NEXT, #func_); \ + if (!(real_##func_##_)) { \ + fprintf(stderr, "HERMES Adapter failed to map symbol: %s\n", #func_); \ + exit(1); \ + } \ + } + +#ifdef __cplusplus +extern "C" { +#endif + +hid_t H5FD_hermes_init(); +herr_t H5Pset_fapl_hermes(hid_t fapl_id, hbool_t persistence, size_t page_size); + +HERMES_FORWARD_DECL(H5_init_library, herr_t, ()); +HERMES_FORWARD_DECL(H5_term_library, herr_t, ()); + +HERMES_FORWARD_DECL(MPI_Init, int, (int *argc, char ***argv)); +HERMES_FORWARD_DECL(MPI_Finalize, int, (void)); + +#ifdef __cplusplus +} +#endif + +#endif /* end H5FDhermes_H */ diff --git a/adapter/vfd/H5FDhermes_err.h b/adapter/vfd/H5FDhermes_err.h new file mode 100644 index 000000000..3d910b670 --- /dev/null +++ b/adapter/vfd/H5FDhermes_err.h @@ -0,0 +1,199 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of the HDF5 HERMES Virtual File Driver. The full * + * copyright notice, including terms governing use, modification, and * + * redistribution, is contained in the COPYING file, which can be found at * + * the root of the source code distribution tree. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Error handling for the HERMES VFD + */ + +#ifndef H5FDhermes_err_h +#define H5FDhermes_err_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "H5Epublic.h" + +extern hid_t H5FDhermes_err_stack_g; +extern hid_t H5FDhermes_err_class_g; + +#define H5FD_HERMES_ERR_CLS_NAME "HDF5 HERMES VFD" +#define H5FD_HERMES_ERR_LIB_NAME "HDF5 HERMES VFD" +#define H5FD_HERMES_ERR_VER "0.1.0" + +#define SUCCEED 0 +#define FAIL (-1) + +#ifndef FALSE + #define FALSE false +#endif +#ifndef TRUE + #define TRUE true +#endif + +#define H5_ATTR_UNUSED __attribute__((unused)) + +/* Error macros */ + +/* + * Macro to push the current function to the current error stack + * and then goto the "done" label, which should appear inside the + * function. (compatible with v1 and v2 errors) + */ +#define H5FD_HERMES_GOTO_ERROR(err_major, err_minor, ret_val, ...) \ + do { \ + unsigned is_v2_err; \ + union { \ + H5E_auto1_t err_func_v1; \ + H5E_auto2_t err_func_v2; \ + } err_func; \ + \ + /* Determine version of error */ \ + (void)H5Eauto_is_v2(H5E_DEFAULT, &is_v2_err); \ + \ + if (is_v2_err) { \ + (void)H5Eget_auto2(H5E_DEFAULT, &err_func.err_func_v2, NULL); \ + } else { \ + (void)H5Eget_auto1(&err_func.err_func_v1, NULL); \ + } \ + /* Check whether automatic error reporting has been disabled */ \ + if ( (is_v2_err && err_func.err_func_v2) || \ + (!is_v2_err && err_func.err_func_v1) ) { \ + if (H5FDhermes_err_stack_g >= 0 && H5FDhermes_err_class_g >= 0) { \ + H5Epush2(H5FDhermes_err_stack_g, __FILE__, __func__, __LINE__, \ + H5FDhermes_err_class_g, err_major, err_minor, __VA_ARGS__); \ + } else { \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } \ + } \ + \ + ret_value = ret_val; \ + goto done; \ + } while (0) + +/* + * Macro to push the current function to the current error stack + * without calling goto. This is used for handling the case where + * an error occurs during cleanup past the "done" label inside a + * function so that an infinite loop does not occur where goto + * continually branches back to the label. (compatible with v1 + * and v2 errors) + */ +#define H5FD_HERMES_DONE_ERROR(err_major, err_minor, ret_val, ...) \ + do { \ + unsigned is_v2_err; \ + union { \ + H5E_auto1_t err_func_v1; \ + H5E_auto2_t err_func_v2; \ + } err_func; \ + \ + /* Determine version of error */ \ + (void)H5Eauto_is_v2(H5E_DEFAULT, &is_v2_err); \ + \ + if (is_v2_err) { \ + (void)H5Eget_auto2(H5E_DEFAULT, &err_func.err_func_v2, NULL); \ + } else { \ + (void)H5Eget_auto1(&err_func.err_func_v1, NULL); \ + } \ + /* Check whether automatic error reporting has been disabled */ \ + if ( (is_v2_err && err_func.err_func_v2) || \ + (!is_v2_err && err_func.err_func_v1) ) { \ + if (H5FDhermes_err_stack_g >= 0 && H5FDhermes_err_class_g >= 0) { \ + H5Epush2(H5FDhermes_err_stack_g, __FILE__, __func__, __LINE__, \ + H5FDhermes_err_class_g, err_major, err_minor, __VA_ARGS__); \ + } else { \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } \ + } \ + \ + ret_value = ret_val; \ + } while (0) + +/* + * Macro to print out the current error stack and then clear it + * for future use. (compatible with v1 and v2 errors) + */ +#define PRINT_ERROR_STACK \ + do { \ + unsigned is_v2_err; \ + union { \ + H5E_auto1_t err_func_v1; \ + H5E_auto2_t err_func_v2; \ + } err_func; \ + \ + /* Determine version of error */ \ + (void)H5Eauto_is_v2(H5E_DEFAULT, &is_v2_err); \ + \ + if (is_v2_err) { \ + (void)H5Eget_auto2(H5E_DEFAULT, &err_func.err_func_v2, NULL); \ + } else { \ + (void)H5Eget_auto1(&err_func.err_func_v1, NULL); \ + } \ + /* Check whether automatic error reporting has been disabled */ \ + if ( (is_v2_err && err_func.err_func_v2) || \ + (!is_v2_err && err_func.err_func_v1) ) { \ + if ((H5FDhermes_err_stack_g >= 0) && \ + (H5Eget_num(H5FDhermes_err_stack_g) > 0)) { \ + H5Eprint2(H5FDhermes_err_stack_g, NULL); \ + H5Eclear2(H5FDhermes_err_stack_g); \ + } \ + } \ + } while (0) + +#define H5FD_HERMES_SYS_GOTO_ERROR(err_major, err_minor, ret_val, str) \ + do { \ + int myerrno = errno; \ + H5FD_HERMES_GOTO_ERROR(err_major, err_minor, ret_val, \ + "%s, errno = %d, error message = '%s'", str, \ + myerrno, strerror(myerrno)); \ + } while (0) + +/* + * Macro to simply jump to the "done" label inside the function, + * setting ret_value to the given value. This is often used for + * short circuiting in functions when certain conditions arise. + */ +#define H5FD_HERMES_GOTO_DONE(ret_val) \ + do { \ + ret_value = ret_val; \ + goto done; \ + } while (0) + +/* + * Macro to return from a top-level API function, printing + * out the error stack on the way out. + * It should be ensured that this macro is only called once + * per HDF5 operation. If it is called multiple times per + * operation (e.g. due to calling top-level API functions + * internally), the error stack will be inconsistent/incoherent. + */ +#define H5FD_HERMES_FUNC_LEAVE_API \ + do { \ + PRINT_ERROR_STACK; \ + return ret_value; \ + } while (0) + +/* + * Macro to return from internal functions. + */ +#define H5FD_HERMES_FUNC_LEAVE \ + do { \ + return ret_value; \ + } while (0) + +#ifdef __cplusplus +} +#endif + +#endif /* H5FDhermes_err_h */ diff --git a/adapter/vfd/README.md b/adapter/vfd/README.md new file mode 100644 index 000000000..b89c17050 --- /dev/null +++ b/adapter/vfd/README.md @@ -0,0 +1,102 @@ +# HDF5 Hermes VFD + +## 1. Description +The HDF5 Hermes VFD is a [Virtual File +Driver](https://portal.hdfgroup.org/display/HDF5/Virtual+File+Drivers) (VFD) for +HDF5 that can be used to interface with the Hermes API. The driver is built as a +plugin library that is external to HDF5. + +## 2. Dependencies +The Hermes VFD requires [HDF5](https://github.com/HDFGroup/hdf5) >= `1.13.0`, +which is the version that first introduced dynamically loadable VFDs. + +## 3. Usage +To use the HDF5 Hermes VFD in an HDF5 application, the driver can either be +linked with the application during compilation, or it can be dynamically loaded +via an environment variable. It is more convenient to load the VFD as a dynamic +plugin because it does not require code changes or recompilation. + +### Method 1: Dynamically loaded by environment variable (recommended) + +As of HDF5 `1.13.0` each file in an HDF5 app opened or created with the default +file access property list (FAPL) will use the VFD specified in the `HDF5_DRIVER` +environment variable rather than the default "sec2" (POSIX) driver. To use the +Hermes VFD, simply set + +```sh +HDF5_DRIVER=hermes +``` + +Now we must tell the HDF5 library where to find the Hermes VFD. That is done +with the following environment variable: + +```sh +HDF5_PLUGIN_PATH=/lib/hermes_vfd +``` + +The Hermes VFD has two configuration options. +1. persistence - if `true`, the HDF5 application will produce the same output + files with the Hermes VFD as it would without it. If `false`, the files are + buffered in Hermes during the application run, but are not persisted when the + application terminates. Thus, no files are produced. +2. page size - The Hermes VFD works by mapping HDF5 files into its internal data + structures. This happens in pages. The `page size` configuration option + allows the user to specify the size, in bytes, of these pages. If your app + does lots 2 MiB writes, then it's a good idea to set the page size to 2 + MiB. A smaller page size, 1 KiB for example, would convert each 2 MiB write + into 2048 1 KiB writes. However, be aware that using pages that are too large + can slow down metadata operations, which are usually less than 2 KiB. To + combat the tradeoff between small metadata pages and large raw data pages, + the Hermes VFD can be stacked underneath the [split VFD](https://docs.hdfgroup.org/hdf5/develop/group___f_a_p_l.html#ga502f1ad38f5143cf281df8282fef26ed). + + +These two configuration options are passed as a space-delimited string through +an environment variable: + +```sh +# Example of configuring the Hermes VFD with `persistent_mode=true` and +# `page_size=64KiB` +HDF5_DRIVER_CONFIG="true 65536" +``` + +Finally we need to provide a configuration file for Hermes itself, and +`LD_PRELOAD` the Hermes VFD so we can intercept HDF5 and MPI calls for proper +initialization and finalization: + +```sh +HERMES_CONF=/hermes.yaml +LD_PRELOAD=/hermes_vfd/libhdf5_hermes_vfd.so +``` + +Heres is a full example of running an HDF5 app with the Hermes VFD: + +```sh +HDF5_DRIVER=hermes \ + HDF5_PLUGIN_PATH=/hermes.yaml \ + LD_PRELOAD=/hermes_vfd/libhdf5_hermes_vfd.so \ + ./my_hdf5_app +``` + +### Method 2: Linked into application + +To link the Hermes VFD into an HDF5 application, the application should include +the `H5FDhermes.h` header and should link the installed VFD library, +`libhdf5_hermes_vfd.so`, into the application. Once this has been done, Hermes +VFD access can be set up by calling `H5Pset_fapl_hermes()` on a FAPL within the +HDF5 application. In this case, the `persistence` and `page_size` configuration +options are pass directly to this function: + +```C +herr_t H5Pset_fapl_hermes(hid_t fapl_id, hbool_t persistence, size_t page_size) +``` + +The resulting `fapl_id` should then be passed to each file open or creation for +which you wish to use the Hermes VFD. + +## 4. More Information +* [Hermes VFD performance results](https://github.com/HDFGroup/hermes/wiki/HDF5-Hermes-VFD) + +* [Hermes VFD with hdf5-iotest](https://github.com/HDFGroup/hermes/tree/master/benchmarks/HermesVFD) +* [HDF5 VFD Plugins RFC](https://github.com/HDFGroup/hdf5doc/blob/master/RFCs/HDF5_Library/VFL_DriverPlugins/RFC__A_Plugin_Interface_for_HDF5_Virtual_File_Drivers.pdf) diff --git a/benchmarks/put_get_bench.cc b/benchmarks/put_get_bench.cc index 66839df5b..f73a103d4 100644 --- a/benchmarks/put_get_bench.cc +++ b/benchmarks/put_get_bench.cc @@ -25,36 +25,40 @@ void GatherTimes(std::string test_name, Timer &t) { } void PutTest(hapi::Hermes *hermes, - int rank, int blobs_per_rank, size_t blob_size) { + int rank, int repeat, int blobs_per_rank, size_t blob_size) { Timer t; auto bkt = hermes->GetBucket("hello"); hermes::api::Context ctx; hermes::BlobId blob_id; hermes::Blob blob(blob_size); t.Resume(); - for (size_t i = 0; i < blobs_per_rank; ++i) { - size_t blob_name_int = rank * blobs_per_rank + i; - std::string name = std::to_string(blob_name_int); - bkt->Put(name, std::move(blob), blob_id, ctx); + for (int j = 0; j < repeat; ++j) { + for (size_t i = 0; i < blobs_per_rank; ++i) { + size_t blob_name_int = rank * blobs_per_rank + i; + std::string name = std::to_string(blob_name_int); + bkt->Put(name, std::move(blob), blob_id, ctx); + } } t.Pause(); GatherTimes("Put", t); } void GetTest(hapi::Hermes *hermes, - int rank, int blobs_per_rank, size_t blob_size) { + int rank, int repeat, int blobs_per_rank, size_t blob_size) { Timer t; auto bkt = hermes->GetBucket("hello"); hermes::api::Context ctx; hermes::BlobId blob_id; hermes::Blob blob(blob_size); t.Resume(); - for (size_t i = 0; i < blobs_per_rank; ++i) { - size_t blob_name_int = rank * blobs_per_rank + i; - std::string name = std::to_string(blob_name_int); - hermes::Blob ret; - bkt->GetBlobId(name, blob_id, ctx); - bkt->Get(blob_id, ret, ctx); + for (int j = 0; j < repeat; ++j) { + for (size_t i = 0; i < blobs_per_rank; ++i) { + size_t blob_name_int = rank * blobs_per_rank + i; + std::string name = std::to_string(blob_name_int); + hermes::Blob ret; + bkt->GetBlobId(name, blob_id, ctx); + bkt->Get(blob_id, ret, ctx); + } } t.Pause(); GatherTimes("Get", t); @@ -66,9 +70,12 @@ int main(int argc, char **argv) { MPI_Comm_rank(MPI_COMM_WORLD, &rank); auto hermes = hapi::Hermes::Create(hermes::HermesType::kClient); int blobs_per_rank = 1024; + size_t blob_size = KILOBYTES(64); - PutTest(hermes, rank, blobs_per_rank, blob_size); - GetTest(hermes, rank, blobs_per_rank, blob_size); + MPI_Barrier(MPI_COMM_WORLD); + PutTest(hermes, rank, 1, blobs_per_rank, blob_size); + MPI_Barrier(MPI_COMM_WORLD); + // GetTest(hermes, rank, 1, blobs_per_rank, blob_size); hermes->Finalize(); MPI_Finalize(); } \ No newline at end of file diff --git a/config/hermes_server_default.yaml b/config/hermes_server_default.yaml index 32d757a9d..b24350557 100644 --- a/config/hermes_server_default.yaml +++ b/config/hermes_server_default.yaml @@ -12,7 +12,7 @@ devices: # The maximum buffering capacity in MiB of each device. Here we say that all 4 # devices get 50 MiB of buffering capacity. - capacity: 50MB + capacity: 5000MB # The size of the smallest available buffer in KiB. In general this should be # the page size of your system for byte addressable storage, and the block size diff --git a/src/io_clients/posix.h b/src/io_clients/posix.h index 58935be8f..f10932420 100644 --- a/src/io_clients/posix.h +++ b/src/io_clients/posix.h @@ -32,7 +32,11 @@ class PosixIoClient : public IoClient { size_t off, size_t size) override { auto api = HERMES_POSIX_API; int fd = api->open((*dev_info.mount_point_).c_str(), O_RDWR); - if (fd < 0) { return false; } + if (fd < 0) { + LOG(INFO) << "Failed to open (write): " + << dev_info.mount_point_->str() << std::endl; + return false; + } size_t count = api->pwrite(fd, data, size, off); api->close(fd); return count == size; @@ -42,7 +46,11 @@ class PosixIoClient : public IoClient { size_t off, size_t size) override { auto api = HERMES_POSIX_API; int fd = api->open((*dev_info.mount_point_).c_str(), O_RDWR); - if (fd < 0) { return false; } + if (fd < 0) { + LOG(INFO) << "Failed to open (read): " + << dev_info.mount_point_->str() << std::endl; + return false; + } size_t count = api->pread(fd, data, size, off); api->close(fd); return count == size; diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index c51990d80..c8aaee1fd 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -20,12 +20,12 @@ void MetadataManager::shm_init(ServerConfig *config, header_->id_alloc_ = 1; // Create the metadata maps - blob_id_map_ = lipc::make_mptr(); - bkt_id_map_ = lipc::make_mptr(); - vbkt_id_map_ = lipc::make_mptr(); - blob_map_ = lipc::make_mptr(); - bkt_map_ = lipc::make_mptr(); - vbkt_map_ = lipc::make_mptr(); + blob_id_map_ = lipc::make_mptr(16384); + bkt_id_map_ = lipc::make_mptr(16384); + vbkt_id_map_ = lipc::make_mptr(16384); + blob_map_ = lipc::make_mptr(16384); + bkt_map_ = lipc::make_mptr(16384); + vbkt_map_ = lipc::make_mptr(16384); // Create the DeviceInfo vector devices_ = lipc::make_mptr>( diff --git a/src/prefetcher.cc b/src/prefetcher.cc new file mode 100644 index 000000000..24f274612 --- /dev/null +++ b/src/prefetcher.cc @@ -0,0 +1,225 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "prefetcher_factory.h" +#include "metadata_manager.h" +#include "singleton.h" + +using hermes::api::Hermes; + +namespace hermes { + +bool Prefetcher::LogIoStat(Hermes *hermes, IoLogEntry &entry) { + RpcContext *rpc = &hermes->rpc_; + u32 target_node = HashToNode(hermes, entry); + bool result = false; + if (target_node == rpc->node_id) { + auto prefetcher = Singleton::GetInstance(); + prefetcher->Log(entry); + result = true; + } else { + result = RpcCall(rpc, target_node, + "LogIoStat", entry); + } + return result; +} + +/** + * HashToNode + * + * Determines which node an IoLogEntry should be keyed to. + * We hash IoLogEntries to nodes using only the BucketId. + * This way, IoLogEntries regarding a particular blob are + * always placed on the same node. + * + * This approach assumes that prefetching decisions are based + * solely on the bucket's access pattern, not patterns across-buckets. + * */ + +size_t Prefetcher::HashToNode(Hermes *hermes, IoLogEntry &entry) { + CommunicationContext *comm = &hermes->comm_; + size_t hash = std::hash{}(entry.bkt_id_.as_int); + return (hash % comm->num_nodes) + 1; +} + +void Prefetcher::Log(IoLogEntry &entry) { + LOG(INFO) << "Logging I/O stat" << std::endl; + lock_.lock(); + if (log_.size() == max_length_) { + log_.pop_front(); + } + timespec_get(&entry.timestamp_, TIME_UTC); + log_.emplace_back(entry); + lock_.unlock(); +} + +float Prefetcher::EstimateBlobMovementTime(BlobId blob_id) { + Arena arena = InitArenaAndAllocate(MEGABYTES(1)); + u32 *buffer_sizes = 0; + BufferIdArray id_array = GetBufferIdsFromBlobId(&arena, + &hermes_->context_, + &hermes_->rpc_, + blob_id, + &buffer_sizes); + std::vector buffer_ids(id_array.ids, + id_array.ids + id_array.length); + DestroyArena(&arena); + std::vector buffer_info = GetBufferInfo( + &hermes_->context_, &hermes_->rpc_, buffer_ids); + + float xfer_time = 0; + for (auto &info : buffer_info) { + xfer_time += static_cast(info.size) / MEGABYTES(info.bandwidth_mbps); + /*LOG(INFO) << "size: " << info.size / MEGABYTES(1) + << " bw: " << info.bandwidth_mbps + << " current total: " << xfer_time << std::endl;*/ + } + xfer_time *= 2; // x2 because movement reads, and then writes data + return xfer_time; +} + +bool HasOnlyDemotions(PrefetchDecision &decision, float &decay) { + decay = std::numeric_limits::infinity(); + if (decision.stats_.size() == 0) return false; + for (auto &prefetch_stat : decision.stats_) { + if (prefetch_stat.decay_ < 0) { + return false; + } + decay = std::min(decay, prefetch_stat.decay_); + } + return true; +}; + +void Prefetcher::CalculateBlobScore(struct timespec &ts, + PrefetchDecision &decision) { + float est_xfer_time = decision.est_xfer_time_; + decision.new_score_ = -1; + decision.queue_later_ = false; + + float decay; + if (HasOnlyDemotions(decision, decay)) { + decision.new_score_ = GetBlobImportanceScore(&hermes_->context_, + &hermes_->rpc_, + decision.blob_id_); + decision.new_score_ *= decay; + if (decision.new_score_ < 0) { + decision.new_score_ = 0; + } + decision.decay_ = true; + return; + } + + for (auto &prefetch_stat : decision.stats_) { + if (prefetch_stat.decay_ >= 0) continue; + // Wait until the I/O for this Get seems to have completed + /*float time_left_on_io = prefetch_stat.TimeLeftOnIo( + est_xfer_time, &ts); + LOG(INFO) << "Blob id: " << decision.blob_id_.as_int + << " Time left before starting prefetch: " + << time_left_on_io << std::endl; + if (time_left_on_io > 0) { + decision.queue_later_ = true; + continue; + }*/ + float next_access_sec = prefetch_stat.TimeToNextIo(&ts); + LOG(INFO) << "Next access sec: " << next_access_sec << std::endl; + LOG(INFO) << "Est xfer time : " << est_xfer_time << std::endl; + // if (next_access_sec < est_xfer_time) continue; + float max_access_wait = std::max(max_wait_xfer_*est_xfer_time, + max_wait_sec_); + LOG(INFO) << "Max access wait: " << max_access_wait << std::endl; + float est_wait = (next_access_sec - est_xfer_time); + if (est_wait > max_access_wait) { + decision.queue_later_ = true; + continue; + } + float score = (max_access_wait - est_wait) / max_access_wait; + if (score > decision.new_score_) { + decision.new_score_ = score; + } + } +} + +void Prefetcher::Process() { + // Group log by I/O hint + lock_.lock(); + std::unordered_map> hint_logs; + for (auto &entry : log_) { + hint_logs[entry.pctx_.hint_].emplace_back(entry); + } + log_.erase(log_.begin(), log_.end()); + lock_.unlock(); + if (hint_logs.size() == 0 && queue_later_.size() == 0) { + return; + } + + // Based on the current log, determine what blobs to prefetch + PrefetchSchema schema; + for (auto &[hint, hint_log] : hint_logs) { + auto algorithm = PrefetcherFactory::Get(hint); + algorithm->Process(hint_log, schema); + } + + // Take into consideration old prefetching decisions + for (auto &[blob_id, decision] : queue_later_) { + schema.emplace(decision); + } + queue_later_.erase(queue_later_.begin(), queue_later_.end()); + + // Get the current time + struct timespec ts; + timespec_get(&ts, TIME_UTC); + + // Calculate new blob scores + for (auto &[blob_id, decision] : schema) { + if (decision.est_xfer_time_ == -1) { + decision.est_xfer_time_ = EstimateBlobMovementTime(blob_id); + } + CalculateBlobScore(ts, decision); + if (decision.new_score_ < 0) { + if (decision.queue_later_) { + queue_later_.emplace(blob_id, decision); + } + } + } + + // Process decay blobs first (make room) + for (auto &[blob_id, decision] : schema) { + if (!decision.decay_) { continue; } + LOG(INFO) << "Decaying Blob: " << blob_id.as_int + << " to score: " << decision.new_score_ << std::endl; + OrganizeBlob(&hermes_->context_, &hermes_->rpc_, + decision.bkt_id_, decision.blob_name_, + epsilon_, decision.new_score_); + } + + // TODO(llogan): a hack to help BORG shuffle data + struct timespec ts2; + while(PrefetchStat::DiffTimespec(&ts2, &ts) < 1) { + timespec_get(&ts2, TIME_UTC); + ABT_thread_yield(); + } + + // Calculate new blob scores + for (auto &[blob_id, decision] : schema) { + if (decision.decay_) { continue; } + if (decision.new_score_ < 0) { continue; } + LOG(INFO) << "Prefetching bkt_id: " << decision.bkt_id_.as_int + << " blob_id: " << decision.blob_name_ + << " score: " << decision.new_score_ << std::endl; + OrganizeBlob(&hermes_->context_, &hermes_->rpc_, + decision.bkt_id_, decision.blob_name_, + epsilon_, 1.0); + } +} + +} // namespace hermes diff --git a/src/prefetcher.h b/src/prefetcher.h new file mode 100644 index 000000000..3ea3e8512 --- /dev/null +++ b/src/prefetcher.h @@ -0,0 +1,264 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SRC_PREFETCHER_H_ +#define HERMES_SRC_PREFETCHER_H_ + +#include "hermes.h" +#include "hermes_types.h" +#include "rpc_thallium.h" +#include +#include +#include +#include +#include + +namespace hermes { + +using hermes::api::PrefetchContext; +using hermes::api::PrefetchHint; + +enum class IoType { + kNone, kPut, kGet +}; + +struct GlobalThreadID { + int rank_; + int tid_; + GlobalThreadID() : rank_(0), tid_(0) {} + explicit GlobalThreadID(int rank) : rank_(rank) { + ABT_unit_id tid_argo; + ABT_thread_self_id(&tid_argo); + tid_ = tid_argo; + } + + bool operator==(const GlobalThreadID &other) const { + return (rank_ == other.rank_ && tid_ == other.tid_); + } +}; + +struct UniqueBucket { + VBucketId vbkt_id_; + BucketId bkt_id_; + + UniqueBucket() = default; + UniqueBucket(VBucketId vbkt_id, BucketId bkt_id) : + vbkt_id_(vbkt_id), bkt_id_(bkt_id) {} + + bool operator==(const UniqueBucket &other) const { + return (vbkt_id_ == other.vbkt_id_ && + bkt_id_ == other.bkt_id_); + } +}; + +struct IoLogEntry { + VBucketId vbkt_id_; + BucketId bkt_id_; + BlobId blob_id_; + IoType type_; + off_t off_; + size_t size_; + PrefetchContext pctx_; + GlobalThreadID tid_; + bool historical_; + struct timespec timestamp_; +}; + +struct PrefetchStat { + float est_next_time_; + struct timespec start_; + float decay_; + + PrefetchStat() : est_next_time_(0), decay_(-1) {} + + explicit PrefetchStat(float est_next_time, struct timespec &start) : + est_next_time_(est_next_time), start_(start), decay_(-1) {} + + explicit PrefetchStat(float decay) : decay_(decay) {} + + float TimeLeftOnIo(float est_xfer_time, const struct timespec *cur) { + float diff = DiffTimespec(cur, &start_); + /*LOG(INFO) << "Time since I/O submitted: " << diff << std::endl; + LOG(INFO) << "Est I/O time: " << est_xfer_time << std::endl;*/ + return est_xfer_time - diff; + } + + float TimeToNextIo(const struct timespec *cur) { + float diff = DiffTimespec(cur, &start_); + return est_next_time_ - diff; + } + + static float DiffTimespec(const struct timespec *left, + const struct timespec *right) { + return (left->tv_sec - right->tv_sec) + + (left->tv_nsec - right->tv_nsec) / 1000000000.0; + } +}; + +struct PrefetchDecision { + BucketId bkt_id_; + BlobId blob_id_; + std::string blob_name_; + std::list stats_; + bool queue_later_; + float est_xfer_time_; + float new_score_; + bool decay_; + + PrefetchDecision() : queue_later_(false), + est_xfer_time_(-1), + new_score_(-1), + decay_(false) {} + void AddStat(float est_access_time, struct timespec &start) { + stats_.emplace_back(est_access_time, start); + } + void AddStat(float decay) { + stats_.emplace_back(decay); + } +}; + +class PrefetchSchema { + private: + std::unordered_map schema_; + + public: + void emplace(PrefetchDecision &decision) { + auto prior_decision_iter = schema_.find(decision.blob_id_); + if (prior_decision_iter == schema_.end()) { + schema_.emplace(decision.blob_id_, decision); + return; + } + auto &[blob_id, prior_decision] = (*prior_decision_iter); + prior_decision.est_xfer_time_ = decision.est_xfer_time_; + prior_decision.stats_.splice( + prior_decision.stats_.end(), + decision.stats_); + } + + std::unordered_map::iterator begin() { + return schema_.begin(); + } + + std::unordered_map::iterator end() { + return schema_.end(); + } +}; + +class PrefetchAlgorithm { + public: + virtual void Process(std::list &log, + PrefetchSchema &schema) = 0; +}; + +class Prefetcher { + private: + uint32_t max_length_; + thallium::mutex lock_; + std::list log_; + std::unordered_map queue_later_; + + public: + float max_wait_xfer_; + float max_wait_sec_; + float epsilon_; + + public: + std::shared_ptr hermes_; + + Prefetcher() : max_length_(4096), max_wait_xfer_(10), max_wait_sec_(60), + epsilon_(.05) {} + void SetHermes(std::shared_ptr &hermes) { hermes_ = hermes; } + void SetLogLength(uint32_t max_length) { max_length_ = max_length; } + void Log(IoLogEntry &entry); + static bool LogIoStat(api::Hermes *hermes, IoLogEntry &entry); + void Process(); + + private: + static size_t HashToNode(api::Hermes *hermes, IoLogEntry &entry); + float EstimateBlobMovementTime(BlobId blob_id); + void CalculateBlobScore(struct timespec &ts, + PrefetchDecision &decision); +}; + +/** RPC SERIALIZERS */ + +// IoType +template +void save(A &ar, IoType &hint) { + ar << static_cast(hint); +} +template +void load(A &ar, IoType &hint) { + int hint_i; + ar >> hint_i; + hint = static_cast(hint_i); +} + +// struct timespec +template +void save(A &ar, struct timespec &ts) { + ar << ts.tv_sec; + ar << ts.tv_nsec; +} +template +void load(A &ar, struct timespec &ts) { + ar >> ts.tv_sec; + ar >> ts.tv_nsec; +} + +// GlobalThreadID +template +void serialize(A &ar, GlobalThreadID &tid) { + ar & tid.rank_; + ar & tid.tid_; +} + +// IoLogEntry +template +void serialize(A &ar, IoLogEntry &entry) { + ar & entry.vbkt_id_; + ar & entry.bkt_id_; + ar & entry.blob_id_; + ar & entry.type_; + ar & entry.off_; + ar & entry.size_; + ar & entry.pctx_; + ar & entry.tid_; + // ar & entry.timestamp_; + ar & entry.historical_; +} + +} // namespace hermes + +namespace std { +template <> +struct hash { + std::size_t operator()(const hermes::GlobalThreadID &key) const { + size_t h1 = std::hash{}(key.rank_); + size_t h2 = std::hash{}(key.tid_); + size_t hash = h1^h2; + return hash; + } +}; + +template <> +struct hash { + std::size_t operator()(const hermes::UniqueBucket &key) const { + size_t h1 = std::hash{}(key.vbkt_id_); + size_t h2 = std::hash{}(key.bkt_id_); + size_t hash = h1^h2; + return hash; + } +}; +} // namespace std + +#endif // HERMES_SRC_PREFETCHER_H_ diff --git a/src/prefetcher_factory.h b/src/prefetcher_factory.h new file mode 100644 index 000000000..ecb138f2b --- /dev/null +++ b/src/prefetcher_factory.h @@ -0,0 +1,48 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SRC_PREFETCHER_FACTORY_H_ +#define HERMES_SRC_PREFETCHER_FACTORY_H_ + +#include "prefetcher.h" +#include + +#include "prefetchers/sequential.h" +#include "prefetchers/apriori.h" +#include "singleton.h" + +namespace hermes { + +class PrefetcherFactory { + public: + /** + * Return the instance of mapper given a type. Uses factory pattern. + * + * @param type, MapperType, type of mapper to be used by the STDIO adapter. + * @return Instance of mapper given a type. + */ + static PrefetchAlgorithm* Get(const PrefetchHint &type) { + switch (type) { + case PrefetchHint::kFileSequential: { + return Singleton::GetInstance(); + } + case PrefetchHint::kApriori: { + return Singleton::GetInstance(); + } + default: return nullptr; + } + } +}; + +} // namespace hermes + +#endif // HERMES_SRC_PREFETCHER_FACTORY_H_ diff --git a/src/prefetchers/apriori.cc b/src/prefetchers/apriori.cc new file mode 100644 index 000000000..88f58be94 --- /dev/null +++ b/src/prefetchers/apriori.cc @@ -0,0 +1,13 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "apriori.h" diff --git a/src/prefetchers/apriori.h b/src/prefetchers/apriori.h new file mode 100644 index 000000000..666c5d0e9 --- /dev/null +++ b/src/prefetchers/apriori.h @@ -0,0 +1,28 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SRC_PREFETCHERS_APRIORI_H_ +#define HERMES_SRC_PREFETCHERS_APRIORI_H_ + +#include "prefetcher.h" + +namespace hermes { + +class AprioriPrefetcher : public PrefetchAlgorithm { + public: + void Process(std::list &log, + PrefetchSchema &schema) {} +}; + +} // namespace hermes + +#endif // HERMES_SRC_PREFETCHERS_APRIORI_H_ diff --git a/src/prefetchers/sequential.cc b/src/prefetchers/sequential.cc new file mode 100644 index 000000000..a2ba1b736 --- /dev/null +++ b/src/prefetchers/sequential.cc @@ -0,0 +1,145 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "sequential.h" +#include "singleton.h" +#include "api/bucket.h" +#include + +using hermes::adapter::BlobPlacement; + +namespace hermes { + +void SequentialPrefetcher::Process(std::list &log, + PrefetchSchema &schema) { + auto prefetcher = Singleton::GetInstance(); + + // Increase each unique_bucket access count + for (auto &entry : log) { + UniqueBucket id(entry.vbkt_id_, entry.bkt_id_); + auto &state = state_[id]; + if (state.count_ == 0) { + state.first_access_ = entry.timestamp_; + } + ++state.count_; + } + + // Append time estimates and read-aheads to the schema + for (auto &entry : log) { + UniqueBucket id(entry.vbkt_id_, entry.bkt_id_); + auto &state = state_[id]; + float cur_runtime = PrefetchStat::DiffTimespec(&entry.timestamp_, + &state.first_access_); + float avg_time = cur_runtime / state.count_; + if (avg_time == 0) { + avg_time = prefetcher->max_wait_sec_ / 2.0; + } + LOG(INFO) << "Avg time: " << avg_time << std::endl; + + // Read-ahead the next few blobs + BlobId cur_id = entry.blob_id_; + for (int i = 0; i < entry.pctx_.read_ahead_; ++i) { + PrefetchDecision decision; + decision.bkt_id_ = entry.bkt_id_; + if (IsNullVBucketId(entry.vbkt_id_)) { + GetNextFromBucket(entry, decision, cur_id); + } else { + GetNextFromVbucket(entry, decision, cur_id); + } + if (IsNullBlobId(decision.blob_id_)) { + break; + } + decision.AddStat((i+1)*avg_time, entry.timestamp_); + schema.emplace(decision); + cur_id = decision.blob_id_; + } + + // Demote the previous blobs + cur_id = entry.blob_id_; + for (int i = 0; i < entry.pctx_.read_ahead_; ++i) { + PrefetchDecision decision; + if (IsNullVBucketId(entry.vbkt_id_)) { + GetPriorFromBucket(entry, decision, cur_id); + } else { + GetPriorFromVbucket(entry, decision, cur_id); + } + if (IsNullBlobId(decision.blob_id_)) { + break; + } + decision.AddStat(entry.pctx_.decay_); + schema.emplace(decision); + cur_id = decision.blob_id_; + } + } +} + +void SequentialPrefetcher::GetNextFromBucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobId &cur_id) { + // Get current blob name + auto prefetcher = Singleton::GetInstance(); + auto hermes = prefetcher->hermes_; + std::string blob_name = GetBlobNameFromId(&hermes->context_, + &hermes->rpc_, + cur_id); + + // Get next blob name + BlobPlacement p; + p.DecodeBlobName(blob_name); + p.page_ += 1; + decision.blob_name_ = p.CreateBlobName(); + + // Get the next blob ID from the bucket + decision.blob_id_ = GetBlobId(&hermes->context_, &hermes->rpc_, + decision.blob_name_, entry.bkt_id_, + false); +} + +void SequentialPrefetcher::GetNextFromVbucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobId &cur_id) { + // TODO(llogan): Not implemented for now. +} + +void SequentialPrefetcher::GetPriorFromBucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobId &cur_id) { + // Get current blob name + auto prefetcher = Singleton::GetInstance(); + auto hermes = prefetcher->hermes_; + std::string blob_name = GetBlobNameFromId(&hermes->context_, + &hermes->rpc_, + cur_id); + + // Get prior blob name + BlobPlacement p; + p.DecodeBlobName(blob_name); + if (p.page_ == 0) { + cur_id.as_int = 0; + return; + } + p.page_ -= 1; + decision.blob_name_ = p.CreateBlobName(); + + // Get the prior blob ID from the bucket + decision.blob_id_ = GetBlobId(&hermes->context_, &hermes->rpc_, + decision.blob_name_, entry.bkt_id_, + false); +} + +void SequentialPrefetcher::GetPriorFromVbucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobId &cur_id) { + // TODO(llogan): Not implemented for now. +} + +} // namespace hermes diff --git a/src/prefetchers/sequential.h b/src/prefetchers/sequential.h new file mode 100644 index 000000000..04405d3b8 --- /dev/null +++ b/src/prefetchers/sequential.h @@ -0,0 +1,52 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ +#define HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ + +#include "prefetcher.h" + +namespace hermes { + +struct SequentialState { + struct timespec first_access_; + u32 count_; + + SequentialState() : count_(0) {} +}; + +class SequentialPrefetcher : public PrefetchAlgorithm { + private: + std::unordered_map state_; + + public: + void Process(std::list &log, + PrefetchSchema &schema); + + private: + void GetNextFromBucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobId &cur_id); + void GetNextFromVbucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobId &cur_id); + void GetPriorFromBucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobId &cur_id); + void GetPriorFromVbucket(IoLogEntry &entry, + PrefetchDecision &decision, + BlobId &cur_id); +}; + +} // namespace hermes + +#endif // HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ diff --git a/test/test_vbucket.cc b/test/test_vbucket.cc index b6b25136f..8e86a0a9f 100644 --- a/test/test_vbucket.cc +++ b/test/test_vbucket.cc @@ -34,6 +34,7 @@ void TestVBucketCreateDestroy(hapi::Hermes *hermes) { vbkt->Link(blob_id, ctx); } + TEST_CASE("TestVBucketCreate") { TestVBucketCreateDestroy(HERMES); } \ No newline at end of file From 6b0c7a1378bb5b0dd4afe5019193e79a3b268a41 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 23 Jan 2023 03:54:28 -0600 Subject: [PATCH 087/511] Copy from hermes_old --- adapter/filesystem/filesystem.cc | 8 +- adapter/filesystem/metadata_manager.cc | 57 + adapter/filesystem/metadata_manager.h | 98 ++ adapter/filesystem/singleton.cc | 4 + adapter/filesystem/singleton_macros.h | 9 + adapter/mpiio/CMakeLists.txt | 49 + adapter/mpiio/fs_api.cc | 622 +++++++ adapter/mpiio/fs_api.h | 241 +++ adapter/mpiio/mpiio.cc | 462 ++++++ adapter/mpiio/real_api.h | 301 ++++ adapter/posix/posix.cc | 64 +- adapter/pubsub/CMakeLists.txt | 33 + adapter/pubsub/datastructures.h | 58 + adapter/pubsub/metadata_manager.cc | 60 + adapter/pubsub/metadata_manager.h | 136 ++ adapter/pubsub/pubsub.cc | 177 ++ adapter/pubsub/pubsub.h | 129 ++ adapter/test/CMakeLists.txt | 75 + adapter/test/adapter_test_utils.h | 60 + adapter/test/catch_config.h | 42 + adapter/test/data/hermes.yaml | 45 + adapter/test/data/hermes_ares.yaml | 47 + adapter/test/data/hermes_small.yaml | 46 + adapter/test/mpiio/CMakeLists.txt | 46 + .../test/mpiio/mpiio_adapter_basic_test.cpp | 1044 ++++++++++++ adapter/test/mpiio/mpiio_adapter_test.cpp | 673 ++++++++ adapter/test/mpiio/parallel.cc | 46 + adapter/test/posix/CMakeLists.txt | 73 + .../test/posix/posix_adapter_basic_test.cpp | 1478 +++++++++++++++++ adapter/test/posix/posix_adapter_mpi_test.cpp | 401 +++++ adapter/test/posix/posix_adapter_rs_test.cpp | 1239 ++++++++++++++ .../test/posix/posix_adapter_shared_test.cpp | 78 + adapter/test/posix/posix_adapter_test.cpp | 286 ++++ adapter/test/posix/simple_io.cc | 106 ++ adapter/test/pubsub/CMakeLists.txt | 49 + adapter/test/pubsub/pubsub_end_to_end_test.cc | 64 + .../pubsub/pubsub_end_to_end_test_sync.cc | 68 + adapter/test/pubsub/pubsub_metadata_test.cc | 52 + adapter/test/pubsub/pubsub_topic_test.cc | 41 + adapter/test/pubsub/test_utils.h | 31 + adapter/test/run_hermes.sh | 52 + adapter/test/stdio/CMakeLists.txt | 111 ++ adapter/test/stdio/adapter_utils_test.cc | 104 ++ .../test/stdio/stdio_adapter_basic_test.cpp | 1308 +++++++++++++++ .../test/stdio/stdio_adapter_func_test.cpp | 771 +++++++++ .../stdio_adapter_low_buffer_space_test.cpp | 285 ++++ .../test/stdio/stdio_adapter_mapper_test.cpp | 195 +++ .../test/stdio/stdio_adapter_mode_test.cpp | 340 ++++ adapter/test/stdio/stdio_adapter_mpi_test.cpp | 348 ++++ adapter/test/stdio/stdio_adapter_rs_test.cpp | 1247 ++++++++++++++ .../test/stdio/stdio_adapter_shared_test.cpp | 35 + adapter/test/stdio/stdio_adapter_test.cpp | 256 +++ adapter/test/vfd/CMakeLists.txt | 68 + adapter/test/vfd/hermes_vfd_basic_test.cc | 718 ++++++++ adapter/test/vfd/hermes_vfd_test.cc | 585 +++++++ adapter/utils.h | 8 + 56 files changed, 14993 insertions(+), 36 deletions(-) create mode 100644 adapter/filesystem/metadata_manager.cc create mode 100644 adapter/filesystem/metadata_manager.h create mode 100644 adapter/filesystem/singleton.cc create mode 100644 adapter/filesystem/singleton_macros.h create mode 100644 adapter/mpiio/CMakeLists.txt create mode 100644 adapter/mpiio/fs_api.cc create mode 100644 adapter/mpiio/fs_api.h create mode 100644 adapter/mpiio/mpiio.cc create mode 100644 adapter/mpiio/real_api.h create mode 100644 adapter/pubsub/CMakeLists.txt create mode 100644 adapter/pubsub/datastructures.h create mode 100644 adapter/pubsub/metadata_manager.cc create mode 100644 adapter/pubsub/metadata_manager.h create mode 100644 adapter/pubsub/pubsub.cc create mode 100644 adapter/pubsub/pubsub.h create mode 100644 adapter/test/CMakeLists.txt create mode 100644 adapter/test/adapter_test_utils.h create mode 100644 adapter/test/catch_config.h create mode 100644 adapter/test/data/hermes.yaml create mode 100644 adapter/test/data/hermes_ares.yaml create mode 100644 adapter/test/data/hermes_small.yaml create mode 100644 adapter/test/mpiio/CMakeLists.txt create mode 100644 adapter/test/mpiio/mpiio_adapter_basic_test.cpp create mode 100644 adapter/test/mpiio/mpiio_adapter_test.cpp create mode 100644 adapter/test/mpiio/parallel.cc create mode 100644 adapter/test/posix/CMakeLists.txt create mode 100644 adapter/test/posix/posix_adapter_basic_test.cpp create mode 100644 adapter/test/posix/posix_adapter_mpi_test.cpp create mode 100644 adapter/test/posix/posix_adapter_rs_test.cpp create mode 100644 adapter/test/posix/posix_adapter_shared_test.cpp create mode 100644 adapter/test/posix/posix_adapter_test.cpp create mode 100644 adapter/test/posix/simple_io.cc create mode 100644 adapter/test/pubsub/CMakeLists.txt create mode 100644 adapter/test/pubsub/pubsub_end_to_end_test.cc create mode 100644 adapter/test/pubsub/pubsub_end_to_end_test_sync.cc create mode 100644 adapter/test/pubsub/pubsub_metadata_test.cc create mode 100644 adapter/test/pubsub/pubsub_topic_test.cc create mode 100644 adapter/test/pubsub/test_utils.h create mode 100644 adapter/test/run_hermes.sh create mode 100644 adapter/test/stdio/CMakeLists.txt create mode 100644 adapter/test/stdio/adapter_utils_test.cc create mode 100644 adapter/test/stdio/stdio_adapter_basic_test.cpp create mode 100644 adapter/test/stdio/stdio_adapter_func_test.cpp create mode 100644 adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp create mode 100644 adapter/test/stdio/stdio_adapter_mapper_test.cpp create mode 100644 adapter/test/stdio/stdio_adapter_mode_test.cpp create mode 100644 adapter/test/stdio/stdio_adapter_mpi_test.cpp create mode 100644 adapter/test/stdio/stdio_adapter_rs_test.cpp create mode 100644 adapter/test/stdio/stdio_adapter_shared_test.cpp create mode 100644 adapter/test/stdio/stdio_adapter_test.cpp create mode 100644 adapter/test/vfd/CMakeLists.txt create mode 100644 adapter/test/vfd/hermes_vfd_basic_test.cc create mode 100644 adapter/test/vfd/hermes_vfd_test.cc diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index eee3ff841..da12d1f60 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -96,8 +96,8 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, } HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, - size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { + size_t off, size_t total_size, size_t req_id, + IoStatus &io_status, IoOptions opts) { (void) io_status; LOG(INFO) << "Starting an asynchronous write" << std::endl; auto pool = @@ -117,8 +117,8 @@ HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, } HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, - size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { + size_t off, size_t total_size, size_t req_id, + IoStatus &io_status, IoOptions opts) { (void) io_status; auto pool = Singleton::GetInstance(kNumThreads); diff --git a/adapter/filesystem/metadata_manager.cc b/adapter/filesystem/metadata_manager.cc new file mode 100644 index 000000000..9c151ccc0 --- /dev/null +++ b/adapter/filesystem/metadata_manager.cc @@ -0,0 +1,57 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "metadata_manager.h" + +/** + * Namespace declarations for cleaner code. + */ +using hermes::adapter::fs::AdapterStat; +using hermes::adapter::fs::MetadataManager; + +bool MetadataManager::Create(const File &f, const AdapterStat &stat) { + VLOG(1) << "Create metadata for file handler." << std::endl; + auto ret = metadata.emplace(f, stat); + return ret.second; +} + +bool MetadataManager::Update(const File &f, const AdapterStat &stat) { + VLOG(1) << "Update metadata for file handler." << std::endl; + auto iter = metadata.find(f); + if (iter != metadata.end()) { + metadata.erase(iter); + auto ret = metadata.emplace(f, stat); + return ret.second; + } else { + return false; + } +} + +std::pair MetadataManager::Find(const File &f) { + typedef std::pair MetadataReturn; + auto iter = metadata.find(f); + if (iter == metadata.end()) + return MetadataReturn(AdapterStat(), false); + else + return MetadataReturn(iter->second, true); +} + +bool MetadataManager::Delete(const File &f) { + VLOG(1) << "Delete metadata for file handler." << std::endl; + auto iter = metadata.find(f); + if (iter != metadata.end()) { + metadata.erase(iter); + return true; + } else { + return false; + } +} diff --git a/adapter/filesystem/metadata_manager.h b/adapter/filesystem/metadata_manager.h new file mode 100644 index 000000000..af506bae2 --- /dev/null +++ b/adapter/filesystem/metadata_manager.h @@ -0,0 +1,98 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_ADAPTER_METADATA_MANAGER_H +#define HERMES_ADAPTER_METADATA_MANAGER_H + +#include +#include + +#include +#include + +#include "constants.h" +#include "filesystem.h" + +namespace hermes::adapter::fs { +/** + * Metadata manager for POSIX adapter + */ +class MetadataManager { + private: + std::unordered_map metadata; /**< Map for metadata*/ + int hermes_fd_min_, hermes_fd_max_; /**< Min and max fd values (inclusive)*/ + std::atomic hermes_fd_cur_; /**< Current fd */ + bool is_init_; /**< Whether hermes is initialized yet */ + std::mutex lock_; /**< Lock for init and metadata */ + + public: + /** map for Hermes request */ + std::unordered_map request_map; + + /** Constructor */ + MetadataManager() + : metadata(), is_init_(false) {} + + /** Initialize Hermes (thread-safe) */ + void InitializeHermes() { + if (!is_init_) { + lock_.lock(); + if (!is_init_) { + HERMES->Init(HermesType::kClient); + is_init_ = true; + } + lock_.unlock(); + } + + // TODO(llogan): Recycle old fds + hermes_fd_min_ = 8192; // TODO(llogan): don't assume 8192 + hermes_fd_max_ = INT_MAX; + } + + /** + * Create a metadata entry for POSIX adapter for a given file handler. + * @param f original file handler of the file on the destination + * filesystem. + * @param stat POSIX Adapter version of Stat data structure. + * @return true, if operation was successful. + * false, if operation was unsuccessful. + */ + bool Create(const File& f, const AdapterStat& stat); + + /** + * Update existing metadata entry for POSIX adapter for a given file handler. + * @param f original file handler of the file on the destination. + * @param stat POSIX Adapter version of Stat data structure. + * @return true, if operation was successful. + * false, if operation was unsuccessful or entry doesn't exist. + */ + bool Update(const File& f, const AdapterStat& stat); + + /** + * Delete existing metadata entry for POSIX adapter for a given file handler. + * @param f original file handler of the file on the destination. + * @return true, if operation was successful. + * false, if operation was unsuccessful. + */ + bool Delete(const File& f); + + /** + * Find existing metadata entry for POSIX adapter for a given file handler. + * @param f original file handler of the file on the destination. + * @return The metadata entry if exist. + * The bool in pair indicated whether metadata entry exists. + */ + std::pair Find(const File& f); +}; +} // namespace hermes::adapter::fs + +#endif // HERMES_ADAPTER_METADATA_MANAGER_H diff --git a/adapter/filesystem/singleton.cc b/adapter/filesystem/singleton.cc new file mode 100644 index 000000000..b12c6bf23 --- /dev/null +++ b/adapter/filesystem/singleton.cc @@ -0,0 +1,4 @@ +#include "singleton.h" + +#include "filesystem.h" +template<> std::unique_ptr hermes::Singleton::obj_ = nullptr; diff --git a/adapter/filesystem/singleton_macros.h b/adapter/filesystem/singleton_macros.h new file mode 100644 index 000000000..e868fdaa1 --- /dev/null +++ b/adapter/filesystem/singleton_macros.h @@ -0,0 +1,9 @@ +#ifndef HERMES_SINGLETON_ADAPTER_MACROS_H +#define HERMES_SINGLETON_ADAPTER_MACROS_H + +#include "singleton.h" + +#define HERMES_FS_METADATA_MANAGER hermes::Singleton::GetInstance() +#define HERMES_FS_METADATA_MANAGER_T hermes::adapter::posix::fs::MetadataManager* + +#endif // HERMES_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/mpiio/CMakeLists.txt b/adapter/mpiio/CMakeLists.txt new file mode 100644 index 000000000..556d95567 --- /dev/null +++ b/adapter/mpiio/CMakeLists.txt @@ -0,0 +1,49 @@ +project(MPIIOAdapter VERSION ${HERMES_PACKAGE_VERSION}) +include_directories(${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +# MPIIO src code. We only include mpiio.cc as it includes other cc to reduce compilation time. +set(MPIIO_ADAPTER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/mpiio.cc) + +set(HERMES_MPIIO_ADAPTER_DIR ${HERMES_ADAPTER_DIR}/mpiio) + +# Public headers +set(MPIIO_ADAPTER_PUBLIC_HEADER + ${HERMES_MPIIO_ADAPTER_DIR}/real_api.h + ${HERMES_MPIIO_ADAPTER_DIR}/fs_api.h) + +# Add library hermes_mpiio +add_library(hermes_mpiio_backend ${CMAKE_CURRENT_SOURCE_DIR}/fs_api.cc) +add_dependencies(hermes_mpiio_backend hermes) +target_link_libraries(hermes_mpiio_backend hermes MPI::MPI_CXX glog::glog stdc++fs) + +add_library(hermes_mpiio SHARED ${MPIIO_ADAPTER_PUBLIC_HEADER} ${MPIIO_ADAPTER_SRC}) +add_dependencies(hermes_mpiio hermes_mpiio_backend) +target_link_libraries(hermes_mpiio hermes_mpiio_backend) + +#----------------------------------------------------------------------------- +# Add Target(s) to CMake Install +#----------------------------------------------------------------------------- +install( + TARGETS + hermes_mpiio_backend + EXPORT + ${HERMES_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} +) +install( + TARGETS + hermes_mpiio + EXPORT + ${HERMES_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} +) +#----------------------------------------------------------------------------- +# Add Target(s) to Coverage +#----------------------------------------------------------------------------- +if(HERMES_ENABLE_COVERAGE) + set_coverage_flags(hermes_mpiio) +endif() diff --git a/adapter/mpiio/fs_api.cc b/adapter/mpiio/fs_api.cc new file mode 100644 index 000000000..aff31e030 --- /dev/null +++ b/adapter/mpiio/fs_api.cc @@ -0,0 +1,622 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "fs_api.h" + +namespace hermes::adapter::mpiio { + +size_t IoSizeFromCount(int count, MPI_Datatype datatype, IoOptions &opts) { + int datatype_size; + opts.mpi_type_ = datatype; + opts.count_ = count; + MPI_Type_size(datatype, &datatype_size); + return static_cast(count * datatype_size); +} + +int MpiioFS::Read(File &f, AdapterStat &stat, + void *ptr, size_t offset, + int count, MPI_Datatype datatype, + MPI_Status *status, IoOptions opts) { + opts.mpi_type_ = datatype; + if (offset + count >= static_cast(stat.st_size)) { + status->count_hi_and_cancelled = 0; + status->count_lo = 0; + return 0; + } + IoStatus io_status; + io_status.mpi_status_ptr_ = status; + size_t total_size = IoSizeFromCount(count, datatype, opts); + Filesystem::Read(f, stat, ptr, offset, + total_size, io_status, opts); + return io_status.mpi_ret_; +} + +int MpiioFS::ARead(File &f, AdapterStat &stat, + void *ptr, size_t offset, + int count, MPI_Datatype datatype, + MPI_Request *request, IoOptions opts) { + opts.mpi_type_ = datatype; + IoStatus io_status; + size_t total_size = IoSizeFromCount(count, datatype, opts); + Filesystem::ARead(f, stat, ptr, offset, total_size, + reinterpret_cast(request), + io_status, opts); + return io_status.mpi_ret_; +} + +int MpiioFS::ReadAll(File &f, AdapterStat &stat, + void *ptr, size_t offset, + int count, MPI_Datatype datatype, + MPI_Status *status, IoOptions opts) { + opts.mpi_type_ = datatype; + MPI_Barrier(stat.comm); + size_t ret = Read(f, stat, ptr, offset, count, datatype, status, opts); + MPI_Barrier(stat.comm); + return ret; +} + +int MpiioFS::ReadOrdered(File &f, AdapterStat &stat, + void *ptr, int count, + MPI_Datatype datatype, + MPI_Status *status, IoOptions opts) { + opts.mpi_type_ = datatype; + + int total; + MPI_Scan(&count, &total, 1, MPI_INT, MPI_SUM, stat.comm); + MPI_Offset my_offset = total - count; + size_t ret = ReadAll(f, stat, ptr, my_offset, count, datatype, status, opts); + return ret; +} + +int MpiioFS::Write(File &f, AdapterStat &stat, + const void *ptr, size_t offset, + int count, MPI_Datatype datatype, + MPI_Status *status, IoOptions opts) { + opts.mpi_type_ = datatype; + IoStatus io_status; + io_status.mpi_status_ptr_ = status; + size_t total_size = IoSizeFromCount(count, datatype, opts); + Filesystem::Write(f, stat, ptr, offset, total_size, + io_status, opts); + return io_status.mpi_ret_; +} + +int MpiioFS::AWrite(File &f, AdapterStat &stat, + const void *ptr, size_t offset, + int count, MPI_Datatype datatype, + MPI_Request *request, IoOptions opts) { + opts.mpi_type_ = datatype; + IoStatus io_status; + size_t total_size = IoSizeFromCount(count, datatype, opts); + Filesystem::AWrite(f, stat, ptr, offset, total_size, + reinterpret_cast(request), + io_status, opts); + return io_status.mpi_ret_; +} + +int MpiioFS::WriteAll(File &f, AdapterStat &stat, + const void *ptr, size_t offset, + int count, MPI_Datatype datatype, + MPI_Status *status, IoOptions opts) { + opts.mpi_type_ = datatype; + MPI_Barrier(stat.comm); + int ret = Write(f, stat, ptr, offset, count, datatype, status, opts); + MPI_Barrier(stat.comm); + return ret; +} + +int MpiioFS::WriteOrdered(File &f, AdapterStat &stat, + const void *ptr, int count, + MPI_Datatype datatype, + MPI_Status *status, IoOptions opts) { + opts.mpi_type_ = datatype; + int total; + MPI_Scan(&count, &total, 1, MPI_INT, MPI_SUM, stat.comm); + MPI_Offset my_offset = total - count; + size_t ret = WriteAll(f, stat, ptr, my_offset, count, datatype, status, opts); + return ret; +} + +int MpiioFS::AWriteOrdered(File &f, AdapterStat &stat, + const void *ptr, int count, + MPI_Datatype datatype, + MPI_Request *request, IoOptions opts) { + LOG(INFO) << "Starting an asynchronous write" << std::endl; + auto pool = + Singleton::GetInstance(); + HermesRequest *hreq = new HermesRequest(); + auto lambda = + [](MpiioFS *fs, File &f, AdapterStat &stat, + const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status, + IoOptions opts) { + int ret = fs->WriteOrdered(f, stat, ptr, + count, datatype, status, opts); + return static_cast(ret); + }; + auto func = std::bind(lambda, this, f, stat, ptr, + count, datatype, &hreq->io_status.mpi_status_, + opts); + hreq->return_future = pool->run(func); + auto mdm = Singleton::GetInstance(); + mdm->request_map.emplace(reinterpret_cast(request), hreq); + return MPI_SUCCESS; +} + +int MpiioFS::Wait(MPI_Request *req, MPI_Status *status) { + auto mdm = Singleton::GetInstance(); + auto iter = mdm->request_map.find(reinterpret_cast(req)); + if (iter != mdm->request_map.end()) { + hermes::adapter::fs::HermesRequest *hreq = iter->second; + hreq->return_future.get(); + memcpy(status, + hreq->io_status.mpi_status_ptr_, + sizeof(MPI_Status)); + mdm->request_map.erase(iter); + delete (hreq); + return MPI_SUCCESS; + } + return real_api->MPI_Wait(req, status); +} + +int MpiioFS::WaitAll(int count, MPI_Request *req, MPI_Status *status) { + int ret = 0; + for (int i = 0; i < count; i++) { + auto sub_ret = Wait(&req[i], &status[i]); + if (sub_ret != MPI_SUCCESS) { + ret = sub_ret; + } + } + return ret; +} + +int MpiioFS::Seek(File &f, AdapterStat &stat, + MPI_Offset offset, int whence) { + Filesystem::Seek(f, stat, + MpiioSeekModeConv::Normalize(whence), + offset); + return MPI_SUCCESS; +} + +int MpiioFS::SeekShared(File &f, AdapterStat &stat, + MPI_Offset offset, int whence) { + MPI_Offset sum_offset; + int sum_whence; + int comm_participators; + MPI_Comm_size(stat.comm, &comm_participators); + MPI_Allreduce(&offset, &sum_offset, 1, MPI_LONG_LONG_INT, MPI_SUM, + stat.comm); + MPI_Allreduce(&whence, &sum_whence, 1, MPI_INT, MPI_SUM, + stat.comm); + if (sum_offset / comm_participators != offset) { + LOG(ERROR) + << "Same offset should be passed across the opened file communicator." + << std::endl; + } + if (sum_whence / comm_participators != whence) { + LOG(ERROR) + << "Same whence should be passed across the opened file communicator." + << std::endl; + } + Seek(f, stat, offset, whence); + return 0; +} + +/** + * Variants which internally find the correct offset +* */ + +int MpiioFS::Read(File &f, AdapterStat &stat, + void *ptr, int count, MPI_Datatype datatype, + MPI_Status *status) { + IoOptions opts = IoOptions::DataType(datatype, true); + return Read(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); +} + +int MpiioFS::ARead(File &f, AdapterStat &stat, + void *ptr, int count, MPI_Datatype datatype, MPI_Request *request) { + IoOptions opts = IoOptions::DataType(datatype, true); + return ARead(f, stat, ptr, Tell(f, stat), count, datatype, request, opts); +} + +int MpiioFS::ReadAll(File &f, AdapterStat &stat, + void *ptr, int count, MPI_Datatype datatype, + MPI_Status *status) { + IoOptions opts = IoOptions::DataType(datatype, true); + return ReadAll(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); +} + +int MpiioFS::Write(File &f, AdapterStat &stat, + const void *ptr, int count, MPI_Datatype datatype, + MPI_Status *status) { + IoOptions opts = IoOptions::DataType(datatype, true); + return Write(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); +} + +int MpiioFS::AWrite(File &f, AdapterStat &stat, + const void *ptr, int count, MPI_Datatype datatype, + MPI_Request *request) { + IoOptions opts = IoOptions::DataType(datatype, true); + return AWrite(f, stat, ptr, Tell(f, stat), count, datatype, request, opts); +} + +int MpiioFS::WriteAll(File &f, AdapterStat &stat, + const void *ptr, int count, MPI_Datatype datatype, + MPI_Status *status) { + IoOptions opts = IoOptions::DataType(datatype, true); + return WriteAll(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); +} + + +/** + * Variants which retrieve the stat data structure internally + * */ + +int MpiioFS::Read(File &f, bool &stat_exists, + void *ptr, size_t offset, + int count, MPI_Datatype datatype, + MPI_Status *status) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + IoOptions opts = IoOptions::DataType(datatype, false); + return Read(f, stat, ptr, offset, count, datatype, status, opts); +} + +int MpiioFS::ARead(File &f, bool &stat_exists, + void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Request *request) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + IoOptions opts = IoOptions::DataType(datatype, false); + return ARead(f, stat, ptr, offset, count, datatype, request, opts); +} + +int MpiioFS::ReadAll(File &f, bool &stat_exists, + void *ptr, size_t offset, + int count, MPI_Datatype datatype, + MPI_Status *status) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + IoOptions opts = IoOptions::DataType(datatype, false); + return ReadAll(f, stat, ptr, offset, count, datatype, status, opts); +} + +int MpiioFS::ReadOrdered(File &f, bool &stat_exists, + void *ptr, int count, + MPI_Datatype datatype, + MPI_Status *status) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + IoOptions opts = IoOptions::DataType(datatype, false); + return ReadOrdered(f, stat, ptr, count, datatype, status, opts); +} + +int MpiioFS::Write(File &f, bool &stat_exists, + const void *ptr, size_t offset, + int count, MPI_Datatype datatype, + MPI_Status *status) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + IoOptions opts = IoOptions::DataType(datatype, false); + return Write(f, stat, ptr, offset, count, datatype, status, opts); +} + +int MpiioFS::AWrite(File &f, bool &stat_exists, + const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Request *request) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + IoOptions opts = IoOptions::DataType(datatype, false); + return AWrite(f, stat, ptr, offset, count, datatype, request, opts); +} + +int MpiioFS::WriteAll(File &f, bool &stat_exists, + const void *ptr, size_t offset, + int count, MPI_Datatype datatype, + MPI_Status *status) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + IoOptions opts = IoOptions::DataType(datatype, false); + return WriteAll(f, stat, ptr, offset, count, datatype, status, opts); +} + +int MpiioFS::WriteOrdered(File &f, bool &stat_exists, + const void *ptr, int count, + MPI_Datatype datatype, + MPI_Status *status) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + IoOptions opts = IoOptions::DataType(datatype, false); + return WriteOrdered(f, stat, ptr, count, datatype, status, opts); +} + +int MpiioFS::AWriteOrdered(File &f, bool &stat_exists, + const void *ptr, int count, + MPI_Datatype datatype, + MPI_Request *request) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + IoOptions opts = IoOptions::DataType(datatype, false); + return AWriteOrdered(f, stat, ptr, count, datatype, request, opts); +} + +int MpiioFS::Read(File &f, bool &stat_exists, + void *ptr, int count, MPI_Datatype datatype, + MPI_Status *status) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Read(f, stat, ptr, count, datatype, status); +} + +int MpiioFS::ARead(File &f, bool &stat_exists, + void *ptr, int count, MPI_Datatype datatype, + MPI_Request *request) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return ARead(f, stat, ptr, count, datatype, request); +} + +int MpiioFS::ReadAll(File &f, bool &stat_exists, + void *ptr, int count, MPI_Datatype datatype, + MPI_Status *status) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return ReadAll(f, stat, ptr, count, datatype, status); +} + +int MpiioFS::Write(File &f, bool &stat_exists, + const void *ptr, int count, MPI_Datatype datatype, + MPI_Status *status) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Write(f, stat, ptr, count, datatype, status); +} + +int MpiioFS::AWrite(File &f, bool &stat_exists, + const void *ptr, int count, MPI_Datatype datatype, + MPI_Request *request) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return AWrite(f, stat, ptr, count, datatype, request); +} + +int MpiioFS::WriteAll(File &f, bool &stat_exists, + const void *ptr, int count, MPI_Datatype datatype, + MPI_Status *status) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return WriteAll(f, stat, ptr, count, datatype, status); +} + +int MpiioFS::Seek(File &f, bool &stat_exists, + MPI_Offset offset, int whence) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Seek(f, stat, offset, whence); +} + +int MpiioFS::SeekShared(File &f, bool &stat_exists, + MPI_Offset offset, int whence) { + auto mdm = Singleton::GetInstance(); + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return SeekShared(f, stat, offset, whence); +} + +/** + * Internal overrides + * */ + +File MpiioFS::_RealOpen(AdapterStat &stat, const std::string &path) { + File f; + f.mpi_status_ = real_api->MPI_File_open(stat.comm, path.c_str(), stat.amode, + stat.info, &f.mpi_fh_); + if (f.mpi_status_ != MPI_SUCCESS) { + f.status_ = false; + } + // NOTE(llogan): MPI_Info_get does not behave well, so removing + /* + MPI_Info info; + MPI_File_get_info(f.mpi_fh_, &info); + MPI_Info_set(info, "path", path.c_str()); + MPI_File_set_info(f.mpi_fh_, info);*/ + return f; +} + +void MpiioFS::_InitFile(File &f) { + // NOTE(llogan): MPI_Info_get does not behave well, so removing + (void) f; + /*struct stat st; + std::string filename = GetFilenameFromFP(&f.mpi_fh_); + int fd = posix_api->open(filename.c_str(), O_RDONLY); + posix_api->__fxstat(_STAT_VER, fd, &st); + f.st_dev = st.st_dev; + f.st_ino = st.st_ino; + posix_api->close(fd);*/ +} + +void MpiioFS::_OpenInitStats(File &f, AdapterStat &stat) { + MPI_Offset size = static_cast(stat.st_size); + MPI_File_get_size(f.mpi_fh_, &size); + stat.st_size = size; + if (stat.amode & MPI_MODE_APPEND) { + stat.is_append = true; + } +} + +size_t MpiioFS::_RealWrite(const std::string &filename, off_t offset, + size_t size, const u8 *data_ptr, + IoStatus &io_status, IoOptions &opts) { + LOG(INFO) << "Writing to file: " << filename << " offset: " << offset + << " size:" << size << "." + << " offset:" << offset << "." + << " file_size:" << stdfs::file_size(filename) + << " pid: " << getpid() << std::endl; + MPI_File fh; + int write_count = 0; + io_status.mpi_ret_ = real_api->MPI_File_open(MPI_COMM_SELF, filename.c_str(), + MPI_MODE_RDWR, MPI_INFO_NULL, &fh); + if (io_status.mpi_ret_ != MPI_SUCCESS) { + return 0; + } + + io_status.mpi_ret_ = real_api->MPI_File_seek(fh, offset, MPI_SEEK_SET); + if (io_status.mpi_ret_ != MPI_SUCCESS) { + goto ERROR; + } + io_status.mpi_ret_ = real_api->MPI_File_write(fh, data_ptr, + opts.count_, opts.mpi_type_, + io_status.mpi_status_ptr_); + MPI_Get_count(io_status.mpi_status_ptr_, opts.mpi_type_, &write_count); + if (opts.count_ != write_count) { + LOG(ERROR) << "writing failed: write " << write_count << " of " + << opts.count_ << "." << std::endl; + } + +ERROR: + real_api->MPI_File_close(&fh); + return size; +} + +size_t MpiioFS::_RealRead(const std::string &filename, off_t offset, + size_t size, u8 *data_ptr, + IoStatus &io_status, IoOptions &opts) { + LOG(INFO) << "Read called for filename from destination: " << filename + << " on offset: " << offset << " and size: " << size << "." + << " file_size:" << stdfs::file_size(filename) + << " pid: " << getpid() << std::endl; + MPI_File fh; + int read_count = 0; + io_status.mpi_ret_ = real_api->MPI_File_open(MPI_COMM_SELF, filename.c_str(), + MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); + if (io_status.mpi_ret_ != MPI_SUCCESS) { + return 0; + } + + io_status.mpi_ret_ = real_api->MPI_File_seek(fh, offset, MPI_SEEK_SET); + if (io_status.mpi_ret_ != MPI_SUCCESS) { + goto ERROR; + } + io_status.mpi_ret_ = real_api->MPI_File_read(fh, data_ptr, + opts.count_, opts.mpi_type_, + io_status.mpi_status_ptr_); + MPI_Get_count(io_status.mpi_status_ptr_, + opts.mpi_type_, &read_count); + if (read_count != opts.count_) { + LOG(ERROR) << "reading failed: read " << read_count << " of " << opts.count_ + << "." << std::endl; + } + +ERROR: + real_api->MPI_File_close(&fh); + return size; +} + +void MpiioFS::_IoStats(size_t count, IoStatus &io_status, IoOptions &opts) { + (void) opts; + io_status.mpi_status_ptr_->count_hi_and_cancelled = 0; + io_status.mpi_status_ptr_->count_lo = count; +} + +int MpiioFS::_RealSync(File &f) { + return real_api->MPI_File_sync(f.mpi_fh_); +} + +int MpiioFS::_RealClose(File &f) { + return real_api->MPI_File_close(&f.mpi_fh_); +} + +} // namespace hermes::adapter::mpiio diff --git a/adapter/mpiio/fs_api.h b/adapter/mpiio/fs_api.h new file mode 100644 index 000000000..4819bafb3 --- /dev/null +++ b/adapter/mpiio/fs_api.h @@ -0,0 +1,241 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_ADAPTER_MPIIO_FS_API_H_ +#define HERMES_ADAPTER_MPIIO_FS_API_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "real_api.h" + +namespace hermes::adapter::mpiio { + +using hermes::Singleton; +using hermes::adapter::fs::AdapterStat; +using hermes::adapter::fs::File; +using hermes::adapter::fs::HermesRequest; +using hermes::adapter::fs::IoOptions; +using hermes::adapter::fs::IoStatus; +using hermes::adapter::fs::MetadataManager; +using hermes::adapter::fs::SeekMode; +using hermes::adapter::mpiio::API; + +/** + A class to represent MPI IO seek mode conversion +*/ +class MpiioSeekModeConv { + public: + /** normalize \a mpi_seek MPI seek mode */ + static SeekMode Normalize(int mpi_seek) { + switch (mpi_seek) { + case MPI_SEEK_SET: + return SeekMode::kSet; + case MPI_SEEK_CUR: + return SeekMode::kCurrent; + case MPI_SEEK_END: + return SeekMode::kEnd; + default: + return SeekMode::kNone; + } + } +}; + +/** + A class to represent MPI IO file system +*/ +class MpiioFS : public hermes::adapter::fs::Filesystem { + private: + API *real_api; /**< pointer to real APIs */ + hermes::adapter::posix::API *posix_api; /**< pointer to POSIX APIs */ + + public: + MpiioFS() { + real_api = Singleton::GetInstance(); + posix_api = Singleton::GetInstance(); + } + ~MpiioFS() = default; + + void _InitFile(File &f) override; + + public: + /** get file name from \a fh MPI file pointer */ + static inline std::string GetFilenameFromFP(MPI_File *fh) { + MPI_Info info; + int status = MPI_File_get_info(*fh, &info); + if (status != MPI_SUCCESS) { + LOG(ERROR) << "MPI_File_get_info on file handler failed." << std::endl; + } + const int kMaxSize = 0xFFF; + int flag; + char filename[kMaxSize] = {0}; + MPI_Info_get(info, "filename", kMaxSize, filename, &flag); + return filename; + } + /** Read */ + int Read(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, + MPI_Datatype datatype, MPI_Status *status, + IoOptions opts = IoOptions()); + /** ARead */ + int ARead(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, + MPI_Datatype datatype, MPI_Request *request, + IoOptions opts = IoOptions()); + /** ReadAll */ + int ReadAll(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, + MPI_Datatype datatype, MPI_Status *status, + IoOptions opts = IoOptions()); + /** ReadOrdered */ + int ReadOrdered(File &f, AdapterStat &stat, void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status, + IoOptions opts = IoOptions()); + /** Write */ + int Write(File &f, AdapterStat &stat, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Status *status, + IoOptions opts = IoOptions()); + /** AWrite */ + int AWrite(File &f, AdapterStat &stat, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Request *request, + IoOptions opts = IoOptions()); + /** WriteAll */ + int WriteAll(File &f, AdapterStat &stat, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Status *status, + IoOptions opts = IoOptions()); + /** WriteOrdered */ + int WriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status, + IoOptions opts = IoOptions()); + /** AWriteOrdered */ + int AWriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, + MPI_Datatype datatype, MPI_Request *request, + IoOptions opts = IoOptions()); + /** Wait */ + int Wait(MPI_Request *req, MPI_Status *status); + /** WaitAll */ + int WaitAll(int count, MPI_Request *req, MPI_Status *status); + /** Seek */ + int Seek(File &f, AdapterStat &stat, MPI_Offset offset, int whence); + /** SeekShared */ + int SeekShared(File &f, AdapterStat &stat, MPI_Offset offset, int whence); + + /** + * Variants which internally find the correct offset + */ + + public: + /** Read */ + int Read(File &f, AdapterStat &stat, void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status); + /** ARead */ + int ARead(File &f, AdapterStat &stat, void *ptr, int count, + MPI_Datatype datatype, MPI_Request *request); + /** ReadAll */ + int ReadAll(File &f, AdapterStat &stat, void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status); + /** Write */ + int Write(File &f, AdapterStat &stat, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status); + /** AWrite */ + int AWrite(File &f, AdapterStat &stat, const void *ptr, int count, + MPI_Datatype datatype, MPI_Request *request); + /** WriteAll */ + int WriteAll(File &f, AdapterStat &stat, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status); + + /** + * Variants which retrieve the stat data structure internally + */ + + public: + /** Read */ + int Read(File &f, bool &stat_exists, void *ptr, size_t offset, int count, + MPI_Datatype datatype, MPI_Status *status); + /** ARead */ + int ARead(File &f, bool &stat_exists, void *ptr, size_t offset, int count, + MPI_Datatype datatype, MPI_Request *request); + /** ReadAll */ + int ReadAll(File &f, bool &stat_exists, void *ptr, size_t offset, int count, + MPI_Datatype datatype, MPI_Status *status); + /** ReadOrdered */ + int ReadOrdered(File &f, bool &stat_exists, void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status); + /** Write */ + int Write(File &f, bool &stat_exists, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Status *status); + /** AWrite */ + int AWrite(File &f, bool &stat_exists, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Request *request); + /** WriteAll */ + int WriteAll(File &f, bool &stat_exists, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Status *status); + /** WriteOrdered */ + int WriteOrdered(File &f, bool &stat_exists, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status); + /** AWriteOrdered */ + int AWriteOrdered(File &f, bool &stat_exists, const void *ptr, int count, + MPI_Datatype datatype, MPI_Request *request); + /** Read */ + int Read(File &f, bool &stat_exists, void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status); + /** ARead */ + int ARead(File &f, bool &stat_exists, void *ptr, int count, + MPI_Datatype datatype, MPI_Request *request); + /** ReadAll */ + int ReadAll(File &f, bool &stat_exists, void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status); + /** Write */ + int Write(File &f, bool &stat_exists, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status); + /** AWrite */ + int AWrite(File &f, bool &stat_exists, const void *ptr, int count, + MPI_Datatype datatype, MPI_Request *request); + /** WriteAll */ + int WriteAll(File &f, bool &stat_exists, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status); + /** Seek */ + int Seek(File &f, bool &stat_exists, MPI_Offset offset, int whence); + /** SeekShared */ + int SeekShared(File &f, bool &stat_exists, MPI_Offset offset, int whence); + + /** + * Internal overrides + */ + + private: + /** OpenInitStats */ + void _OpenInitStats(File &f, AdapterStat &stat) override; + /** RealOpen */ + File _RealOpen(AdapterStat &stat, const std::string &path) override; + /** RealWrite */ + size_t _RealWrite(const std::string &filename, off_t offset, size_t size, + const u8 *data_ptr, IoStatus &io_status, + IoOptions &opts) override; + /** RealRead */ + size_t _RealRead(const std::string &filename, off_t offset, size_t size, + u8 *data_ptr, IoStatus &io_status, IoOptions &opts) override; + /** IoStats */ + void _IoStats(size_t count, IoStatus &io_status, IoOptions &opts) override; + /** RealSync */ + int _RealSync(File &f) override; + /** RealClose */ + int _RealClose(File &f) override; +}; + +} // namespace hermes::adapter::mpiio + +#endif // HERMES_ADAPTER_MPIIO_FS_API_H_ diff --git a/adapter/mpiio/mpiio.cc b/adapter/mpiio/mpiio.cc new file mode 100644 index 000000000..91c77f747 --- /dev/null +++ b/adapter/mpiio/mpiio.cc @@ -0,0 +1,462 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +bool mpiio_intercepted = true; + +#include +#include +#include + +#include "real_api.h" +#include "fs_api.h" + +#include "constants.h" +#include "singleton.h" +#include "interceptor.h" +#include "interceptor.cc" + +#include "thread_pool.h" + +/** + * Namespace declarations + */ +using hermes::ThreadPool; +using hermes::adapter::fs::MetadataManager; +using hermes::adapter::fs::File; +using hermes::adapter::mpiio::API; +using hermes::adapter::mpiio::MpiioFS; +using hermes::adapter::mpiio::MpiioSeekModeConv; +using hermes::Singleton; + +namespace hapi = hermes::api; +namespace stdfs = std::experimental::filesystem; +using hermes::adapter::WeaklyCanonical; + +/** + * Internal Functions. + */ + + +inline bool IsTracked(MPI_File *fh) { + if (hermes::adapter::exit) return false; + auto mdm = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + File f; f.mpi_fh_ = (*fh); fs_api->_InitFile(f); + auto [stat, exists] = mdm->Find(f); + return exists; +} + +extern "C" { + +/** + * MPI + */ +int HERMES_DECL(MPI_Init)(int *argc, char ***argv) { + auto real_api = Singleton::GetInstance(); + int status = real_api->MPI_Init(argc, argv); + if (status == 0) { + LOG(INFO) << "MPI Init intercepted." << std::endl; + auto mdm = Singleton::GetInstance(); + mdm->InitializeHermes(true); + Singleton::GetInstance(hermes::adapter::fs::kNumThreads); + } + return status; +} + +int HERMES_DECL(MPI_Finalize)(void) { + LOG(INFO) << "MPI Finalize intercepted." << std::endl; + auto real_api = Singleton::GetInstance(); + auto mdm = Singleton::GetInstance(); + mdm->FinalizeHermes(); + int status = real_api->MPI_Finalize(); + return status; +} + +int HERMES_DECL(MPI_Wait)(MPI_Request *req, MPI_Status *status) { + auto fs_api = Singleton::GetInstance(); + return fs_api->Wait(req, status); +} + +int HERMES_DECL(MPI_Waitall)(int count, MPI_Request *req, MPI_Status *status) { + auto fs_api = Singleton::GetInstance(); + return fs_api->WaitAll(count, req, status); +} + +/** + * Metadata functions + */ +int HERMES_DECL(MPI_File_open)(MPI_Comm comm, const char *filename, int amode, + MPI_Info info, MPI_File *fh) { + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (hermes::adapter::IsTracked(filename)) { + LOG(INFO) << "Intercept MPI_File_open for filename: " << filename + << " and mode: " << amode << " is tracked." << std::endl; + AdapterStat stat; + stat.comm = comm; + stat.amode = amode; + stat.info = info; + File f = fs_api->Open(stat, filename); + (*fh) = f.mpi_fh_; + return f.mpi_status_; + } + return real_api->MPI_File_open(comm, filename, amode, info, fh); +} + +int HERMES_DECL(MPI_File_close)(MPI_File *fh) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(fh)) { + File f; + f.mpi_fh_ = *fh; + fs_api->_InitFile(f); + return fs_api->Close(f, stat_exists); + } + return real_api->MPI_File_close(fh); +} + +int HERMES_DECL(MPI_File_seek)(MPI_File fh, MPI_Offset offset, int whence) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + return fs_api->Seek(f, stat_exists, offset, whence); + } + return real_api->MPI_File_seek(fh, offset, whence); +} + +int HERMES_DECL(MPI_File_seek_shared)(MPI_File fh, MPI_Offset offset, + int whence) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_seek_shared offset:" << offset + << " whence:" << whence << "." << std::endl; + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + return fs_api->SeekShared(f, stat_exists, offset, whence); + } + return real_api->MPI_File_seek_shared(fh, offset, whence); +} + +int HERMES_DECL(MPI_File_get_position)(MPI_File fh, MPI_Offset *offset) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + (*offset) = static_cast(fs_api->Tell(f, stat_exists)); + return MPI_SUCCESS; + } + return real_api->MPI_File_get_position(fh, offset); +} + +int HERMES_DECL(MPI_File_read_all)(MPI_File fh, void *buf, int count, + MPI_Datatype datatype, MPI_Status *status) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_read_all." << std::endl; + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + return fs_api->ReadAll(f, stat_exists, buf, count, datatype, status); + } + return real_api->MPI_File_read_all(fh, buf, count, datatype, status); +} +int HERMES_DECL(MPI_File_read_at_all)(MPI_File fh, MPI_Offset offset, void *buf, + int count, MPI_Datatype datatype, + MPI_Status *status) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + return fs_api->ReadAll(f, stat_exists, buf, offset, count, datatype, + status); + } + return real_api->MPI_File_read_at_all(fh, offset, buf, count, datatype, + status); +} +int HERMES_DECL(MPI_File_read_at)(MPI_File fh, MPI_Offset offset, void *buf, + int count, MPI_Datatype datatype, + MPI_Status *status) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + return fs_api->Read(f, stat_exists, buf, offset, count, datatype, status); + } + return real_api->MPI_File_read_at(fh, offset, buf, count, datatype, status); +} +int HERMES_DECL(MPI_File_read)(MPI_File fh, void *buf, int count, + MPI_Datatype datatype, MPI_Status *status) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + int ret = fs_api->Read(f, stat_exists, buf, count, datatype, status); + if (stat_exists) return ret; + } + return real_api->MPI_File_read(fh, buf, count, datatype, status); +} +int HERMES_DECL(MPI_File_read_ordered)(MPI_File fh, void *buf, int count, + MPI_Datatype datatype, + MPI_Status *status) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + return fs_api->ReadOrdered(f, stat_exists, buf, count, datatype, status); + } + return real_api->MPI_File_read_ordered(fh, buf, count, datatype, status); +} +int HERMES_DECL(MPI_File_read_shared)(MPI_File fh, void *buf, int count, + MPI_Datatype datatype, + MPI_Status *status) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_read_shared." << std::endl; + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + return fs_api->Read(f, stat_exists, buf, count, datatype, status); + } + return real_api->MPI_File_read_shared(fh, buf, count, datatype, status); +} +int HERMES_DECL(MPI_File_write_all)(MPI_File fh, const void *buf, int count, + MPI_Datatype datatype, MPI_Status *status) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_write_all." << std::endl; + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + int ret = fs_api->WriteAll(f, stat_exists, buf, count, datatype, status); + if (stat_exists) return ret; + } + return real_api->MPI_File_write_all(fh, buf, count, datatype, status); +} +int HERMES_DECL(MPI_File_write_at_all)(MPI_File fh, MPI_Offset offset, + const void *buf, int count, + MPI_Datatype datatype, + MPI_Status *status) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + int ret = + fs_api->WriteAll(f, stat_exists, buf, offset, count, datatype, status); + if (stat_exists) return ret; + } + return real_api->MPI_File_write_at_all(fh, offset, buf, count, datatype, + status); +} +int HERMES_DECL(MPI_File_write_at)(MPI_File fh, MPI_Offset offset, + const void *buf, int count, + MPI_Datatype datatype, MPI_Status *status) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + LOG(INFO) << "In MPI_File_write_at" << std::endl; + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + return fs_api->Write(f, stat_exists, buf, offset, count, datatype, status); + } + return real_api->MPI_File_write_at(fh, offset, buf, count, datatype, status); +} +int HERMES_DECL(MPI_File_write)(MPI_File fh, const void *buf, int count, + MPI_Datatype datatype, MPI_Status *status) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + LOG(INFO) << "In MPI_File_write" << std::endl; + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + int ret = fs_api->Write(f, stat_exists, buf, count, datatype, status); + if (stat_exists) return ret; + } + return real_api->MPI_File_write(fh, buf, count, datatype, status); +} +int HERMES_DECL(MPI_File_write_ordered)(MPI_File fh, const void *buf, int count, + MPI_Datatype datatype, + MPI_Status *status) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + return fs_api->WriteOrdered(f, stat_exists, buf, count, datatype, status); + } + return real_api->MPI_File_write_ordered(fh, buf, count, datatype, status); +} +int HERMES_DECL(MPI_File_write_shared)(MPI_File fh, const void *buf, int count, + MPI_Datatype datatype, + MPI_Status *status) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + // NOTE(llogan): originally WriteOrdered + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + return fs_api->WriteOrdered(f, stat_exists, buf, count, datatype, status); + } + return real_api->MPI_File_write_shared(fh, buf, count, datatype, status); +} + +/** + * Async Read/Write + */ +int HERMES_DECL(MPI_File_iread_at)(MPI_File fh, MPI_Offset offset, void *buf, + int count, MPI_Datatype datatype, + MPI_Request *request) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + fs_api->ARead(f, stat_exists, buf, offset, count, datatype, request); + return MPI_SUCCESS; + } + return real_api->MPI_File_iread_at(fh, offset, buf, count, datatype, request); +} +int HERMES_DECL(MPI_File_iread)(MPI_File fh, void *buf, int count, + MPI_Datatype datatype, MPI_Request *request) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + fs_api->ARead(f, stat_exists, buf, count, datatype, request); + } + return real_api->MPI_File_iread(fh, buf, count, datatype, request); +} +int HERMES_DECL(MPI_File_iread_shared)(MPI_File fh, void *buf, int count, + MPI_Datatype datatype, + MPI_Request *request) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + fs_api->ARead(f, stat_exists, buf, count, datatype, request); + return MPI_SUCCESS; + } + return real_api->MPI_File_iread_shared(fh, buf, count, datatype, request); +} +int HERMES_DECL(MPI_File_iwrite_at)(MPI_File fh, MPI_Offset offset, + const void *buf, int count, + MPI_Datatype datatype, + MPI_Request *request) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + fs_api->AWrite(f, stat_exists, buf, offset, count, datatype, request); + return MPI_SUCCESS; + } + return real_api->MPI_File_iwrite_at(fh, offset, buf, count, datatype, + request); +} + +int HERMES_DECL(MPI_File_iwrite)(MPI_File fh, const void *buf, int count, + MPI_Datatype datatype, MPI_Request *request) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + fs_api->AWrite(f, stat_exists, buf, count, datatype, request); + return MPI_SUCCESS; + } + return real_api->MPI_File_iwrite(fh, buf, count, datatype, request); +} +int HERMES_DECL(MPI_File_iwrite_shared)(MPI_File fh, const void *buf, int count, + MPI_Datatype datatype, + MPI_Request *request) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + fs_api->AWriteOrdered(f, stat_exists, buf, count, datatype, request); + return MPI_SUCCESS; + } + return real_api->MPI_File_iwrite_shared(fh, buf, count, datatype, request); +} + +/** + * Other functions + */ +int HERMES_DECL(MPI_File_sync)(MPI_File fh) { + bool stat_exists; + auto real_api = Singleton::GetInstance(); + auto fs_api = Singleton::GetInstance(); + if (IsTracked(&fh)) { + File f; + f.mpi_fh_ = fh; + fs_api->_InitFile(f); + fs_api->Sync(f, stat_exists); + return 0; + } + return real_api->MPI_File_sync(fh); +} + +} // extern C diff --git a/adapter/mpiio/real_api.h b/adapter/mpiio/real_api.h new file mode 100644 index 000000000..93a601367 --- /dev/null +++ b/adapter/mpiio/real_api.h @@ -0,0 +1,301 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_ADAPTER_MPIIO_H +#define HERMES_ADAPTER_MPIIO_H +#include +#include +#include +#include +#include +#include +#include "interceptor.h" +#include "filesystem/filesystem.h" +#include "filesystem/metadata_manager.h" + +#define REQUIRE_API(api_name) \ + if (api_name == nullptr) { \ + LOG(FATAL) << "HERMES Adapter failed to map symbol: " \ + #api_name << std::endl; \ + std::exit(1); \ + } + +extern "C" { +typedef int (*MPI_Init_t)(int * argc, char *** argv); +typedef int (*MPI_Finalize_t)( void); +typedef int (*MPI_Wait_t)(MPI_Request * req, MPI_Status * status); +typedef int (*MPI_Waitall_t)(int count, MPI_Request * req, MPI_Status * status); +typedef int (*MPI_File_open_t)(MPI_Comm comm, const char * filename, int amode, MPI_Info info, MPI_File * fh); +typedef int (*MPI_File_close_t)(MPI_File * fh); +typedef int (*MPI_File_seek_shared_t)(MPI_File fh, MPI_Offset offset, int whence); +typedef int (*MPI_File_seek_t)(MPI_File fh, MPI_Offset offset, int whence); +typedef int (*MPI_File_get_position_t)(MPI_File fh, MPI_Offset * offset); +typedef int (*MPI_File_read_all_t)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Status * status); +typedef int (*MPI_File_read_at_all_t)(MPI_File fh, MPI_Offset offset, void * buf, int count, MPI_Datatype datatype, MPI_Status * status); +typedef int (*MPI_File_read_at_t)(MPI_File fh, MPI_Offset offset, void * buf, int count, MPI_Datatype datatype, MPI_Status * status); +typedef int (*MPI_File_read_t)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Status * status); +typedef int (*MPI_File_read_ordered_t)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Status * status); +typedef int (*MPI_File_read_shared_t)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Status * status); +typedef int (*MPI_File_write_all_t)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status); +typedef int (*MPI_File_write_at_all_t)(MPI_File fh, MPI_Offset offset, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status); +typedef int (*MPI_File_write_at_t)(MPI_File fh, MPI_Offset offset, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status); +typedef int (*MPI_File_write_t)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status); +typedef int (*MPI_File_write_ordered_t)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status); +typedef int (*MPI_File_write_shared_t)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Status * status); +typedef int (*MPI_File_iread_at_t)(MPI_File fh, MPI_Offset offset, void * buf, int count, MPI_Datatype datatype, MPI_Request * request); +typedef int (*MPI_File_iread_t)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Request * request); +typedef int (*MPI_File_iread_shared_t)(MPI_File fh, void * buf, int count, MPI_Datatype datatype, MPI_Request * request); +typedef int (*MPI_File_iwrite_at_t)(MPI_File fh, MPI_Offset offset, const void * buf, int count, MPI_Datatype datatype, MPI_Request * request); +typedef int (*MPI_File_iwrite_t)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Request * request); +typedef int (*MPI_File_iwrite_shared_t)(MPI_File fh, const void * buf, int count, MPI_Datatype datatype, MPI_Request * request); +typedef int (*MPI_File_sync_t)(MPI_File fh); +} + +namespace hermes::adapter::mpiio { + +/** Pointers to the real mpiio API */ +class API { + public: + /** MPI_Init */ + MPI_Init_t MPI_Init = nullptr; + /** MPI_Finalize */ + MPI_Finalize_t MPI_Finalize = nullptr; + /** MPI_Wait */ + MPI_Wait_t MPI_Wait = nullptr; + /** MPI_Waitall */ + MPI_Waitall_t MPI_Waitall = nullptr; + /** MPI_File_open */ + MPI_File_open_t MPI_File_open = nullptr; + /** MPI_File_close */ + MPI_File_close_t MPI_File_close = nullptr; + /** MPI_File_seek_shared */ + MPI_File_seek_shared_t MPI_File_seek_shared = nullptr; + /** MPI_File_seek */ + MPI_File_seek_t MPI_File_seek = nullptr; + /** MPI_File_get_position */ + MPI_File_get_position_t MPI_File_get_position = nullptr; + /** MPI_File_read_all */ + MPI_File_read_all_t MPI_File_read_all = nullptr; + /** MPI_File_read_at_all */ + MPI_File_read_at_all_t MPI_File_read_at_all = nullptr; + /** MPI_File_read_at */ + MPI_File_read_at_t MPI_File_read_at = nullptr; + /** MPI_File_read */ + MPI_File_read_t MPI_File_read = nullptr; + /** MPI_File_read_ordered */ + MPI_File_read_ordered_t MPI_File_read_ordered = nullptr; + /** MPI_File_read_shared */ + MPI_File_read_shared_t MPI_File_read_shared = nullptr; + /** MPI_File_write_all */ + MPI_File_write_all_t MPI_File_write_all = nullptr; + /** MPI_File_write_at_all */ + MPI_File_write_at_all_t MPI_File_write_at_all = nullptr; + /** MPI_File_write_at */ + MPI_File_write_at_t MPI_File_write_at = nullptr; + /** MPI_File_write */ + MPI_File_write_t MPI_File_write = nullptr; + /** MPI_File_write_ordered */ + MPI_File_write_ordered_t MPI_File_write_ordered = nullptr; + /** MPI_File_write_shared */ + MPI_File_write_shared_t MPI_File_write_shared = nullptr; + /** MPI_File_iread_at */ + MPI_File_iread_at_t MPI_File_iread_at = nullptr; + /** MPI_File_iread */ + MPI_File_iread_t MPI_File_iread = nullptr; + /** MPI_File_iread_shared */ + MPI_File_iread_shared_t MPI_File_iread_shared = nullptr; + /** MPI_File_iwrite_at */ + MPI_File_iwrite_at_t MPI_File_iwrite_at = nullptr; + /** MPI_File_iwrite */ + MPI_File_iwrite_t MPI_File_iwrite = nullptr; + /** MPI_File_iwrite_shared */ + MPI_File_iwrite_shared_t MPI_File_iwrite_shared = nullptr; + /** MPI_File_sync */ + MPI_File_sync_t MPI_File_sync = nullptr; + + API() { + void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, "mpiio_intercepted"); + if (is_intercepted) { + MPI_Init = (MPI_Init_t)dlsym(RTLD_NEXT, "MPI_Init"); + } else { + MPI_Init = (MPI_Init_t)dlsym(RTLD_DEFAULT, "MPI_Init"); + } + REQUIRE_API(MPI_Init) + if (is_intercepted) { + MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_NEXT, "MPI_Finalize"); + } else { + MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_DEFAULT, "MPI_Finalize"); + } + REQUIRE_API(MPI_Finalize) + if (is_intercepted) { + MPI_Wait = (MPI_Wait_t)dlsym(RTLD_NEXT, "MPI_Wait"); + } else { + MPI_Wait = (MPI_Wait_t)dlsym(RTLD_DEFAULT, "MPI_Wait"); + } + REQUIRE_API(MPI_Wait) + if (is_intercepted) { + MPI_Waitall = (MPI_Waitall_t)dlsym(RTLD_NEXT, "MPI_Waitall"); + } else { + MPI_Waitall = (MPI_Waitall_t)dlsym(RTLD_DEFAULT, "MPI_Waitall"); + } + REQUIRE_API(MPI_Waitall) + if (is_intercepted) { + MPI_File_open = (MPI_File_open_t)dlsym(RTLD_NEXT, "MPI_File_open"); + } else { + MPI_File_open = (MPI_File_open_t)dlsym(RTLD_DEFAULT, "MPI_File_open"); + } + REQUIRE_API(MPI_File_open) + if (is_intercepted) { + MPI_File_close = (MPI_File_close_t)dlsym(RTLD_NEXT, "MPI_File_close"); + } else { + MPI_File_close = (MPI_File_close_t)dlsym(RTLD_DEFAULT, "MPI_File_close"); + } + REQUIRE_API(MPI_File_close) + if (is_intercepted) { + MPI_File_seek_shared = (MPI_File_seek_shared_t)dlsym(RTLD_NEXT, "MPI_File_seek_shared"); + } else { + MPI_File_seek_shared = (MPI_File_seek_shared_t)dlsym(RTLD_DEFAULT, "MPI_File_seek_shared"); + } + REQUIRE_API(MPI_File_seek_shared) + if (is_intercepted) { + MPI_File_seek = (MPI_File_seek_t)dlsym(RTLD_NEXT, "MPI_File_seek"); + } else { + MPI_File_seek = (MPI_File_seek_t)dlsym(RTLD_DEFAULT, "MPI_File_seek"); + } + REQUIRE_API(MPI_File_seek) + if (is_intercepted) { + MPI_File_get_position = (MPI_File_get_position_t)dlsym(RTLD_NEXT, "MPI_File_get_position"); + } else { + MPI_File_get_position = (MPI_File_get_position_t)dlsym(RTLD_DEFAULT, "MPI_File_get_position"); + } + REQUIRE_API(MPI_File_get_position) + if (is_intercepted) { + MPI_File_read_all = (MPI_File_read_all_t)dlsym(RTLD_NEXT, "MPI_File_read_all"); + } else { + MPI_File_read_all = (MPI_File_read_all_t)dlsym(RTLD_DEFAULT, "MPI_File_read_all"); + } + REQUIRE_API(MPI_File_read_all) + if (is_intercepted) { + MPI_File_read_at_all = (MPI_File_read_at_all_t)dlsym(RTLD_NEXT, "MPI_File_read_at_all"); + } else { + MPI_File_read_at_all = (MPI_File_read_at_all_t)dlsym(RTLD_DEFAULT, "MPI_File_read_at_all"); + } + REQUIRE_API(MPI_File_read_at_all) + if (is_intercepted) { + MPI_File_read_at = (MPI_File_read_at_t)dlsym(RTLD_NEXT, "MPI_File_read_at"); + } else { + MPI_File_read_at = (MPI_File_read_at_t)dlsym(RTLD_DEFAULT, "MPI_File_read_at"); + } + REQUIRE_API(MPI_File_read_at) + if (is_intercepted) { + MPI_File_read = (MPI_File_read_t)dlsym(RTLD_NEXT, "MPI_File_read"); + } else { + MPI_File_read = (MPI_File_read_t)dlsym(RTLD_DEFAULT, "MPI_File_read"); + } + REQUIRE_API(MPI_File_read) + if (is_intercepted) { + MPI_File_read_ordered = (MPI_File_read_ordered_t)dlsym(RTLD_NEXT, "MPI_File_read_ordered"); + } else { + MPI_File_read_ordered = (MPI_File_read_ordered_t)dlsym(RTLD_DEFAULT, "MPI_File_read_ordered"); + } + REQUIRE_API(MPI_File_read_ordered) + if (is_intercepted) { + MPI_File_read_shared = (MPI_File_read_shared_t)dlsym(RTLD_NEXT, "MPI_File_read_shared"); + } else { + MPI_File_read_shared = (MPI_File_read_shared_t)dlsym(RTLD_DEFAULT, "MPI_File_read_shared"); + } + REQUIRE_API(MPI_File_read_shared) + if (is_intercepted) { + MPI_File_write_all = (MPI_File_write_all_t)dlsym(RTLD_NEXT, "MPI_File_write_all"); + } else { + MPI_File_write_all = (MPI_File_write_all_t)dlsym(RTLD_DEFAULT, "MPI_File_write_all"); + } + REQUIRE_API(MPI_File_write_all) + if (is_intercepted) { + MPI_File_write_at_all = (MPI_File_write_at_all_t)dlsym(RTLD_NEXT, "MPI_File_write_at_all"); + } else { + MPI_File_write_at_all = (MPI_File_write_at_all_t)dlsym(RTLD_DEFAULT, "MPI_File_write_at_all"); + } + REQUIRE_API(MPI_File_write_at_all) + if (is_intercepted) { + MPI_File_write_at = (MPI_File_write_at_t)dlsym(RTLD_NEXT, "MPI_File_write_at"); + } else { + MPI_File_write_at = (MPI_File_write_at_t)dlsym(RTLD_DEFAULT, "MPI_File_write_at"); + } + REQUIRE_API(MPI_File_write_at) + if (is_intercepted) { + MPI_File_write = (MPI_File_write_t)dlsym(RTLD_NEXT, "MPI_File_write"); + } else { + MPI_File_write = (MPI_File_write_t)dlsym(RTLD_DEFAULT, "MPI_File_write"); + } + REQUIRE_API(MPI_File_write) + if (is_intercepted) { + MPI_File_write_ordered = (MPI_File_write_ordered_t)dlsym(RTLD_NEXT, "MPI_File_write_ordered"); + } else { + MPI_File_write_ordered = (MPI_File_write_ordered_t)dlsym(RTLD_DEFAULT, "MPI_File_write_ordered"); + } + REQUIRE_API(MPI_File_write_ordered) + if (is_intercepted) { + MPI_File_write_shared = (MPI_File_write_shared_t)dlsym(RTLD_NEXT, "MPI_File_write_shared"); + } else { + MPI_File_write_shared = (MPI_File_write_shared_t)dlsym(RTLD_DEFAULT, "MPI_File_write_shared"); + } + REQUIRE_API(MPI_File_write_shared) + if (is_intercepted) { + MPI_File_iread_at = (MPI_File_iread_at_t)dlsym(RTLD_NEXT, "MPI_File_iread_at"); + } else { + MPI_File_iread_at = (MPI_File_iread_at_t)dlsym(RTLD_DEFAULT, "MPI_File_iread_at"); + } + REQUIRE_API(MPI_File_iread_at) + if (is_intercepted) { + MPI_File_iread = (MPI_File_iread_t)dlsym(RTLD_NEXT, "MPI_File_iread"); + } else { + MPI_File_iread = (MPI_File_iread_t)dlsym(RTLD_DEFAULT, "MPI_File_iread"); + } + REQUIRE_API(MPI_File_iread) + if (is_intercepted) { + MPI_File_iread_shared = (MPI_File_iread_shared_t)dlsym(RTLD_NEXT, "MPI_File_iread_shared"); + } else { + MPI_File_iread_shared = (MPI_File_iread_shared_t)dlsym(RTLD_DEFAULT, "MPI_File_iread_shared"); + } + REQUIRE_API(MPI_File_iread_shared) + if (is_intercepted) { + MPI_File_iwrite_at = (MPI_File_iwrite_at_t)dlsym(RTLD_NEXT, "MPI_File_iwrite_at"); + } else { + MPI_File_iwrite_at = (MPI_File_iwrite_at_t)dlsym(RTLD_DEFAULT, "MPI_File_iwrite_at"); + } + REQUIRE_API(MPI_File_iwrite_at) + if (is_intercepted) { + MPI_File_iwrite = (MPI_File_iwrite_t)dlsym(RTLD_NEXT, "MPI_File_iwrite"); + } else { + MPI_File_iwrite = (MPI_File_iwrite_t)dlsym(RTLD_DEFAULT, "MPI_File_iwrite"); + } + REQUIRE_API(MPI_File_iwrite) + if (is_intercepted) { + MPI_File_iwrite_shared = (MPI_File_iwrite_shared_t)dlsym(RTLD_NEXT, "MPI_File_iwrite_shared"); + } else { + MPI_File_iwrite_shared = (MPI_File_iwrite_shared_t)dlsym(RTLD_DEFAULT, "MPI_File_iwrite_shared"); + } + REQUIRE_API(MPI_File_iwrite_shared) + if (is_intercepted) { + MPI_File_sync = (MPI_File_sync_t)dlsym(RTLD_NEXT, "MPI_File_sync"); + } else { + MPI_File_sync = (MPI_File_sync_t)dlsym(RTLD_DEFAULT, "MPI_File_sync"); + } + REQUIRE_API(MPI_File_sync) + } +}; +} // namespace hermes::adapter::mpiio + +#undef REQUIRE_API + +#endif // HERMES_ADAPTER_MPIIO_H diff --git a/adapter/posix/posix.cc b/adapter/posix/posix.cc index 272e1dda8..037fbbfe2 100644 --- a/adapter/posix/posix.cc +++ b/adapter/posix/posix.cc @@ -35,8 +35,8 @@ extern "C" { */ int HERMES_DECL(open)(const char *path, int flags, ...) { int mode = 0; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (flags & O_CREAT || flags & O_TMPFILE) { va_list arg; va_start(arg, flags); @@ -59,8 +59,8 @@ int HERMES_DECL(open)(const char *path, int flags, ...) { int HERMES_DECL(open64)(const char *path, int flags, ...) { int mode = 0; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (flags & O_CREAT) { va_list arg; va_start(arg, flags); @@ -82,8 +82,8 @@ int HERMES_DECL(open64)(const char *path, int flags, ...) { } int HERMES_DECL(__open_2)(const char *path, int oflag) { - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(path)) { LOG(INFO) << "Intercept __open_2 for filename: " << path << " and mode: " << oflag << " is tracked." << std::endl; @@ -97,8 +97,8 @@ int HERMES_DECL(__open_2)(const char *path, int oflag) { int HERMES_DECL(creat)(const char *path, mode_t mode) { std::string path_str(path); - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(path)) { LOG(INFO) << "Intercept creat for filename: " << path << " and mode: " << mode << " is tracked." << std::endl; @@ -112,8 +112,8 @@ int HERMES_DECL(creat)(const char *path, mode_t mode) { int HERMES_DECL(creat64)(const char *path, mode_t mode) { std::string path_str(path); - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(path)) { LOG(INFO) << "Intercept creat64 for filename: " << path << " and mode: " << mode << " is tracked." << std::endl; @@ -127,8 +127,8 @@ int HERMES_DECL(creat64)(const char *path, mode_t mode) { ssize_t HERMES_DECL(read)(int fd, void *buf, size_t count) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(fd)) { LOG(INFO) << "Intercept read." << std::endl; File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; @@ -140,8 +140,8 @@ ssize_t HERMES_DECL(read)(int fd, void *buf, size_t count) { ssize_t HERMES_DECL(write)(int fd, const void *buf, size_t count) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(fd)) { LOG(INFO) << "Intercept write." << std::endl; File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; @@ -153,8 +153,8 @@ ssize_t HERMES_DECL(write)(int fd, const void *buf, size_t count) { ssize_t HERMES_DECL(pread)(int fd, void *buf, size_t count, off_t offset) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(fd)) { LOG(INFO) << "Intercept pread." << std::endl; File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; @@ -167,8 +167,8 @@ ssize_t HERMES_DECL(pread)(int fd, void *buf, size_t count, off_t offset) { ssize_t HERMES_DECL(pwrite)(int fd, const void *buf, size_t count, off_t offset) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; LOG(INFO) << "Intercept pwrite." << std::endl; @@ -180,8 +180,8 @@ ssize_t HERMES_DECL(pwrite)(int fd, const void *buf, size_t count, ssize_t HERMES_DECL(pread64)(int fd, void *buf, size_t count, off64_t offset) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; LOG(INFO) << "Intercept pread64." << std::endl; @@ -194,8 +194,8 @@ ssize_t HERMES_DECL(pread64)(int fd, void *buf, size_t count, off64_t offset) { ssize_t HERMES_DECL(pwrite64)(int fd, const void *buf, size_t count, off64_t offset) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; LOG(INFO) << "Intercept pwrite." << std::endl; @@ -207,8 +207,8 @@ ssize_t HERMES_DECL(pwrite64)(int fd, const void *buf, size_t count, off_t HERMES_DECL(lseek)(int fd, off_t offset, int whence) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); LOG(INFO) << "Intercept lseek offset:" << offset << " whence:" << whence @@ -221,8 +221,8 @@ off_t HERMES_DECL(lseek)(int fd, off_t offset, int whence) { off64_t HERMES_DECL(lseek64)(int fd, off64_t offset, int whence) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); LOG(INFO) << "Intercept lseek64 offset:" << offset << " whence:" << whence @@ -235,8 +235,8 @@ off64_t HERMES_DECL(lseek64)(int fd, off64_t offset, int whence) { int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { int result = 0; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); LOG(INFO) << "Intercepted fstat." << std::endl; @@ -273,8 +273,8 @@ int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { int HERMES_DECL(fsync)(int fd) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); LOG(INFO) << "Intercept fsync." << std::endl; @@ -285,8 +285,8 @@ int HERMES_DECL(fsync)(int fd) { int HERMES_DECL(close)(int fd) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; if (hermes::adapter::IsTracked(fd)) { LOG(INFO) << "Intercept close(" << std::to_string(fd) << ")"; DLOG(INFO) << " -> " << hermes::adapter::GetFilenameFromFD(fd); diff --git a/adapter/pubsub/CMakeLists.txt b/adapter/pubsub/CMakeLists.txt new file mode 100644 index 000000000..35a88f503 --- /dev/null +++ b/adapter/pubsub/CMakeLists.txt @@ -0,0 +1,33 @@ +project(PubSubAdapter VERSION ${HERMES_PACKAGE_VERSION}) + +set(HERMES_PUBSUB_ADAPTER_DIR ${HERMES_ADAPTER_DIR}/pubsub) + +set(PUBSUB_ADAPTER_PUBLIC_HEADER pubsub.h) +set(PUBSUB_ADAPTER_PRIVATE_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/metadata_manager.h + ${CMAKE_CURRENT_SOURCE_DIR}/datastructures.h + ${HERMES_ADAPTER_DIR}/constants.h) +set(PUBSUB_ADAPTER_SRC pubsub.cc metadata_manager.cc) + +add_library(hermes_pubsub SHARED ${PUBSUB_ADAPTER_PRIVATE_HEADER} ${PUBSUB_ADAPTER_PUBLIC_HEADER} ${PUBSUB_ADAPTER_SRC}) +target_include_directories(hermes_pubsub PRIVATE ${HERMES_ADAPTER_DIR}) +add_dependencies(hermes_pubsub hermes) +target_link_libraries(hermes_pubsub hermes MPI::MPI_CXX glog::glog) + +#----------------------------------------------------------------------------- +# Add Target(s) to CMake Install +#----------------------------------------------------------------------------- +install( + TARGETS + hermes_pubsub + EXPORT + ${HERMES_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} +) +#----------------------------------------------------------------------------- +# Add Target(s) to Coverage +#----------------------------------------------------------------------------- +if(HERMES_ENABLE_COVERAGE) + set_coverage_flags(hermes_pubsub) +endif() diff --git a/adapter/pubsub/datastructures.h b/adapter/pubsub/datastructures.h new file mode 100644 index 000000000..1bbe8a226 --- /dev/null +++ b/adapter/pubsub/datastructures.h @@ -0,0 +1,58 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_PUBSUB_ADAPTER_DATASTRUCTURES_H +#define HERMES_PUBSUB_ADAPTER_DATASTRUCTURES_H + +/** + * Standard header + */ +#include + +/** + * Internal header + */ +#include +#include +#include + +/** + * Namespace simplification. + */ +namespace hapi = hermes::api; + +namespace hermes::adapter::pubsub { + +/** + * Struct that defines the metadata required for the pubsub adapter. + */ +struct ClientMetadata { + /** bucket associated with the topic */ + std::shared_ptr st_bkid; + u64 last_subscribed_blob; /**< Current blob being used */ + timespec st_atim; /**< time of last access */ + /** + * Constructor + */ + ClientMetadata() + : st_bkid(), + last_subscribed_blob(0), + st_atim() {} /* default constructor */ + explicit ClientMetadata(const struct ClientMetadata &st) + : st_bkid(st.st_bkid), + last_subscribed_blob(st.last_subscribed_blob), + st_atim(st.st_atim) {} /**< parameterized constructor */ +}; + +} // namespace hermes::adapter::pubsub + +#endif // HERMES_PUBSUB_ADAPTER_DATASTRUCTURES_H diff --git a/adapter/pubsub/metadata_manager.cc b/adapter/pubsub/metadata_manager.cc new file mode 100644 index 000000000..28c755796 --- /dev/null +++ b/adapter/pubsub/metadata_manager.cc @@ -0,0 +1,60 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "metadata_manager.h" + +/** + * Namespace declarations for cleaner code. + */ +using hermes::adapter::pubsub::MetadataManager; +using hermes::adapter::pubsub::MetadataManager; + +bool MetadataManager::Create(const std::string& topic, + const ClientMetadata&stat) { + LOG(INFO) << "Create metadata for topic: " << topic << std::endl; + auto ret = metadata.emplace(topic, stat); + return ret.second; +} + +bool MetadataManager::Update(const std::string& topic, + const ClientMetadata&stat) { + LOG(INFO) << "Update metadata for topic: " << topic << std::endl; + auto iter = metadata.find(topic); + if (iter != metadata.end()) { + metadata.erase(iter); + auto ret = metadata.emplace(topic, stat); + return ret.second; + } else { + return false; + } +} + +std::pair MetadataManager::Find( + const std::string& topic) { + typedef std::pair MetadataReturn; + auto iter = metadata.find(topic); + if (iter == metadata.end()) + return MetadataReturn(ClientMetadata(), false); + else + return MetadataReturn(iter->second, true); +} + +bool MetadataManager::Delete(const std::string& topic) { + LOG(INFO) << "Delete metadata for topic: " << topic << std::endl; + auto iter = metadata.find(topic); + if (iter != metadata.end()) { + metadata.erase(iter); + return true; + } else { + return false; + } +} diff --git a/adapter/pubsub/metadata_manager.h b/adapter/pubsub/metadata_manager.h new file mode 100644 index 000000000..28eb1918f --- /dev/null +++ b/adapter/pubsub/metadata_manager.h @@ -0,0 +1,136 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_PUBSUB_ADAPTER_METADATA_MANAGER_H +#define HERMES_PUBSUB_ADAPTER_METADATA_MANAGER_H + +/** + * Standard headers + */ +#include + +#include + +/** + * Internal headers + */ +#include "datastructures.h" + +using hermes::adapter::pubsub::ClientMetadata; + +namespace hermes::adapter::pubsub { +/** + * Metadata manager for PubSub adapter + */ +class MetadataManager { + private: + /** + * Private members + */ + std::unordered_map metadata; + /** + * hermes attribute to initialize Hermes + */ + std::shared_ptr hermes; + /** + * references of how many times hermes was tried to initialize. + */ + std::atomic ref; + + public: + int mpi_rank; /**< rank of MPI processor */ + /** + * Constructor + */ + explicit MetadataManager(bool is_mpi = true) : metadata(), ref(0) { + if (is_mpi) { + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + } else { + // branch exists for testing puropses + mpi_rank = 0; + } + } + /** + * Get the instance of hermes. + */ + std::shared_ptr& GetHermes() { return hermes; } + + /** + * Initialize hermes. + */ + void InitializeHermes(const char* config_file) { + if (ref == 0) { + hermes = hapi::InitHermes(config_file, false, true); + } + ref++; + } + + /** + * Finalize hermes if reference is equal to one. Else just + * decrement the ref counter. + */ + void FinalizeHermes() { + if (ref == 1) { + hermes->Finalize(); + } + ref--; + } + + /** + check if this application is client or core + */ + bool isClient() { return hermes->IsApplicationCore(); } + + /** + * \brief Create a metadata entry for pubsub adapter for a given topic. + * \param topic name of the managed topic. + * \param stat current metadata of the topic. + * \return true, if operation was successful. + * false, if operation was unsuccessful. + */ + bool Create(const std::string& topic, const ClientMetadata& stat); + + /** + * \brief Update existing metadata entry for pubsub adapter for a given file + * handler. + * \param topic name of the managed topic. + * \param stat current metadata of the topic to replace previous one. + * \return true, if operation was successful. + * false, if operation was unsuccessful or entry doesn't exist. + * \remark Update call will not degenerate into a create call + * if topic is not being tracked. + */ + bool Update(const std::string& topic, const ClientMetadata& stat); + + /** + * \brief Delete existing metadata entry for pubsub adapter for a given file + * handler. + * \param topic name of the managed topic. + * \return true, if operation was successful. + * false, if operation was unsuccessful. + */ + bool Delete(const std::string& topic); + + /** + * \brief Find existing metadata entry for pubsub adapter for a given file + * handler. + * \param topic name of the managed topic. + * \return The metadata entry if exist. + * + * The bool in pair indicates whether metadata entry exists or not. + */ + std::pair Find(const std::string& topic); +}; + +} // namespace hermes::adapter::pubsub + +#endif // HERMES_PUBSUB_ADAPTER_METADATA_MANAGER_H diff --git a/adapter/pubsub/pubsub.cc b/adapter/pubsub/pubsub.cc new file mode 100644 index 000000000..21c739fd6 --- /dev/null +++ b/adapter/pubsub/pubsub.cc @@ -0,0 +1,177 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "pubsub.h" + +namespace hapi = hapi; + +hapi::Status hermes::pubsub::mpiInit(int argc, char **argv) { + LOG(INFO) << "Starting MPI" << std::endl; + int mpi_threads_provided; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &mpi_threads_provided); + if (mpi_threads_provided < MPI_THREAD_MULTIPLE) { + fprintf(stderr, "Didn't receive appropriate MPI threading specification\n"); + return hapi::Status(hermes::INVALID_FILE); + } + return hapi::Status(hermes::HERMES_SUCCESS); +} + +hapi::Status hermes::pubsub::connect(const std::string &config_file) { + LOG(INFO) << "Connecting adapter" << std::endl; + auto mdm = hermes::Singleton + ::GetInstance(); + try { + mdm->InitializeHermes(config_file.c_str()); + if (mdm->isClient()) { + return hapi::Status(hermes::HERMES_SUCCESS); + } else { + return hapi::Status(hermes::INVALID_FILE); + } + } catch (const std::exception& e) { + LOG(FATAL) << "Could not connect to hermes daemon" <::GetInstance(); + try { + mdm->FinalizeHermes(); + return hapi::Status(hermes::HERMES_SUCCESS); + } catch (const std::exception& e) { + LOG(FATAL) << "Could not disconnect from hermes" <::GetInstance(); + auto existing = mdm->Find(topic); + if (!existing.second) { + LOG(INFO) << "Topic not currently tracked" << std::endl; + ClientMetadata stat; + struct timespec ts{}; + timespec_get(&ts, TIME_UTC); + stat.st_atim = ts; + stat.st_bkid = std::make_shared(topic, mdm->GetHermes(), ctx); + if (!stat.st_bkid->IsValid()) return hapi::Status(hermes::INVALID_BUCKET); + if (!mdm->Create(topic, stat)) return hapi::Status(hermes::INVALID_BUCKET); + } else { + LOG(INFO) << "Topic is tracked, attaching to it" << std::endl; + struct timespec ts{}; + timespec_get(&ts, TIME_UTC); + existing.first.st_atim = ts; + if (!mdm->Update(topic, existing.first)) { + return hapi::Status(hermes::INVALID_BUCKET); + } + } + return hapi::Status(hermes::HERMES_SUCCESS); +} + +hapi::Status hermes::pubsub::detach(const std::string& topic) { + LOG(INFO) << "Detaching from topic: " << topic << std::endl; + hapi::Context ctx; + auto mdm = hermes::Singleton + ::GetInstance(); + auto existing = mdm->Find(topic); + if (existing.second) { + mdm->Delete(topic); + return existing.first.st_bkid->Release(ctx); + } + return hapi::Status(hermes::INVALID_BUCKET); +} + +hapi::Status hermes::pubsub::publish(const std::string& topic, + const hapi::Blob& message) { + LOG(INFO) << "Publish to : " << topic << std::endl; + auto mdm = hermes::Singleton + ::GetInstance(); + auto metadata = mdm->Find(topic); + + if (!metadata.second) { + if (attach(topic) == hermes::HERMES_SUCCESS) { + metadata = mdm->Find(topic); + } else { + return hapi::Status(hermes::INVALID_BUCKET); + } + } + + hapi::Context ctx; + struct timespec ts{}; + timespec_get(&ts, TIME_UTC); + + std::string blob_name = std::to_string(mdm->mpi_rank) + "_" + + std::to_string(ts.tv_nsec); + LOG(INFO) << "Publishing to blob with id " << blob_name << std::endl; + auto status = metadata.first.st_bkid->Put(blob_name, message, ctx); + if (status.Failed()) { + return hapi::Status(hermes::INVALID_BLOB); + } + + metadata.first.st_atim = ts; + mdm->Update(topic, metadata.first); + + return hapi::Status(hermes::HERMES_SUCCESS); +} + +std::pair hermes::pubsub::subscribe( + const std::string& topic) { + LOG(INFO) << "Subscribe to : " << topic << std::endl; + typedef std::pair SubscribeReturn; + + auto mdm = hermes::Singleton + ::GetInstance(); + auto metadata = mdm->Find(topic); + + if (!metadata.second) { + if (attach(topic) == hermes::HERMES_SUCCESS) { + metadata = mdm->Find(topic); + } else { + return SubscribeReturn(hapi::Blob(), + hapi::Status(hermes::INVALID_BUCKET)); + } + } + + hapi::Context ctx; + u64 index = metadata.first.last_subscribed_blob; + + hapi::Blob read_data(0); + LOG(INFO) << "Subscribing to " << topic << " at blob id " << index + << std::endl; + auto bucket = metadata.first.st_bkid; + auto exiting_blob_size = bucket->GetNext(index, read_data, ctx); + read_data.resize(exiting_blob_size); + + if (bucket->GetNext(index, read_data, ctx) != exiting_blob_size) { + return SubscribeReturn(hapi::Blob(), + hapi::Status(hermes::BLOB_NOT_IN_BUCKET)); + } + + metadata.first.last_subscribed_blob++; + struct timespec ts{}; + timespec_get(&ts, TIME_UTC); + metadata.first.st_atim = ts; + mdm->Update(topic, metadata.first); + + return SubscribeReturn(read_data, + hapi::Status(hermes::HERMES_SUCCESS)); +} diff --git a/adapter/pubsub/pubsub.h b/adapter/pubsub/pubsub.h new file mode 100644 index 000000000..8ee1e0106 --- /dev/null +++ b/adapter/pubsub/pubsub.h @@ -0,0 +1,129 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_PUBSUB_H +#define HERMES_PUBSUB_H + +/** + * Standard header + */ + +#include + +/** + * Dependent library headers + */ +#include + +/** + * Internal headers + */ +#include +#include + +#include "../constants.h" +#include "metadata_manager.h" +#include "singleton.h" + +namespace hermes::pubsub { + +/** + * \brief Helper function to initialize MPI + * + * \return The return code/status + * + */ +hapi::Status mpiInit(int argc, char** argv); + +/** + * \brief Connects to the Hermes instance + * + * \param config_file Path to the config file of Hermes + * + * \return The return code/status + * + */ +hapi::Status connect(const std::string& config_file); + +/** + * \brief Connects to the Hermes instance + * + * \return The return code/status + * + * \pre Assumes that the config file path is loaded into a environment variable + * defined in constants.h under kHermesConf + * + */ +hapi::Status connect(); + +/** + * \brief Connects from the Hermes instance + * + * \return The return code/status + */ +hapi::Status disconnect(); + +/** + * \brief Attaches to a topic, creating it if it doesnt exists. + * + * \param topic The name of the topic + * + * \return The return code/status + * + */ +hapi::Status attach(const std::string& topic); + +/** + * \brief Detaches from the topic. Cleaning up all metadata + * + * \param topic The name of the topic + * + * \return The return code/status + * + * \pre Detaching doesnt delete the topic + * + */ +hapi::Status detach(const std::string& topic); + +/** + * \brief Puts a message to a topic + * + * \param topic The name of the topic + * \param message the data buffer + * + * \return The return code/status + * + * \remark Using std::vector as equivalent to Blob + * + */ +hapi::Status publish(const std::string& topic, + const std::vector& message); + +/** + * \brief Retrieves the next message from the topic + * + * \param topic The name of the topic + * + * \return A pair of: + * the return code/status + * and, if successful, the subscribed message. + * + * \remark Message order is tracked by Hermes. Current message is tracked + * per-process by a metadata manager + * + */ +std::pair, hapi::Status> subscribe( + const std::string& topic); + +} // namespace hermes::pubsub + +#endif // HERMES_PUBSUB_H diff --git a/adapter/test/CMakeLists.txt b/adapter/test/CMakeLists.txt new file mode 100644 index 000000000..2ee65699f --- /dev/null +++ b/adapter/test/CMakeLists.txt @@ -0,0 +1,75 @@ +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHERMES_PRELOAD -DHERMES_RPC_THALLIUM") +set(ADAPTER_COMMON ${CMAKE_CURRENT_SOURCE_DIR}/catch_config.h) +set(HERMES_ADAPTER_TEST_DIR ${HERMES_ADAPTER_DIR}/test) + +find_package(Catch2 REQUIRED) +add_executable(hermes_daemon hermes_daemon.cc) +target_link_libraries(hermes_daemon -ldl -lc MPI::MPI_CXX glog::glog) +target_link_libraries(hermes_daemon hermes) +add_dependencies(hermes_daemon hermes) + +function(gcc exec args) + add_test(NAME Test${exec} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${args}) + set_property(TEST Test${exec} + PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) + set_property(TEST Test${exec} APPEND + PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) +endfunction() + +function(mpi exec mpi_proc args) + add_test(NAME Test${exec}_${mpi_proc} + COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${mpi_proc} + "${CMAKE_BINARY_DIR}/bin/${exec}" ${args} -d yes) + set_property(TEST Test${exec}_${mpi_proc} + PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) + set_property(TEST Test${exec}_${mpi_proc} APPEND + PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) +endfunction() + +find_program(BASH_PROGRAM bash) + +function(mpi_daemon test_exec test_mpi_proc test_args arg_name daemon_procs) + #MPI_EXEC=$1 TEST_EXEC=$2 TEST_PROCS=$3 HERMES_EXEC=$4 HERMES_PROCS=$5 HERMES_CONF=$6 + add_test(Test${test_exec}_${test_mpi_proc}_${arg_name} ${BASH_PROGRAM} + ${CMAKE_SOURCE_DIR}/adapter/test/run_hermes.sh ${MPIEXEC_EXECUTABLE} + ${CMAKE_BINARY_DIR}/bin/${test_exec} ${test_mpi_proc} + ${CMAKE_BINARY_DIR}/bin/hermes_daemon ${daemon_procs} + ${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml + ${test_args}) + set_property(TEST Test${test_exec}_${test_mpi_proc}_${arg_name} + PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) + set_property(TEST Test${test_exec}_${test_mpi_proc}_${arg_name} APPEND + PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) +endfunction() + +enable_testing() + +if(HERMES_ENABLE_STDIO_ADAPTER) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/stdio) +endif() + +if(HERMES_ENABLE_POSIX_ADAPTER) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/posix) +endif() + +if(HERMES_ENABLE_MPIIO_ADAPTER) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/mpiio) +endif() + +if(HERMES_ENABLE_PUBSUB_ADAPTER) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/pubsub) +endif() + +if(HERMES_ENABLE_VFD) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vfd) +endif() + +install( + TARGETS + hermes_daemon + EXPORT + ${HERMES_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} +) diff --git a/adapter/test/adapter_test_utils.h b/adapter/test/adapter_test_utils.h new file mode 100644 index 000000000..e8d4ecb64 --- /dev/null +++ b/adapter/test/adapter_test_utils.h @@ -0,0 +1,60 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_ADAPTER_TEST_UTILS_H +#define HERMES_ADAPTER_TEST_UTILS_H +#include +#include +#include + +bool FilesystemSupportsTmpfile() { + bool result = false; + +#if O_TMPFILE + // NOTE(chogan): Even if O_TMPFILE is defined, the underlying filesystem might + // not support it. + int tmp_fd = open("/tmp", O_WRONLY | O_TMPFILE, 0600); + if (tmp_fd > 0) { + result = true; + close(tmp_fd); + } +#endif + + return result; +} + +size_t GetRandomOffset(size_t i, unsigned int offset_seed, size_t stride, + size_t total_size) { + return abs((int)(((i * rand_r(&offset_seed)) % stride) % total_size)); +} + +std::string GenRandom(const int len) { + std::string tmp_s; + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + srand(100); + + tmp_s.reserve(len); + + for (int i = 0; i < len; ++i) { + tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)]; + } + + tmp_s[len - 1] = '\n'; + + return tmp_s; +} + +#endif // HERMES_ADAPTER_TEST_UTILS_H diff --git a/adapter/test/catch_config.h b/adapter/test/catch_config.h new file mode 100644 index 000000000..1317e1e50 --- /dev/null +++ b/adapter/test/catch_config.h @@ -0,0 +1,42 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_CATCH_CONFIG_H +#define HERMES_CATCH_CONFIG_H + +#define CATCH_CONFIG_RUNNER +#include + +#include + +namespace cl = Catch::Clara; + +cl::Parser define_options(); + +int init(int* argc, char*** argv); +int finalize(); + +int main(int argc, char* argv[]) { + Catch::Session session; + auto cli = session.cli() | define_options(); + int returnCode = init(&argc, &argv); + if (returnCode != 0) return returnCode; + session.cli(cli); + returnCode = session.applyCommandLine(argc, argv); + if (returnCode != 0) return returnCode; + int test_return_code = session.run(); + returnCode = finalize(); + if (returnCode != 0) return returnCode; + return test_return_code; +} + +#endif diff --git a/adapter/test/data/hermes.yaml b/adapter/test/data/hermes.yaml new file mode 100644 index 000000000..c17827c11 --- /dev/null +++ b/adapter/test/data/hermes.yaml @@ -0,0 +1,45 @@ +# Test configuration + +num_devices: 4 +num_targets: 4 + +capacities_mb: [4096, 8192, 16384, 32768] +block_sizes_kb: [4, 4, 4, 4] +num_slabs: [4, 4, 4, 4] + +slab_unit_sizes: [ + [1, 4, 16, 32], + [1, 4, 16, 32], + [1, 4, 16, 32], + [1, 4, 16, 32] +] + +desired_slab_percentages: [ + [0.25, 0.25, 0.25, 0.25], + [0.25, 0.25, 0.25, 0.25], + [0.25, 0.25, 0.25, 0.25], + [0.25, 0.25, 0.25, 0.25] +] + +bandwidths_mbps: [6000, 300, 150, 70] +latencies_us: [15, 250000, 500000, 1000000] + +buffer_pool_arena_percentage: 0.85 +metadata_arena_percentage: 0.08 +transient_arena_percentage: 0.07 + +max_buckets_per_node: 16 +max_vbuckets_per_node: 32 +system_view_state_update_interval_ms: 1000 + +mount_points: ["", "./", "./", "./"] +swap_mount: "./" +num_buffer_organizer_retries: 3 +rpc_server_base_name: "localhost" +rpc_protocol: "ofi+sockets" +rpc_port: 8080 +buffer_organizer_port: 8081 +rpc_host_number_range: [] +rpc_num_threads: 1 +buffer_organizer_num_threads: 4 +buffer_pool_shmem_name: "/hermes_buffer_pool_" diff --git a/adapter/test/data/hermes_ares.yaml b/adapter/test/data/hermes_ares.yaml new file mode 100644 index 000000000..336e34ffc --- /dev/null +++ b/adapter/test/data/hermes_ares.yaml @@ -0,0 +1,47 @@ +# Test configuration + +num_devices: 4 +num_targets: 4 + +capacities_mb: [16384, 16384, 65536, 131072] +block_sizes_kb: [4, 4, 4, 4] +num_slabs: [4, 4, 4, 4] + +slab_unit_sizes: [ + [1, 4, 16, 32], + [1, 4, 16, 32], + [1, 4, 16, 32], + [1, 4, 16, 32] +] + +desired_slab_percentages: [ + [0.25, 0.25, 0.25, 0.25], + [0.25, 0.25, 0.25, 0.25], + [0.25, 0.25, 0.25, 0.25], + [0.25, 0.25, 0.25, 0.25] +] + +bandwidths_mbps: [6000, 4000, 2000, 200] +latencies_us: [15, 250000, 500000, 1000000] + +buffer_pool_arena_percentage: 0.85 +metadata_arena_percentage: 0.08 +transient_arena_percentage: 0.07 + +max_buckets_per_node: 16 +max_vbuckets_per_node: 8 +system_view_state_update_interval_ms: 1000 + +mount_points: ["", "./", "./", "./"] +swap_mount: "./" +num_buffer_organizer_retries: 3 +rpc_server_base_name: "ares-comp-" +rpc_server_suffix: "-40g" +rpc_protocol: "ofi+sockets" +rpc_domain: "" +rpc_port: 8080 +buffer_organizer_port: 8081 +rpc_host_number_range: [20-23] +rpc_num_threads: 4 +buffer_organizer_num_threads: 4 +buffer_pool_shmem_name: "/hermes_buffer_pool_" \ No newline at end of file diff --git a/adapter/test/data/hermes_small.yaml b/adapter/test/data/hermes_small.yaml new file mode 100644 index 000000000..d72ad420a --- /dev/null +++ b/adapter/test/data/hermes_small.yaml @@ -0,0 +1,46 @@ +# Test configuration + +num_devices: 4 +num_targets: 4 + +#2 is used for RAM because some space is taken by the Arena. +capacities_mb: [2, 1, 1, 1] +block_sizes_kb: [4, 4, 4, 4] +num_slabs: [4, 4, 4, 4] + +slab_unit_sizes: [ + [1, 4, 16, 32], + [1, 4, 16, 32], + [1, 4, 16, 32], + [1, 4, 16, 32], +] + +desired_slab_percentages: [ + [0.25, 0.25, 0.25, 0.25], + [0.25, 0.25, 0.25, 0.25], + [0.25, 0.25, 0.25, 0.25], + [0.25, 0.25, 0.25, 0.25], +] + +bandwidths_mbps: [6000, 300, 150, 70] +latencies_us: [15, 250000, 500000, 1000000] + +buffer_pool_arena_percentage: 0.85 +metadata_arena_percentage: 0.08 +transient_arena_percentage: 0.07 + +max_buckets_per_node: 16 +max_vbuckets_per_node: 8 +system_view_state_update_interval_ms: 1000 + +mount_points: ["", "./", "./", "./"] +swap_mount: "./" +num_buffer_organizer_retries: 3 +rpc_server_base_name: "localhost" +rpc_protocol: "ofi+sockets" +rpc_port: 8080 +buffer_organizer_port: 8081 +rpc_host_number_range: [] +rpc_num_threads: 1 +buffer_organizer_num_threads: 4 +buffer_pool_shmem_name: "/hermes_buffer_pool_" diff --git a/adapter/test/mpiio/CMakeLists.txt b/adapter/test/mpiio/CMakeLists.txt new file mode 100644 index 000000000..cfd3a2ab1 --- /dev/null +++ b/adapter/test/mpiio/CMakeLists.txt @@ -0,0 +1,46 @@ +add_executable(mpiio_adapter_test mpiio_adapter_test.cpp ${ADAPTER_COMMON}) +mpi(mpiio_adapter_test 2 "") + +add_executable(hermes_mpiio_adapter_test mpiio_adapter_test.cpp ${ADAPTER_COMMON}) +target_link_libraries(hermes_mpiio_adapter_test hermes_mpiio) +add_dependencies(hermes_mpiio_adapter_test hermes_mpiio hermes_daemon) +set_target_properties(hermes_mpiio_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") + +mpi_daemon(hermes_mpiio_adapter_test 2 "[synchronicity=async] -d yes" "async" 1) +mpi_daemon(hermes_mpiio_adapter_test 2 "[synchronicity=sync] -d yes" "sync" 1) + +set(MPIIO_TESTS + mpiio_adapter_test + hermes_mpiio_adapter_test +) + +foreach(program ${MPIIO_TESTS}) + target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_DIR}) + target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_TEST_DIR}) + target_link_libraries(${program} Catch2::Catch2 -lstdc++fs -lc MPI::MPI_CXX) +endforeach() + +if(HERMES_INSTALL_TESTS) + foreach(program ${MPIIO_TESTS}) + install( + TARGETS + ${program} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} + ) + endforeach() +endif() + +add_executable(mpi_parallel parallel.cc) +add_dependencies(mpi_parallel hermes_mpiio hermes_daemon) +target_link_libraries(mpi_parallel hermes_mpiio Catch2::Catch2 -lstdc++fs -lc MPI::MPI_CXX) +set_target_properties(mpi_parallel PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") + +install( + TARGETS + mpi_parallel + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} +) \ No newline at end of file diff --git a/adapter/test/mpiio/mpiio_adapter_basic_test.cpp b/adapter/test/mpiio/mpiio_adapter_basic_test.cpp new file mode 100644 index 000000000..9035bd5d4 --- /dev/null +++ b/adapter/test/mpiio/mpiio_adapter_basic_test.cpp @@ -0,0 +1,1044 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +TEST_CASE("Open", "[process=" + std::to_string(info.comm_size) + + "]" + "[coordination=independent]" + "[synchronicity=sync]" + "[operation=single_open]" + "[repetition=1][file=1]") { + pretest(); + SECTION("open non-existant file") { + test::test_open(info.new_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(test::status_orig != MPI_SUCCESS); + test::test_open(info.new_file.c_str(), MPI_MODE_RDWR | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(test::status_orig != MPI_SUCCESS); + } + + SECTION("opening existing file write-only") { + test::test_open(info.existing_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + SECTION("opening existing file and read/write") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("open existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(test::status_orig != MPI_SUCCESS); + test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("append write existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_APPEND | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(test::status_orig != MPI_SUCCESS); + test::test_open(info.existing_file.c_str(), MPI_MODE_APPEND, MPI_COMM_SELF); + REQUIRE(test::status_orig != MPI_SUCCESS); + test::test_open(info.existing_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_APPEND, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_open(info.existing_file.c_str(), + MPI_MODE_RDONLY | MPI_MODE_APPEND, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR | MPI_MODE_APPEND, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("append write and read new file") { + test::test_open(info.existing_file.c_str(), + MPI_MODE_RDWR | MPI_MODE_APPEND | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("delete on close mode") { + test::test_open( + info.new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::exists(info.new_file.c_str())); + test::test_close(); + REQUIRE(!stdfs::exists(info.new_file.c_str())); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + posttest(); +} + +TEST_CASE("OpenCollective", "[process=" + std::to_string(info.comm_size) + + "]" + "[coordination=collective]" + "[synchronicity=sync]" + "[operation=single_open]" + "[repetition=1][file=1]") { + pretest(); + SECTION("open on non-existant shared file") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_RDONLY | MPI_MODE_EXCL, MPI_COMM_WORLD); + REQUIRE(test::status_orig != MPI_SUCCESS); + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_RDONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig != MPI_SUCCESS); + test::test_open(info.shared_new_file.c_str(), MPI_MODE_RDWR | MPI_MODE_EXCL, + MPI_COMM_WORLD); + REQUIRE(test::status_orig != MPI_SUCCESS); + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_RDWR | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("open on shared existing file") { + test::test_open(info.shared_existing_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_EXCL, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_open(info.shared_existing_file.c_str(), + MPI_MODE_RDWR | MPI_MODE_EXCL, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_open(info.shared_existing_file.c_str(), + MPI_MODE_RDONLY | MPI_MODE_EXCL, MPI_COMM_WORLD); + REQUIRE(test::status_orig != MPI_SUCCESS); + test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDWR, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("append write/read on shared existing file") { + test::test_open(info.shared_existing_file.c_str(), + MPI_MODE_RDWR | MPI_MODE_APPEND, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("append write and read on shared new file") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_RDWR | MPI_MODE_APPEND | MPI_MODE_CREATE, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("delete on close mode on new file") { + test::test_open( + info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(!stdfs::exists(info.shared_new_file.c_str())); + } + posttest(); +} + +TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_write]" + "[synchronicity=sync]" + "[coordination=independent]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + bool check_bytes = true; + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("write to new file") { + test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); + } + + SECTION("write to new file with allocate") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_preallocate(args.request_size * info.comm_size); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(args.request_size * info.rank, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + MPI_Barrier(MPI_COMM_WORLD); + REQUIRE(stdfs::file_size(info.shared_new_file) == + (size_t)test::size_written_orig * info.comm_size); + } + + SECTION("append to existing file") { + auto existing_size = stdfs::file_size(info.existing_file); + test::test_open(info.existing_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.existing_file) == + existing_size + test::size_written_orig); + } + + SECTION("append to new file") { + test::test_open(info.new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); + } + + SECTION("write_at to existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_write_at(info.write_data.c_str(), args.request_size, MPI_CHAR, + info.rank * args.request_size); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("write_at to new file") { + test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_write_at(info.write_data.c_str(), args.request_size, MPI_CHAR, + 0); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); + } + + SECTION("delete on close mode on new file") { + test::test_open( + info.new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + REQUIRE(stdfs::exists(info.new_file.c_str())); + test::test_close(); + REQUIRE(!stdfs::exists(info.new_file.c_str())); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("delete on close mode on existing file") { + auto original_size = stdfs::file_size(info.existing_file); + test::test_open(info.existing_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_EXCL | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + REQUIRE(stdfs::exists(info.existing_file.c_str())); + auto new_size = + original_size > (size_t)test::size_written_orig * info.comm_size + ? original_size + : test::size_written_orig * info.comm_size; + REQUIRE(stdfs::file_size(info.existing_file) == (size_t)new_size); + test::test_close(); + REQUIRE(!stdfs::exists(info.existing_file.c_str())); + REQUIRE(test::status_orig == MPI_SUCCESS); + check_bytes = false; + } + posttest(check_bytes); +} + +TEST_CASE("SingleWriteCollective", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_write]" + "[synchronicity=sync]" + "[coordination=collective]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + bool check_bytes = true; + SECTION("write to existing file") { + test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDWR, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("write to new file") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.shared_new_file) == + (size_t)test::size_written_orig); + } + + // TODO(chogan): This test fails intermittently. Needs diagnosis. + // https://github.com/HDFGroup/hermes/issues/209 + SECTION("write to new file using shared ptr") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write_shared(info.write_data.c_str(), args.request_size, + MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.shared_new_file) == + (size_t)test::size_written_orig * info.comm_size); + } + + SECTION("write to new file with allocate") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_preallocate(args.request_size * info.comm_size); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(args.request_size * info.rank, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + MPI_Barrier(MPI_COMM_WORLD); + REQUIRE(stdfs::file_size(info.shared_new_file) == + (size_t)test::size_written_orig * info.comm_size); + } + + SECTION("write_at_all to existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_write_at_all(info.write_data.c_str(), args.request_size, + MPI_CHAR, info.rank * args.request_size); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("write_at_all to new file") { + test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_write_at_all(info.write_data.c_str(), args.request_size, + MPI_CHAR, 0); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); + } + + SECTION("append to existing file") { + auto existing_size = stdfs::file_size(info.existing_file); + test::test_open(info.shared_existing_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_write_all(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.shared_existing_file) == + existing_size + test::size_written_orig); + } + + SECTION("append to new file") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_write_all(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.shared_new_file) == + (size_t)test::size_written_orig); + } + + SECTION("write_ordered to existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_write_ordered(info.write_data.c_str(), args.request_size, + MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("write_ordered to new file") { + test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_write_ordered(info.write_data.c_str(), args.request_size, + MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); + } + SECTION("delete on close mode on new file") { + test::test_open( + info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + REQUIRE(stdfs::exists(info.shared_new_file.c_str())); + MPI_Barrier(MPI_COMM_WORLD); + test::test_close(); + REQUIRE(!stdfs::exists(info.shared_new_file.c_str())); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("delete on close mode on existing file") { + auto original_size = stdfs::file_size(info.shared_existing_file); + test::test_open(info.shared_existing_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_EXCL | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + REQUIRE(stdfs::exists(info.shared_existing_file.c_str())); + auto new_size = + original_size > (size_t)test::size_written_orig * info.comm_size + ? original_size + : test::size_written_orig * info.comm_size; + REQUIRE(stdfs::file_size(info.shared_existing_file) == (size_t)new_size); + test::test_close(); + REQUIRE(!stdfs::exists(info.shared_existing_file.c_str())); + REQUIRE(test::status_orig == MPI_SUCCESS); + check_bytes = false; + } + posttest(check_bytes); +} + +TEST_CASE("SingleAsyncWrite", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_write]" + "[coordination=independent]" + "[synchronicity=async]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + bool check_bytes = true; + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("write to new file") { + test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); + } + + SECTION("write to new file using shared ptr") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iwrite_shared(info.write_data.c_str(), args.request_size, + MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.shared_new_file) == + (size_t)test::size_written_orig * info.comm_size); + } + + SECTION("write to new file with allocate") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_preallocate(args.request_size * info.comm_size); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(args.request_size * info.rank, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + MPI_Barrier(MPI_COMM_WORLD); + REQUIRE(stdfs::file_size(info.shared_new_file) == + (size_t)test::size_written_orig * info.comm_size); + } + + SECTION("append to existing file") { + auto existing_size = stdfs::file_size(info.existing_file); + test::test_open(info.existing_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.existing_file) == + existing_size + test::size_written_orig); + } + + SECTION("append to new file") { + test::test_open(info.new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); + } + + SECTION("write_at to existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_iwrite_at(info.write_data.c_str(), args.request_size, MPI_CHAR, + info.rank * args.request_size); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("write_at to new file") { + test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_iwrite_at(info.write_data.c_str(), args.request_size, MPI_CHAR, + 0); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); + } + + SECTION("delete on close mode on new file") { + test::test_open( + info.new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + REQUIRE(stdfs::exists(info.new_file.c_str())); + test::test_close(); + REQUIRE(!stdfs::exists(info.new_file.c_str())); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("delete on close mode on existing file") { + test::test_open(info.existing_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_EXCL | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + REQUIRE(stdfs::exists(info.existing_file.c_str())); + test::test_close(); + REQUIRE(!stdfs::exists(info.existing_file.c_str())); + REQUIRE(test::status_orig == MPI_SUCCESS); + check_bytes = false; + } + posttest(check_bytes); +} + +TEST_CASE("SingleAsyncWriteCollective", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_write]" + "[synchronicity=async]" + "[coordination=collective]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + bool check_bytes = true; + SECTION("write to existing file") { + test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDWR, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("write to new file") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.shared_new_file) == + (size_t)test::size_written_orig); + } + + SECTION("write to new file using shared ptr") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iwrite_shared(info.write_data.c_str(), args.request_size, + MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.shared_new_file) == + (size_t)test::size_written_orig * info.comm_size); + } + + SECTION("write to new file with allocate") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_preallocate(args.request_size * info.comm_size); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(args.request_size * info.rank, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + MPI_Barrier(MPI_COMM_WORLD); + REQUIRE(stdfs::file_size(info.shared_new_file) == + (size_t)test::size_written_orig * info.comm_size); + } + + SECTION("write_at_all to existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_iwrite_at_all(info.write_data.c_str(), args.request_size, + MPI_CHAR, info.rank * args.request_size); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("write_at_all to new file") { + test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_iwrite_at_all(info.write_data.c_str(), args.request_size, + MPI_CHAR, 0); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); + } + SECTION("append to existing file") { + auto existing_size = stdfs::file_size(info.existing_file); + test::test_open(info.shared_existing_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_iwrite_all(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.shared_existing_file) == + existing_size + test::size_written_orig); + } + + SECTION("append to new file") { + test::test_open(info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_iwrite_all(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + REQUIRE(stdfs::file_size(info.shared_new_file) == + (size_t)test::size_written_orig); + } + SECTION("delete on close mode on new file") { + test::test_open( + info.shared_new_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + REQUIRE(stdfs::exists(info.shared_new_file.c_str())); + test::test_close(); + REQUIRE(!stdfs::exists(info.shared_new_file.c_str())); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("delete on close mode on existing file") { + auto original_size = stdfs::file_size(info.shared_existing_file); + test::test_open(info.shared_existing_file.c_str(), + MPI_MODE_WRONLY | MPI_MODE_EXCL | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_written_orig == args.request_size); + REQUIRE(stdfs::exists(info.shared_existing_file.c_str())); + auto new_size = + original_size > (size_t)test::size_written_orig * info.comm_size + ? original_size + : test::size_written_orig * info.comm_size; + REQUIRE(stdfs::file_size(info.shared_existing_file) == (size_t)new_size); + test::test_close(); + REQUIRE(!stdfs::exists(info.shared_existing_file.c_str())); + REQUIRE(test::status_orig == MPI_SUCCESS); + check_bytes = false; + } + posttest(check_bytes); +} + +TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_read]" + "[synchronicity=sync]" + "[coordination=independent]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + SECTION("read from non-existing file") { + test::test_open(info.new_file.c_str(), MPI_MODE_RDONLY | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(test::status_orig != MPI_SUCCESS); + } + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_read(info.read_data.data(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("read from existing file using shared ptr") { + test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_read_shared(info.read_data.data(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("read at the end of existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(0, MPI_SEEK_END); + REQUIRE(test::status_orig == MPI_SUCCESS); + MPI_Offset offset; + MPI_File_get_position(test::fh_orig, &offset); + REQUIRE(offset == (long long)(args.request_size * info.num_iterations)); + test::test_read(info.read_data.data(), args.request_size, MPI_CHAR); + REQUIRE(test::size_read_orig == 0); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("read_at from existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_read_at(info.read_data.data(), args.request_size, MPI_CHAR, + info.rank * args.request_size); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + posttest(); +} + +TEST_CASE("SingleReadCollective", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_read]" + "[synchronicity=sync]" + "[coordination=collective]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + SECTION("read from non-existing file") { + test::test_open(info.shared_new_file.c_str(), MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(test::status_orig != MPI_SUCCESS); + } + + SECTION("read from existing file") { + test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_read_all(info.read_data.data(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("read from existing file using shared ptr") { + test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_read_shared(info.read_data.data(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("read_at_all from existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_read_at_all(info.read_data.data(), args.request_size, MPI_CHAR, + info.rank * args.request_size); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("read_ordered from existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_read_ordered(info.read_data.data(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + posttest(); +} + +TEST_CASE("SingleAsyncRead", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_read]" + "[synchronicity=async]" + "[coordination=independent]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + SECTION("read from non-existing file") { + test::test_open(info.new_file.c_str(), MPI_MODE_RDONLY | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(test::status_orig != MPI_SUCCESS); + } + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iread(info.read_data.data(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("read from existing file using shared ptr") { + test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, + MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iread_shared(info.read_data.data(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("read at the end of existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(0, MPI_SEEK_END); + REQUIRE(test::status_orig == MPI_SUCCESS); + MPI_Offset offset; + MPI_File_get_position(test::fh_orig, &offset); + REQUIRE(offset == (long long)(args.request_size * info.num_iterations)); + test::test_iread(info.read_data.data(), args.request_size, MPI_CHAR); + REQUIRE(test::size_read_orig == 0); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("read_at from existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_iread_at(info.read_data.data(), args.request_size, MPI_CHAR, + info.rank * args.request_size); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + posttest(); +} + +// TODO(chogan): This test fails sporadically. +// https://github.com/HDFGroup/hermes/issues/413 +TEST_CASE("SingleAsyncReadCollective", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_read]" + "[synchronicity=async]" + "[coordination=collective]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + SECTION("read from non-existing file") { + test::test_open(info.shared_new_file.c_str(), MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(test::status_orig != MPI_SUCCESS); + } + + SECTION("read from existing file") { + test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iread_all(info.read_data.data(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("read from existing file using shared ptr") { + test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_iread_shared(info.read_data.data(), args.request_size, MPI_CHAR); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + + SECTION("read_at_all from existing file") { + test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(test::status_orig == MPI_SUCCESS); + test::test_iread_at_all(info.read_data.data(), args.request_size, MPI_CHAR, + info.rank * args.request_size); + REQUIRE((size_t)test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == MPI_SUCCESS); + } + posttest(); +} diff --git a/adapter/test/mpiio/mpiio_adapter_test.cpp b/adapter/test/mpiio/mpiio_adapter_test.cpp new file mode 100644 index 000000000..70dc5c018 --- /dev/null +++ b/adapter/test/mpiio/mpiio_adapter_test.cpp @@ -0,0 +1,673 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include +#include + +#include "adapter_test_utils.h" +#include "catch_config.h" +#if HERMES_INTERCEPT == 1 +#include "filesystem/filesystem.h" +#endif + +#include "adapter_test_utils.h" + +namespace stdfs = std::experimental::filesystem; + +namespace hermes::adapter::mpiio::test { +struct Arguments { + std::string filename = "test.dat"; + std::string directory = "/tmp"; + size_t request_size = 65536; +}; +struct Info { + bool debug = false; + int rank = 0; + int comm_size = 1; + std::string write_data; + std::string read_data; + std::string new_file; + std::string existing_file; + std::string shared_new_file; + std::string shared_existing_file; + std::string new_file_cmp; + std::string existing_file_cmp; + std::string shared_new_file_cmp; + std::string shared_existing_file_cmp; + size_t num_iterations = 64; + unsigned int offset_seed = 1; + unsigned int rs_seed = 1; + unsigned int temporal_interval_seed = 5; + size_t total_size; + size_t stride_size = 512; + unsigned int temporal_interval_ms = 1; + size_t small_min = 1, small_max = 4 * 1024; + size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; + size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; +}; +} // namespace hermes::adapter::mpiio::test +hermes::adapter::mpiio::test::Arguments args; +hermes::adapter::mpiio::test::Info info; + +int init(int* argc, char*** argv) { + MPI_Init(argc, argv); + info.write_data = GenRandom(args.request_size); + info.read_data = std::string(args.request_size, 'r'); + MPI_Comm_rank(MPI_COMM_WORLD, &info.rank); + MPI_Comm_size(MPI_COMM_WORLD, &info.comm_size); + if (info.debug && info.rank == 0) { + printf("ready for attach\n"); + fflush(stdout); + sleep(30); + } + MPI_Barrier(MPI_COMM_WORLD); + return 0; +} +int finalize() { + MPI_Finalize(); + return 0; +} + +const char* kUser = "USER"; + +int pretest() { + stdfs::path fullpath = args.directory; + fullpath /= args.filename + "_" + std::string(getenv(kUser)); + info.new_file = fullpath.string() + "_new_" + std::to_string(getpid()); + info.existing_file = fullpath.string() + "_ext_" + std::to_string(getpid()); + info.new_file_cmp = + fullpath.string() + "_new_cmp" + "_" + std::to_string(getpid()); + info.existing_file_cmp = + fullpath.string() + "_ext_cmp" + "_" + std::to_string(getpid()); + info.shared_new_file = + fullpath.string() + "_shared_new_" + std::to_string(info.comm_size); + info.shared_existing_file = + fullpath.string() + "_shared_ext_" + std::to_string(info.comm_size); + info.shared_new_file_cmp = + fullpath.string() + "_shared_new_cmp_" + std::to_string(info.comm_size); + info.shared_existing_file_cmp = + fullpath.string() + "_shared_ext_cmp_" + std::to_string(info.comm_size); + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + if (!stdfs::exists(info.existing_file)) { + std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + + std::to_string(args.request_size * info.num_iterations) + + "; } > " + info.existing_file + " 2> /dev/null"; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file) == + args.request_size * info.num_iterations); + info.total_size = stdfs::file_size(info.existing_file); + } + MPI_Barrier(MPI_COMM_WORLD); + if (!stdfs::exists(info.existing_file_cmp)) { + std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file_cmp) == + args.request_size * info.num_iterations); + } + MPI_Barrier(MPI_COMM_WORLD); + if (info.rank == 0) { + if (stdfs::exists(info.shared_new_file)) + stdfs::remove(info.shared_new_file); + if (stdfs::exists(info.shared_existing_file)) + stdfs::remove(info.shared_existing_file); + if (!stdfs::exists(info.shared_existing_file)) { + std::string cmd = + "cp " + info.existing_file + " " + info.shared_existing_file; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.shared_existing_file) == + args.request_size * info.num_iterations); + } + if (stdfs::exists(info.shared_new_file_cmp)) + stdfs::remove(info.shared_new_file_cmp); + if (stdfs::exists(info.shared_existing_file_cmp)) + stdfs::remove(info.shared_existing_file_cmp); + if (!stdfs::exists(info.shared_existing_file_cmp)) { + std::string cmd = + "cp " + info.existing_file + " " + info.shared_existing_file_cmp; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.shared_existing_file_cmp) == + args.request_size * info.num_iterations); + } + } + MPI_Barrier(MPI_COMM_WORLD); + REQUIRE(info.total_size > 0); +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.shared_new_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert( + info.shared_existing_file_cmp); +#endif + return 0; +} + +int posttest(bool compare_data = true) { +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); +#endif + if (compare_data && stdfs::exists(info.new_file) && + stdfs::exists(info.new_file_cmp)) { + size_t size = stdfs::file_size(info.new_file); + REQUIRE(size == stdfs::file_size(info.new_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.new_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + if (compare_data && stdfs::exists(info.existing_file) && + stdfs::exists(info.existing_file_cmp)) { + size_t size = stdfs::file_size(info.existing_file); + if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); + REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + /* Clean up. */ + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); +#endif + return 0; +} + +cl::Parser define_options() { + return cl::Opt(args.filename, "filename")["-f"]["--filename"]( + "Filename used for performing I/O") | + cl::Opt(args.directory, "dir")["-d"]["--directory"]( + "Directory used for performing I/O") | + cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( + "Request size used for performing I/O"); +} + +namespace test { +MPI_File fh_orig; +MPI_File fh_cmp; +int status_orig; +int size_read_orig; +int size_written_orig; + +void test_read_data(size_t size_read, size_t count, int type_size, + char* read_data, char* ptr) { + if (size_read > 0) { + size_t unmatching_chars = 0; + for (size_t i = 0; i < count * type_size; ++i) { + if (read_data[i] != ptr[i]) { + unmatching_chars = i; + break; + } + } + REQUIRE(unmatching_chars == 0); + } +} + +void test_open(const char* path, int mode, MPI_Comm comm) { + std::string cmp_path; + if (strcmp(path, info.new_file.c_str()) == 0) { + cmp_path = info.new_file_cmp; + } else if (strcmp(path, info.existing_file.c_str()) == 0) { + cmp_path = info.existing_file_cmp; + } else if (strcmp(path, info.shared_new_file.c_str()) == 0) { + cmp_path = info.shared_new_file_cmp; + } else { + cmp_path = info.shared_existing_file_cmp; + } + status_orig = MPI_File_open(comm, path, mode, MPI_INFO_NULL, &fh_orig); + auto status_cmp = + MPI_File_open(comm, cmp_path.c_str(), mode, MPI_INFO_NULL, &fh_cmp); + bool is_same = (status_orig != MPI_SUCCESS && status_cmp != MPI_SUCCESS) || + (status_orig == MPI_SUCCESS && status_cmp == MPI_SUCCESS); + REQUIRE(is_same); +} +void test_close() { + status_orig = MPI_File_close(&fh_orig); + int status = MPI_File_close(&fh_cmp); + REQUIRE(status == status_orig); +} + +void test_preallocate(MPI_Offset size) { + status_orig = MPI_File_preallocate(fh_orig, size); + int status = MPI_File_preallocate(fh_cmp, size); + REQUIRE(status == status_orig); +} + +void test_write(const void* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = MPI_File_write(fh_orig, ptr, count, datatype, &stat_orig); + int size_written; + auto ret_cmp = MPI_File_write(fh_cmp, ptr, count, datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_written_orig); + MPI_Get_count(&stat_cmp, datatype, &size_written); + REQUIRE(size_written == size_written_orig); +} + +void test_iwrite(const void* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = MPI_File_iwrite(fh_orig, ptr, count, datatype, &request[0]); + int size_written; + auto ret_cmp = MPI_File_iwrite(fh_cmp, ptr, count, datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_written_orig); + MPI_Get_count(&stat[1], datatype, &size_written); + REQUIRE(size_written == size_written_orig); +} + +void test_write_shared(const void* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_write_shared(fh_orig, ptr, count, datatype, &stat_orig); + int size_written; + auto ret_cmp = MPI_File_write_shared(fh_cmp, ptr, count, datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_written_orig); + MPI_Get_count(&stat_cmp, datatype, &size_written); + REQUIRE(size_written == size_written_orig); +} + +void test_iwrite_shared(const void* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iwrite_shared(fh_orig, ptr, count, datatype, &request[0]); + int size_written; + auto ret_cmp = + MPI_File_iwrite_shared(fh_cmp, ptr, count, datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_written_orig); + MPI_Get_count(&stat[1], datatype, &size_written); + REQUIRE(size_written == size_written_orig); +} + +void test_write_all(const void* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = MPI_File_write_all(fh_orig, ptr, count, datatype, &stat_orig); + int size_written; + auto ret_cmp = MPI_File_write_all(fh_cmp, ptr, count, datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_written_orig); + MPI_Get_count(&stat_cmp, datatype, &size_written); + REQUIRE(size_written == size_written_orig); +} + +void test_iwrite_all(const void* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iwrite_all(fh_orig, ptr, count, datatype, &request[0]); + int size_written; + auto ret_cmp = MPI_File_iwrite_all(fh_cmp, ptr, count, datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_written_orig); + MPI_Get_count(&stat[1], datatype, &size_written); + REQUIRE(size_written == size_written_orig); +} + +void test_write_at(const void* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_write_at(fh_orig, offset, ptr, count, datatype, &stat_orig); + int size_written; + auto ret_cmp = + MPI_File_write_at(fh_cmp, offset, ptr, count, datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_written_orig); + MPI_Get_count(&stat_cmp, datatype, &size_written); + REQUIRE(size_written == size_written_orig); +} + +void test_iwrite_at(const void* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iwrite_at(fh_orig, offset, ptr, count, datatype, &request[0]); + int size_written; + auto ret_cmp = + MPI_File_iwrite_at(fh_cmp, offset, ptr, count, datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_written_orig); + MPI_Get_count(&stat[0], datatype, &size_written); + REQUIRE(size_written == size_written_orig); +} + +void test_write_at_all(const void* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_write_at_all(fh_orig, offset, ptr, count, datatype, &stat_orig); + int size_written; + auto ret_cmp = + MPI_File_write_at_all(fh_cmp, offset, ptr, count, datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_written_orig); + MPI_Get_count(&stat_cmp, datatype, &size_written); + REQUIRE(size_written == size_written_orig); +} + +void test_iwrite_at_all(const void* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = MPI_File_iwrite_at_all(fh_orig, offset, ptr, count, datatype, + &request[0]); + int size_written; + auto ret_cmp = + MPI_File_iwrite_at_all(fh_cmp, offset, ptr, count, datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_written_orig); + MPI_Get_count(&stat[1], datatype, &size_written); + REQUIRE(size_written == size_written_orig); +} + +void test_write_ordered(const void* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_write_ordered(fh_orig, ptr, count, datatype, &stat_orig); + int size_written; + auto ret_cmp = + MPI_File_write_ordered(fh_cmp, ptr, count, datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_written_orig); + MPI_Get_count(&stat_cmp, datatype, &size_written); + REQUIRE(size_written == size_written_orig); +} + +void test_read(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = MPI_File_read(fh_orig, ptr, count, datatype, &stat_orig); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = + MPI_File_read(fh_cmp, read_data.data(), count, datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_read_orig); + MPI_Get_count(&stat_cmp, datatype, &size_read); + REQUIRE(size_read == size_read_orig); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); +} + +void test_iread(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = MPI_File_iread(fh_orig, ptr, count, datatype, &request[0]); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = + MPI_File_iread(fh_cmp, read_data.data(), count, datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_read_orig); + MPI_Get_count(&stat[1], datatype, &size_read); + REQUIRE(size_read == size_read_orig); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); +} + +void test_read_shared(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_read_shared(fh_orig, ptr, count, datatype, &stat_orig); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_read_shared(fh_cmp, read_data.data(), count, datatype, + &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_read_orig); + MPI_Get_count(&stat_cmp, datatype, &size_read); + REQUIRE(size_read == size_read_orig); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); +} + +void test_iread_shared(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iread_shared(fh_orig, ptr, count, datatype, &request[0]); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_iread_shared(fh_cmp, read_data.data(), count, + datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_read_orig); + MPI_Get_count(&stat[1], datatype, &size_read); + REQUIRE(size_read == size_read_orig); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); +} + +void test_read_all(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = MPI_File_read_all(fh_orig, ptr, count, datatype, &stat_orig); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = + MPI_File_read_all(fh_cmp, read_data.data(), count, datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_read_orig); + MPI_Get_count(&stat_cmp, datatype, &size_read); + REQUIRE(size_read == size_read_orig); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); +} + +void test_iread_all(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iread_all(fh_orig, ptr, count, datatype, &request[0]); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_iread_all(fh_cmp, read_data.data(), count, datatype, + &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_read_orig); + MPI_Get_count(&stat[1], datatype, &size_read); + REQUIRE(size_read == size_read_orig); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); +} + +void test_read_ordered(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_read_ordered(fh_orig, ptr, count, datatype, &stat_orig); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_read_ordered(fh_cmp, read_data.data(), count, + datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_read_orig); + MPI_Get_count(&stat_cmp, datatype, &size_read); + REQUIRE(size_read == size_read_orig); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); +} + +void test_read_at(char* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_read_at(fh_orig, offset, ptr, count, datatype, &stat_orig); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_read_at(fh_cmp, offset, read_data.data(), count, + datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_read_orig); + MPI_Get_count(&stat_cmp, datatype, &size_read); + REQUIRE(size_read == size_read_orig); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); +} + +void test_iread_at(char* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iread_at(fh_orig, offset, ptr, count, datatype, &request[0]); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_iread_at(fh_cmp, offset, read_data.data(), count, + datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_read_orig); + MPI_Get_count(&stat[1], datatype, &size_read); + REQUIRE(size_read == size_read_orig); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); +} + +void test_read_at_all(char* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_read_at_all(fh_orig, offset, ptr, count, datatype, &stat_orig); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_read_at_all(fh_cmp, offset, read_data.data(), count, + datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_read_orig); + MPI_Get_count(&stat_cmp, datatype, &size_read); + REQUIRE(size_read == size_read_orig); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); +} + +void test_iread_at_all(char* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iread_at_all(fh_orig, offset, ptr, count, datatype, &request[0]); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_iread_at_all(fh_cmp, offset, read_data.data(), count, + datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_read_orig); + MPI_Get_count(&stat[1], datatype, &size_read); + REQUIRE(size_read == size_read_orig); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); +} + +void test_seek(MPI_Offset offset, int whence) { + status_orig = MPI_File_seek(fh_orig, offset, whence); + int status = MPI_File_seek(fh_cmp, offset, whence); + REQUIRE(status == status_orig); +} + +void test_seek_shared(MPI_Offset offset, int whence) { + status_orig = MPI_File_seek_shared(fh_orig, offset, whence); + int status = MPI_File_seek_shared(fh_cmp, offset, whence); + REQUIRE(status == status_orig); +} +} // namespace test + +#include "mpiio_adapter_basic_test.cpp" diff --git a/adapter/test/mpiio/parallel.cc b/adapter/test/mpiio/parallel.cc new file mode 100644 index 000000000..9f91a59b5 --- /dev/null +++ b/adapter/test/mpiio/parallel.cc @@ -0,0 +1,46 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "mpi.h" +#include +#include +#include +#include + +namespace stdfs = std::experimental::filesystem; + +int main(int argc, char **argv) { + MPI_File f; + MPI_Status status; + int count = 1024 * 1024 / 8; + int rank, nprocs; + MPI_Init(&argc, &argv); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nprocs); + std::string path = argv[1]; + std::vector buf(count, rank); + if (rank == 0) { + FILE *fp = fopen(path.c_str(), "w"); + std::vector init(count*nprocs, -1); + fwrite(init.data(), 1, count*nprocs, fp); + fclose(fp); + } + MPI_Barrier(MPI_COMM_WORLD); + + MPI_File_open(MPI_COMM_WORLD, path.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_INFO_NULL, &f); + MPI_File_write_at(f, rank*count, buf.data(), count, + MPI_CHAR, &status); + MPI_File_sync(f); + MPI_File_close(&f); + MPI_Finalize(); +} diff --git a/adapter/test/posix/CMakeLists.txt b/adapter/test/posix/CMakeLists.txt new file mode 100644 index 000000000..7b7ac5b58 --- /dev/null +++ b/adapter/test/posix/CMakeLists.txt @@ -0,0 +1,73 @@ +function(gcc_hermes exec tag_name tags conf) + add_test(NAME Test${exec}_${tag_name} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) + set_property(TEST Test${exec}_${tag_name} + PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/${conf}.yaml) + set_property(TEST Test${exec}_${tag_name} APPEND + PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) +endfunction() + +function(gcc_hermes_mode exec tag_name tags mode path) + set(test_name Test${exec}_${tag_name}_${mode}_${path}) + add_test(NAME ${test_name} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) + set_property(TEST ${test_name} + PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) + set_property(TEST ${test_name} APPEND + PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) + set_property(TEST ${test_name} APPEND + PROPERTY ENVIRONMENT ADAPTER_MODE=${mode}) + set_property(TEST ${test_name} APPEND + PROPERTY ENVIRONMENT SET_PATH=${path}) +endfunction() + +#------------------------------------------------------------------------------ +# Posix Adapter tests +#------------------------------------------------------------------------------ + +add_executable(posix_adapter_test posix_adapter_test.cpp ${ADAPTER_COMMON}) +gcc(posix_adapter_test "") + +add_executable(posix_adapter_mpi_test posix_adapter_mpi_test.cpp ${ADAPTER_COMMON}) +mpi(posix_adapter_mpi_test 2 "") + +add_executable(hermes_posix_adapter_test posix_adapter_test.cpp ${ADAPTER_COMMON}) +target_link_libraries(hermes_posix_adapter_test hermes_posix) +add_dependencies(hermes_posix_adapter_test hermes_posix hermes_daemon) +set_target_properties(hermes_posix_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") +gcc_hermes(hermes_posix_adapter_test "" "~[request_size=range-large]" hermes) +gcc_hermes(hermes_posix_adapter_test "large" "[request_size=range-large]" hermes) + +add_executable(hermes_posix_adapter_mpi_test posix_adapter_mpi_test.cpp ${ADAPTER_COMMON}) +target_link_libraries(hermes_posix_adapter_mpi_test hermes_posix) +add_dependencies(hermes_posix_adapter_mpi_test hermes_posix hermes_daemon) +set_target_properties(hermes_posix_adapter_mpi_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") +mpi_daemon(hermes_posix_adapter_mpi_test 2 "~[request_size=range-large]" "" 1) +mpi_daemon(hermes_posix_adapter_mpi_test 2 "[request_size=range-large]" "large" 1) + +include_directories(${CMAKE_SOURCE_DIR}/adapter) +add_executable(posix_simple_io simple_io.cc) + +set(POSIX_TESTS + posix_adapter_test + hermes_posix_adapter_test + posix_adapter_mpi_test + hermes_posix_adapter_mpi_test + posix_simple_io +) + +foreach(program ${POSIX_TESTS}) + target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_DIR}) + target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_TEST_DIR}) + target_link_libraries(${program} Catch2::Catch2 -lstdc++fs -lc MPI::MPI_CXX) +endforeach() + +if(HERMES_INSTALL_TESTS) + foreach(program ${POSIX_TESTS}) + install( + TARGETS + ${program} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} + ) + endforeach() +endif() diff --git a/adapter/test/posix/posix_adapter_basic_test.cpp b/adapter/test/posix/posix_adapter_basic_test.cpp new file mode 100644 index 000000000..ef66c577e --- /dev/null +++ b/adapter/test/posix/posix_adapter_basic_test.cpp @@ -0,0 +1,1478 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +TEST_CASE("Open", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_open]" + "[repetition=1][file=1]") { + pretest(); + SECTION("open non-existant file") { + test::test_open(info.new_file.c_str(), O_WRONLY); + REQUIRE(test::fh_orig == -1); + test::test_open(info.new_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig == -1); + test::test_open(info.new_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig == -1); + } + + SECTION("truncate existing file and write-only") { + test::test_open(info.existing_file.c_str(), O_WRONLY | O_TRUNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + SECTION("truncate existing file and read/write") { + test::test_open(info.existing_file.c_str(), O_RDWR | O_TRUNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + SECTION("open existing file") { + test::test_open(info.existing_file.c_str(), O_WRONLY); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + SECTION("append write existing file") { + test::test_open(info.existing_file.c_str(), O_APPEND); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + SECTION("create a new file") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + stdfs::remove(info.new_file); + + test::test_open(info.new_file.c_str(), O_RDONLY | O_CREAT, 0600); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + stdfs::remove(info.new_file); + + test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT, 0600); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + SECTION("create a existing file") { + test::test_open(info.existing_file.c_str(), O_WRONLY | O_CREAT, 0600); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDONLY | O_CREAT, 0600); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDWR | O_CREAT, 0600); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + + test::test_open(info.existing_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, + 0600); + REQUIRE(test::fh_orig == -1); + test::test_open(info.existing_file.c_str(), O_RDONLY | O_CREAT | O_EXCL, + 0600); + REQUIRE(test::fh_orig == -1); + test::test_open(info.existing_file.c_str(), O_RDWR | O_CREAT | O_EXCL, + 0600); + REQUIRE(test::fh_orig == -1); + } + SECTION("Async I/O") { + test::test_open(info.existing_file.c_str(), O_WRONLY | O_ASYNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDONLY | O_ASYNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDWR | O_ASYNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_APPEND | O_ASYNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + + test::test_open(info.existing_file.c_str(), O_WRONLY | O_NONBLOCK); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDONLY | O_NONBLOCK); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDWR | O_NONBLOCK); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_APPEND | O_NONBLOCK); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + + test::test_open(info.existing_file.c_str(), O_WRONLY | O_NDELAY); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDONLY | O_NDELAY); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDWR | O_NDELAY); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_APPEND | O_NDELAY); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + SECTION("Async I/O") { + test::test_open(info.existing_file.c_str(), O_WRONLY | O_DIRECT); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDONLY | O_DIRECT); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDWR | O_DIRECT); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_APPEND | O_DIRECT); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + SECTION("Write Synchronize") { + /* File synchronicity */ + test::test_open(info.existing_file.c_str(), O_WRONLY | O_DSYNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDONLY | O_DSYNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDWR | O_DSYNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_APPEND | O_DSYNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + + /* Write synchronicity */ + test::test_open(info.existing_file.c_str(), O_WRONLY | O_SYNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDONLY | O_SYNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_RDWR | O_SYNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.existing_file.c_str(), O_APPEND | O_SYNC); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + SECTION("Temporary file") { + if (info.supports_tmpfile) { + test::test_open("/tmp", O_WRONLY | O_TMPFILE, 0600); + REQUIRE(test::fh_orig != -1); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.new_file.c_str(), O_RDONLY | O_TMPFILE, 0600); + REQUIRE(test::fh_orig == -1); + test::test_open(info.new_file.c_str(), O_RDWR | O_TMPFILE, 0600); + REQUIRE(test::fh_orig == -1); + test::test_open(info.new_file.c_str(), O_APPEND | O_TMPFILE, 0600); + REQUIRE(test::fh_orig == -1); + + test::test_open(info.existing_file.c_str(), O_WRONLY | O_TMPFILE, 0600); + REQUIRE(test::fh_orig == -1); + test::test_open(info.existing_file.c_str(), O_RDONLY | O_TMPFILE, 0600); + REQUIRE(test::fh_orig == -1); + test::test_open(info.existing_file.c_str(), O_RDWR | O_TMPFILE, 0600); + REQUIRE(test::fh_orig == -1); + } + } + posttest(); +} + +TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_write]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + SECTION("write to new file") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == test::size_written_orig); + } + + SECTION("write to existing file with truncate") { + test::test_open(info.existing_file.c_str(), O_WRONLY | O_TRUNC); + REQUIRE(test::fh_orig != -1); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.existing_file) == test::size_written_orig); + } + + SECTION("write to existing file at the end") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + test::test_seek(0, SEEK_END); + REQUIRE(((size_t)test::status_orig) == + args.request_size * info.num_iterations); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.existing_file) == + test::size_written_orig + args.request_size * info.num_iterations); + } + + SECTION("append to existing file") { + auto existing_size = stdfs::file_size(info.existing_file); + test::test_open(info.existing_file.c_str(), O_RDWR | O_APPEND); + REQUIRE(test::fh_orig != -1); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.existing_file) == + existing_size + test::size_written_orig); + } + + SECTION("append to new file") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == test::size_written_orig); + } + posttest(); +} + +TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_read]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + SECTION("read from non-existing file") { + test::test_open(info.new_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig == -1); + } + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig != -1); + test::test_seek(0, SEEK_CUR); + REQUIRE(test::status_orig == 0); + test::test_read(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + SECTION("read at the end of existing file") { + test::test_open(info.existing_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig != -1); + test::test_seek(0, SEEK_END); + REQUIRE(((size_t)test::status_orig) == + args.request_size * info.num_iterations); + test::test_read(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == 0); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedWriteSequential", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == args.request_size); + } + + SECTION("write to new file always at start") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == + info.num_iterations * args.request_size); + } + posttest(); +} + +TEST_CASE("BatchedReadSequential", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_read(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_open(info.existing_file.c_str(), O_WRONLY); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadRandom", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed]" + "[repetition=" + + std::to_string(info.num_iterations) + + "][pattern=random][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + rand_r(&info.offset_seed) % (info.total_size - args.request_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + test::test_read(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateRandom", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=random][file=1]") { + pretest(); + SECTION("update into existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + rand_r(&info.offset_seed) % (info.total_size - args.request_size - 1); + test::test_seek(offset, SEEK_SET); // 630978 + REQUIRE(((size_t)test::status_orig) == offset); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + fsync(test::fh_orig); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideFixed", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = (i * info.stride_size) % info.total_size; + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + test::test_read(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixed", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = (i * info.stride_size) % info.total_size; + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + test::test_write(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideDynamic", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + test::test_read(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamic", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + test::test_write(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedWriteRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + + SECTION("write to new file always at the start") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + size_t biggest_size_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + args.request_size + (rand_r(&info.offset_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + if (biggest_size_written < request_size) + biggest_size_written = request_size; + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == biggest_size_written); + } + + SECTION("write to new file") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + size_t total_size_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + args.request_size + (rand_r(&info.offset_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + total_size_written += test::size_written_orig; + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == total_size_written); + } + posttest(); +} + +TEST_CASE("BatchedReadSequentialRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = (args.request_size + + (rand_r(&info.offset_seed) % args.request_size)) % + (info.total_size - current_offset); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + current_offset += test::size_read_orig; + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_open(info.existing_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + args.request_size + (rand_r(&info.offset_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadRandomRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable]" + "[repetition=" + + std::to_string(info.num_iterations) + + "][pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + rand_r(&info.offset_seed) % (info.total_size - args.request_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % + (info.total_size - offset); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + rand_r(&info.offset_seed) % (info.total_size - args.request_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + args.request_size + (rand_r(&info.rs_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = (i * info.stride_size) % info.total_size; + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % + (info.total_size - offset); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = (i * info.stride_size) % info.total_size; + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + args.request_size + (rand_r(&info.rs_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + args.request_size + (rand_r(&info.rs_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + args.request_size + (rand_r(&info.rs_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideNegative", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + size_t prev_offset = info.total_size + 1; + for (size_t i = 0; i < info.num_iterations; ++i) { + auto stride_offset = info.total_size - i * info.stride_size; + REQUIRE(prev_offset > stride_offset); + prev_offset = stride_offset; + size_t offset = (stride_offset) % (info.total_size - args.request_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + test::test_read(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegative", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + info.total_size - ((i * info.stride_size) % info.total_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + test::test_write(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = (info.total_size - i * info.stride_size) % + (info.total_size - 2 * args.request_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % + (info.total_size - offset); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + info.total_size - ((i * info.stride_size) % info.total_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + args.request_size + (rand_r(&info.rs_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStride2D", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - args.request_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + test::test_read(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStride2D", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - args.request_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + test::test_write(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStride2DRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - 2 * args.request_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % + (info.total_size - offset); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - 2 * args.request_size); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + args.request_size + (rand_r(&info.rs_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +/** + * Temporal Fixed + */ + +TEST_CASE("BatchedWriteTemporalFixed", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1][temporal=fixed]") { + pretest(); + + SECTION("write to existing file") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + usleep(info.temporal_interval_ms * 1000); + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == args.request_size); + } + + SECTION("write to new file always at start") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + usleep(info.temporal_interval_ms * 1000); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == + info.num_iterations * args.request_size); + } + posttest(); +} + +TEST_CASE("BatchedReadSequentialTemporalFixed", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1][temporal=fixed]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + usleep(info.temporal_interval_ms * 1000); + test::test_read(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_open(info.existing_file.c_str(), O_WRONLY); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + usleep(info.temporal_interval_ms * 1000); + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedWriteTemporalVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1][temporal=variable]") { + pretest(); + + SECTION("write to existing file") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + info.temporal_interval_ms = + rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; + usleep(info.temporal_interval_ms * 1000); + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == args.request_size); + } + + SECTION("write to new file always at start") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + info.temporal_interval_ms = + rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; + usleep(info.temporal_interval_ms * 1000); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == + info.num_iterations * args.request_size); + } + posttest(); +} + +TEST_CASE("BatchedReadSequentialTemporalVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1][temporal=variable]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + info.temporal_interval_ms = + rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; + usleep(info.temporal_interval_ms * 1000); + test::test_read(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_open(info.existing_file.c_str(), O_WRONLY); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + info.temporal_interval_ms = + rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; + usleep(info.temporal_interval_ms * 1000); + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedMixedSequential", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_mixed]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("read after write on new file") { + test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + size_t last_offset = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_seek(last_offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == last_offset); + test::test_read(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + last_offset += args.request_size; + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + SECTION("write and read alternative existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + if (i % 2 == 0) { + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } else { + test::test_read(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + SECTION("update after read existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + size_t last_offset = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_read(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + test::test_seek(last_offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == last_offset); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + last_offset += args.request_size; + } + + test::test_close(); + REQUIRE(test::status_orig == 0); + } + SECTION("read all after write all on new file in single open") { + test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_read(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + SECTION("read all after write all on new file in different open") { + test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.new_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_read(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("SingleMixed", "[process=" + std::to_string(info.comm_size) + + "][operation=single_mixed]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + SECTION("read after write from new file") { + test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_read(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + SECTION("update after read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + test::test_read(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + + test::test_close(); + REQUIRE(test::status_orig == 0); + } + SECTION("read after write from new file different opens") { + test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == 0); + test::test_open(info.new_file.c_str(), O_RDWR); + test::test_read(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("fstat") { + pretest(); + + SECTION("fstat on new file") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(test::fh_orig != -1); + test::test_write(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + + struct stat buf = {}; + int result = __fxstat(_STAT_VER, test::fh_orig, &buf); + REQUIRE(result == 0); + REQUIRE(buf.st_size == (off_t)test::size_written_orig); + + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + posttest(); +} diff --git a/adapter/test/posix/posix_adapter_mpi_test.cpp b/adapter/test/posix/posix_adapter_mpi_test.cpp new file mode 100644 index 000000000..2dbdeeec0 --- /dev/null +++ b/adapter/test/posix/posix_adapter_mpi_test.cpp @@ -0,0 +1,401 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include + +#include +#include + +#include "catch_config.h" + +#ifndef O_TMPFILE +#define O_TMPFILE 0 +#endif + +#include "adapter_test_utils.h" + +#if HERMES_INTERCEPT == 1 +#include "posix/real_api.h" +#endif + +namespace stdfs = std::experimental::filesystem; + +namespace hermes::adapter::posix::test { +struct Arguments { + std::string filename = "test.dat"; + std::string directory = "/tmp"; + size_t request_size = 65536; +}; +struct Info { + bool debug = false; + bool supports_tmpfile; + int rank = 0; + int comm_size = 1; + std::vector write_data; + std::vector read_data; + std::string new_file; + std::string existing_file; + std::string shared_new_file; + std::string existing_shared_file; + std::string new_file_cmp; + std::string existing_file_cmp; + std::string existing_shared_file_cmp; + std::string shared_new_file_cmp; + size_t num_iterations = 64; + unsigned int offset_seed = 1; + unsigned int rs_seed = 1; + unsigned int temporal_interval_seed = 1; + size_t total_size; + size_t stride_size = 4 * 1024; + unsigned int temporal_interval_ms = 5; + size_t small_min = 1, small_max = 4 * 1024; + size_t medium_min = 4 * 1024 + 1, medium_max = 512 * 1024; + size_t large_min = 512 * 1024 + 1, large_max = 3 * 1024 * 1024; +}; +} // namespace hermes::adapter::posix::test + +hermes::adapter::posix::test::Arguments args; +hermes::adapter::posix::test::Info info; +std::vector gen_random(const int len) { + std::vector tmp_s(len); + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + srand((unsigned)time(NULL) * getpid()); + + tmp_s.reserve(len); + + for (int i = 0; i < len; ++i) + tmp_s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; + + return tmp_s; +} + +int init(int* argc, char*** argv) { + MPI_Init(argc, argv); + info.write_data = gen_random(args.request_size); + info.read_data = std::vector(args.request_size, 'r'); + info.supports_tmpfile = FilesystemSupportsTmpfile(); + MPI_Comm_rank(MPI_COMM_WORLD, &info.rank); + MPI_Comm_size(MPI_COMM_WORLD, &info.comm_size); + if (info.debug && info.rank == 0) { + printf("%d ready for attach\n", info.comm_size); + fflush(stdout); + sleep(30); + } + MPI_Barrier(MPI_COMM_WORLD); + return 0; +} + +int finalize() { + MPI_Finalize(); + return 0; +} + +int pretest() { + REQUIRE(info.comm_size > 1); + stdfs::path fullpath = args.directory; + fullpath /= args.filename; + info.new_file = fullpath.string() + "_new_" + std::to_string(info.rank) + + "_of_" + std::to_string(info.comm_size) + "_" + + std::to_string(getpid()); + info.existing_file = fullpath.string() + "_ext_" + std::to_string(info.rank) + + "_of_" + std::to_string(info.comm_size) + "_" + + std::to_string(getpid()); + info.new_file_cmp = + fullpath.string() + "_new_cmp_" + std::to_string(info.rank) + "_of_" + + std::to_string(info.comm_size) + "_" + std::to_string(getpid()); + info.existing_file_cmp = + fullpath.string() + "_ext_cmp_" + std::to_string(info.rank) + "_of_" + + std::to_string(info.comm_size) + "_" + std::to_string(getpid()); + info.existing_shared_file = + fullpath.string() + "_shared_ext_" + std::to_string(info.comm_size); + info.existing_shared_file_cmp = + fullpath.string() + "_shared_ext_cmp_" + std::to_string(info.comm_size); + info.shared_new_file = + fullpath.string() + "_shared_new_" + std::to_string(info.comm_size); + info.shared_new_file_cmp = + fullpath.string() + "_shared_new_cmp_" + std::to_string(info.comm_size); + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + if (stdfs::exists(info.existing_shared_file)) + stdfs::remove(info.existing_shared_file); + if (stdfs::exists(info.existing_shared_file_cmp)) + stdfs::remove(info.existing_shared_file_cmp); + if (stdfs::exists(info.shared_new_file)) stdfs::remove(info.shared_new_file); + if (stdfs::exists(info.shared_new_file_cmp)) + stdfs::remove(info.shared_new_file_cmp); + stdfs::path temp_fullpath = "/tmp"; + temp_fullpath /= args.filename; + std::string temp_ext_file = + temp_fullpath.string() + "_temp_" + std::to_string(info.rank) + "_of_" + + std::to_string(info.comm_size) + "_" + std::to_string(getpid()); + if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); + if (!stdfs::exists(temp_ext_file)) { + std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + + std::to_string(args.request_size * info.num_iterations) + + "; } > " + temp_ext_file + " 2> /dev/null"; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(temp_ext_file) == + args.request_size * info.num_iterations); + info.total_size = stdfs::file_size(temp_ext_file); + } + if (info.rank == 0 && !stdfs::exists(info.existing_shared_file)) { + std::string cmd = "cp " + temp_ext_file + " " + info.existing_shared_file; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_shared_file) == + args.request_size * info.num_iterations); + } + if (info.rank == 0 && !stdfs::exists(info.existing_shared_file_cmp)) { + std::string cmd = + "cp " + temp_ext_file + " " + info.existing_shared_file_cmp; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_shared_file_cmp) == + args.request_size * info.num_iterations); + } + if (!stdfs::exists(info.existing_file)) { + std::string cmd = "cp " + temp_ext_file + " " + info.existing_file; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file) == + args.request_size * info.num_iterations); + info.total_size = stdfs::file_size(info.existing_file); + } + if (!stdfs::exists(info.existing_file_cmp)) { + std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file_cmp) == + args.request_size * info.num_iterations); + } + if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); + REQUIRE(info.total_size > 0); + MPI_Barrier(MPI_COMM_WORLD); +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert( + info.existing_shared_file_cmp); +#endif + return 0; +} + +int posttest(bool compare_data = true) { +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_shared_file); +#endif + if (compare_data && stdfs::exists(info.new_file) && + stdfs::exists(info.new_file_cmp)) { + size_t size = stdfs::file_size(info.new_file); + REQUIRE(size == stdfs::file_size(info.new_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.new_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + if (compare_data && stdfs::exists(info.existing_file) && + stdfs::exists(info.existing_file_cmp)) { + size_t size = stdfs::file_size(info.existing_file); + if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); + REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + if (compare_data && stdfs::exists(info.existing_shared_file) && + stdfs::exists(info.existing_shared_file_cmp)) { + size_t size = stdfs::file_size(info.existing_shared_file); + if (size != stdfs::file_size(info.existing_shared_file_cmp)) sleep(1); + REQUIRE(size == stdfs::file_size(info.existing_shared_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.existing_shared_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.existing_shared_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + /* Clean up. */ + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + MPI_Barrier(MPI_COMM_WORLD); + if (info.rank == 0) { + if (stdfs::exists(info.existing_shared_file)) + stdfs::remove(info.existing_shared_file); + if (stdfs::exists(info.existing_shared_file_cmp)) + stdfs::remove(info.existing_shared_file_cmp); + } + +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file_cmp); +#endif + return 0; +} + +cl::Parser define_options() { + return cl::Opt(args.filename, "filename")["-f"]["--filename"]( + "Filename used for performing I/O") | + cl::Opt(args.directory, "dir")["-d"]["--directory"]( + "Directory used for performing I/O") | + cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( + "Request size used for performing I/O"); +} + +namespace test { +int fh_orig; +int fh_cmp; +int status_orig; +size_t size_read_orig; +size_t size_written_orig; + +void test_open(const char* path, int flags, ...) { + int mode = 0; + if (flags & O_CREAT || flags & O_TMPFILE) { + va_list arg; + va_start(arg, flags); + mode = va_arg(arg, int); + va_end(arg); + } + std::string cmp_path; + if (strcmp(path, info.new_file.c_str()) == 0) { + cmp_path = info.new_file_cmp; + } else if (strcmp(path, info.shared_new_file.c_str()) == 0) { + cmp_path = info.shared_new_file_cmp; + } else if (strcmp(path, "/tmp") == 0) { + cmp_path = "/tmp"; + } else { + cmp_path = info.existing_file_cmp; + } + if (flags & O_CREAT || flags & O_TMPFILE) { + fh_orig = open(path, flags, mode); + fh_cmp = open(cmp_path.c_str(), flags, mode); + } else { + fh_orig = open(path, flags); + fh_cmp = open(cmp_path.c_str(), flags); + } + bool is_same = + (fh_cmp != -1 && fh_orig != -1) || (fh_cmp == -1 && fh_orig == -1); + REQUIRE(is_same); +} +void test_close() { + status_orig = close(fh_orig); + int status = close(fh_cmp); + REQUIRE(status == status_orig); +} +void test_write(const void* ptr, size_t size) { + size_written_orig = write(fh_orig, ptr, size); + size_t size_written = write(fh_cmp, ptr, size); + REQUIRE(size_written == size_written_orig); +} +void test_read(char* ptr, size_t size) { + size_read_orig = read(fh_orig, ptr, size); + std::vector read_data(size, 'r'); + size_t size_read = read(fh_cmp, read_data.data(), size); + REQUIRE(size_read == size_read_orig); + if (size_read > 0) { + size_t unmatching_chars = 0; + for (size_t i = 0; i < size; ++i) { + if (read_data[i] != ptr[i]) { + unmatching_chars = i; + break; + } + } + REQUIRE(unmatching_chars == 0); + } +} +void test_seek(long offset, int whence) { + status_orig = lseek(fh_orig, offset, whence); + int status = lseek(fh_cmp, offset, whence); + REQUIRE(status == status_orig); +} +} // namespace test + +#include "posix_adapter_basic_test.cpp" +#include "posix_adapter_rs_test.cpp" +// TODO(chogan): Disabling until issue #302 is fixed +// #include "posix_adapter_shared_test.cpp" diff --git a/adapter/test/posix/posix_adapter_rs_test.cpp b/adapter/test/posix/posix_adapter_rs_test.cpp new file mode 100644 index 000000000..d52d4438d --- /dev/null +++ b/adapter/test/posix/posix_adapter_rs_test.cpp @@ -0,0 +1,1239 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +TEST_CASE("BatchedWriteRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("write to new file always at the start") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); + REQUIRE(test::fh_orig != -1); + size_t biggest_size_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + if (biggest_size_written < request_size) + biggest_size_written = request_size; + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == biggest_size_written); + } + + SECTION("write to new file") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); + REQUIRE(test::fh_orig != -1); + size_t total_size_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + total_size_written += test::size_written_orig; + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == total_size_written); + } + posttest(); +} + +TEST_CASE("BatchedReadSequentialRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_open(info.existing_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadRandomRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-small]" + "[repetition=" + + std::to_string(info.num_iterations) + + "][pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + rand_r(&info.offset_seed) % (info.total_size - info.small_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + rand_r(&info.offset_seed) % (info.total_size - info.small_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + (i * info.stride_size) % (info.total_size - info.small_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + (i * info.stride_size) % (info.total_size - info.small_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size - info.small_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size - info.small_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = (info.total_size - i * info.stride_size) % + (info.total_size - info.small_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = info.total_size - ((i * info.stride_size) % + (info.total_size - info.small_max)); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStride2DRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - info.small_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - info.small_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} +/** + * Medium RS + **/ + +TEST_CASE("BatchedWriteRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("write to new file always at the start") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); + REQUIRE(test::fh_orig != -1); + size_t biggest_size_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + if (biggest_size_written < request_size) + biggest_size_written = request_size; + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == biggest_size_written); + } + + SECTION("write to new file") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); + REQUIRE(test::fh_orig != -1); + size_t total_size_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + total_size_written += test::size_written_orig; + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == total_size_written); + } + posttest(); +} + +TEST_CASE("BatchedReadSequentialRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + (info.medium_min + (rand_r(&info.rs_seed) % info.medium_max)) % + (info.total_size - current_offset); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + current_offset += test::size_read_orig; + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_open(info.existing_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadRandomRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-medium]" + "[repetition=" + + std::to_string(info.num_iterations) + + "][pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + rand_r(&info.offset_seed) % (info.total_size - info.medium_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + rand_r(&info.offset_seed) % (info.total_size - info.medium_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + (i * info.stride_size) % (info.total_size - info.medium_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + (i * info.stride_size) % (info.total_size - info.medium_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size - info.medium_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size - info.medium_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = (info.total_size - i * info.stride_size) % + (info.total_size - info.medium_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = info.total_size - ((i * info.stride_size) % + (info.total_size - info.medium_max)); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStride2DRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - info.medium_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - info.medium_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} +/** + * Large RS + **/ + +TEST_CASE("BatchedWriteRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("write to new file always at the start") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); + REQUIRE(test::fh_orig != -1); + size_t biggest_size_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + if (biggest_size_written < request_size) + biggest_size_written = request_size; + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == biggest_size_written); + } + + SECTION("write to new file") { + test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); + REQUIRE(test::fh_orig != -1); + size_t total_size_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + total_size_written += test::size_written_orig; + } + test::test_close(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == total_size_written); + } + posttest(); +} + +TEST_CASE("BatchedReadSequentialRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig != -1); + std::string data(args.request_size, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % + (info.total_size - current_offset); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + current_offset += test::size_read_orig; + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_open(info.existing_file.c_str(), O_RDONLY); + REQUIRE(test::fh_orig != -1); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_seek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadRandomRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-large]" + "[repetition=" + + std::to_string(info.num_iterations) + + "][pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + rand_r(&info.offset_seed) % (info.total_size - info.large_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % + (info.total_size - test::status_orig); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + rand_r(&info.offset_seed) % (info.total_size - info.large_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + (i * info.stride_size) % (info.total_size - info.large_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = + (i * info.stride_size) % (info.total_size - info.large_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size - info.large_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size - info.large_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = (info.total_size - i * info.stride_size) % + (info.total_size - info.large_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % + (info.total_size - info.large_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t offset = info.total_size - ((i * info.stride_size) % + (info.total_size - info.large_max)); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStride2DRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("read from existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - info.large_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_read(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("write to existing file") { + test::test_open(info.existing_file.c_str(), O_RDWR); + REQUIRE(test::fh_orig != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - info.large_max); + test::test_seek(offset, SEEK_SET); + REQUIRE(((size_t)test::status_orig) == offset); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_write(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_close(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} diff --git a/adapter/test/posix/posix_adapter_shared_test.cpp b/adapter/test/posix/posix_adapter_shared_test.cpp new file mode 100644 index 000000000..0b64d299e --- /dev/null +++ b/adapter/test/posix/posix_adapter_shared_test.cpp @@ -0,0 +1,78 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +TEST_CASE("SharedFile", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[mode=shared]" + "[pattern=sequential][file=1]") { + pretest(); + REQUIRE(info.comm_size == 2); + SECTION("producer-consumer") { + bool producer = info.rank % 2 == 0; + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + lock.l_pid = getpid(); + if (producer) { + int fd = open(info.shared_new_file.c_str(), O_RDWR | O_CREAT, 0666); + REQUIRE(fd != -1); + MPI_Barrier(MPI_COMM_WORLD); + int status = -1; + for (size_t i = 0; i < info.num_iterations; ++i) { + status = fcntl(fd, F_SETLKW, &lock); + REQUIRE(status != -1); + size_t write_bytes = + write(fd, info.write_data.data(), args.request_size); + REQUIRE(write_bytes == args.request_size); + lock.l_type = F_UNLCK; + status = fcntl(fd, F_SETLK, &lock); + REQUIRE(status != -1); + } + status = close(fd); + REQUIRE(status != -1); + } else { + MPI_Barrier(MPI_COMM_WORLD); + int fd = open(info.shared_new_file.c_str(), O_RDONLY); + REQUIRE(fd != -1); + int status = -1; + size_t bytes_read = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + lock.l_type = F_RDLCK; + status = fcntl(fd, F_SETLKW, &lock); + REQUIRE(status != -1); + size_t file_size = lseek(fd, 0, SEEK_END); + size_t cur_offset = lseek(fd, bytes_read, SEEK_SET); + REQUIRE(cur_offset == bytes_read); + if (file_size > bytes_read) { + size_t read_size = args.request_size < file_size - bytes_read + ? args.request_size + : file_size - bytes_read; + size_t read_bytes = read(fd, info.read_data.data(), read_size); + REQUIRE(read_bytes == read_size); + bytes_read += read_bytes; + } + lock.l_type = F_UNLCK; + status = fcntl(fd, F_SETLK, &lock); + REQUIRE(status != -1); + } + status = close(fd); + REQUIRE(status != -1); + } + } + posttest(); +} diff --git a/adapter/test/posix/posix_adapter_test.cpp b/adapter/test/posix/posix_adapter_test.cpp new file mode 100644 index 000000000..c57c0a402 --- /dev/null +++ b/adapter/test/posix/posix_adapter_test.cpp @@ -0,0 +1,286 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include + +#include +#include + +#include "catch_config.h" +#if HERMES_INTERCEPT == 1 +#include "posix/real_api.h" +#endif + +#ifndef O_TMPFILE +#define O_TMPFILE 0 +#endif + +#include "adapter_test_utils.h" + +namespace stdfs = std::experimental::filesystem; + +namespace hermes::adapter::posix::test { +struct Arguments { + std::string filename = "test.dat"; + std::string directory = "/tmp"; + size_t request_size = 65536; +}; +struct Info { + int rank = 0; + int comm_size = 1; + bool supports_tmpfile; + std::vector write_data; + std::vector read_data; + std::string new_file; + std::string existing_file; + std::string new_file_cmp; + std::string existing_file_cmp; + size_t num_iterations = 64; + unsigned int offset_seed = 1; + unsigned int rs_seed = 1; + unsigned int temporal_interval_seed = 5; + size_t total_size; + size_t stride_size = 1024; + unsigned int temporal_interval_ms = 1; + size_t small_min = 1, small_max = 4 * 1024; + size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; + size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; +}; +} // namespace hermes::adapter::posix::test +hermes::adapter::posix::test::Arguments args; +hermes::adapter::posix::test::Info info; +std::vector gen_random(const int len) { + auto tmp_s = std::vector(len); + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + srand(100); + for (int i = 0; i < len; ++i) + tmp_s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; + return tmp_s; +} + +int init(int* argc, char*** argv) { + MPI_Init(argc, argv); + info.write_data = gen_random(args.request_size); + info.read_data = std::vector(args.request_size, 'r'); + info.supports_tmpfile = FilesystemSupportsTmpfile(); + return 0; +} + +int finalize() { + MPI_Finalize(); + return 0; +} + +int pretest() { + stdfs::path fullpath = args.directory; + fullpath /= args.filename; + info.new_file = fullpath.string() + "_new_" + std::to_string(getpid()); + info.existing_file = fullpath.string() + "_ext_" + std::to_string(getpid()); + info.new_file_cmp = + fullpath.string() + "_new_cmp" + "_" + std::to_string(getpid()); + info.existing_file_cmp = + fullpath.string() + "_ext_cmp" + "_" + std::to_string(getpid()); + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + if (!stdfs::exists(info.existing_file)) { + std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + + std::to_string(args.request_size * info.num_iterations) + + "; } > " + info.existing_file + " 2> /dev/null"; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file) == + args.request_size * info.num_iterations); + info.total_size = stdfs::file_size(info.existing_file); + } + if (!stdfs::exists(info.existing_file_cmp)) { + std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file_cmp) == + args.request_size * info.num_iterations); + } + REQUIRE(info.total_size > 0); +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); +#endif + return 0; +} + +int posttest(bool compare_data = true) { +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); +#endif + if (compare_data && stdfs::exists(info.new_file) && + stdfs::exists(info.new_file_cmp)) { + size_t size = stdfs::file_size(info.new_file); + REQUIRE(size == stdfs::file_size(info.new_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.new_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + if (compare_data && stdfs::exists(info.existing_file) && + stdfs::exists(info.existing_file_cmp)) { + size_t size = stdfs::file_size(info.existing_file); + if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); + REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); + if (size > 0) { + std::vector d1(size, 'r'); + std::vector d2(size, 'w'); + + FILE* fh1 = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), sizeof(unsigned char), size, fh1); + REQUIRE(read_d1 == size); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), sizeof(unsigned char), size, fh2); + REQUIRE(read_d2 == size); + status = fclose(fh2); + REQUIRE(status == 0); + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) { + char_mismatch = pos; + break; + } + } + REQUIRE(char_mismatch == 0); + } + } + /* Clean up. */ + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); +#endif + return 0; +} + +cl::Parser define_options() { + return cl::Opt(args.filename, "filename")["-f"]["--filename"]( + "Filename used for performing I/O") | + cl::Opt(args.directory, "dir")["-d"]["--directory"]( + "Directory used for performing I/O") | + cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( + "Request size used for performing I/O"); +} + +namespace test { +int fh_orig; +int fh_cmp; +int status_orig; +size_t size_read_orig; +size_t size_written_orig; +void test_open(const char* path, int flags, ...) { + int mode = 0; + if (flags & O_CREAT || flags & O_TMPFILE) { + va_list arg; + va_start(arg, flags); + mode = va_arg(arg, int); + va_end(arg); + } + std::string cmp_path; + if (strcmp(path, info.new_file.c_str()) == 0) { + cmp_path = info.new_file_cmp; + } else if (strcmp(path, "/tmp") == 0) { + cmp_path = "/tmp"; + } else { + cmp_path = info.existing_file_cmp; + } + if (flags & O_CREAT || flags & O_TMPFILE) { + fh_orig = open(path, flags, mode); + fh_cmp = open(cmp_path.c_str(), flags, mode); + } else { + fh_orig = open(path, flags); + fh_cmp = open(cmp_path.c_str(), flags); + } + bool is_same = + (fh_cmp != -1 && fh_orig != -1) || (fh_cmp == -1 && fh_orig == -1); + REQUIRE(is_same); +} +void test_close() { + status_orig = close(fh_orig); + int status = close(fh_cmp); + REQUIRE(status == status_orig); +} +void test_write(const void* ptr, size_t size) { + size_written_orig = write(fh_orig, ptr, size); + size_t size_written = write(fh_cmp, ptr, size); + REQUIRE(size_written == size_written_orig); +} +void test_read(char* ptr, size_t size) { + size_read_orig = read(fh_orig, ptr, size); + std::vector read_data(size, 'r'); + size_t size_read = read(fh_cmp, read_data.data(), size); + REQUIRE(size_read == size_read_orig); + if (size_read > 0) { + size_t unmatching_chars = 0; + for (size_t i = 0; i < size; ++i) { + if (read_data[i] != ptr[i]) { + unmatching_chars = i; + break; + } + } + REQUIRE(unmatching_chars == 0); + } +} +void test_seek(long offset, int whence) { + status_orig = lseek(fh_orig, offset, whence); + int status = lseek(fh_cmp, offset, whence); + REQUIRE(status == status_orig); +} +} // namespace test + +#include "posix_adapter_basic_test.cpp" +#include "posix_adapter_rs_test.cpp" diff --git a/adapter/test/posix/simple_io.cc b/adapter/test/posix/simple_io.cc new file mode 100644 index 000000000..78db64ab9 --- /dev/null +++ b/adapter/test/posix/simple_io.cc @@ -0,0 +1,106 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "mpi.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool VerifyBuffer(char *ptr, size_t size, char nonce) { + for (size_t i = 0; i < size; ++i) { + if (ptr[i] != nonce) { + std::cout << (int)ptr[i] << " != " << (int)nonce << std::endl; + return false; + } + } + return true; +} + +int main(int argc, char **argv) { + int rank, nprocs; + MPI_Init(&argc, &argv); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nprocs); + if (argc != 7) { + std::cout << "USAGE: ./posix_simple_io" + << " [path] [read] [block_size (kb)] [count]" + << " [off (blocks)] [lag (sec)]"; + exit(1); + } + + char *path = argv[1]; + int do_read = atoi(argv[2]); + int block_size = atoi(argv[3])*1024; + int count = atoi(argv[4]); + int block_off = atoi(argv[5]); + int lag = atoi(argv[6]); + if (do_read) { + count -= block_off; + } else { + block_off = 0; + } + size_t size = count * block_size; + size_t total_size = size * nprocs; + int off = (rank * size) + block_off * block_size; + + std::stringstream ss; + ss << "RANK: " << rank << std::endl + << " PATH: " << path << std::endl + << " READ or WRITE: " << (do_read ? "READ" : "WRITE") << std::endl + << " Block Off: " << block_off << std::endl + << " Block Size: " << block_size << std::endl + << " Count: " << count << std::endl + << " Proc Size (MB): " << size / (1<<20) << std::endl; + std::cout << ss.str() << std::endl; + + sleep(lag); + + char *buf = (char*)malloc(size); + int fd = open(path, O_CREAT | O_RDWR, 0666); + lseek(fd, off, SEEK_SET); + + struct stat st; + __fxstat(_STAT_VER, fd, &st); + if (do_read && (st.st_size - total_size) > 3) { + if (rank == 0) { + std::cout << "File sizes aren't equivalent: " + << " stat: " << st.st_size + << " real: " << total_size << std::endl; + } + exit(1); + } + + for (int i = 0; i < count; ++i) { + char nonce = i; + if (!do_read) { + memset(buf, nonce, block_size); + write(fd, buf, block_size); + } else { + memset(buf, 0, block_size); + read(fd, buf, block_size); + if (!VerifyBuffer(buf, block_size, nonce)) { + std::cout << "Buffer verification failed!" << std::endl; + exit(1); + } + } + } + + close(fd); + MPI_Finalize(); +} diff --git a/adapter/test/pubsub/CMakeLists.txt b/adapter/test/pubsub/CMakeLists.txt new file mode 100644 index 000000000..32f868453 --- /dev/null +++ b/adapter/test/pubsub/CMakeLists.txt @@ -0,0 +1,49 @@ +#------------------------------------------------------------------------------ +# PubSub Adapter tests +#------------------------------------------------------------------------------ +add_executable(pubsub_metadata_test ${CMAKE_CURRENT_SOURCE_DIR}/pubsub_metadata_test.cc) +add_test(NAME "pubsub_metadata_test" COMMAND "${CMAKE_BINARY_DIR}/bin/pubsub_metadata_test") +target_link_libraries(pubsub_metadata_test ${LIBRT} hermes MPI::MPI_CXX + $<$:thallium> hermes_pubsub) +add_dependencies(pubsub_metadata_test hermes_pubsub) + +set(SINGLE_NODE_PUBSUB_TESTS pubsub_topic_test pubsub_end_to_end_test) +set(MULTI_NODE_PUBSUB_TESTS pubsub_end_to_end_test_sync) +set(EXTENDED_PUBSUB_TESTS ${SINGLE_NODE_PUBSUB_TESTS} ${MULTI_NODE_PUBSUB_TESTS} pubsub_metadata_test) + +foreach(program ${SINGLE_NODE_PUBSUB_TESTS}) + add_executable(${program} ${CMAKE_CURRENT_SOURCE_DIR}/${program}.cc) + add_dependencies(${program} hermes_pubsub) + target_link_libraries(${program} ${LIBRT} hermes MPI::MPI_CXX + $<$:thallium> hermes_pubsub) + target_compile_definitions(${program} + PRIVATE $<$:HERMES_RPC_THALLIUM>) + mpi_daemon(${program} 1 "" "" 1) +endforeach() + +foreach(program ${MULTI_NODE_PUBSUB_TESTS}) + add_executable(${program} ${CMAKE_CURRENT_SOURCE_DIR}/${program}.cc) + add_dependencies(${program} hermes_pubsub) + target_link_libraries(${program} ${LIBRT} hermes MPI::MPI_CXX + $<$:thallium> hermes_pubsub) + target_compile_definitions(${program} + PRIVATE $<$:HERMES_RPC_THALLIUM>) + mpi_daemon(${program} 2 "" "" 1) +endforeach() + +foreach(program ${EXTENDED_PUBSUB_TESTS}) + target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_DIR}) + target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_TEST_DIR}) +endforeach() + +if(HERMES_INSTALL_TESTS) + foreach(program ${EXTENDED_PUBSUB_TESTS}) + install( + TARGETS + ${program} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} + ) + endforeach() +endif() diff --git a/adapter/test/pubsub/pubsub_end_to_end_test.cc b/adapter/test/pubsub/pubsub_end_to_end_test.cc new file mode 100644 index 000000000..15ffa4d04 --- /dev/null +++ b/adapter/test/pubsub/pubsub_end_to_end_test.cc @@ -0,0 +1,64 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include "test_utils.h" + +int main(int argc, char **argv) { + hermes::pubsub::mpiInit(argc, argv); + + char *config_file = 0; + if (argc == 2) { + config_file = argv[1]; + } else { + config_file = getenv(kHermesConf); + } + + auto connect_ret = hermes::pubsub::connect(config_file); + Assert(connect_ret.Succeeded()); + + if (connect_ret.Succeeded()) { + auto attach_ret = hermes::pubsub::attach("test"); + Assert(attach_ret.Succeeded()); + + hapi::Blob data1(4*1024, rand() % 255); + hapi::Blob data2(4*1024, rand() % 255); + hapi::Blob data3(4*1024, rand() % 255); + + auto publish_ret = hermes::pubsub::publish("test", data1); + Assert(publish_ret.Succeeded()); + + auto subscribe_ret_1 = hermes::pubsub::subscribe("test"); + Assert(subscribe_ret_1.second.Succeeded()); + Assert(data1 == subscribe_ret_1.first); + + publish_ret = hermes::pubsub::publish("test", data2); + Assert(publish_ret.Succeeded()); + + publish_ret = hermes::pubsub::publish("test", data3); + Assert(publish_ret.Succeeded()); + + // this subscribe reads data2; + hermes::pubsub::subscribe("test"); + + auto subscribe_ret_2 = hermes::pubsub::subscribe("test"); + Assert(subscribe_ret_2.second.Succeeded()); + Assert(data3 == subscribe_ret_2.first); + + auto detach_ret = hermes::pubsub::detach("test"); + Assert(detach_ret.Succeeded()); + } + auto disconnect_ret = hermes::pubsub::disconnect(); + Assert(disconnect_ret.Succeeded()); + + MPI_Finalize(); +} diff --git a/adapter/test/pubsub/pubsub_end_to_end_test_sync.cc b/adapter/test/pubsub/pubsub_end_to_end_test_sync.cc new file mode 100644 index 000000000..6e5839e08 --- /dev/null +++ b/adapter/test/pubsub/pubsub_end_to_end_test_sync.cc @@ -0,0 +1,68 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include "test_utils.h" + +int main(int argc, char **argv) { + hermes::pubsub::mpiInit(argc, argv); + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + int comm_size; + MPI_Comm_size(MPI_COMM_WORLD, &comm_size); + + char *config_file = 0; + if (argc == 2) { + config_file = argv[1]; + } else { + config_file = getenv(kHermesConf); + } + + auto connect_ret = hermes::pubsub::connect(config_file); + + if (connect_ret.Succeeded()) { + auto attach_ret = hermes::pubsub::attach("test"); + Assert(attach_ret.Succeeded()); + + std::vector full_data; + hapi::Blob data1(4*1024, rand() % 255); + hapi::Blob data2(4*1024, rand() % 255); + hapi::Blob data3(4*1024, rand() % 255); + full_data.push_back(data1); + full_data.push_back(data2); + full_data.push_back(data3); + + for (const auto& data : full_data) { + auto publish_ret = hermes::pubsub::publish("test", data); + Assert(publish_ret.Succeeded()); + } + + auto hermes = hermes::Singleton + ::GetInstance()->GetHermes(); + MPI_Comm comm = *(MPI_Comm*)hermes->GetAppCommunicator(); + MPI_Barrier(comm); + + unsigned long num_messages = full_data.size(); + std::pair subscribe_ret; + for (unsigned long i = 0; i < num_messages*comm_size; i++) { + subscribe_ret = hermes::pubsub::subscribe("test"); + Assert(subscribe_ret.second.Succeeded()); + } + + auto detach_ret = hermes::pubsub::detach("test"); + Assert(detach_ret.Succeeded()); + } + auto disconnect_ret = hermes::pubsub::disconnect(); + Assert(disconnect_ret.Succeeded()); + + MPI_Finalize(); +} diff --git a/adapter/test/pubsub/pubsub_metadata_test.cc b/adapter/test/pubsub/pubsub_metadata_test.cc new file mode 100644 index 000000000..051fc2ab2 --- /dev/null +++ b/adapter/test/pubsub/pubsub_metadata_test.cc @@ -0,0 +1,52 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include "singleton.h" +#include "test_utils.h" + +int main() { + auto mdm = hermes::Singleton + ::GetInstance(false); + ClientMetadata stat; + struct timespec ts{}; + timespec_get(&ts, TIME_UTC); + stat.st_atim = ts; + + auto create_ret = mdm->Create("test", stat); + Assert(create_ret == true); + create_ret = mdm->Create("test", stat); + Assert(create_ret == false); + + auto find_ret = mdm->Find("test"); + Assert(find_ret.second == true); + Assert(find_ret.first.st_atim.tv_nsec == ts.tv_nsec); + + struct timespec ts1{}; + timespec_get(&ts1, TIME_UTC); + stat.st_atim = ts1; + auto update_ret = mdm->Update("test", stat); + Assert(update_ret == true); + find_ret = mdm->Find("test"); + Assert(find_ret.second == true); + Assert(find_ret.first.st_atim.tv_nsec >= ts.tv_nsec); + Assert(find_ret.first.st_atim.tv_nsec == ts1.tv_nsec); + + auto delete_ret = mdm->Delete("test"); + Assert(delete_ret == true); + delete_ret = mdm->Delete("test"); + Assert(delete_ret == false); + find_ret = mdm->Find("test"); + Assert(find_ret.second == false); + update_ret = mdm->Update("test", stat); + Assert(update_ret == false); +} diff --git a/adapter/test/pubsub/pubsub_topic_test.cc b/adapter/test/pubsub/pubsub_topic_test.cc new file mode 100644 index 000000000..aa8de63ac --- /dev/null +++ b/adapter/test/pubsub/pubsub_topic_test.cc @@ -0,0 +1,41 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include "test_utils.h" + +int main(int argc, char **argv) { + hermes::pubsub::mpiInit(argc, argv); + + char *config_file = 0; + if (argc == 2) { + config_file = argv[1]; + } else { + config_file = getenv(kHermesConf); + } + + auto connect_ret = hermes::pubsub::connect(config_file); + Assert(connect_ret.Succeeded()); + + auto attach_ret = hermes::pubsub::attach("test"); + Assert(attach_ret.Succeeded()); + + auto detach_ret = hermes::pubsub::detach("test"); + Assert(detach_ret.Succeeded()); + + auto disconnect_ret = hermes::pubsub::disconnect(); + Assert(disconnect_ret.Succeeded()); + + MPI_Finalize(); + + return 0; +} diff --git a/adapter/test/pubsub/test_utils.h b/adapter/test/pubsub/test_utils.h new file mode 100644 index 000000000..2fcece367 --- /dev/null +++ b/adapter/test/pubsub/test_utils.h @@ -0,0 +1,31 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_PUBSUB_TEST_UTILS_H_ +#define HERMES_PUBSUB_TEST_UTILS_H_ + +namespace hermes::pubsub::testing { + +void Assert(bool expr, const char *file, int lineno, const char *message) { + if (!expr) { + fprintf(stderr, "Assertion failed at %s: line %d: %s\n", file, lineno, + message); + exit(-1); + } +} + +#define Assert(expr) \ + hermes::pubsub::testing::Assert((expr), __FILE__, __LINE__, #expr) + +} // namespace hermes::pubsub::testing + +#endif // HERMES_PUBSUB_TEST_UTILS_H_ diff --git a/adapter/test/run_hermes.sh b/adapter/test/run_hermes.sh new file mode 100644 index 000000000..cfa45b668 --- /dev/null +++ b/adapter/test/run_hermes.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +MPI_EXEC=$1 +TEST_EXEC=$2 +TEST_PROCS=$3 +HERMES_EXEC=$4 +HERMES_PROCS=$5 +HERMES_CONF=$6 +TEST_ARGS="${@:7}" +SLEEP_TIME=3 + +error_ct=0 +if [[ ! -f "$MPI_EXEC" ]]; then + echo "MPI_EXEC ${MPI_EXEC} does not exists." >&2 + error_ct=$((error_ct + 1)) +fi +if [[ ! -f "${TEST_EXEC}" ]]; then + echo "TEST_EXEC ${TEST_EXEC} does not exists." >&2 + error_ct=$((error_ct + 1)) +fi +if [[ ! -f "${HERMES_EXEC}" ]]; then + echo "HERMES_EXEC ${HERMES_EXEC} does not exists." >&2 + error_ct=$((error_ct + 1)) +fi +if [[ ! -f "${HERMES_CONF}" ]]; then + echo "HERMES_CONF ${HERMES_CONF} does not exists." >&2 + error_ct=$((error_ct + 1)) +fi +if [ $error_ct -gt 0 ]; then + echo "Arguments are wrong !!!" >&2 + exit $error_ct +fi + +echo "${MPI_EXEC} -n ${HERMES_PROCS} ${HERMES_EXEC} ${HERMES_CONF} &" +${MPI_EXEC} -n ${HERMES_PROCS} ${HERMES_EXEC} ${HERMES_CONF} & +HERMES_EXEC_PID=$! +echo "process spawned ${HERMES_EXEC_PID}" + +echo "Started hermes daemon with ${HERMES_PROCS} procs. sleeping for ${SLEEP_TIME} seconds" +sleep ${SLEEP_TIME} + +echo "${MPI_EXEC} -n ${TEST_PROCS} ${TEST_EXEC} ${TEST_ARGS}" +${MPI_EXEC} -n ${TEST_PROCS} ${TEST_EXEC} ${TEST_ARGS} +status=$? +echo "Killing Hermes daemon with PID ${HERMES_EXEC_PID}" +kill ${HERMES_EXEC_PID} +if [ $status -gt 0 ]; then + echo "Test failed with code $status!" >&2 + exit $status +fi +echo "Finishing test." +exit 0 diff --git a/adapter/test/stdio/CMakeLists.txt b/adapter/test/stdio/CMakeLists.txt new file mode 100644 index 000000000..c1d2fb4f8 --- /dev/null +++ b/adapter/test/stdio/CMakeLists.txt @@ -0,0 +1,111 @@ +function(gcc_hermes exec tag_name tags conf async) + set(TEST_NAME Test${exec}_${tag_name}_${async}) + add_test(NAME ${TEST_NAME} + COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) + set_property(TEST ${TEST_NAME} + PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/${conf}.yaml) + set_property(TEST ${TEST_NAME} APPEND + PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) + + if ("${async}" STREQUAL "async") + set_property(TEST ${TEST_NAME} APPEND PROPERTY ENVIRONMENT HERMES_ASYNC_FLUSH=1) + endif() +endfunction() + +function(gcc_hermes_mode exec tag_name tags mode path) + set(test_name Test${exec}_${tag_name}_${mode}_${path}) + add_test(NAME ${test_name} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) + set_property(TEST ${test_name} + PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) + set_property(TEST ${test_name} APPEND + PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) + set_property(TEST ${test_name} APPEND + PROPERTY ENVIRONMENT ADAPTER_MODE=${mode}) + set_property(TEST ${test_name} APPEND + PROPERTY ENVIRONMENT SET_PATH=${path}) +endfunction() + +#------------------------------------------------------------------------------ +# STDIO Adapter Internal tests +#------------------------------------------------------------------------------ +add_executable(stdio_adapter_mapper_test stdio_adapter_mapper_test.cpp ${ADAPTER_COMMON}) +target_link_libraries(stdio_adapter_mapper_test hermes_stdio) +add_dependencies(stdio_adapter_mapper_test hermes_stdio) +gcc(stdio_adapter_mapper_test "") + +#------------------------------------------------------------------------------ +# STDIO Adapter End to End tests +#------------------------------------------------------------------------------ +add_executable(stdio_adapter_test stdio_adapter_test.cpp ${ADAPTER_COMMON}) +gcc(stdio_adapter_test "") + +add_executable(stdio_adapter_mpi_test stdio_adapter_mpi_test.cpp ${ADAPTER_COMMON}) +mpi(stdio_adapter_mpi_test 2 "") + +add_executable(hermes_stdio_adapter_test stdio_adapter_test.cpp ${ADAPTER_COMMON}) +target_link_libraries(hermes_stdio_adapter_test hermes_stdio) +add_dependencies(hermes_stdio_adapter_test hermes_stdio hermes_daemon) +set_target_properties(hermes_stdio_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") +gcc_hermes(hermes_stdio_adapter_test "" "~[request_size=range-large]" hermes "") +gcc_hermes(hermes_stdio_adapter_test "large" "[request_size=range-large]" hermes "") +gcc_hermes(hermes_stdio_adapter_test "" "~[request_size=range-large]" hermes async) +gcc_hermes(hermes_stdio_adapter_test "large" "[request_size=range-large]" hermes async) + +add_executable(hermes_stdio_low_buf_adapter_test stdio_adapter_low_buffer_space_test.cpp ${ADAPTER_COMMON}) +target_link_libraries(hermes_stdio_low_buf_adapter_test hermes_stdio) +add_dependencies(hermes_stdio_low_buf_adapter_test hermes_stdio hermes_daemon) +set_target_properties(hermes_stdio_low_buf_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") +gcc_hermes(hermes_stdio_low_buf_adapter_test "" "" hermes_small "") +gcc_hermes(hermes_stdio_low_buf_adapter_test "" "" hermes_small async) + +add_executable(hermes_stdio_adapter_mode_test stdio_adapter_mode_test.cpp ${ADAPTER_COMMON}) +target_link_libraries(hermes_stdio_adapter_mode_test hermes_stdio) +add_dependencies(hermes_stdio_adapter_mode_test hermes_stdio hermes_daemon) +set_target_properties(hermes_stdio_adapter_mode_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") +gcc_hermes_mode(hermes_stdio_adapter_mode_test "persistent" "[hermes_mode=persistent]" "DEFAULT" "0") +gcc_hermes_mode(hermes_stdio_adapter_mode_test "scratch" "[hermes_mode=scratch]" "SCRATCH" "0") +gcc_hermes_mode(hermes_stdio_adapter_mode_test "bypass" "[hermes_mode=bypass]" "BYPASS" "0") +gcc_hermes_mode(hermes_stdio_adapter_mode_test "persistent" "[hermes_mode=persistent]" "DEFAULT" "1") +gcc_hermes_mode(hermes_stdio_adapter_mode_test "scratch" "[hermes_mode=scratch]" "SCRATCH" "1") +gcc_hermes_mode(hermes_stdio_adapter_mode_test "bypass" "[hermes_mode=bypass]" "BYPASS" "1") + +add_executable(hermes_stdio_adapter_mpi_test stdio_adapter_mpi_test.cpp ${ADAPTER_COMMON}) +target_link_libraries(hermes_stdio_adapter_mpi_test hermes_stdio) +add_dependencies(hermes_stdio_adapter_mpi_test hermes_stdio hermes_daemon) +set_target_properties(hermes_stdio_adapter_mpi_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") +mpi_daemon(hermes_stdio_adapter_mpi_test 2 "~[request_size=range-large]" "" 1) +mpi_daemon(hermes_stdio_adapter_mpi_test 2 "[request_size=range-large]" "large" 1) + +add_executable(adapter_utils_test adapter_utils_test.cc ${ADAPTER_COMMON}) +target_link_libraries(adapter_utils_test hermes_stdio) +add_dependencies(adapter_utils_test hermes_stdio) +gcc(adapter_utils_test "") + +set(STDIO_TESTS + stdio_adapter_mapper_test + stdio_adapter_test + hermes_stdio_adapter_test + hermes_stdio_low_buf_adapter_test + hermes_stdio_adapter_mode_test + stdio_adapter_mpi_test + hermes_stdio_adapter_mpi_test + adapter_utils_test +) + +foreach(program ${STDIO_TESTS}) + target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_DIR}) + target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_TEST_DIR}) + target_link_libraries(${program} Catch2::Catch2 -lstdc++fs -lc MPI::MPI_CXX) +endforeach() + +if(HERMES_INSTALL_TESTS) + foreach(program ${STDIO_TESTS}) + install( + TARGETS + ${program} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} + ) + endforeach() +endif() diff --git a/adapter/test/stdio/adapter_utils_test.cc b/adapter/test/stdio/adapter_utils_test.cc new file mode 100644 index 000000000..c9bd32ef4 --- /dev/null +++ b/adapter/test/stdio/adapter_utils_test.cc @@ -0,0 +1,104 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "catch_config.h" +#include "adapter_utils.h" + +namespace stdfs = std::experimental::filesystem; + +int init(int* argc, char*** argv) { + (void)argc; + (void)argv; + return 0; +} + +int finalize() { + return 0; +} + +cl::Parser define_options() { + return cl::Parser(); +} + +// NOTE(chogan) GCC's test for weakly_canonical +TEST_CASE("WeaklyCanonical") { + namespace had = hermes::adapter; + + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + + auto dir = stdfs::path("tmp"); + if (stdfs::exists(dir)) { + stdfs::remove_all(dir, ec); + } + + stdfs::create_directory(dir); + const auto dirc = stdfs::canonical(dir); + stdfs::path foo = dir/"foo", bar = dir/"bar"; + stdfs::create_directory(foo); + stdfs::create_directory(bar); + stdfs::create_directory(bar/"baz"); + stdfs::path p; + + stdfs::create_symlink("../bar", foo/"bar"); + + p = had::WeaklyCanonical(dir/"foo//./bar///../biz/."); + REQUIRE(p == dirc/"biz"); + p = had::WeaklyCanonical(dir/"foo/.//bar/././baz/."); + REQUIRE(p == dirc/"bar/baz"); + p = had::WeaklyCanonical(stdfs::current_path()/dir/"bar//../foo/bar/baz"); + REQUIRE(p == dirc/"bar/baz"); + + ec = bad_ec; + p = had::WeaklyCanonical(dir/"foo//./bar///../biz/.", ec); + REQUIRE(!ec); + REQUIRE(p == dirc/"biz"); + ec = bad_ec; + p = had::WeaklyCanonical(dir/"foo/.//bar/././baz/.", ec); + REQUIRE(!ec); + REQUIRE(p == dirc/"bar/baz"); + ec = bad_ec; + p = had::WeaklyCanonical(stdfs::current_path()/dir/"bar//../foo/bar/baz", ec); + REQUIRE(!ec); + REQUIRE(p == dirc/"bar/baz"); + + ec = bad_ec; + p = had::WeaklyCanonical(dir/"bar/", ec); + REQUIRE(!ec); + REQUIRE(p == dirc/"bar"); + + // As above, but using "foo/.." instead of "foo", + // because there is no "foo/bar" symlink + + p = had::WeaklyCanonical(dir/"./bar///../biz/."); + REQUIRE(p == dirc/"biz"); + p = had::WeaklyCanonical(dir/"foo/.././/bar/././baz/."); + REQUIRE(p == dirc/"bar/baz"); + p = had::WeaklyCanonical(stdfs::current_path()/dir/"bar//../foo/../bar/baz"); + REQUIRE(p == dirc/"bar/baz"); + + ec = bad_ec; + p = had::WeaklyCanonical(dir/"foo/..//./bar///../biz/.", ec); + REQUIRE(!ec); + REQUIRE(p == dirc/"biz"); + ec = bad_ec; + p = had::WeaklyCanonical(dir/"foo/.././/bar/././baz/.", ec); + REQUIRE(!ec); + REQUIRE(p == dirc/"bar/baz"); + ec = bad_ec; + p = had::WeaklyCanonical( + stdfs::current_path()/dir/"bar//../foo/../bar/baz", ec); + REQUIRE(!ec); + REQUIRE(p == dirc/"bar/baz"); + + stdfs::remove_all(dir, ec); +} diff --git a/adapter/test/stdio/stdio_adapter_basic_test.cpp b/adapter/test/stdio/stdio_adapter_basic_test.cpp new file mode 100644 index 000000000..7dacb3f52 --- /dev/null +++ b/adapter/test/stdio/stdio_adapter_basic_test.cpp @@ -0,0 +1,1308 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +TEST_CASE("Open", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_open]" + "[repetition=1][file=1]") { + pretest(); + SECTION("open non-existant file") { + test::test_fopen(info.new_file.c_str(), "r"); + REQUIRE(test::fh_orig == nullptr); + test::test_fopen(info.new_file.c_str(), "r+"); + REQUIRE(test::fh_orig == nullptr); + } + + SECTION("truncate existing file and write-only") { + test::test_fopen(info.existing_file.c_str(), "w"); + REQUIRE(test::fh_orig != nullptr); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + SECTION("truncate existing file and read/write") { + test::test_fopen(info.existing_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("open existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + test::test_fopen(info.existing_file.c_str(), "r"); + REQUIRE(test::fh_orig != nullptr); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("append write existing file") { + test::test_fopen(info.existing_file.c_str(), "a"); + REQUIRE(test::fh_orig != nullptr); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("append write and read existing file") { + test::test_fopen(info.existing_file.c_str(), "a+"); + REQUIRE(test::fh_orig != nullptr); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_write]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("write to new file") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == test::size_written_orig); + } + + SECTION("write to existing file with truncate") { + test::test_fopen(info.existing_file.c_str(), "w"); + REQUIRE(test::fh_orig != nullptr); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.existing_file) == test::size_written_orig); + } + + SECTION("write to existing file at the end") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + test::test_fseek(0, SEEK_END); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == args.request_size * info.num_iterations); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.existing_file) == + test::size_written_orig + offset); + } + + SECTION("append to existing file") { + auto existing_size = stdfs::file_size(info.existing_file); + test::test_fopen(info.existing_file.c_str(), "a+"); + REQUIRE(test::fh_orig != nullptr); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.existing_file) == + existing_size + test::size_written_orig); + } + + SECTION("append to new file") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == test::size_written_orig); + } + posttest(); +} + +TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_read]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + SECTION("read from non-existing file") { + test::test_fopen(info.new_file.c_str(), "r"); + REQUIRE(test::fh_orig == nullptr); + } + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r"); + REQUIRE(test::fh_orig != nullptr); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + test::test_fread(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + SECTION("read at the end of existing file") { + test::test_fopen(info.existing_file.c_str(), "r"); + REQUIRE(test::fh_orig != nullptr); + test::test_fseek(0, SEEK_END); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == args.request_size * info.num_iterations); + test::test_fread(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == 0); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedWriteSequential", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("write to new file always at beginning") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == args.request_size); + } + + SECTION("write to new file sequentially") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == + info.num_iterations * args.request_size); + } + posttest(); +} + +TEST_CASE("BatchedReadSequential", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fread(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_fopen(info.existing_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadRandom", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed]" + "[repetition=" + + std::to_string(info.num_iterations) + + "][pattern=random][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + rand_r(&info.offset_seed) % (info.total_size - args.request_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fread(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateRandom", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_update]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=random][file=1]") { + pretest(); + SECTION("update into existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + rand_r(&info.offset_seed) % (info.total_size - args.request_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fwrite(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + fflush(test::fh_orig); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideFixed", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = (i * info.stride_size) % info.total_size; + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fread(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixed", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_update]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + + SECTION("update from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = (i * info.stride_size) % info.total_size; + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fwrite(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideDynamic", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fread(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamic", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_update]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("update from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fwrite(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedWriteRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + + SECTION("write to new file always at the start") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + size_t biggest_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + size_t request_size = + args.request_size + (rand_r(&info.offset_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_fwrite(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + if (biggest_written < request_size) biggest_written = request_size; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == biggest_written); + } + + SECTION("write to new file") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + size_t total_test_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + args.request_size + (rand_r(&info.offset_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_fwrite(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + total_test_written += test::size_written_orig; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == total_test_written); + } + posttest(); +} + +TEST_CASE("BatchedReadSequentialRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = (args.request_size + + (rand_r(&info.offset_seed) % args.request_size)) % + (info.total_size - current_offset); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + current_offset += test::size_read_orig; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_fopen(info.existing_file.c_str(), "r"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + size_t request_size = + args.request_size + (rand_r(&info.offset_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadRandomRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable]" + "[repetition=" + + std::to_string(info.num_iterations) + + "][pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + rand_r(&info.offset_seed) % (info.total_size - args.request_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % + (info.total_size - offset); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_update]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + rand_r(&info.offset_seed) % (info.total_size - args.request_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + args.request_size + (rand_r(&info.rs_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_fwrite(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = (i * info.stride_size) % info.total_size; + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % + (info.total_size - offset); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_update]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = (i * info.stride_size) % info.total_size; + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + args.request_size + (rand_r(&info.rs_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_fwrite(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + args.request_size + (rand_r(&info.rs_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_update]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + args.request_size + (rand_r(&info.rs_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_fwrite(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideNegative", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + size_t prev_offset = info.total_size + 1; + for (size_t i = 0; i < info.num_iterations; ++i) { + auto stride_offset = info.total_size - i * info.stride_size; + REQUIRE(prev_offset > stride_offset); + prev_offset = stride_offset; + auto offset = (stride_offset) % (info.total_size - args.request_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fread(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegative", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_update]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + info.total_size - ((i * info.stride_size) % info.total_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fwrite(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = (info.total_size - i * info.stride_size) % + (info.total_size - 2 * args.request_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % + (info.total_size - offset); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_update]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + info.total_size - ((i * info.stride_size) % info.total_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + args.request_size + (rand_r(&info.rs_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_fwrite(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStride2D", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - args.request_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fread(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStride2D", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_update]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - args.request_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fwrite(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStride2DRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - 2 * args.request_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % + (info.total_size - offset); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_update]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - 2 * args.request_size); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + args.request_size + (rand_r(&info.rs_seed) % args.request_size); + std::string data(request_size, '1'); + test::test_fwrite(data.c_str(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +/** + * Temporal Fixed + */ + +TEST_CASE("BatchedWriteTemporalFixed", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1][temporal=fixed]") { + pretest(); + + SECTION("write to existing file") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + usleep(info.temporal_interval_ms * 1000); + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == args.request_size); + } + + SECTION("write to new file always at start") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + usleep(info.temporal_interval_ms * 1000); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == + info.num_iterations * args.request_size); + } + posttest(); +} + +TEST_CASE("BatchedReadSequentialTemporalFixed", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1][temporal=fixed]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + usleep(info.temporal_interval_ms * 1000); + test::test_fread(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_fopen(info.existing_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + usleep(info.temporal_interval_ms * 1000); + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedWriteTemporalVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1][temporal=variable]") { + pretest(); + + SECTION("write to existing file") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + info.temporal_interval_ms = + rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; + usleep(info.temporal_interval_ms * 1000); + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == args.request_size); + } + + SECTION("write to new file always at start") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + info.temporal_interval_ms = + rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; + usleep(info.temporal_interval_ms * 1000); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == + info.num_iterations * args.request_size); + } + posttest(); +} + +TEST_CASE("BatchedReadSequentialTemporalVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1][temporal=variable]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + info.temporal_interval_ms = + rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; + usleep(info.temporal_interval_ms * 1000); + test::test_fread(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_fopen(info.existing_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + info.temporal_interval_ms = + rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; + usleep(info.temporal_interval_ms * 1000); + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedMixedSequential", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_mixed]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("read after write on new file") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + size_t last_offset = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fwrite(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_fseek(last_offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fread(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + last_offset += args.request_size; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("write and read alternative existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + if (i % 2 == 0) { + test::test_fwrite(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } else { + test::test_fread(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + SECTION("update after read existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + size_t last_offset = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fread(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + test::test_fseek(last_offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fwrite(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + last_offset += args.request_size; + } + + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + SECTION("read all after write all on new file in single open") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fwrite(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fread(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + SECTION("read all after write all on new file in different open") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fwrite(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + test::test_fopen(info.new_file.c_str(), "r"); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fread(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("SingleMixed", "[process=" + std::to_string(info.comm_size) + + "][operation=single_mixed]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + pretest(); + SECTION("read after write from new file") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + test::test_fwrite(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fread(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + SECTION("update after read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + test::test_fread(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + test::test_fwrite(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + SECTION("read after write from new file different opens") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + test::test_fwrite(info.write_data.data(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + test::test_fopen(info.new_file.c_str(), "r+"); + test::test_fread(info.read_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} diff --git a/adapter/test/stdio/stdio_adapter_func_test.cpp b/adapter/test/stdio/stdio_adapter_func_test.cpp new file mode 100644 index 000000000..b3dda30a5 --- /dev/null +++ b/adapter/test/stdio/stdio_adapter_func_test.cpp @@ -0,0 +1,771 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +TEST_CASE("FFlush", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_fflush]" + "[repetition=1][file=1]") { + pretest(); + SECTION("Flushing contents of file in different modes") { + FILE* fd = fopen(info.existing_file.c_str(), "w"); + REQUIRE(fd != nullptr); + int status = fflush(fd); + REQUIRE(status == 0); + status = fclose(fd); + REQUIRE(status == 0); + + fd = fopen(info.existing_file.c_str(), "w+"); + REQUIRE(fd != nullptr); + status = fflush(fd); + REQUIRE(status == 0); + status = fclose(fd); + REQUIRE(status == 0); + + fd = fopen(info.existing_file.c_str(), "r+"); + REQUIRE(fd != nullptr); + status = fflush(fd); + REQUIRE(status == 0); + status = fclose(fd); + REQUIRE(status == 0); + + fd = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fd != nullptr); + status = fflush(fd); + REQUIRE(status == 0); + status = fclose(fd); + REQUIRE(status == 0); + + fd = fopen(info.existing_file.c_str(), "a"); + REQUIRE(fd != nullptr); + status = fflush(fd); + REQUIRE(status == 0); + status = fclose(fd); + REQUIRE(status == 0); + + fd = fopen(info.existing_file.c_str(), "a+"); + REQUIRE(fd != nullptr); + status = fflush(fd); + REQUIRE(status == 0); + status = fclose(fd); + REQUIRE(status == 0); + } + SECTION("Flushing contents of all files") { + int status = fflush(nullptr); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("Fdopen", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_fdopen]" + "[repetition=1][file=1]") { + pretest(); + SECTION("Associate a FILE ptr with read mode") { + int fd = open(info.existing_file.c_str(), O_RDWR); + REQUIRE(fd != -1); + + FILE* fh = fdopen(fd, "r"); + REQUIRE(fh != nullptr); + size_t read_size = + fread(info.read_data.data(), sizeof(char), args.request_size, fh); + REQUIRE(read_size == args.request_size); + int status = fclose(fh); + REQUIRE(status == 0); + + status = fcntl(fd, F_GETFD); + REQUIRE(fd != -1); + + status = close(fd); + REQUIRE(status == -1); + } + SECTION("Associate a FILE ptr with write mode") { + int fd = open(info.existing_file.c_str(), O_RDWR); + REQUIRE(fd != -1); + + FILE* fh = fdopen(fd, "w"); + REQUIRE(fh != nullptr); + size_t write_size = + fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fh); + REQUIRE(write_size == args.request_size); + int status = fclose(fh); + REQUIRE(status == 0); + + status = close(fd); + REQUIRE(status == -1); + } + SECTION("Associate a FILE ptr with read plus mode") { + int fd = open(info.existing_file.c_str(), O_RDWR); + REQUIRE(fd != -1); + + FILE* fh = fdopen(fd, "r"); + REQUIRE(fh != nullptr); + size_t read_size = + fread(info.read_data.data(), sizeof(char), args.request_size, fh); + REQUIRE(read_size == args.request_size); + int status = fclose(fh); + REQUIRE(status == 0); + + status = fcntl(fd, F_GETFD); + REQUIRE(fd != -1); + + status = close(fd); + REQUIRE(status == -1); + } + SECTION("Associate a FILE ptr with write plus mode") { + int fd = open(info.existing_file.c_str(), O_RDWR); + REQUIRE(fd != -1); + + FILE* fh = fdopen(fd, "w+"); + REQUIRE(fh != nullptr); + size_t write_size = + fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fh); + REQUIRE(write_size == args.request_size); + int status = fclose(fh); + REQUIRE(status == 0); + + status = fcntl(fd, F_GETFD); + REQUIRE(fd != -1); + + status = close(fd); + REQUIRE(status == -1); + } + SECTION("Associate a FILE ptr with append mode") { + int fd = open(info.existing_file.c_str(), O_RDWR | O_APPEND); + REQUIRE(fd != -1); + + FILE* fh = fdopen(fd, "a"); + REQUIRE(fh != nullptr); + size_t write_size = + fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fh); + REQUIRE(write_size == args.request_size); + int status = fclose(fh); + REQUIRE(status == 0); + + status = fcntl(fd, F_GETFD); + REQUIRE(fd != -1); + + status = close(fd); + REQUIRE(status == -1); + } + SECTION("Associate a FILE ptr with append plus mode") { + int fd = open(info.existing_file.c_str(), O_RDWR | O_APPEND); + REQUIRE(fd != -1); + + FILE* fh = fdopen(fd, "a+"); + REQUIRE(fh != nullptr); + size_t write_size = + fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fh); + REQUIRE(write_size == args.request_size); + int status = fclose(fh); + REQUIRE(status == 0); + + status = fcntl(fd, F_GETFD); + REQUIRE(fd != -1); + + status = close(fd); + REQUIRE(status == -1); + } + SECTION("Associate a FILE ptr with read mode twice") { + int fd = open(info.existing_file.c_str(), O_RDWR); + REQUIRE(fd != -1); + + FILE* fh = fdopen(fd, "r"); + REQUIRE(fh != nullptr); + size_t read_size = + fread(info.read_data.data(), sizeof(char), args.request_size, fh); + REQUIRE(read_size == args.request_size); + + int status = fclose(fh); + REQUIRE(status == 0); + + status = close(fd); + REQUIRE(status == -1); + } + SECTION("Associate a FILE ptr with read mode twice after one closes") { + int fd = open(info.existing_file.c_str(), O_RDWR); + REQUIRE(fd != -1); + + FILE* fh = fdopen(fd, "r"); + REQUIRE(fh != nullptr); + size_t read_size = + fread(info.read_data.data(), sizeof(char), args.request_size, fh); + REQUIRE(read_size == args.request_size); + + int status = fcntl(fd, F_GETFD); + REQUIRE(fd != -1); + + status = fclose(fh); + REQUIRE(status == 0); + + FILE* fh2 = fdopen(fd, "r"); + REQUIRE(fh2 == nullptr); + + status = close(fd); + REQUIRE(status == -1); + } + posttest(false); +} + +TEST_CASE("Freopen", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_freopen]" + "[repetition=1][file=1]") { + pretest(); + SECTION("change different modes") { + FILE* fhr = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fhr != nullptr); + + FILE* fhw = freopen(info.existing_file.c_str(), "w", fhr); + REQUIRE(fhw != nullptr); + size_t write_size = + fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhw); + REQUIRE(write_size == args.request_size); + + FILE* fhwp = freopen(info.existing_file.c_str(), "w+", fhw); + REQUIRE(fhwp != nullptr); + write_size = + fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhwp); + REQUIRE(write_size == args.request_size); + + FILE* fha = freopen(info.existing_file.c_str(), "a", fhwp); + REQUIRE(fha != nullptr); + write_size = + fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhwp); + REQUIRE(write_size == args.request_size); + + FILE* fhap = freopen(info.existing_file.c_str(), "a+", fha); + REQUIRE(fhap != nullptr); + write_size = + fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhap); + REQUIRE(write_size == args.request_size); + + int status = fclose(fhap); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("fgetc", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_fgetc]" + "[repetition=" + + std::to_string(info.num_iterations) + "][file=1]") { + pretest(); + SECTION("iterate and get all characters") { + FILE* fh = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + size_t total_chars = 0; + int c = '0'; + do { + c = fgetc(fh); + total_chars++; + if (total_chars >= info.num_iterations) break; + } while (c != EOF); + REQUIRE(total_chars == info.num_iterations); + int status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("getc", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_getc]" + "[repetition=" + + std::to_string(info.num_iterations) + "][file=1]") { + pretest(); + SECTION("iterate and get all characters") { + FILE* fh = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + size_t total_chars = 0; + int c = '0'; + do { + c = getc(fh); + total_chars++; + if (total_chars >= info.num_iterations) break; + } while (c != EOF); + REQUIRE(total_chars == info.num_iterations); + int status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("getw", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_getw]" + "[repetition=" + + std::to_string(info.num_iterations) + "][file=1]") { + pretest(); + SECTION("iterate and get all characters") { + FILE* fh = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + size_t total_chars = 0; + int c = '0'; + do { + c = getw(fh); + total_chars++; + if (total_chars >= info.num_iterations) break; + } while (c != EOF); + REQUIRE(total_chars == info.num_iterations); + int status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("fgets", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_fgets]" + "[repetition=1][file=1]") { + pretest(); + SECTION("iterate and get all characters") { + FILE* fh = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + auto ret_str = fgets(info.read_data.data(), args.request_size, fh); + REQUIRE(ret_str != NULL); + REQUIRE(strlen(ret_str) == args.request_size - 1); + int status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("fputc", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_fputc]" + "[repetition=" + + std::to_string(info.num_iterations) + "][file=1]") { + pretest(); + SECTION("iterate and get all characters") { + FILE* fh = fopen(info.new_file.c_str(), "w+"); + REQUIRE(fh != nullptr); + size_t total_chars = info.num_iterations; + char c = 'w'; + for (size_t i = 0; i < total_chars; ++i) { + int ret_char = fputc(c, fh); + REQUIRE(ret_char == c); + } + int status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("putc", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_putc]" + "[repetition=" + + std::to_string(info.num_iterations) + "][file=1]") { + pretest(); + SECTION("iterate and get all characters") { + FILE* fh = fopen(info.new_file.c_str(), "w+"); + REQUIRE(fh != nullptr); + size_t total_chars = info.num_iterations; + char c = 'w'; + for (size_t i = 0; i < total_chars; ++i) { + int ret_char = putc(c, fh); + REQUIRE(ret_char == c); + } + int status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} +TEST_CASE("putw", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_putw]" + "[repetition=" + + std::to_string(info.num_iterations) + "][file=1]") { + pretest(); + SECTION("iterate and get all characters") { + FILE* fh = fopen(info.new_file.c_str(), "w+"); + REQUIRE(fh != nullptr); + size_t total_chars = info.num_iterations; + int c = 'w'; + for (size_t i = 0; i < total_chars; ++i) { + int ret = putw(c, fh); + REQUIRE(ret == 0); + } + int status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("fputs", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_fputs]" + "[repetition=1][file=1]") { + pretest(); + SECTION("iterate and get all characters") { + FILE* fh = fopen(info.existing_file.c_str(), "w+"); + REQUIRE(fh != nullptr); + int status = fputs(info.write_data.c_str(), fh); + REQUIRE(status != -1); + status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("fseek", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_fseek]" + "[repetition=1][file=1]") { + pretest(); + SECTION("test all seek modes") { + FILE* fh = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + int status = fseek(fh, 0, SEEK_SET); + REQUIRE(status == 0); + size_t offset = ftell(fh); + REQUIRE(offset == 0); + + status = fseek(fh, 0, SEEK_CUR); + REQUIRE(status == 0); + offset = ftell(fh); + REQUIRE(offset == 0); + + status = fseek(fh, 0, SEEK_END); + REQUIRE(status == 0); + offset = ftell(fh); + REQUIRE(offset == info.total_size); + + status = fseek(fh, 0, SEEK_CUR); + REQUIRE(status == 0); + offset = ftell(fh); + REQUIRE(offset == info.total_size); + + status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("fseeko", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_fseeko]" + "[repetition=1][file=1]") { + pretest(); + SECTION("test all seek modes") { + FILE* fh = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + int status = fseeko(fh, 0, SEEK_SET); + REQUIRE(status == 0); + size_t offset = ftell(fh); + REQUIRE(offset == 0); + + status = fseeko(fh, 0, SEEK_CUR); + REQUIRE(status == 0); + offset = ftell(fh); + REQUIRE(offset == 0); + + status = fseeko(fh, 0, SEEK_END); + REQUIRE(status == 0); + offset = ftell(fh); + REQUIRE(offset == info.total_size); + + status = fseeko(fh, 0, SEEK_CUR); + REQUIRE(status == 0); + offset = ftell(fh); + REQUIRE(offset == info.total_size); + + status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("fseeko64", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_fseeko64]" + "[repetition=1][file=1]") { + pretest(); + SECTION("test all seek modes") { + FILE* fh = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + int status = fseeko64(fh, 0, SEEK_SET); + REQUIRE(status == 0); + size_t offset = ftell(fh); + REQUIRE(offset == 0); + + status = fseeko64(fh, 0, SEEK_CUR); + REQUIRE(status == 0); + offset = ftell(fh); + REQUIRE(offset == 0); + + status = fseeko64(fh, 0, SEEK_END); + REQUIRE(status == 0); + offset = ftell(fh); + REQUIRE(offset == info.total_size); + + status = fseeko64(fh, 0, SEEK_CUR); + REQUIRE(status == 0); + offset = ftell(fh); + REQUIRE(offset == info.total_size); + + status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("rewind", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_rewind]" + "[repetition=1][file=1]") { + pretest(); + SECTION("test all seek modes") { + FILE* fh = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + int status = fseeko(fh, 0, SEEK_SET); + REQUIRE(status == 0); + size_t offset = ftell(fh); + REQUIRE(offset == 0); + rewind(fh); + offset = ftell(fh); + REQUIRE(offset == 0); + + status = fseeko(fh, 0, SEEK_END); + REQUIRE(status == 0); + offset = ftell(fh); + REQUIRE(offset == info.total_size); + rewind(fh); + offset = ftell(fh); + REQUIRE(offset == 0); + + status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("fsetpos", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_fsetpos]" + "[repetition=1][file=1]") { + pretest(); + SECTION("test all seek modes") { + FILE* fh = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + fpos_t position; + fgetpos(fh, &position); + + position.__pos = 0; + int status = fsetpos(fh, &position); + REQUIRE(status == 0); + size_t offset = ftell(fh); + REQUIRE(offset == 0); + + position.__pos = info.total_size; + status = fsetpos(fh, &position); + REQUIRE(status == 0); + offset = ftell(fh); + REQUIRE(offset == info.total_size); + + status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("fsetpos64", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_fsetpos64]" + "[repetition=1][file=1]") { + pretest(); + SECTION("test all seek modes") { + FILE* fh = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + fpos64_t position; + fgetpos64(fh, &position); + + position.__pos = 0; + int status = fsetpos64(fh, &position); + REQUIRE(status == 0); + size_t offset = ftell(fh); + REQUIRE(offset == 0); + + position.__pos = info.total_size; + status = fsetpos64(fh, &position); + REQUIRE(status == 0); + offset = ftell(fh); + REQUIRE(offset == info.total_size); + + status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("fgetpos", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_fgetpos]" + "[repetition=1][file=1]") { + pretest(); + SECTION("test all seek modes") { + FILE* fh = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + fpos_t position; + + int status = fseek(fh, 0, SEEK_SET); + REQUIRE(status == 0); + status = fgetpos(fh, &position); + REQUIRE(position.__pos == 0); + + status = fseek(fh, 0, SEEK_END); + REQUIRE(status == 0); + status = fgetpos(fh, &position); + REQUIRE(position.__pos == (long int)info.total_size); + + status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("fgetpos64", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_fgetpos64]" + "[repetition=1][file=1]") { + pretest(); + SECTION("test all seek modes") { + FILE* fh = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + fpos64_t position; + + int status = fseek(fh, 0, SEEK_SET); + REQUIRE(status == 0); + status = fgetpos64(fh, &position); + REQUIRE(position.__pos == 0); + + status = fseek(fh, 0, SEEK_END); + REQUIRE(status == 0); + status = fgetpos64(fh, &position); + REQUIRE(position.__pos == (long int)info.total_size); + + status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("Open64", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_open]" + "[repetition=1][file=1]") { + pretest(); + SECTION("open non-existant file") { + FILE* fh = fopen64(info.new_file.c_str(), "r"); + REQUIRE(fh == nullptr); + fh = fopen64(info.new_file.c_str(), "r+"); + REQUIRE(fh == nullptr); + } + + SECTION("truncate existing file and write-only") { + FILE* fh = fopen64(info.existing_file.c_str(), "w"); + REQUIRE(fh != nullptr); + int status = fclose(fh); + REQUIRE(status == 0); + } + SECTION("truncate existing file and read/write") { + FILE* fh = fopen64(info.existing_file.c_str(), "w+"); + REQUIRE(fh != nullptr); + int status = fclose(fh); + REQUIRE(status == 0); + } + + SECTION("open existing file") { + FILE* fh = fopen64(info.existing_file.c_str(), "r+"); + REQUIRE(fh != nullptr); + int status = fclose(fh); + REQUIRE(status == 0); + fh = fopen64(info.existing_file.c_str(), "r"); + REQUIRE(fh != nullptr); + status = fclose(fh); + REQUIRE(status == 0); + } + + SECTION("append write existing file") { + FILE* fh = fopen64(info.existing_file.c_str(), "a"); + REQUIRE(fh != nullptr); + int status = fclose(fh); + REQUIRE(status == 0); + } + + SECTION("append write and read existing file") { + FILE* fh = fopen64(info.existing_file.c_str(), "a+"); + REQUIRE(fh != nullptr); + int status = fclose(fh); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("Freopen64", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_freopen]" + "[repetition=1][file=1]") { + pretest(); + SECTION("change different modes") { + FILE* fhr = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fhr != nullptr); + + FILE* fhw = freopen64(info.existing_file.c_str(), "w", fhr); + REQUIRE(fhw != nullptr); + size_t write_size = + fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhw); + REQUIRE(write_size == args.request_size); + + FILE* fhwp = freopen64(info.existing_file.c_str(), "w+", fhw); + REQUIRE(fhwp != nullptr); + write_size = + fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhwp); + REQUIRE(write_size == args.request_size); + + FILE* fha = freopen64(info.existing_file.c_str(), "a", fhwp); + REQUIRE(fha != nullptr); + write_size = + fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhwp); + REQUIRE(write_size == args.request_size); + + FILE* fhap = freopen64(info.existing_file.c_str(), "a+", fha); + REQUIRE(fhap != nullptr); + write_size = + fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhap); + REQUIRE(write_size == args.request_size); + + int status = fclose(fhap); + REQUIRE(status == 0); + } + posttest(false); +} + +TEST_CASE("MultiOpen", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=multi_open]" + "[repetition=1][file=1]") { + pretest(); + SECTION("Open same file twice and then close both fps") { + FILE* fh1 = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + FILE* fh2 = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh2 != nullptr); + int status = fclose(fh1); + REQUIRE(status == 0); + status = fclose(fh2); + REQUIRE(status == 0); + } + posttest(false); +} diff --git a/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp b/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp new file mode 100644 index 000000000..3f8903321 --- /dev/null +++ b/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp @@ -0,0 +1,285 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include + +#include +#include + +#include "adapter_test_utils.h" +#include "catch_config.h" +#if HERMES_INTERCEPT == 1 +#include "stdio/real_api.h" +#endif + +namespace stdfs = std::experimental::filesystem; + +namespace hermes::adapter::stdio::test { +struct Arguments { + std::string filename = "test.dat"; + std::string directory = "/tmp"; + size_t request_size = 65536; +}; +struct Info { + int rank = 0; + int comm_size = 1; + std::string write_data; + std::string read_data; + std::string new_file; + std::string existing_file; + std::string new_file_cmp; + std::string existing_file_cmp; + size_t num_iterations = 64; + unsigned int offset_seed = 1; + unsigned int rs_seed = 1; + unsigned int temporal_interval_seed = 5; + size_t total_size; + size_t stride_size = 512; + unsigned int temporal_interval_ms = 1; + size_t small_min = 1, small_max = 4 * 1024; + size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; + size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; +}; +} // namespace hermes::adapter::stdio::test +hermes::adapter::stdio::test::Arguments args; +hermes::adapter::stdio::test::Info info; + +int init(int* argc, char*** argv) { + MPI_Init(argc, argv); + info.write_data = GenRandom(args.request_size); + info.read_data = std::string(args.request_size, 'r'); + return 0; +} +int finalize() { + MPI_Finalize(); + return 0; +} + +int pretest() { + stdfs::path fullpath = args.directory; + fullpath /= args.filename; + info.new_file = fullpath.string() + "_new_" + std::to_string(getpid()); + info.existing_file = fullpath.string() + "_ext_" + std::to_string(getpid()); + info.new_file_cmp = + fullpath.string() + "_new_cmp" + "_" + std::to_string(getpid()); + info.existing_file_cmp = + fullpath.string() + "_ext_cmp" + "_" + std::to_string(getpid()); + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + if (!stdfs::exists(info.existing_file)) { + std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + + std::to_string(args.request_size * info.num_iterations) + + "; } > " + info.existing_file + " 2> /dev/null"; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file) == + args.request_size * info.num_iterations); + info.total_size = stdfs::file_size(info.existing_file); + } + if (!stdfs::exists(info.existing_file_cmp)) { + std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file_cmp) == + args.request_size * info.num_iterations); + } + REQUIRE(info.total_size > 0); +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); +#endif + return 0; +} + +int posttest(bool compare_data = true) { +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); +#endif + if (compare_data && stdfs::exists(info.new_file) && + stdfs::exists(info.new_file_cmp)) { + size_t size = stdfs::file_size(info.new_file); + REQUIRE(size == stdfs::file_size(info.new_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.new_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) { + char_mismatch = pos; + break; + } + } + REQUIRE(char_mismatch == 0); + } + } + if (compare_data && stdfs::exists(info.existing_file) && + stdfs::exists(info.existing_file_cmp)) { + size_t size = stdfs::file_size(info.existing_file); + if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); + REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + /* Clean up. */ + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); +#endif + return 0; +} + +cl::Parser define_options() { + return cl::Opt(args.filename, "filename")["-f"]["--filename"]( + "Filename used for performing I/O") | + cl::Opt(args.directory, "dir")["-d"]["--directory"]( + "Directory used for performing I/O") | + cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( + "Request size used for performing I/O"); +} + +namespace test { +FILE* fh_orig; +FILE* fh_cmp; +int status_orig; +size_t size_read_orig; +size_t size_written_orig; +void test_fopen(const char* path, const char* mode) { + std::string cmp_path; + if (strcmp(path, info.new_file.c_str()) == 0) { + cmp_path = info.new_file_cmp; + } else { + cmp_path = info.existing_file_cmp; + } + fh_orig = fopen(path, mode); + fh_cmp = fopen(cmp_path.c_str(), mode); + bool is_same = (fh_cmp != nullptr && fh_orig != nullptr) || + (fh_cmp == nullptr && fh_orig == nullptr); + REQUIRE(is_same); +} +void test_fclose() { + status_orig = fclose(fh_orig); + int status = fclose(fh_cmp); + REQUIRE(status == status_orig); +} +void test_fwrite(const void* ptr, size_t size) { + size_written_orig = fwrite(ptr, sizeof(char), size, fh_orig); + size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp); + REQUIRE(size_written == size_written_orig); +} +void test_fread(char* ptr, size_t size) { + size_read_orig = fread(ptr, sizeof(char), size, fh_orig); + std::vector read_data(size, 'r'); + size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp); + REQUIRE(size_read == size_read_orig); + if (size_read > 0) { + size_t unmatching_chars = 0; + for (size_t i = 0; i < size; ++i) { + if (read_data[i] != ptr[i]) { + unmatching_chars = i; + break; + } + } + REQUIRE(unmatching_chars == 0); + } +} +void test_fseek(long offset, int whence) { + status_orig = fseek(fh_orig, offset, whence); + int status = fseek(fh_cmp, offset, whence); + REQUIRE(status == status_orig); +} +} // namespace test + +TEST_CASE("BatchedWriteSequential", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("write to new file one big write") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + auto write_size = args.request_size * (info.num_iterations + 1); + info.write_data = GenRandom(write_size); + test::test_fwrite(info.write_data.c_str(), write_size); + REQUIRE(test::size_written_orig == write_size); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == write_size); + } + SECTION("write to new file multiple write") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i <= info.num_iterations; ++i) { + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + REQUIRE(test::size_written_orig == args.request_size); + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == + args.request_size * (info.num_iterations + 1)); + } + posttest(); +} diff --git a/adapter/test/stdio/stdio_adapter_mapper_test.cpp b/adapter/test/stdio/stdio_adapter_mapper_test.cpp new file mode 100644 index 000000000..1d5eb7ede --- /dev/null +++ b/adapter/test/stdio/stdio_adapter_mapper_test.cpp @@ -0,0 +1,195 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "catch_config.h" +#include "constants.h" +#include "mapper/mapper_factory.h" +#include "stdio/fs_api.h" + +using hermes::adapter::BlobPlacements; +using hermes::adapter::MapperFactory; +using hermes::adapter::fs::kMapperType; +using hermes::adapter::fs::MetadataManager; + +namespace stdfs = std::experimental::filesystem; + +namespace hermes::adapter::stdio::test { +struct Arguments { + std::string filename = "test.dat"; + std::string directory = "/tmp"; + size_t request_size = 65536; + size_t num_iterations = 1024; +}; +struct Info { + int rank = 0; + int comm_size = 1; + std::string new_file; + std::string existing_file; + unsigned int offset_seed = 1; + unsigned int rs_seed = 1; + size_t total_size; + size_t stride_size = 1024; + size_t small_min = 1, small_max = 4 * 1024; + size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; + size_t large_min = 256 * 1024 + 1, large_max = 4 * 1024 * 1024; +}; +} // namespace hermes::adapter::stdio::test +hermes::adapter::stdio::test::Arguments args; +hermes::adapter::stdio::test::Info info; + +int init(int* argc, char*** argv) { + MPI_Init(argc, argv); + + return 0; +} +int finalize() { + MPI_Finalize(); + + return 0; +} + +int pretest() { + stdfs::path fullpath = args.directory; + fullpath /= args.filename; + info.new_file = fullpath.string() + "_new"; + info.existing_file = fullpath.string() + "_ext"; + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (!stdfs::exists(info.existing_file)) { + std::string cmd = "dd if=/dev/zero of=" + info.existing_file + + " bs=1 count=0 seek=" + + std::to_string(args.request_size * args.num_iterations) + + " > /dev/null 2>&1"; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file) == + args.request_size * args.num_iterations); + info.total_size = stdfs::file_size(info.existing_file); + } + REQUIRE(info.total_size > 0); + return 0; +} + +int posttest() { + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + return 0; +} + +cl::Parser define_options() { + return cl::Opt(args.filename, "filename")["-f"]["--filename"]( + "Filename used for performing I/O") | + cl::Opt(args.directory, "dir")["-d"]["--directory"]( + "Directory used for performing I/O") | + cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( + "Request size used for performing I/O") | + cl::Opt(args.num_iterations, "iterations")["-n"]["--iterations"]( + "Number of iterations of requests"); +} + +TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_write]" + "[request_size=type-fixed][repetition=1]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("Map a one request") { + auto mapper = MapperFactory().Get(kMapperType); + size_t total_size = args.request_size; + FILE* fp = fopen(info.new_file.c_str(), "w+"); + REQUIRE(fp != nullptr); + size_t offset = 0; + REQUIRE(kPageSize > total_size + offset); + BlobPlacements mapping; + mapper->map(offset, total_size, mapping); + REQUIRE(mapping.size() == 1); + REQUIRE(mapping[0].bucket_off_ == offset); + REQUIRE(mapping[0].blob_size_ == total_size); + REQUIRE(mapping[0].blob_off_ == offset); + int status = fclose(fp); + REQUIRE(status == 0); + } + SECTION("Map a one big request") { + auto mapper = MapperFactory().Get(kMapperType); + size_t total_size = args.request_size * args.num_iterations; + FILE* fp = fopen(info.new_file.c_str(), "w+"); + REQUIRE(fp != nullptr); + size_t offset = 0; + BlobPlacements mapping; + mapper->map(offset, total_size, mapping); + REQUIRE(mapping.size() == ceil((double)total_size / kPageSize)); + for (const auto& item : mapping) { + size_t mapped_size = + total_size - offset > kPageSize ? kPageSize : total_size - offset; + REQUIRE(item.bucket_off_ == offset); + REQUIRE(item.blob_size_ == mapped_size); + REQUIRE(item.blob_off_ == offset % kPageSize); + offset += mapped_size; + } + int status = fclose(fp); + REQUIRE(status == 0); + } + SECTION("Map a one large unaligned request") { + auto mapper = MapperFactory().Get(kMapperType); + size_t total_size = args.request_size * args.num_iterations; + FILE* fp = fopen(info.new_file.c_str(), "w+"); + REQUIRE(fp != nullptr); + size_t offset = 1; + BlobPlacements mapping; + mapper->map(offset, total_size, mapping); + bool has_rem = (total_size + offset) % kPageSize != 0; + if (has_rem) { + REQUIRE(mapping.size() == ceil((double)total_size / kPageSize) + 1); + } else { + REQUIRE(mapping.size() == ceil((double)total_size / kPageSize)); + } + + size_t i = 0; + size_t current_offset = offset; + for (const auto& item : mapping) { + size_t mapped_size = 0; + if (i == 0) { + mapped_size = kPageSize - offset; + } else if (i == mapping.size() - 1) { + mapped_size = offset; + } else { + mapped_size = kPageSize; + } + REQUIRE(item.bucket_off_ == current_offset); + REQUIRE(item.blob_size_ == mapped_size); + REQUIRE(item.blob_off_ == current_offset % kPageSize); + current_offset += mapped_size; + i++; + } + int status = fclose(fp); + REQUIRE(status == 0); + } + SECTION("Map a one small unaligned request") { + auto mapper = MapperFactory().Get(kMapperType); + size_t total_size = args.request_size; + FILE* fp = fopen(info.new_file.c_str(), "w+"); + REQUIRE(fp != nullptr); + size_t offset = 1; + REQUIRE(kPageSize > total_size + offset); + BlobPlacements mapping; + mapper->map(offset, total_size, mapping); + REQUIRE(mapping.size() == 1); + REQUIRE(mapping[0].bucket_off_ == offset); + REQUIRE(mapping[0].blob_size_ == total_size); + REQUIRE(mapping[0].blob_off_ == 1); + int status = fclose(fp); + REQUIRE(status == 0); + } + posttest(); +} diff --git a/adapter/test/stdio/stdio_adapter_mode_test.cpp b/adapter/test/stdio/stdio_adapter_mode_test.cpp new file mode 100644 index 000000000..d315c56e5 --- /dev/null +++ b/adapter/test/stdio/stdio_adapter_mode_test.cpp @@ -0,0 +1,340 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include +#include + +#include +#include + +#if HERMES_INTERCEPT == 1 +#include "stdio/real_api.h" +#endif + +#include "adapter_test_utils.h" + +namespace stdfs = std::experimental::filesystem; + +namespace hermes::adapter::stdio::test { +struct Arguments { + std::string filename = "test.dat"; + std::string directory = "/tmp"; + size_t request_size = 65536; +}; +struct Info { + int rank = 0; + int comm_size = 1; + std::string write_data; + std::string read_data; + std::string new_file; + std::string existing_file; + std::string new_file_cmp; + std::string existing_file_cmp; + size_t num_iterations = 64; + unsigned int offset_seed = 1; + unsigned int rs_seed = 1; + unsigned int temporal_interval_seed = 5; + size_t total_size; + size_t stride_size = 512; + unsigned int temporal_interval_ms = 1; + size_t small_min = 1, small_max = 4 * 1024; + size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; + size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; +}; +} // namespace hermes::adapter::stdio::test +hermes::adapter::stdio::test::Arguments args; +hermes::adapter::stdio::test::Info info; + +int init(int* argc, char*** argv) { + stdfs::path fullpath = args.directory; + fullpath /= args.filename; + info.new_file = fullpath.string() + "_new" + std::to_string(getpid()); + info.existing_file = fullpath.string() + "_ext" + std::to_string(getpid()); + info.new_file_cmp = fullpath.string() + "_new_cmp" + std::to_string(getpid()); + info.existing_file_cmp = + fullpath.string() + "_ext_cmp" + std::to_string(getpid()); + char* set_path = getenv("SET_PATH"); + if (set_path && strcmp(set_path, "1") == 0) { + auto paths = info.new_file + "," + info.existing_file; + setenv(kAdapterModeInfo, paths.c_str(), 1); + } + MPI_Init(argc, argv); + info.write_data = GenRandom(args.request_size); + info.read_data = std::string(args.request_size, 'r'); + return 0; +} +int finalize() { + MPI_Finalize(); + return 0; +} + +int pretest() { + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + if (!stdfs::exists(info.existing_file)) { + std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + + std::to_string(args.request_size * info.num_iterations) + + "; } > " + info.existing_file + " 2> /dev/null"; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file) == + args.request_size * info.num_iterations); + info.total_size = stdfs::file_size(info.existing_file); + } + if (!stdfs::exists(info.existing_file_cmp)) { + std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file_cmp) == + args.request_size * info.num_iterations); + } + REQUIRE(info.total_size > 0); +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); +#endif + return 0; +} + +int posttest(bool compare_data = true) { +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); +#endif + if (compare_data && stdfs::exists(info.new_file) && + stdfs::exists(info.new_file_cmp)) { + size_t size = stdfs::file_size(info.new_file); + REQUIRE(size == stdfs::file_size(info.new_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.new_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + if (compare_data && stdfs::exists(info.existing_file) && + stdfs::exists(info.existing_file_cmp)) { + size_t size = stdfs::file_size(info.existing_file); + if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); + REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + /* Clean up. */ + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); +#endif + return 0; +} + +cl::Parser define_options() { + return cl::Opt(args.filename, "filename")["-f"]["--filename"]( + "Filename used for performing I/O") | + cl::Opt(args.directory, "dir")["-d"]["--directory"]( + "Directory used for performing I/O") | + cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( + "Request size used for performing I/O"); +} + +namespace test { +FILE* fh_orig; +FILE* fh_cmp; +int status_orig; +size_t size_read_orig; +size_t size_written_orig; +void test_fopen(const char* path, const char* mode) { + std::string cmp_path; + if (strcmp(path, info.new_file.c_str()) == 0) { + cmp_path = info.new_file_cmp; + } else { + cmp_path = info.existing_file_cmp; + } + fh_orig = fopen(path, mode); + fh_cmp = fopen(cmp_path.c_str(), mode); + bool is_same = (fh_cmp != nullptr && fh_orig != nullptr) || + (fh_cmp == nullptr && fh_orig == nullptr); + REQUIRE(is_same); +} +void test_fclose() { + status_orig = fclose(fh_orig); + int status = fclose(fh_cmp); + REQUIRE(status == status_orig); +} +void test_fwrite(const void* ptr, size_t size) { + size_written_orig = fwrite(ptr, sizeof(char), size, fh_orig); + size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp); + REQUIRE(size_written == size_written_orig); +} +void test_fread(char* ptr, size_t size) { + size_read_orig = fread(ptr, sizeof(char), size, fh_orig); + std::vector read_data(size, 'r'); + size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp); + REQUIRE(size_read == size_read_orig); + if (size_read > 0) { + size_t unmatching_chars = 0; + for (size_t i = 0; i < size; ++i) { + if (read_data[i] != ptr[i]) { + unmatching_chars = i; + break; + } + } + REQUIRE(unmatching_chars == 0); + } +} +void test_fseek(long offset, int whence) { + status_orig = fseek(fh_orig, offset, whence); + int status = fseek(fh_cmp, offset, whence); + REQUIRE(status == status_orig); +} +} // namespace test + +TEST_CASE("BatchedWriteSequentialPersistent", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[hermes_mode=persistent]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + char* adapter_mode = getenv(kAdapterMode); + REQUIRE(adapter_mode != nullptr); + bool is_same = strcmp(kAdapterDefaultMode, adapter_mode) == 0; + REQUIRE(is_same); + pretest(); + SECTION("write to new file always at end") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == + info.num_iterations * args.request_size); + } + posttest(); +} + +TEST_CASE("BatchedWriteSequentialBypass", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[hermes_mode=bypass]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + char* adapter_mode = getenv(kAdapterMode); + REQUIRE(adapter_mode != nullptr); + bool is_same = strcmp(kAdapterBypassMode, adapter_mode) == 0; + REQUIRE(is_same); + pretest(); + SECTION("write to new file always at end") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == + info.num_iterations * args.request_size); + } + posttest(); +} + +TEST_CASE("BatchedWriteSequentialScratch", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[hermes_mode=scratch]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + char* adapter_mode = getenv(kAdapterMode); + REQUIRE(adapter_mode != nullptr); + bool is_same = strcmp(kAdapterScratchMode, adapter_mode) == 0; + REQUIRE(is_same); + pretest(); + SECTION("write to new file always at end") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fwrite(info.write_data.c_str(), args.request_size); + REQUIRE(test::size_written_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == 0); + } + posttest(false); +} diff --git a/adapter/test/stdio/stdio_adapter_mpi_test.cpp b/adapter/test/stdio/stdio_adapter_mpi_test.cpp new file mode 100644 index 000000000..c279dd786 --- /dev/null +++ b/adapter/test/stdio/stdio_adapter_mpi_test.cpp @@ -0,0 +1,348 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include +#include +#include + +#include +#include +#if HERMES_INTERCEPT == 1 +#include "stdio/real_api.h" +#endif + +namespace stdfs = std::experimental::filesystem; + +namespace hermes::adapter::stdio::test { +struct Arguments { + std::string filename = "test.dat"; + std::string directory = "/tmp"; + size_t request_size = 65536; +}; +struct Info { + bool debug = false; + int rank = 0; + int comm_size = 1; + std::string write_data; + std::string read_data; + std::string new_file; + std::string existing_file; + std::string existing_shared_file; + std::string new_file_cmp; + std::string existing_file_cmp; + std::string existing_shared_file_cmp; + size_t num_iterations = 64; + unsigned int offset_seed = 1; + unsigned int rs_seed = 1; + unsigned int temporal_interval_seed = 1; + size_t total_size; + size_t stride_size = 4 * 1024; + unsigned int temporal_interval_ms = 5; + size_t small_min = 1, small_max = 4 * 1024; + size_t medium_min = 4 * 1024 + 1, medium_max = 512 * 1024; + size_t large_min = 512 * 1024 + 1, large_max = 3 * 1024 * 1024; +}; +} // namespace hermes::adapter::stdio::test + +hermes::adapter::stdio::test::Arguments args; +hermes::adapter::stdio::test::Info info; + +int init(int* argc, char*** argv) { + MPI_Init(argc, argv); + info.write_data = GenRandom(args.request_size); + info.read_data = std::string(args.request_size, 'r'); + MPI_Comm_rank(MPI_COMM_WORLD, &info.rank); + MPI_Comm_size(MPI_COMM_WORLD, &info.comm_size); + if (info.debug && info.rank == 0) { + printf("%d ready for attach\n", info.comm_size); + fflush(stdout); + sleep(30); + } + MPI_Barrier(MPI_COMM_WORLD); + return 0; +} +int finalize() { + MPI_Finalize(); + return 0; +} + +namespace test { +FILE* fh_orig; +FILE* fh_cmp; +int status_orig; +size_t size_read_orig; +size_t size_written_orig; +void test_fopen(const char* path, const char* mode) { + std::string cmp_path; + if (strcmp(path, info.new_file.c_str()) == 0) { + cmp_path = info.new_file_cmp; + } else if (strcmp(path, info.existing_file.c_str()) == 0) { + cmp_path = info.existing_file_cmp; + } else { + cmp_path = info.existing_shared_file_cmp; + } + fh_orig = fopen(path, mode); + fh_cmp = fopen(cmp_path.c_str(), mode); + bool is_same = (fh_cmp != nullptr && fh_orig != nullptr) || + (fh_cmp == nullptr && fh_orig == nullptr); + REQUIRE(is_same); +} +void test_fclose() { + status_orig = fclose(fh_orig); + int status = fclose(fh_cmp); + REQUIRE(status == status_orig); +} +void test_fwrite(const void* ptr, size_t size) { + size_written_orig = fwrite(ptr, sizeof(char), size, fh_orig); + size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp); + REQUIRE(size_written == size_written_orig); +} +void test_fread(char* ptr, size_t size) { + size_read_orig = fread(ptr, sizeof(char), size, fh_orig); + std::vector read_data(size, 'r'); + size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp); + REQUIRE(size_read == size_read_orig); + if (size_read > 0) { + size_t unmatching_chars = 0; + for (size_t i = 0; i < size; ++i) { + if (read_data[i] != ptr[i]) unmatching_chars++; + } + REQUIRE(unmatching_chars == 0); + } +} +void test_fseek(long offset, int whence) { + status_orig = fseek(fh_orig, offset, whence); + int status = fseek(fh_cmp, offset, whence); + REQUIRE(status == status_orig); +} +} // namespace test + +int pretest() { + REQUIRE(info.comm_size > 1); + stdfs::path fullpath = args.directory; + fullpath /= args.filename; + info.new_file = fullpath.string() + "_new_" + std::to_string(info.rank) + + "_of_" + std::to_string(info.comm_size) + "_" + + std::to_string(getpid()); + info.existing_file = fullpath.string() + "_ext_" + std::to_string(info.rank) + + "_of_" + std::to_string(info.comm_size) + "_" + + std::to_string(getpid()); + info.new_file_cmp = + fullpath.string() + "_new_cmp_" + std::to_string(info.rank) + "_of_" + + std::to_string(info.comm_size) + "_" + std::to_string(getpid()); + info.existing_file_cmp = + fullpath.string() + "_ext_cmp_" + std::to_string(info.rank) + "_of_" + + std::to_string(info.comm_size) + "_" + std::to_string(getpid()); + info.existing_shared_file = + fullpath.string() + "_ext_" + std::to_string(info.comm_size); + info.existing_shared_file_cmp = + fullpath.string() + "_ext_cmp_" + std::to_string(info.comm_size); + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + if (stdfs::exists(info.existing_shared_file)) + stdfs::remove(info.existing_shared_file); + if (stdfs::exists(info.existing_shared_file_cmp)) + stdfs::remove(info.existing_shared_file_cmp); + stdfs::path temp_fullpath = "/tmp"; + temp_fullpath /= args.filename; + std::string temp_ext_file = + temp_fullpath.string() + "_temp_" + std::to_string(info.rank) + "_of_" + + std::to_string(info.comm_size) + "_" + std::to_string(getpid()); + if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); + if (!stdfs::exists(temp_ext_file)) { + std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + + std::to_string(args.request_size * info.num_iterations) + + "; } > " + temp_ext_file + " 2> /dev/null"; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(temp_ext_file) == + args.request_size * info.num_iterations); + info.total_size = stdfs::file_size(temp_ext_file); + } + if (info.rank == 0 && !stdfs::exists(info.existing_shared_file)) { + std::string cmd = "cp " + temp_ext_file + " " + info.existing_shared_file; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_shared_file) == + args.request_size * info.num_iterations); + } + if (info.rank == 0 && !stdfs::exists(info.existing_shared_file_cmp)) { + std::string cmd = + "cp " + temp_ext_file + " " + info.existing_shared_file_cmp; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_shared_file_cmp) == + args.request_size * info.num_iterations); + } + if (!stdfs::exists(info.existing_file)) { + std::string cmd = "cp " + temp_ext_file + " " + info.existing_file; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file) == + args.request_size * info.num_iterations); + info.total_size = stdfs::file_size(info.existing_file); + } + if (!stdfs::exists(info.existing_file_cmp)) { + std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file_cmp) == + args.request_size * info.num_iterations); + } + if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); + REQUIRE(info.total_size > 0); + MPI_Barrier(MPI_COMM_WORLD); +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert( + info.existing_shared_file_cmp); +#endif + return 0; +} + +int posttest(bool compare_data = true) { +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_shared_file); +#endif + if (compare_data && stdfs::exists(info.new_file) && + stdfs::exists(info.new_file_cmp)) { + size_t size = stdfs::file_size(info.new_file); + REQUIRE(size == stdfs::file_size(info.new_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.new_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + if (compare_data && stdfs::exists(info.existing_file) && + stdfs::exists(info.existing_file_cmp)) { + size_t size = stdfs::file_size(info.existing_file); + if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); + REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + if (compare_data && stdfs::exists(info.existing_shared_file) && + stdfs::exists(info.existing_shared_file_cmp)) { + size_t size = stdfs::file_size(info.existing_shared_file); + if (size != stdfs::file_size(info.existing_shared_file_cmp)) sleep(1); + REQUIRE(size == stdfs::file_size(info.existing_shared_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.existing_shared_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.existing_shared_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + /* Clean up. */ + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + MPI_Barrier(MPI_COMM_WORLD); + if (info.rank == 0) { + if (stdfs::exists(info.existing_shared_file)) + stdfs::remove(info.existing_shared_file); + if (stdfs::exists(info.existing_shared_file_cmp)) + stdfs::remove(info.existing_shared_file_cmp); + } + +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file_cmp); +#endif + return 0; +} + +cl::Parser define_options() { + return cl::Opt(args.filename, "filename")["-f"]["--filename"]( + "Filename used for performing I/O") | + cl::Opt(args.directory, "dir")["-d"]["--directory"]( + "Directory used for performing I/O") | + cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( + "Request size used for performing I/O"); +} + +#include "stdio_adapter_basic_test.cpp" +#include "stdio_adapter_func_test.cpp" +#include "stdio_adapter_rs_test.cpp" +#include "stdio_adapter_shared_test.cpp" diff --git a/adapter/test/stdio/stdio_adapter_rs_test.cpp b/adapter/test/stdio/stdio_adapter_rs_test.cpp new file mode 100644 index 000000000..b6a4ea629 --- /dev/null +++ b/adapter/test/stdio/stdio_adapter_rs_test.cpp @@ -0,0 +1,1247 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +TEST_CASE("BatchedWriteRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("write to new file always at the start") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + size_t biggest_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + if (biggest_written < request_size) biggest_written = request_size; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == biggest_written); + } + + SECTION("write to new file") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + size_t total_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + total_written += test::size_written_orig; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == total_written); + } + posttest(); +} + +TEST_CASE("BatchedReadSequentialRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + current_offset += test::size_read_orig; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_fopen(info.existing_file.c_str(), "r"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadRandomRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-small]" + "[repetition=" + + std::to_string(info.num_iterations) + + "][pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + rand_r(&info.offset_seed) % (info.total_size - info.small_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + rand_r(&info.offset_seed) % (info.total_size - info.small_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = (i * info.stride_size) % (info.total_size - info.small_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = (i * info.stride_size) % (info.total_size - info.small_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size - info.small_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size - info.small_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = (info.total_size - i * info.stride_size) % + (info.total_size - info.small_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = info.total_size - ((i * info.stride_size) % + (info.total_size - info.small_max)); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStride2DRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - info.small_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSRangeSmall", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - info.small_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.small_min + (rand_r(&info.rs_seed) % info.small_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} +/** + * Medium RS + **/ + +TEST_CASE("BatchedWriteRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("write to new file always at the start") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + size_t biggest_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + if (biggest_written < request_size) biggest_written = request_size; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == biggest_written); + } + + SECTION("write to new file") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + size_t total_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + total_written += test::size_written_orig; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadSequentialRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + (info.medium_min + (rand_r(&info.rs_seed) % info.medium_max)) % + (info.total_size - current_offset); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + current_offset += test::size_read_orig; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_fopen(info.existing_file.c_str(), "r"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadRandomRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-medium]" + "[repetition=" + + std::to_string(info.num_iterations) + + "][pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + rand_r(&info.offset_seed) % (info.total_size - info.medium_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=random][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + rand_r(&info.offset_seed) % (info.total_size - info.medium_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + (i * info.stride_size) % (info.total_size - info.medium_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + (i * info.stride_size) % (info.total_size - info.medium_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size - info.medium_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size - info.medium_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = (info.total_size - i * info.stride_size) % + (info.total_size - info.medium_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = info.total_size - ((i * info.stride_size) % + (info.total_size - info.medium_max)); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStride2DRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - info.medium_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSRangeMedium", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - info.medium_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} +/** + * Large RS + **/ + +TEST_CASE("BatchedWriteRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("write to new file always at the start") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + size_t biggest_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + if (biggest_written < request_size) biggest_written = request_size; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("write to new file") { + test::test_fopen(info.new_file.c_str(), "w+"); + REQUIRE(test::fh_orig != nullptr); + size_t total_written = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + total_written += test::size_written_orig; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + REQUIRE(stdfs::file_size(info.new_file) == total_written); + } + posttest(); +} + +TEST_CASE("BatchedReadSequentialRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = + (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % + (info.total_size - current_offset); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + current_offset += test::size_read_orig; + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + + SECTION("read from existing file always at start") { + test::test_fopen(info.existing_file.c_str(), "r"); + REQUIRE(test::fh_orig != nullptr); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fseek(0, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t offset = ftell(test::fh_orig); + REQUIRE(offset == 0); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadRandomRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-large]" + "[repetition=" + + std::to_string(info.num_iterations) + + "][pattern=random][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + rand_r(&info.offset_seed) % (info.total_size - info.large_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % + (info.total_size - offset); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=random][file=1]") { + pretest(); + + SECTION("write into existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = + rand_r(&info.offset_seed) % (info.total_size - info.large_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data = GenRandom(request_size); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = (i * info.stride_size) % (info.total_size - info.large_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_fixed][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = (i * info.stride_size) % (info.total_size - info.large_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size - info.large_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_dynamic][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, + info.total_size - info.large_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = (info.total_size - i * info.stride_size) % + (info.total_size - info.large_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % + (info.total_size - info.large_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_negative][file=1]") { + pretest(); + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + for (size_t i = 0; i < info.num_iterations; ++i) { + auto offset = info.total_size - ((i * info.stride_size) % + (info.total_size - info.large_max)); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedReadStride2DRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("read from existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - info.large_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_fread(data.data(), request_size); + REQUIRE(test::size_read_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSRangeLarge", + "[process=" + std::to_string(info.comm_size) + + "]" + "" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=stride_2d][file=1]") { + pretest(); + size_t rows = sqrt(info.total_size); + size_t cols = rows; + REQUIRE(rows * cols == info.total_size); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / info.num_iterations; + SECTION("write to existing file") { + test::test_fopen(info.existing_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (info.total_size - info.large_max); + test::test_fseek(offset, SEEK_SET); + REQUIRE(test::status_orig == 0); + size_t request_size = + info.large_min + (rand_r(&info.rs_seed) % info.large_max); + std::string data(request_size, '1'); + test::test_fwrite(data.data(), request_size); + REQUIRE(test::size_written_orig == request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} diff --git a/adapter/test/stdio/stdio_adapter_shared_test.cpp b/adapter/test/stdio/stdio_adapter_shared_test.cpp new file mode 100644 index 000000000..5a9f437e3 --- /dev/null +++ b/adapter/test/stdio/stdio_adapter_shared_test.cpp @@ -0,0 +1,35 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +TEST_CASE("SharedSTDIORead", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[mode=shared]" + "[pattern=sequential][file=1]") { + pretest(); + + SECTION("read from existing file") { + test::test_fopen(info.existing_shared_file.c_str(), "r+"); + REQUIRE(test::fh_orig != nullptr); + std::string data(args.request_size, '1'); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::test_fread(data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); + } + test::test_fclose(); + REQUIRE(test::status_orig == 0); + } + posttest(); +} diff --git a/adapter/test/stdio/stdio_adapter_test.cpp b/adapter/test/stdio/stdio_adapter_test.cpp new file mode 100644 index 000000000..a88853f45 --- /dev/null +++ b/adapter/test/stdio/stdio_adapter_test.cpp @@ -0,0 +1,256 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include + +#include +#include + +#include "adapter_test_utils.h" +#include "catch_config.h" +#if HERMES_INTERCEPT == 1 +#include "stdio/real_api.h" +#endif + +#include "adapter_test_utils.h" + +namespace stdfs = std::experimental::filesystem; + +namespace hermes::adapter::stdio::test { +struct Arguments { + std::string filename = "test.dat"; + std::string directory = "/tmp"; + size_t request_size = 65536; +}; +struct Info { + int rank = 0; + int comm_size = 1; + std::string write_data; + std::string read_data; + std::string new_file; + std::string existing_file; + std::string new_file_cmp; + std::string existing_file_cmp; + size_t num_iterations = 64; + unsigned int offset_seed = 1; + unsigned int rs_seed = 1; + unsigned int temporal_interval_seed = 5; + size_t total_size; + size_t stride_size = 512; + unsigned int temporal_interval_ms = 1; + size_t small_min = 1, small_max = 4 * 1024; + size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; + size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; +}; +} // namespace hermes::adapter::stdio::test + +hermes::adapter::stdio::test::Arguments args; +hermes::adapter::stdio::test::Info info; + +int init(int* argc, char*** argv) { + MPI_Init(argc, argv); + info.write_data = GenRandom(args.request_size); + info.read_data = std::string(args.request_size, 'r'); + return 0; +} + +int finalize() { + MPI_Finalize(); + return 0; +} + +int pretest() { + stdfs::path fullpath = args.directory; + fullpath /= args.filename; + info.new_file = fullpath.string() + "_new_" + std::to_string(getpid()); + info.existing_file = fullpath.string() + "_ext_" + std::to_string(getpid()); + info.new_file_cmp = + fullpath.string() + "_new_cmp" + "_" + std::to_string(getpid()); + info.existing_file_cmp = + fullpath.string() + "_ext_cmp" + "_" + std::to_string(getpid()); + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + if (!stdfs::exists(info.existing_file)) { + std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + + std::to_string(args.request_size * info.num_iterations) + + "; } > " + info.existing_file + " 2> /dev/null"; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file) == + args.request_size * info.num_iterations); + info.total_size = stdfs::file_size(info.existing_file); + } + if (!stdfs::exists(info.existing_file_cmp)) { + std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(stdfs::file_size(info.existing_file_cmp) == + args.request_size * info.num_iterations); + } + REQUIRE(info.total_size > 0); +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); +#endif + return 0; +} + +int posttest(bool compare_data = true) { +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); +#endif + if (compare_data && stdfs::exists(info.new_file) && + stdfs::exists(info.new_file_cmp)) { + size_t size = stdfs::file_size(info.new_file); + REQUIRE(size == stdfs::file_size(info.new_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.new_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) { + char_mismatch++; + } + } + REQUIRE(char_mismatch == 0); + } + } + if (compare_data && stdfs::exists(info.existing_file) && + stdfs::exists(info.existing_file_cmp)) { + size_t size = stdfs::file_size(info.existing_file); + if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); + REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); + if (size > 0) { + std::vector d1(size, '0'); + std::vector d2(size, '1'); + + FILE* fh1 = fopen(info.existing_file.c_str(), "r"); + REQUIRE(fh1 != nullptr); + size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); + REQUIRE(read_d1 == sizeof(unsigned char)); + int status = fclose(fh1); + REQUIRE(status == 0); + + FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); + REQUIRE(fh2 != nullptr); + size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); + REQUIRE(read_d2 == sizeof(unsigned char)); + status = fclose(fh2); + REQUIRE(status == 0); + size_t char_mismatch = 0; + for (size_t pos = 0; pos < size; ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } + } + /* Clean up. */ + if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); + if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); + if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); + +#if HERMES_INTERCEPT == 1 + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); +#endif + return 0; +} + +cl::Parser define_options() { + return cl::Opt(args.filename, "filename")["-f"]["--filename"]( + "Filename used for performing I/O") | + cl::Opt(args.directory, "dir")["-d"]["--directory"]( + "Directory used for performing I/O") | + cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( + "Request size used for performing I/O"); +} + +namespace test { +FILE* fh_orig; +FILE* fh_cmp; +int status_orig; +size_t size_read_orig; +size_t size_written_orig; +void test_fopen(const char* path, const char* mode) { + std::string cmp_path; + if (strcmp(path, info.new_file.c_str()) == 0) { + cmp_path = info.new_file_cmp; + } else { + cmp_path = info.existing_file_cmp; + } + fh_orig = fopen(path, mode); + fh_cmp = fopen(cmp_path.c_str(), mode); + bool is_same = (fh_cmp != nullptr && fh_orig != nullptr) || + (fh_cmp == nullptr && fh_orig == nullptr); + REQUIRE(is_same); +} +void test_fclose() { + status_orig = fclose(fh_orig); + int status = fclose(fh_cmp); + REQUIRE(status == status_orig); +} +void test_fwrite(const void* ptr, size_t size) { + size_written_orig = fwrite(ptr, sizeof(char), size, fh_orig); + size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp); + REQUIRE(size_written == size_written_orig); +} +void test_fread(char* ptr, size_t size) { + size_read_orig = fread(ptr, sizeof(char), size, fh_orig); + std::vector read_data(size, 'r'); + size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp); + REQUIRE(size_read == size_read_orig); + if (size_read > 0) { + size_t unmatching_chars = 0; + for (size_t i = 0; i < size; ++i) { + if (read_data[i] != ptr[i]) { + unmatching_chars = i; + break; + } + } + REQUIRE(unmatching_chars == 0); + } +} +void test_fseek(long offset, int whence) { + status_orig = fseek(fh_orig, offset, whence); + int status = fseek(fh_cmp, offset, whence); + REQUIRE(status == status_orig); +} +} // namespace test + +#include "stdio_adapter_basic_test.cpp" +#include "stdio_adapter_func_test.cpp" +#include "stdio_adapter_rs_test.cpp" diff --git a/adapter/test/vfd/CMakeLists.txt b/adapter/test/vfd/CMakeLists.txt new file mode 100644 index 000000000..3903fc5a8 --- /dev/null +++ b/adapter/test/vfd/CMakeLists.txt @@ -0,0 +1,68 @@ +set(HERMES_VFD_DIR ${HERMES_ADAPTER_DIR}/vfd) + +set(hermes_vfd_tests + hermes_vfd_test +) + +add_executable(hermes_vfd_test ${CMAKE_CURRENT_SOURCE_DIR}/hermes_vfd_test.cc) +target_include_directories(hermes_vfd_test PRIVATE ${HERMES_VFD_DIR}) +target_include_directories(hermes_vfd_test PRIVATE ${HERMES_ADAPTER_TEST_DIR}) +target_include_directories(hermes_vfd_test + SYSTEM PRIVATE ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} +) + +target_link_libraries(hermes_vfd_test + hermes + Catch2::Catch2 + MPI::MPI_CXX + glog::glog + stdc++fs + ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES} +) + +if(HERMES_USE_ADDRESS_SANITIZER) + execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=libasan.so + OUTPUT_VARIABLE LIBASAN_PATH + RESULT_VARIABLE ASAN_PRINT_FILE_NAME_RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(ASAN_PRINT_FILE_NAME_RESULT EQUAL 0) + message(STATUS "Found libasan.so at ${LIBASAN_PATH}") + else() + message(FATAL_ERROR + "Couldn't find the path to libasan.so which is required by the Hermes HDF5 VFD tests. \ + Recompile with HERMES_ENABLE_ADDRESS_SANITIZER=OFF") + endif() +endif() + +function(set_vfd_test_properties test_name) + set_property(TEST ${test_name} + PROPERTY ENVIRONMENT HERMES_CONF=${HERMES_ADAPTER_TEST_DIR}/data/hermes.yaml) + set_property(TEST ${test_name} APPEND + PROPERTY ENVIRONMENT HDF5_PLUGIN_PATH=${HERMES_VFD_LIBRARY_DIR}) + set_property(TEST ${test_name} APPEND + PROPERTY ENVIRONMENT HDF5_DRIVER=hermes) + set_property(TEST ${test_name} APPEND + PROPERTY ENVIRONMENT LD_PRELOAD=${LIBASAN_PATH}:$) + set_property(TEST ${test_name} APPEND + PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) +endfunction() + +add_test(NAME "TestVfd" COMMAND hermes_vfd_test --reporter compact -d yes) +set_vfd_test_properties("TestVfd") +set_property(TEST "TestVfd" APPEND + PROPERTY ENVIRONMENT HDF5_DRIVER_CONFIG=true\ 65536) + +add_test(NAME "TestVfdScratchMode" COMMAND hermes_vfd_test "[scratch]" --reporter compact -d yes) +set_vfd_test_properties("TestVfdScratchMode") +set_property(TEST "TestVfdScratchMode" APPEND + PROPERTY ENVIRONMENT HDF5_DRIVER_CONFIG=false\ 65536) + +# IOR tests +if(HERMES_HAVE_IOR) + set(IOR_TEST_NAME "TestVfdIor") + add_test(NAME ${IOR_TEST_NAME} COMMAND ${IOR_EXE} -a HDF5 -w -W -r -R) + set_vfd_test_properties(${IOR_TEST_NAME}) + set_property(TEST ${IOR_TEST_NAME} APPEND + PROPERTY ENVIRONMENT HDF5_DRIVER_CONFIG=true\ 262144) +endif() diff --git a/adapter/test/vfd/hermes_vfd_basic_test.cc b/adapter/test/vfd/hermes_vfd_basic_test.cc new file mode 100644 index 000000000..67f8b9277 --- /dev/null +++ b/adapter/test/vfd/hermes_vfd_basic_test.cc @@ -0,0 +1,718 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +using hermes::adapter::vfd::test::MuteHdf5Errors; + +/** Returns a number in the range [1, upper_bound] */ +static inline size_t Random1ToUpperBound(size_t upper_bound) { + size_t result = ((size_t)GenNextRandom() % upper_bound) + 1; + + return result; +} + +/** Returns a string in the range ["0", "upper_bound") */ +static inline std::string RandomDatasetName(size_t upper_bound) { + size_t dset_index = Random1ToUpperBound(upper_bound) - 1; + std::string result = std::to_string(dset_index); + + return result; +} + +TEST_CASE("H5FOpen", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_open]" + "[repetition=1][file=1]") { + Pretest(); + SECTION("open non-existent file") { + MuteHdf5Errors mute; + test::TestOpen(info.new_file, H5F_ACC_RDONLY); + REQUIRE(test::hermes_hid == H5I_INVALID_HID); + test::TestOpen(info.new_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid == H5I_INVALID_HID); + } + + SECTION("truncate existing file") { + test::TestOpen(info.existing_file, H5F_ACC_TRUNC, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("open existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + + test::TestOpen(info.existing_file, H5F_ACC_RDONLY); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("create existing file exclusively") { + MuteHdf5Errors mute; + test::TestOpen(info.existing_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid == H5I_INVALID_HID); + } + + Posttest(); +} + +TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_write]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + Pretest(); + + SECTION("overwrite dataset in existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + test::TestWritePartial1d("0", info.write_data.data(), 0, + info.nelems_per_dataset); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("write to new file") { + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + test::TestWriteDataset("0", info.write_data); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("write to existing file with truncate") { + test::TestOpen(info.existing_file, H5F_ACC_TRUNC, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + test::TestWriteDataset("0", info.write_data); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("add dataset to existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + test::TestWriteDataset(std::to_string(info.num_iterations), + info.write_data); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + Posttest(); +} + +TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=single_read]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + Pretest(); + SECTION("read from non-existing file") { + MuteHdf5Errors mute; + test::TestOpen(info.new_file, H5F_ACC_RDONLY); + REQUIRE(test::hermes_hid == H5I_INVALID_HID); + } + + SECTION("read first dataset from existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDONLY); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + test::TestRead("0", info.read_data, 0, info.nelems_per_dataset); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("read last dataset of existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDONLY); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + test::TestRead(std::to_string(info.num_iterations - 1), info.read_data, 0, + info.nelems_per_dataset); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + Posttest(); +} + +TEST_CASE("BatchedWriteSequential", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + Pretest(); + SECTION("write to new file") { + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::TestWriteDataset(std::to_string(i), info.write_data); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("overwrite first dataset") { + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + test::TestWriteDataset("0", info.write_data); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::TestWritePartial1d("0", info.write_data.data(), 0, + info.nelems_per_dataset); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + Posttest(); +} + +TEST_CASE("BatchedReadSequential", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + Pretest(); + SECTION("read from existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + std::vector buf(info.nelems_per_dataset, 0.0f); + for (size_t i = 0; i < info.num_iterations; ++i) { + test::TestRead(std::to_string(i), buf, 0, info.nelems_per_dataset); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("read from existing file always at start") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::TestRead("0", info.read_data, 0, info.nelems_per_dataset); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + Posttest(); +} + +TEST_CASE("BatchedReadRandom", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed]" + "[repetition=" + + std::to_string(info.num_iterations) + + "][pattern=random][file=1]") { + Pretest(); + SECTION("read from existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + std::vector buf(info.nelems_per_dataset, 0.0f); + for (size_t i = 0; i < info.num_iterations; ++i) { + u32 dataset = GenNextRandom() % info.num_iterations; + test::TestRead(std::to_string(dataset), buf, 0, info.nelems_per_dataset); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + Posttest(); +} + +TEST_CASE("BatchedUpdateRandom", "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=random][file=1]") { + Pretest(); + SECTION("update entire dataset in existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + u32 dataset = GenNextRandom() % info.num_iterations; + test::TestWritePartial1d(std::to_string(dataset), info.write_data.data(), + 0, info.nelems_per_dataset); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("update partial dataset in existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + u32 dataset = GenNextRandom() % info.num_iterations; + // NOTE(chogan): Subtract 1 from size so we're always writing at least 1 + // element + hsize_t offset = GenNextRandom() % (info.write_data.size() - 1); + hsize_t elements_to_write = info.write_data.size() - offset; + test::TestWritePartial1d(std::to_string(dataset), info.write_data.data(), + offset, elements_to_write); + } + + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + Posttest(); +} + +TEST_CASE("BatchedWriteRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + Pretest(); + + SECTION("write to new file always at the start") { + MuteHdf5Errors mute; + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); + std::vector data(request_size, 2.0f); + test::TestWritePartial1d(std::to_string(i), data.data(), 0, request_size); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + Posttest(); +} + +TEST_CASE("BatchedReadSequentialRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + Pretest(); + + SECTION("read from existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDONLY); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); + size_t starting_element = info.nelems_per_dataset - request_size; + std::vector data(request_size, 1.5f); + test::TestRead(std::to_string(i), data, starting_element, request_size); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("read from existing file always at start") { + test::TestOpen(info.existing_file, H5F_ACC_RDONLY); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); + std::vector data(request_size, 3.0f); + test::TestRead(std::to_string(i), data, 0, request_size); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + Posttest(); +} + +TEST_CASE("BatchedReadRandomRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_read]" + "[request_size=type-variable]" + "[repetition=" + + std::to_string(info.num_iterations) + + "][pattern=random][file=1]") { + Pretest(); + + SECTION("read from existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + std::vector data(info.nelems_per_dataset, 5.0f); + for (size_t i = 0; i < info.num_iterations; ++i) { + std::string dset_name = RandomDatasetName(info.num_iterations); + size_t starting_element = Random1ToUpperBound(info.nelems_per_dataset); + size_t request_elements = + Random1ToUpperBound(info.nelems_per_dataset - starting_element); + std::vector data(request_elements, 3.8f); + test::TestRead(dset_name, data, starting_element, request_elements); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + Posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=random][file=1]") { + Pretest(); + + SECTION("write to existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + std::vector data(info.nelems_per_dataset, 8.0f); + for (size_t i = 0; i < info.num_iterations; ++i) { + std::string dset_name = RandomDatasetName(info.num_iterations); + size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); + test::TestWritePartial1d(dset_name, data.data(), 0, request_size); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + Posttest(); +} + +TEST_CASE("BatchedWriteTemporalFixed", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1][temporal=fixed]") { + Pretest(); + + SECTION("write to existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + usleep(info.temporal_interval_ms * 1000); + test::TestWritePartial1d(std::to_string(i), info.write_data.data(), 0, + info.nelems_per_dataset); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("write to new file always at start") { + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + usleep(info.temporal_interval_ms * 1000); + test::TestWriteDataset(std::to_string(i), info.write_data); + } + test::TestClose(); + } + + Posttest(); +} + +TEST_CASE("BatchedWriteTemporalVariable", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1][temporal=variable]") { + Pretest(); + + SECTION("write to existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t sleep_interval_ms = + GenNextRandom() % (info.temporal_interval_ms + 2); + usleep(sleep_interval_ms * 1000); + test::TestWritePartial1d(std::to_string(i), info.write_data.data(), 0, + info.nelems_per_dataset); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("write to new file always at start") { + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + size_t sleep_interval_ms = + GenNextRandom() % (info.temporal_interval_ms + 2); + usleep(sleep_interval_ms * 1000); + test::TestWriteDataset(std::to_string(i), info.write_data); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + Posttest(); +} + +TEST_CASE("BatchedMixedSequential", + "[process=" + std::to_string(info.comm_size) + + "]" + "[operation=batched_mixed]" + "[request_size=type-fixed][repetition=" + + std::to_string(info.num_iterations) + + "]" + "[pattern=sequential][file=1]") { + Pretest(); + + SECTION("read after write on new file") { + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + std::string dset_name = std::to_string(i); + test::TestWriteDataset(dset_name, info.write_data); + test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("alternate write and read existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + std::string dset_name = std::to_string(i); + + if (i % 2 == 0) { + test::TestWritePartial1d(dset_name, info.write_data.data(), 0, + info.nelems_per_dataset); + } else { + test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); + } + } + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("update after read existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + std::string dset_name = std::to_string(i); + test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); + test::TestWritePartial1d(dset_name, info.write_data.data(), 0, + info.nelems_per_dataset); + } + + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("read all after write all on new file in single open") { + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + std::string dset_name = std::to_string(i); + test::TestWriteDataset(dset_name, info.write_data); + } + + for (size_t i = 0; i < info.num_iterations; ++i) { + std::string dset_name = std::to_string(i); + test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); + } + + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("read all after write all on new file in different open") { + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::TestWriteDataset(std::to_string(i), info.write_data); + } + + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + + test::TestOpen(info.new_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::TestRead(std::to_string(i), info.read_data, 0, + info.nelems_per_dataset); + } + + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + Posttest(); +} + +TEST_CASE("SingleMixed", "[process=" + std::to_string(info.comm_size) + + "][operation=single_mixed]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + Pretest(); + + SECTION("read after write from new file") { + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + std::string dset_name("0"); + test::TestWriteDataset(dset_name, info.write_data); + test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("update after read from existing file") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + std::string dset_name("0"); + test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); + test::TestWritePartial1d(dset_name, info.write_data.data(), 0, + info.nelems_per_dataset); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("read after write from new file different opens") { + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + std::string dset_name("0"); + test::TestWriteDataset(dset_name, info.write_data); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + + test::TestOpen(info.new_file, H5F_ACC_RDWR); + test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + Posttest(); +} + +TEST_CASE("CompactDatasets") { + Pretest(); + + SECTION("create many and read randomly") { + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + size_t num_elements = KILOBYTES(32) / sizeof(f32); + + for (size_t i = 0; i < info.num_iterations; ++i) { + std::vector data(num_elements); + for (size_t i = 0; i < data.size(); ++i) { + data[i] = GenRandom0to1(); + } + test::TestMakeCompactDataset(std::to_string(i), data); + } + + std::vector read_buf(num_elements, 0.0f); + for (size_t i = 0; i < info.num_iterations; ++i) { + std::string dset_name = RandomDatasetName(info.num_iterations); + test::TestRead(dset_name, read_buf, 0, num_elements); + } + + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + Posttest(); +} + +TEST_CASE("PartialUpdateToLastPage") { + Pretest(); + + SECTION("beginning of last page") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + test::TestWritePartial1d(std::to_string(info.num_iterations - 1), + info.write_data.data(), 0, + info.nelems_per_dataset / 2); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("in middle of last page") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + test::TestWritePartial1d(std::to_string(info.num_iterations - 1), + info.write_data.data(), + info.nelems_per_dataset / 4, + info.nelems_per_dataset / 2); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + SECTION("at end of last page") { + test::TestOpen(info.existing_file, H5F_ACC_RDWR); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + test::TestWritePartial1d(std::to_string(info.num_iterations - 1), + info.write_data.data(), + info.nelems_per_dataset / 2, + info.nelems_per_dataset / 2); + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + } + + Posttest(); +} + +TEST_CASE("ScratchMode", "[scratch]") { + Pretest(); + + SECTION("created files shouldn't persist") { + test::TestOpen(info.new_file, H5F_ACC_EXCL, true); + REQUIRE(test::hermes_hid != H5I_INVALID_HID); + + for (size_t i = 0; i < info.num_iterations; ++i) { + test::TestWriteDataset(std::to_string(i), info.write_data); + } + + for (size_t i = 0; i < info.num_iterations; ++i) { + std::string dset_name = RandomDatasetName(info.num_iterations); + test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); + } + + test::TestClose(); + REQUIRE(test::hermes_herr >= 0); + + if (info.scratch_mode) { + REQUIRE(!stdfs::exists(info.new_file)); + } + } + + Posttest(); +} diff --git a/adapter/test/vfd/hermes_vfd_test.cc b/adapter/test/vfd/hermes_vfd_test.cc new file mode 100644 index 000000000..e3458950e --- /dev/null +++ b/adapter/test/vfd/hermes_vfd_test.cc @@ -0,0 +1,585 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "hermes_types.h" +#include "adapter_test_utils.h" +#include "catch_config.h" + +namespace stdfs = std::experimental::filesystem; +using hermes::f32; +using hermes::u32; + +namespace hermes::adapter::vfd::test { + +/** + A structure to represent test arguments +*/ +struct Arguments { + std::string filename = "test"; /**< test file name */ + std::string directory = "/tmp"; /**< test directory name */ + size_t request_size = 65536; /**< test request size */ +}; + +/** + A structure to represent test information +*/ +struct TestInfo { + static const int element_size = sizeof(f32); /**< test element size */ + + // int rank = 0; + int comm_size = 1; /**< communicator size */ + std::vector write_data; /**< test data for writing */ + std::vector read_data; /**< test data for reading */ + std::string new_file; /**< new file name */ + std::string existing_file; /**< existing file name */ + std::string new_file_cmp; /**< new file name to compare */ + std::string existing_file_cmp; /**< existing file name to compare */ + std::string hdf5_extension = ".h5"; /**< HDF5 file extention to use */ + size_t num_iterations = 64; /**< number of iterations */ + // int offset_seed = 1; + // unsigned int rs_seed = 1; + // unsigned int temporal_interval_seed = 5; + size_t total_size; /**< total size */ + // size_t stride_size = 512; + unsigned int temporal_interval_ms = 1; /**< interval in milliseconds */ + // size_t small_min = 1; + // size_t small_max = KILOBYTES(4); + // size_t medium_min = KILOBYTES(4) + 1; + // size_t medium_max = KILOBYTES(256); + // size_t large_min = KILOBYTES(256) + 1; + // size_t large_max = MEGABYTES(3); + size_t nelems_per_dataset; /**< number of elements per dataset */ + bool scratch_mode = false; /**< flag for scratch mode */ +}; + +/** + * Temporarily disable printing of the HDF5 error stack. + * + * Some tests intentionally trigger HDF5 errors, and in those cases we don't + * want to clutter the output with HDF5 error messages. + */ +class MuteHdf5Errors { + H5E_auto2_t old_func; /**< error handler callback function */ + void *old_client_data; /**< pointer to client data for old_func */ + + public: + MuteHdf5Errors() { + // Save old error handler + H5Eget_auto(H5E_DEFAULT, &old_func, &old_client_data); + + // Turn off error stack printing + H5Eset_auto(H5E_DEFAULT, NULL, NULL); + } + + ~MuteHdf5Errors() { + // Restore previous error handler + H5Eset_auto(H5E_DEFAULT, old_func, old_client_data); + } +}; + +/** + * HDF5 identifiers required for reads and writes. + */ +struct RwIds { + hid_t dset_id; /**< dataset ID */ + hid_t dspace_id; /**< data space ID */ + hid_t mspace_id; /**< memory space ID */ +}; + +/** + * The I/O API for this adapter layer. + * + * Ideally we would have a high level Adapter I/O API that each adapter inherits + * from so that the adapter tests can reuse more code. This is a step in that + * direction. + */ +struct Hdf5Api { + /** + * A file access property list representing the sec2 (POSIX) VFD. + */ + hid_t sec2_fapl; + + Hdf5Api() : sec2_fapl(H5I_INVALID_HID) { + sec2_fapl = H5Pcreate(H5P_FILE_ACCESS); + REQUIRE(sec2_fapl != H5I_INVALID_HID); + REQUIRE(H5Pset_fapl_sec2(sec2_fapl) >= 0); + } + + ~Hdf5Api() { + REQUIRE(H5Pclose(sec2_fapl) >= 0); + sec2_fapl = H5I_INVALID_HID; + } + + /** + * Open an existing file using the default VFD. Since the tests are run with + * HDF5_DRIVER=hermes, the default VFD will be the Hermes VFD. + */ + hid_t Open(const std::string &fname, unsigned flags) { + hid_t result = H5Fopen(fname.c_str(), flags, H5P_DEFAULT); + + return result; + } + + /** + * Open an existing file using the POSIX VFD. This will bypass Hermes. + */ + hid_t OpenPosix(const std::string &fname, unsigned flags) { + hid_t result = H5Fopen(fname.c_str(), flags, sec2_fapl); + + return result; + } + + /** + * Create a file using the default VFD. + */ + hid_t Create(const std::string &fname, unsigned flags) { + hid_t result = H5Fcreate(fname.c_str(), flags, H5P_DEFAULT, H5P_DEFAULT); + + return result; + } + + /** + * Create a file using the POSIX VFD. + */ + hid_t CreatePosix(const std::string &fname, unsigned flags) { + hid_t result = H5Fcreate(fname.c_str(), flags, H5P_DEFAULT, sec2_fapl); + + return result; + } + + /** + * Boilerplate necessary before calling H5Dread or H5Dwrite. + */ + RwIds RwPreamble(hid_t hid, const std::string &dset_name, hsize_t offset, + hsize_t nelems, hsize_t stride = 1) { + hid_t dset_id = H5Dopen2(hid, dset_name.c_str(), H5P_DEFAULT); + + hid_t memspace_id = H5Screate_simple(1, &nelems, NULL); + REQUIRE(memspace_id != H5I_INVALID_HID); + + if (dset_id == H5I_INVALID_HID) { + dset_id = H5Dcreate2(hid, dset_name.c_str(), H5T_NATIVE_FLOAT, + memspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + + REQUIRE(dset_id != H5I_INVALID_HID); + hid_t dspace_id = H5Dget_space(dset_id); + REQUIRE(dspace_id != H5I_INVALID_HID); + herr_t status = H5Sselect_hyperslab(dspace_id, H5S_SELECT_SET, &offset, + &stride, &nelems, NULL); + REQUIRE(status >= 0); + + RwIds result = {dset_id, dspace_id, memspace_id}; + + return result; + } + + /** + * Cleanup code required after H5Dread and H5Dwrite. + */ + void RwCleanup(RwIds *ids) { + REQUIRE(H5Sclose(ids->mspace_id) >= 0); + REQUIRE(H5Sclose(ids->dspace_id) >= 0); + REQUIRE(H5Dclose(ids->dset_id) >= 0); + } + + /** + * Reads @p nelems elements from the object represented by @p hid into @p buf, + * starting at element @p offset. + */ + void Read(hid_t hid, const std::string &dset_name, std::vector &buf, + hsize_t offset, hsize_t nelems) { + RwIds ids = RwPreamble(hid, dset_name, offset, nelems); + herr_t status = H5Dread(ids.dset_id, H5T_NATIVE_FLOAT, ids.mspace_id, + ids.dspace_id, H5P_DEFAULT, buf.data()); + REQUIRE(status >= 0); + + RwCleanup(&ids); + } + /** + Create a 1-dimensional dataset using \a data vector. + */ + void MakeDataset(hid_t hid, const std::string &dset_name, + const std::vector &data, bool compact = false) { + MakeDataset(hid, dset_name, data.data(), data.size(), compact); + } + + /** + * Create a 1-dimensional dataset named @p dset_name in object @p hid with @p + * nelems elements from the array @p data. + */ + void MakeDataset(hid_t hid, const std::string &dset_name, const f32 *data, + hsize_t nelems, bool compact = false) { + hid_t dcpl = H5P_DEFAULT; + herr_t status = 0; + + if (compact) { + REQUIRE(nelems * sizeof(f32) <= KILOBYTES(64)); + dcpl = H5Pcreate(H5P_DATASET_CREATE); + REQUIRE(dcpl != H5I_INVALID_HID); + status = H5Pset_layout(dcpl, H5D_COMPACT); + REQUIRE(status >= 0); + } + + hid_t memspace_id = H5Screate_simple(1, &nelems, NULL); + REQUIRE(memspace_id != H5I_INVALID_HID); + + hid_t dset_id = H5Dcreate2(hid, dset_name.c_str(), H5T_NATIVE_FLOAT, + memspace_id, H5P_DEFAULT, dcpl, H5P_DEFAULT); + REQUIRE(dset_id != H5I_INVALID_HID); + + hid_t dspace_id = H5Dget_space(dset_id); + REQUIRE(dspace_id != H5I_INVALID_HID); + + status = H5Dwrite(dset_id, H5T_NATIVE_FLOAT, memspace_id, + dspace_id, H5P_DEFAULT, data); + REQUIRE(status >= 0); + REQUIRE(H5Sclose(memspace_id) >= 0); + REQUIRE(H5Sclose(dspace_id) >= 0); + REQUIRE(H5Dclose(dset_id) >= 0); + + if (compact) { + REQUIRE(H5Pclose(dcpl) >= 0); + } + } + + /** + * Write @p nelems elements to the dataset @p dset_name in file @p hid + * starting at element @p offset. The dataset will be created if it doesn't + * already exist. + */ + void WritePartial1d(hid_t hid, const std::string &dset_name, + const f32 *data, hsize_t offset, hsize_t nelems) { + RwIds ids = RwPreamble(hid, dset_name, offset, nelems); + herr_t status = H5Dwrite(ids.dset_id, H5T_NATIVE_FLOAT, ids.mspace_id, + ids.dspace_id, H5P_DEFAULT, data); + REQUIRE(status >= 0); + + RwCleanup(&ids); + } + /** + Close HDF5 file. + */ + herr_t Close(hid_t id) { + herr_t result = H5Fclose(id); + + return result; + } +}; + +// xoshiro128+ random number generation. 2x speedup over std::mt19937: +// https://prng.di.unimi.it/xoshiro128plus.c + +static inline u32 RotateLeft(const u32 x, int k) { + u32 result = (x << k) | (x >> (32 - k)); + + return result; +} + +static u32 random_state[4] = {111, 222, 333, 444}; + +u32 GenNextRandom() { + const u32 random = random_state[0] + random_state[3]; + + const u32 t = random_state[1] << 9; + + random_state[2] ^= random_state[0]; + random_state[3] ^= random_state[1]; + random_state[1] ^= random_state[2]; + random_state[0] ^= random_state[3]; + + random_state[2] ^= t; + + random_state[3] = RotateLeft(random_state[3], 11); + + return random; +} + +/** + * Return a random float in the range [0.0f, 1.0f] + */ +f32 GenRandom0to1() { + u32 random_u32 = GenNextRandom(); + + f32 result = (random_u32 >> 8) * 0x1.0p-24f; + + return result; +} + +/** + * Create an HDF5 file called @p fname with @p num_datasets datasets, each with + * @p num_dataset_elems elements. + */ +void GenHdf5File(std::string fname, size_t num_dataset_elems, + size_t num_datasets) { + std::vector data(num_dataset_elems * num_datasets); + + for (size_t i = 0; i < data.size(); ++i) { + data[i] = GenRandom0to1(); + } + + Hdf5Api api; + f32 *at = data.data(); + + hid_t file_id = api.CreatePosix(fname, H5F_ACC_TRUNC); + REQUIRE(file_id != H5I_INVALID_HID); + + for (size_t i = 0; i < num_datasets; ++i) { + api.MakeDataset(file_id, std::to_string(i), at, num_dataset_elems); + at += num_dataset_elems; + } + + REQUIRE(api.Close(file_id) > -1); +} + +} // namespace hermes::adapter::vfd::test + +hermes::adapter::vfd::test::Arguments args; +hermes::adapter::vfd::test::TestInfo info; + +using hermes::adapter::vfd::test::GenHdf5File; +using hermes::adapter::vfd::test::GenNextRandom; +using hermes::adapter::vfd::test::GenRandom0to1; + +/** + * Called in the Catch2 main function (see catch_config.h) before any tests are + * run. Initialize sizes, filenames, and read/write buffers. + */ +int init(int* argc, char*** argv) { + MPI_Init(argc, argv); + if (args.request_size % info.element_size != 0) { + LOG(FATAL) << "request_size must be a multiple of " << info.element_size; + } + info.nelems_per_dataset = args.request_size / info.element_size; + + info.write_data.resize(info.nelems_per_dataset); + for (size_t i = 0; i < info.write_data.size(); ++i) { + info.write_data[i] = GenRandom0to1(); + } + info.read_data.resize(info.nelems_per_dataset); + for (size_t i = 0; i < info.read_data.size(); ++i) { + info.read_data[i] = 0.0f; + } + + stdfs::path fullpath = args.directory; + fullpath /= args.filename; + std::string suffix = std::to_string(getpid()) + info.hdf5_extension; + info.new_file = fullpath.string() + "_new_" + suffix; + info.existing_file = fullpath.string() + "_ext_" + suffix; + info.new_file_cmp = fullpath.string() + "_new_cmp_" + suffix; + info.existing_file_cmp = fullpath.string() + "_ext_cmp_" + suffix; + + char *driver_config = getenv("HDF5_DRIVER_CONFIG"); + if (driver_config) { + std::string looking_for("false"); + std::string conf_str(driver_config); + if (!conf_str.compare(0, looking_for.size(), looking_for)) { + info.scratch_mode = true; + } + } + + return 0; +} + +/** + * Called from catch_config.h after all tests are run. + */ +int finalize() { + MPI_Finalize(); + return 0; +} + +/** + * Remove all files generated by the tests + */ +void CleanupFiles() { + if (stdfs::exists(info.new_file)) + stdfs::remove(info.new_file); + if (stdfs::exists(info.new_file_cmp)) + stdfs::remove(info.new_file_cmp); + if (stdfs::exists(info.existing_file)) + stdfs::remove(info.existing_file); + if (stdfs::exists(info.existing_file_cmp)) + stdfs::remove(info.existing_file_cmp); +} + +/** + * Called before each individual test. + * + * Generates files for tests that operate on existing files. + */ +int Pretest() { + CleanupFiles(); + + GenHdf5File(info.existing_file, info.nelems_per_dataset, info.num_iterations); + info.total_size = stdfs::file_size(info.existing_file); + std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; + int status = system(cmd.c_str()); + REQUIRE(status != -1); + REQUIRE(info.total_size > 0); + + return 0; +} + +/** + * Use h5diff to ensure that the resulting files from the Hermes VFD and the + * POSIX VFD are the same. + */ +void CheckResults(const std::string &file1, const std::string &file2) { + if (stdfs::exists(file1) && stdfs::exists(file2)) { + std::string h5diff_cmd = "h5diff " + file1 + " " + file2; + int status = system(h5diff_cmd.c_str()); + if (status != 0) { + LOG(ERROR) << "Failing h5diff command: " << h5diff_cmd; + } + REQUIRE(status == 0); + } +} + +/** + * Called after each individual test. + */ +int Posttest() { + if (!info.scratch_mode) { + // NOTE(chogan): This is necessary so that h5diff doesn't use the Hermes VFD + // in CheckResults. We don't need to reset LD_PRELOAD because it only has an + // effect when an application first starts. + unsetenv("LD_PRELOAD"); + unsetenv("HDF5_DRIVER"); + CheckResults(info.new_file, info.new_file_cmp); + CheckResults(info.existing_file, info.existing_file_cmp); + setenv("HDF5_DRIVER", "hermes", 1); + } + + CleanupFiles(); + + return 0; +} + +cl::Parser define_options() { + return cl::Opt(args.filename, "filename")["-f"]["--filename"]( + "Filename used for performing I/O") | + cl::Opt(args.directory, "dir")["-d"]["--directory"]( + "Directory used for performing I/O") | + cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( + "Request size used for performing I/O"); +} + +using hermes::adapter::vfd::test::Hdf5Api; + +/** + * The functions in this namespace perform operations on 2 files: the "main" + * file, which is the one going through the Hermes VFD, and a comparison file + * (with a "_cmp" suffix) which goes through the POSIX VFD. The idea is to + * perfrom each test on 2 files (Hermes VFD and POSIX VFD) and then compare the + * results at the end with h5diff. In persistent mode, the file produced by the + * Hermes VFD should be exactly the same as the one produced by the POSIX VFD. + */ +namespace test { + +hid_t hermes_hid; /**< Hermes handle ID */ +hid_t sec2_hid; /**< POSIX driver handle ID */ +herr_t hermes_herr; /**< Hermes error return value */ +/** + Test creating and opening a new file. +*/ +void TestOpen(const std::string &path, unsigned flags, bool create = false) { + Hdf5Api api; + + std::string cmp_path; + if (path == info.new_file) { + cmp_path = info.new_file_cmp; + } else { + cmp_path = info.existing_file_cmp; + } + + if (create) { + hermes_hid = api.Create(path, flags); + sec2_hid = api.CreatePosix(cmp_path, flags); + } else { + hermes_hid = api.Open(path, flags); + sec2_hid = api.OpenPosix(cmp_path, flags); + } + bool is_same = + (sec2_hid != H5I_INVALID_HID && hermes_hid != H5I_INVALID_HID) || + (sec2_hid == H5I_INVALID_HID && hermes_hid == H5I_INVALID_HID); + + REQUIRE(is_same); +} +/** + Test Close() calls. +*/ +void TestClose() { + Hdf5Api api; + hermes_herr = api.Close(hermes_hid); + herr_t status = api.Close(sec2_hid); + REQUIRE(status == hermes_herr); +} + +/** + Test writing partial 1-D dataset. +*/ +void TestWritePartial1d(const std::string &dset_name, const f32 *data, + hsize_t offset, hsize_t nelems) { + Hdf5Api api; + api.WritePartial1d(test::hermes_hid, dset_name, data, offset, nelems); + api.WritePartial1d(test::sec2_hid, dset_name, data, offset, nelems); +} + +/** + Test making dataset. +*/ +void TestWriteDataset(const std::string &dset_name, + const std::vector &data) { + Hdf5Api api; + api.MakeDataset(test::hermes_hid, dset_name, data); + api.MakeDataset(test::sec2_hid, dset_name, data); +} + + +/** + Test making compact dataset. +*/ +void TestMakeCompactDataset(const std::string &dset_name, + const std::vector &data) { + Hdf5Api api; + api.MakeDataset(test::hermes_hid, dset_name, data, true); + api.MakeDataset(test::sec2_hid, dset_name, data, true); +} + +/** + Test reading dataset. +*/ +void TestRead(const std::string &dset_name, std::vector &buf, + hsize_t offset, hsize_t nelems) { + Hdf5Api api; + api.Read(test::hermes_hid, dset_name, buf, offset, nelems); + std::vector sec2_read_buf(nelems, 0.0f); + api.Read(test::sec2_hid, dset_name, sec2_read_buf, offset, nelems); + + REQUIRE(std::equal(buf.begin(), buf.begin() + nelems, sec2_read_buf.begin())); +} +} // namespace test + +#include "hermes_vfd_basic_test.cc" diff --git a/adapter/utils.h b/adapter/utils.h index 3db768b93..5ab017e47 100644 --- a/adapter/utils.h +++ b/adapter/utils.h @@ -7,4 +7,12 @@ #define HERMES_DECL +namespace hermes::adapter { + +bool IsTracked(int fd) { + +} + +} // namespace hermes::adapter + #endif // HERMES_ADAPTER_UTILS_H_ From 41d784ae586505b48b56034f16371985b1fd9e12 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 29 Jan 2023 22:52:10 -0600 Subject: [PATCH 088/511] Begin switch to other unordered_map --- CMakeLists.txt | 3 +- adapter/CMakeLists.txt | 1 + adapter/posix/CMakeLists.txt | 5 +- benchmarks/put_get_bench.cc | 2 +- src/api/bucket.cc | 2 +- src/api/bucket.h | 2 +- src/api/hermes.cc | 13 +-- src/buffer_organizer.cc | 16 ++-- src/buffer_organizer.h | 2 +- src/buffer_pool.cc | 5 +- src/buffer_pool.h | 4 +- src/config_server.cc | 2 +- src/config_server.h | 70 +++++++------- src/data_structures.h | 4 +- src/metadata_manager.cc | 74 +++++++++------ src/metadata_manager.h | 25 +++-- src/metadata_types.h | 176 ++++++++++++++++++----------------- 17 files changed, 218 insertions(+), 188 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f295f6cdc..1430282e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,9 +19,10 @@ project(HERMES) #------------------------------------------------------------------------------ message(${CMAKE_BUILD_TYPE}) if (CMAKE_BUILD_TYPE STREQUAL "Release") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O1") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") message("This IS a release build") else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") message("This is NOT a release build") endif() diff --git a/adapter/CMakeLists.txt b/adapter/CMakeLists.txt index 4268d3669..e88b353a3 100644 --- a/adapter/CMakeLists.txt +++ b/adapter/CMakeLists.txt @@ -1,6 +1,7 @@ # Set hermes to preload if adapter is linked. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHERMES_PRELOAD -DHERMES_RPC_THALLIUM") +set(HERMES_SRC_DIR ${CMAKE_SOURCE_DIR}/src) set(HERMES_ADAPTER_DIR ${CMAKE_SOURCE_DIR}/adapter) include_directories(${CMAKE_SOURCE_DIR}/src) diff --git a/adapter/posix/CMakeLists.txt b/adapter/posix/CMakeLists.txt index b53300cc5..dd71ff5fb 100644 --- a/adapter/posix/CMakeLists.txt +++ b/adapter/posix/CMakeLists.txt @@ -1,4 +1,7 @@ -include_directories(${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) +include_directories( + ${HERMES_SRC_DIR} + ${HERMES_ADAPTER_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}) # Create the hermes_posix_singleton add_library(hermes_posix_singleton SHARED ${CMAKE_CURRENT_SOURCE_DIR}/singleton.cc) diff --git a/benchmarks/put_get_bench.cc b/benchmarks/put_get_bench.cc index f73a103d4..26b945e11 100644 --- a/benchmarks/put_get_bench.cc +++ b/benchmarks/put_get_bench.cc @@ -36,7 +36,7 @@ void PutTest(hapi::Hermes *hermes, for (size_t i = 0; i < blobs_per_rank; ++i) { size_t blob_name_int = rank * blobs_per_rank + i; std::string name = std::to_string(blob_name_int); - bkt->Put(name, std::move(blob), blob_id, ctx); + bkt->Put(name, blob, blob_id, ctx); } } t.Pause(); diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 0af3485c8..c4e95f02b 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -52,7 +52,7 @@ Status Bucket::GetBlobId(std::string blob_name, /** * Put \a blob_id Blob into the bucket * */ -Status Bucket::Put(std::string blob_name, Blob blob, +Status Bucket::Put(std::string blob_name, const Blob &blob, BlobId &blob_id, Context &ctx) { // Calculate placement auto dpe = DPEFactory::Get(ctx.policy); diff --git a/src/api/bucket.h b/src/api/bucket.h index 7f516532e..41bcb2612 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -84,7 +84,7 @@ class Bucket { /** * Put \a blob_id Blob into the bucket * */ - Status Put(std::string blob_name, Blob blob, + Status Put(std::string blob_name, const Blob &blob, BlobId &blob_id, Context &ctx); /** diff --git a/src/api/hermes.cc b/src/api/hermes.cc index a37b0d678..4e94530d8 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -104,13 +104,14 @@ void Hermes::LoadClientConfig(std::string config_path) { void Hermes::InitSharedMemory() { // Create shared-memory allocator auto mem_mngr = LABSTOR_MEMORY_MANAGER; - mem_mngr->CreateBackend(lipc::MemoryBackendType::kPosixShmMmap, - lipc::MemoryManager::kDefaultBackendSize, - server_config_.shmem_name_); + mem_mngr->CreateBackend( + lipc::MemoryManager::kDefaultBackendSize, + server_config_.shmem_name_); main_alloc_ = - mem_mngr->CreateAllocator(lipc::AllocatorType::kStackAllocator, - server_config_.shmem_name_, main_alloc_id, - sizeof(HermesShmHeader)); + mem_mngr->CreateAllocator( + server_config_.shmem_name_, + main_alloc_id, + sizeof(HermesShmHeader)); header_ = main_alloc_->GetCustomHeader(); } diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 830ca1a00..acb8c0422 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -11,7 +11,7 @@ namespace hermes { static size_t SumBufferBlobSizes(lipc::vector &buffers) { size_t sum = 0; - for (lipc::Ref buffer_ref : buffers) { + for (lipc::ShmRef buffer_ref : buffers) { sum += (*buffer_ref).blob_size_; } return sum; @@ -23,8 +23,8 @@ static size_t SumBufferBlobSizes(lipc::vector &buffers) { * */ void BufferOrganizer::shm_init() { mdm_ = &HERMES->mdm_; - for (lipc::Ref target : (*mdm_->targets_)) { - lipc::Ref dev_info = + for (lipc::ShmRef target : (*mdm_->targets_)) { + lipc::ShmRef dev_info = (*mdm_->devices_)[target->id_.GetDeviceId()]; if (dev_info->mount_dir_->size() == 0) { dev_info->header_->io_api_ = IoInterface::kRam; @@ -50,13 +50,13 @@ void BufferOrganizer::shm_deserialize() { /** Stores a blob into a set of buffers */ RPC void BufferOrganizer::LocalPlaceBlobInBuffers( - Blob &blob, lipc::vector &buffers) { + const Blob &blob, lipc::vector &buffers) { size_t blob_off = 0; - for (lipc::Ref buffer_info : buffers) { + for (lipc::ShmRef buffer_info : buffers) { if (buffer_info->tid_.GetNodeId() != mdm_->rpc_->node_id_) { continue; } - lipc::Ref dev_info = + lipc::ShmRef dev_info = (*mdm_->devices_)[buffer_info->tid_.GetDeviceId()]; auto io_client = IoClientFactory::Get(dev_info->header_->io_api_); bool ret = io_client->Write(*dev_info, blob.data() + blob_off, @@ -74,11 +74,11 @@ RPC Blob BufferOrganizer::LocalReadBlobFromBuffers( lipc::vector &buffers) { Blob blob(SumBufferBlobSizes(buffers)); size_t blob_off = 0; - for (lipc::Ref buffer_info : buffers) { + for (lipc::ShmRef buffer_info : buffers) { if (buffer_info->tid_.GetNodeId() != mdm_->rpc_->node_id_) { continue; } - lipc::Ref dev_info = + lipc::ShmRef dev_info = (*mdm_->devices_)[buffer_info->tid_.GetDeviceId()]; auto io_client = IoClientFactory::Get(dev_info->header_->io_api_); bool ret = io_client->Read(*dev_info, blob.data_mutable() + blob_off, diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index fd7d59c3b..6c60cde96 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -37,7 +37,7 @@ class BufferOrganizer { void shm_deserialize(); /** Stores a blob into a set of buffers */ - RPC void LocalPlaceBlobInBuffers(Blob &blob, + RPC void LocalPlaceBlobInBuffers(const Blob &blob, lipc::vector &buffers); /** Stores a blob into a set of buffers */ diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 566c47d1c..f3bdfc168 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -45,7 +45,8 @@ void BufferPool::shm_deserialize(BufferPoolShmHeader *header) { * TODO(llogan): use better allocator policy * */ lipc::vector -BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, Blob &blob) { +BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, + const Blob &blob) { lipc::vector buffers(HERMES->main_alloc_); size_t blob_off_ = 0; for (auto plcmnt : schema.plcmnts_) { @@ -53,7 +54,7 @@ BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, Blob &blob) { blob_off_ += plcmnt.size_; continue; } - lipc::Ref alloc = + lipc::ShmRef alloc = (*target_allocs_)[plcmnt.tid_.GetDeviceId()]; BufferInfo info; info.t_off_ = alloc->cur_off_; diff --git a/src/buffer_pool.h b/src/buffer_pool.h index 07762afef..dabab5b75 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -22,7 +22,7 @@ struct BufferPoolAllocator { * The shared-memory representation of the BufferPool * */ struct BufferPoolShmHeader { - lipc::ShmArchive> alloc_ar_; + lipc::TypedPointer> alloc_ar_; }; /** @@ -57,7 +57,7 @@ class BufferPool { * Allocate buffers from the targets according to the schema * */ RPC lipc::vector - LocalAllocateAndSetBuffers(PlacementSchema &schema, Blob &blob); + LocalAllocateAndSetBuffers(PlacementSchema &schema, const Blob &blob); /** * Free buffers from the BufferPool diff --git a/src/config_server.cc b/src/config_server.cc index c2a377d44..1b75f9e99 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -23,7 +23,7 @@ namespace hermes::config { void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { devices_.clear(); for (auto device : yaml_conf) { - DeviceInfo dev(SHM_ALLOCATOR_NULL); + DeviceInfo dev(lipc::typed_nullptr()); auto dev_info = device.second; (*dev.dev_name_) = lipc::string( device.first.as()); diff --git a/src/config_server.h b/src/config_server.h index 421ea045a..d42bc2408 100644 --- a/src/config_server.h +++ b/src/config_server.h @@ -25,17 +25,17 @@ enum class IoInterface { template<> struct ShmHeader : public lipc::ShmBaseHeader { /** The human-readable name of the device */ - lipc::ShmArchive dev_name_; + lipc::TypedPointer dev_name_; /** The I/O interface for the device */ IoInterface io_api_; /** The minimum transfer size of each device */ size_t block_size_; /** The unit of each slab, a multiple of the Device's block size */ - lipc::ShmArchive> slab_sizes_; + lipc::TypedPointer> slab_sizes_; /** The directory the device is mounted on */ - lipc::ShmArchive mount_dir_; + lipc::TypedPointer mount_dir_; /** The file to create on the device */ - lipc::ShmArchive mount_point_; + lipc::TypedPointer mount_point_; /** Device capacity (bytes) */ size_t capacity_; /** Bandwidth of a device (MBps) */ @@ -51,8 +51,8 @@ struct ShmHeader : public lipc::ShmBaseHeader { /** * Device information defined in server config * */ -struct DeviceInfo : public SHM_CONTAINER(DeviceInfo) { - SHM_CONTAINER_TEMPLATE(DeviceInfo, DeviceInfo) +struct DeviceInfo : public lipc::ShmContainer { + SHM_CONTAINER_TEMPLATE(DeviceInfo, DeviceInfo, ShmHeader) /** The human-readable name of the device */ lipc::mptr dev_name_; @@ -63,60 +63,60 @@ struct DeviceInfo : public SHM_CONTAINER(DeviceInfo) { /** The file to create on the device */ lipc::mptr mount_point_; - void shm_init_main(lipc::ShmArchive *ar, + void shm_init_main(ShmHeader *header, lipc::Allocator *alloc) { - shm_init_header(ar, alloc); - dev_name_.shm_init(alloc); - slab_sizes_.shm_init(alloc); - mount_dir_.shm_init(alloc); - mount_point_.shm_init(alloc); - shm_serialize(ar_); + shm_init_allocator(alloc); + shm_init_header(header); + dev_name_.shm_init(alloc_); + slab_sizes_.shm_init(alloc_); + mount_dir_.shm_init(alloc_); + mount_point_.shm_init(alloc_); + shm_serialize_main(); } - void shm_destroy(bool destroy_header = true) { - SHM_DESTROY_DATA_START + void shm_destroy_main() { dev_name_.shm_destroy(); slab_sizes_.shm_destroy(); mount_dir_.shm_destroy(); mount_point_.shm_destroy(); - SHM_DESTROY_DATA_END - SHM_DESTROY_END } - void shm_serialize(lipc::ShmArchive &ar) const { - shm_serialize_header(ar.header_ptr_); + void shm_serialize_main() const { dev_name_ >> header_->dev_name_; slab_sizes_ >> header_->slab_sizes_; mount_dir_ >> header_->mount_dir_; mount_point_ >> header_->mount_point_; } - void shm_deserialize(const lipc::ShmArchive &ar) { - shm_deserialize_header(ar.header_ptr_); + void shm_deserialize_main() { dev_name_ << header_->dev_name_; slab_sizes_ << header_->slab_sizes_; mount_dir_ << header_->mount_dir_; mount_point_ << header_->mount_point_; } - void WeakMove(DeviceInfo &other) { - SHM_WEAK_MOVE_START(SHM_WEAK_MOVE_DEFAULT(DeviceInfo)) + void shm_weak_move_main(ShmHeader *header, + lipc::Allocator *alloc, + DeviceInfo &other) { + shm_init_allocator(alloc); + shm_init_header(header); (*header_) = (*other.header_); - (*dev_name_) = lipc::Move(*other.dev_name_); - (*slab_sizes_) = lipc::Move(*other.slab_sizes_); - (*mount_dir_) = lipc::Move(*other.mount_dir_); - (*mount_point_) = lipc::Move(*other.mount_point_); - SHM_WEAK_MOVE_END() + (*dev_name_) = std::move(*other.dev_name_); + (*slab_sizes_) = std::move(*other.slab_sizes_); + (*mount_dir_) = std::move(*other.mount_dir_); + (*mount_point_) = std::move(*other.mount_point_); } - void StrongCopy(const DeviceInfo &other) { - SHM_STRONG_COPY_START(SHM_STRONG_COPY_DEFAULT(DeviceInfo)) + void shm_strong_copy_main(ShmHeader *header, + lipc::Allocator *alloc, + const DeviceInfo &other) { + shm_init_allocator(alloc); + shm_init_header(header); (*header_) = (*other.header_); - (*dev_name_) = lipc::Copy(*other.dev_name_); - (*slab_sizes_) = lipc::Copy(*other.slab_sizes_); - (*mount_dir_) = lipc::Copy(*other.mount_dir_); - (*mount_point_) = lipc::Copy(*other.mount_point_); - SHM_STRONG_COPY_END() + (*dev_name_) = (*other.dev_name_); + (*slab_sizes_) = (*other.slab_sizes_); + (*mount_dir_) = (*other.mount_dir_); + (*mount_point_) = (*other.mount_point_); } }; diff --git a/src/data_structures.h b/src/data_structures.h index 8c8901d1e..362d77a28 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -5,11 +5,11 @@ #ifndef HERMES_SRC_DATA_STRUCTURES_H_ #define HERMES_SRC_DATA_STRUCTURES_H_ -#include +#include #include #include #include -#include +#include namespace lipc = labstor::ipc; diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index c8aaee1fd..7628fe76b 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -117,7 +117,8 @@ BucketId MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { if (iter == bkt_id_map_->end()) { return BucketId::GetNull(); } - bkt_id = *(*iter).val_; + lipc::ShmRef> info = (*iter); + bkt_id = *info->second_; } return bkt_id; @@ -134,7 +135,8 @@ BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { if (iter == bkt_id_map_->end()) { return BucketId::GetNull(); } - BucketId bkt_id = *(*iter).val_; + lipc::ShmRef> info = (*iter); + BucketId bkt_id = *info->second_; return bkt_id; } @@ -151,7 +153,8 @@ bool MetadataManager::LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id) { return false; } // Get the blob info - BlobInfo &blob_info = *(*iter).val_; + lipc::ShmRef> info = (*iter); + BlobInfo &blob_info = *info->second_; return blob_info.bkt_id_ == bkt_id; } @@ -167,8 +170,8 @@ bool MetadataManager::LocalRenameBucket(BucketId bkt_id, if (iter == bkt_map_->end()) { return true; } - lipc::Ref bkt_info = (*iter).val_; - lipc::string &old_bkt_name = *bkt_info->name_; + lipc::ShmRef> info = (*iter); + lipc::string &old_bkt_name = *info->second_->name_; bkt_id_map_->emplace(new_bkt_name, bkt_id); bkt_id_map_->erase(old_bkt_name); return true; @@ -198,7 +201,7 @@ bool MetadataManager::LocalDestroyBucket(BucketId bkt_id) { * */ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, const lipc::charbuf &blob_name, - Blob &data, + const Blob &data, lipc::vector &buffers) { lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); @@ -212,11 +215,13 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, (*blob_info.name_) = std::move(internal_blob_name); (*blob_info.buffers_) = std::move(buffers); blob_map_->emplace(blob_id, std::move(blob_info)); + std::cout << "HERE" << std::endl; } else { blob_id = *(*blob_id_map_)[internal_blob_name]; auto iter = blob_map_->find(blob_id); - lipc::Ref blob_info = (*iter).val_; - (*blob_info->buffers_) = std::move(buffers); + lipc::ShmRef> info = (*iter); + BlobInfo &blob_info = *info->second_; + (*blob_info.buffers_) = std::move(buffers); } return blob_id; @@ -230,8 +235,9 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, * */ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { auto iter = blob_map_->find(blob_id); - lipc::Ref blob_info = (*iter).val_; - lipc::vector &buffers = (*blob_info->buffers_); + lipc::ShmRef> info = (*iter); + BlobInfo &blob_info = *info->second_; + lipc::vector &buffers = *blob_info.buffers_; return borg_->LocalReadBlobFromBuffers(buffers); } @@ -248,7 +254,8 @@ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, if (iter == blob_id_map_->end()) { return BlobId::GetNull(); } - return *(*iter).val_; + lipc::ShmRef> info = *iter; + return *info->second_; } /** @@ -262,8 +269,9 @@ lipc::vector MetadataManager::LocalGetBlobBuffers(BlobId blob_id) { if (iter == blob_map_->end()) { return lipc::vector(); } - lipc::Ref blob_info = (*iter).val_; - return (*blob_info->buffers_); + lipc::ShmRef> info = (*iter); + BlobInfo &blob_info = *info->second_; + return (*blob_info.buffers_); } /** @@ -279,8 +287,9 @@ bool MetadataManager::LocalRenameBlob(BucketId bkt_id, BlobId blob_id, if (iter == blob_map_->end()) { return true; } - lipc::Ref blob_info = (*iter).val_; - lipc::charbuf &old_blob_name = (*blob_info->name_); + lipc::ShmRef> info = (*iter); + BlobInfo &blob_info = *info->second_; + lipc::charbuf &old_blob_name = (*blob_info.name_); lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, new_blob_name); blob_id_map_->erase(old_blob_name); blob_id_map_->emplace(internal_blob_name, blob_id); @@ -300,8 +309,9 @@ bool MetadataManager::LocalDestroyBlob(BucketId bkt_id, if (iter == blob_map_->end()) { return true; } - lipc::Ref blob_info = (*iter).val_; - lipc::charbuf &blob_name = (*blob_info->name_); + lipc::ShmRef> info = (*iter); + BlobInfo &blob_info = *info->second_; + lipc::charbuf &blob_name = (*blob_info.name_); blob_id_map_->erase(blob_name); blob_map_->erase(blob_id); return true; @@ -329,11 +339,10 @@ VBucketId MetadataManager::LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name) { if (iter == vbkt_id_map_->end()) { return VBucketId::GetNull(); } - vbkt_id = *(*iter).val_; + lipc::ShmRef> info = (*iter); + vbkt_id = *info->second_; } - return vbkt_id; - } /** @@ -347,7 +356,8 @@ VBucketId MetadataManager::LocalGetVBucketId(lipc::charbuf &vbkt_name) { if (iter == vbkt_id_map_->end()) { return VBucketId::GetNull(); } - VBucketId vbkt_id = *(*iter).val_; + lipc::ShmRef> info = (*iter); + VBucketId vbkt_id = *info->second_; return vbkt_id; } @@ -363,8 +373,9 @@ bool MetadataManager::LocalVBucketLinkBlob(VBucketId vbkt_id, if (iter == vbkt_map_->end()) { return true; } - lipc::Ref vbkt_info = (*iter).val_; - vbkt_info->blobs_->emplace(blob_id, blob_id); + lipc::ShmRef> info = (*iter); + VBucketInfo &vbkt_info = *info->second_; + vbkt_info.blobs_->emplace(blob_id, blob_id); return true; } @@ -381,8 +392,9 @@ bool MetadataManager::LocalVBucketUnlinkBlob(VBucketId vbkt_id, if (iter == vbkt_map_->end()) { return true; } - lipc::Ref vbkt_info = (*iter).val_; - vbkt_info->blobs_->erase(blob_id); + lipc::ShmRef> info = (*iter); + VBucketInfo &vbkt_info = *info->second_; + vbkt_info.blobs_->erase(blob_id); return true; } @@ -406,9 +418,10 @@ bool MetadataManager::LocalVBucketContainsBlob(VBucketId vbkt_id, if (iter == vbkt_map_->end()) { return true; } - lipc::Ref vbkt_info = (*iter).val_; - auto link_iter = vbkt_info->blobs_->find(blob_id); - return link_iter != vbkt_info->blobs_->end(); + lipc::ShmRef> info = (*iter); + VBucketInfo &vbkt_info = *info->second_; + auto link_iter = vbkt_info.blobs_->find(blob_id); + return link_iter != vbkt_info.blobs_->end(); } /** @@ -423,8 +436,9 @@ bool MetadataManager::LocalRenameVBucket(VBucketId vbkt_id, if (iter == vbkt_map_->end()) { return true; } - lipc::Ref vbkt_info = (*iter).val_; - lipc::string &old_bkt_name = *vbkt_info->name_; + lipc::ShmRef> info = (*iter); + VBucketInfo &vbkt_info = *info->second_; + lipc::string &old_bkt_name = *vbkt_info.name_; vbkt_id_map_->emplace(new_vbkt_name, vbkt_id); vbkt_id_map_->erase(old_bkt_name); return true; diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 8aa926f83..b17c77ac7 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -32,21 +32,21 @@ typedef lipc::unordered_map VBKT_MAP_T; * */ struct MetadataManagerShmHeader { /// SHM representation of blob id map - lipc::ShmArchive> blob_id_map_ar_; + lipc::TypedPointer> blob_id_map_ar_; /// SHM representation of bucket id map - lipc::ShmArchive> bkt_id_map_ar_; + lipc::TypedPointer> bkt_id_map_ar_; /// SHM representation of vbucket id map - lipc::ShmArchive> vbkt_id_map_ar_; + lipc::TypedPointer> vbkt_id_map_ar_; /// SHM representation of blob map - lipc::ShmArchive> blob_map_ar_; + lipc::TypedPointer> blob_map_ar_; /// SHM representation of bucket map - lipc::ShmArchive> bkt_map_ar_; + lipc::TypedPointer> bkt_map_ar_; /// SHM representation of vbucket map - lipc::ShmArchive> vbkt_map_ar_; + lipc::TypedPointer> vbkt_map_ar_; /// SHM representation of device vector - lipc::ShmArchive>> devices_; + lipc::TypedPointer>> devices_; /// SHM representation of target info vector - lipc::ShmArchive>> targets_; + lipc::TypedPointer>> targets_; /// Used to create unique ids. Starts at 1. std::atomic id_alloc_; }; @@ -76,6 +76,9 @@ class MetadataManager { lipc::mptr> devices_; lipc::mptr> targets_; + /** A global lock for simplifying MD management */ + RwLock lock_; + public: MetadataManager() = default; @@ -165,8 +168,10 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BlobId LocalBucketPutBlob(BucketId bkt_id, const lipc::charbuf &blob_name, - Blob &data, lipc::vector &buffers); + RPC BlobId LocalBucketPutBlob(BucketId bkt_id, + const lipc::charbuf &blob_name, + const Blob &data, + lipc::vector &buffers); /** * Get a blob from a bucket diff --git a/src/metadata_types.h b/src/metadata_types.h index 383e4454b..e63a8abf4 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -27,8 +27,10 @@ struct TargetInfo { double bandwidth_; /**< the bandwidth of the device */ double latency_; /**< the latency of the device */ + /** Default constructor */ TargetInfo() = default; + /** Primary constructor */ TargetInfo(TargetId id, size_t max_cap, size_t rem_cap, double bandwidth, double latency) : id_(id), max_cap_(max_cap), rem_cap_(rem_cap), @@ -43,8 +45,10 @@ struct BufferInfo { size_t blob_off_; /**< Offset in the blob */ size_t blob_size_; /**< The amount of the blob being placed */ + /** Default constructor */ BufferInfo() = default; + /** Primary constructor */ BufferInfo(TargetId tid, size_t t_off, size_t t_size, size_t blob_off, size_t blob_size) : tid_(tid), t_off_(t_off), t_size_(t_size), @@ -86,9 +90,10 @@ struct BufferInfo { template<> struct ShmHeader : public lipc::ShmBaseHeader { BucketId bkt_id_; /**< The bucket containing the blob */ - lipc::ShmArchive name_ar_; - lipc::ShmArchive> buffers_ar_; - RwLock rwlock_; + lipc::TypedPointer name_ar_; /**< SHM pointer to string */ + lipc::TypedPointer> + buffers_ar_; /**< SHM pointer to BufferInfo vector */ + RwLock rwlock_; /**< Ensures BlobInfo access is synchronized */ /** Default constructor */ ShmHeader() = default; @@ -127,9 +132,9 @@ struct ShmHeader : public lipc::ShmBaseHeader { }; /** Blob metadata */ -struct BlobInfo : public SHM_CONTAINER(BlobInfo){ +struct BlobInfo : public lipc::ShmContainer { public: - SHM_CONTAINER_TEMPLATE(BlobInfo, BlobInfo); + SHM_CONTAINER_TEMPLATE(BlobInfo, BlobInfo, ShmHeader); public: /// The bucket containing the blob @@ -143,135 +148,134 @@ struct BlobInfo : public SHM_CONTAINER(BlobInfo){ BlobInfo() = default; /** Initialize the data structure */ - void shm_init_main(lipc::ShmArchive *ar, + void shm_init_main(ShmHeader *header, lipc::Allocator *alloc) { - shm_init_header(ar, alloc); - name_.shm_init(alloc); - buffers_.shm_init(alloc); - shm_serialize(ar_); + shm_init_allocator(alloc); + shm_init_header(header); + name_.shm_init(alloc_); + buffers_.shm_init(alloc_); + shm_serialize_main(); } /** Destroy all allocated data */ - void shm_destroy(bool destroy_header = true) { - SHM_DESTROY_DATA_START + void shm_destroy_main() { name_.shm_destroy(); buffers_.shm_destroy(); - SHM_DESTROY_DATA_END - SHM_DESTROY_END } - /** Serialize into \a ShmArchive */ - void shm_serialize(lipc::ShmArchive &ar) const { - shm_serialize_header(ar.header_ptr_); + /** Serialize pointers */ + void shm_serialize_main() const { header_->bkt_id_ = bkt_id_; name_ >> header_->name_ar_; buffers_ >> header_->buffers_ar_; } - /** Deserialize from \a ShmArchive */ - void shm_deserialize(const lipc::ShmArchive &ar) { - if(!shm_deserialize_header(ar.header_ptr_)) { return; } + /** Deserialize pointers */ + void shm_deserialize_main() { bkt_id_ = header_->bkt_id_; name_ << header_->name_ar_; buffers_ << header_->buffers_ar_; } /** Move pointers into another BlobInfo */ - void WeakMove(BlobInfo &other) { - SHM_WEAK_MOVE_START(SHM_WEAK_MOVE_DEFAULT(BlobInfo)) + void shm_weak_move_main(ShmHeader *header, + lipc::Allocator *alloc, + BlobInfo &other) { + shm_init_allocator(alloc); + shm_init_header(header); (*header_) = (*other.header_); bkt_id_ = other.bkt_id_; - (*name_) = lipc::Move(*other.name_); - (*buffers_) = lipc::Move(*other.buffers_); - SHM_WEAK_MOVE_END() + (name_) = std::move(other.name_); + (buffers_) = std::move(other.buffers_); } /** Deep copy data into another BlobInfo */ - void StrongCopy(const BlobInfo &other) { - SHM_STRONG_COPY_START(SHM_STRONG_COPY_DEFAULT(BlobInfo)) + void shm_strong_copy_main(ShmHeader *header, + lipc::Allocator *alloc, + const BlobInfo &other) { + shm_init_allocator(alloc); + shm_init_header(header); (*header_) = (*other.header_); bkt_id_ = other.bkt_id_; - (*name_) = lipc::Copy(*other.name_); - (*buffers_) = lipc::Copy(*other.buffers_); - SHM_STRONG_COPY_END() + (*name_) = (*other.name_); + (*buffers_) = (*other.buffers_); } }; /** Represents BucketInfo in shared memory */ template<> struct ShmHeader : public lipc::ShmBaseHeader { - lipc::ShmArchive name_ar_; + lipc::TypedPointer name_ar_; size_t num_blobs_; }; /** Metadata for a Bucket */ -struct BucketInfo : public SHM_CONTAINER(BucketInfo) { +struct BucketInfo : public lipc::ShmContainer { public: - SHM_CONTAINER_TEMPLATE(BucketInfo, BucketInfo); + SHM_CONTAINER_TEMPLATE(BucketInfo, BucketInfo, ShmHeader); public: - /** The name of the bucket */ - lipc::mptr name_; + lipc::mptr name_; /**< The name of the bucket */ public: /** Default constructor */ BucketInfo() = default; /** Initialize the data structure */ - void shm_init_main(lipc::ShmArchive *ar, + void shm_init_main(ShmHeader *header, lipc::Allocator *alloc) { - shm_init_header(ar, alloc); - name_.shm_init(alloc); + shm_init_allocator(alloc); + shm_init_header(header); + name_ = lipc::make_mptr(alloc); } /** Destroy all allocated data */ - void shm_destroy(bool destroy_header = true) { - SHM_DESTROY_DATA_START + void shm_destroy_main(bool destroy_header = true) { name_.shm_destroy(); - SHM_DESTROY_DATA_END - SHM_DESTROY_END } - /** Serialize into \a ShmArchive */ - void shm_serialize(lipc::ShmArchive &ar) const { - shm_serialize_header(ar.header_ptr_); + /** Serialize pointers */ + void shm_serialize_main() const { name_ >> header_->name_ar_; } - /** Deserialize from \a ShmArchive */ - void shm_deserialize(const lipc::ShmArchive &ar) { - if(!shm_deserialize_header(ar.header_ptr_)) { return; } + /** Deserialize pointers */ + void shm_deserialize_main() { name_ << header_->name_ar_; } - void WeakMove(BucketInfo &other) { - SHM_WEAK_MOVE_START(SHM_WEAK_MOVE_DEFAULT(BucketInfo)) + void shm_weak_move_main(ShmHeader *header, + lipc::Allocator *alloc, + BucketInfo &other) { + shm_init_allocator(alloc); + shm_init_header(header); (*header_) = (*other.header_); - (*name_) = lipc::Move(*other.name_); - shm_serialize(ar_); - SHM_WEAK_MOVE_END() + (*name_) = (*other.name_); + shm_serialize_main(); } - void StrongCopy(const BucketInfo &other) { - SHM_STRONG_COPY_START(SHM_STRONG_COPY_DEFAULT(BucketInfo)) + void shm_strong_copy_main(ShmHeader *header, + lipc::Allocator *alloc, + const BucketInfo &other) { + shm_init_allocator(alloc); + shm_init_header(header); (*header_) = (*other.header_); - (*name_) = lipc::Copy(*other.name_); - shm_serialize(ar_); - SHM_STRONG_COPY_END() + (*name_) = (*other.name_); + shm_serialize_main(); } }; /** Represents a VBucket in shared memory */ template<> struct ShmHeader : public lipc::ShmBaseHeader { - lipc::ShmArchive name_; - lipc::ShmArchive> blobs_; + lipc::TypedPointer name_; + lipc::TypedPointer> blobs_; }; /** Metadata for a VBucket */ -struct VBucketInfo : public SHM_CONTAINER(VBucketInfo) { +struct VBucketInfo : public lipc::ShmContainer { public: - SHM_CONTAINER_TEMPLATE(VBucketInfo, VBucketInfo); + SHM_CONTAINER_TEMPLATE(VBucketInfo, VBucketInfo, ShmHeader); public: lipc::mptr name_; @@ -280,49 +284,49 @@ struct VBucketInfo : public SHM_CONTAINER(VBucketInfo) { public: VBucketInfo() = default; - void shm_init_main(lipc::ShmArchive *ar, + void shm_init_main(ShmHeader *header, lipc::Allocator *alloc) { - shm_init_header(ar, alloc); - name_.shm_init(alloc); - blobs_.shm_init(alloc_); + shm_init_allocator(alloc); + shm_init_header(header); + name_ = lipc::make_mptr(alloc_); + blobs_ = lipc::make_mptr>(alloc_); } - void shm_destroy(bool destroy_header = true) { - SHM_DESTROY_DATA_START + void shm_destroy_main(bool destroy_header = true) { name_.shm_destroy(); blobs_.shm_destroy(); - SHM_DESTROY_DATA_END - SHM_DESTROY_END } - void shm_serialize(lipc::ShmArchive &ar) const { - shm_serialize_header(ar.header_ptr_); + void shm_serialize_main() const { name_ >> header_->name_; blobs_ >> header_->blobs_; } - void shm_deserialize(const lipc::ShmArchive &ar) { - if(!shm_deserialize_header(ar.header_ptr_)) { return; } + void shm_deserialize_main() { name_ << header_->name_; blobs_ << header_->blobs_; } - void WeakMove(VBucketInfo &other) { - SHM_WEAK_MOVE_START(SHM_WEAK_MOVE_DEFAULT(VBucketInfo)) + void shm_weak_move_main(ShmHeader *header, + lipc::Allocator *alloc, + VBucketInfo &other) { + shm_init_allocator(alloc); + shm_init_header(header); (*header_) = (*other.header_); - (*name_) = lipc::Move(*other.name_); - (*blobs_) = lipc::Move(*other.blobs_); - shm_serialize(ar_); - SHM_WEAK_MOVE_END() + (*name_) = std::move(*other.name_); + (*blobs_) = std::move(*other.blobs_); + shm_serialize_main(); } - void StrongCopy(const VBucketInfo &other) { - SHM_STRONG_COPY_START(SHM_STRONG_COPY_DEFAULT(VBucketInfo)) + void shm_strong_copy_main(ShmHeader *header, + lipc::Allocator *alloc, + const VBucketInfo &other) { + shm_init_allocator(alloc); + shm_init_header(header); (*header_) = (*other.header_); - (*name_) = lipc::Copy(*other.name_); - (*blobs_) = lipc::Copy(*other.blobs_); - shm_serialize(ar_); - SHM_STRONG_COPY_END() + (*name_) = (*other.name_); + (*blobs_) = (*other.blobs_); + shm_serialize_main(); } }; From ad6386ff48179071aa8a51299e15da5fdfe2768f Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 30 Jan 2023 03:14:38 -0600 Subject: [PATCH 089/511] Switching to boost for comparison --- src/api/hermes.cc | 2 +- src/api/hermes_daemon.cc | 3 +++ src/config_server.h | 9 +++++++++ src/io_clients/posix.h | 5 +++-- src/metadata_manager.cc | 3 ++- src/metadata_manager.h | 26 +++++++++++++++++++++++--- src/metadata_types.h | 11 ++++++++++- 7 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 4e94530d8..ef409aba0 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -74,6 +74,7 @@ void Hermes::InitClient(std::string server_config_path, mdm_.shm_deserialize(&header_->mdm_); bpm_.shm_deserialize(&header_->bpm_); borg_.shm_deserialize(); + mdm_.PrintDeviceInfo(); } void Hermes::InitColocated(std::string server_config_path, @@ -125,7 +126,6 @@ void Hermes::LoadSharedMemory() { } void Hermes::FinalizeServer() { - // TODO(llogan): Fix the shared memory segfault // NOTE(llogan): rpc_.Finalize() is called internally by daemon in this case bpm_.shm_destroy(); mdm_.shm_destroy(); diff --git a/src/api/hermes_daemon.cc b/src/api/hermes_daemon.cc index 7ad25c129..8a8513277 100644 --- a/src/api/hermes_daemon.cc +++ b/src/api/hermes_daemon.cc @@ -29,6 +29,9 @@ int main(int argc, char* argv[]) { auto hermes = hapi::Hermes::Create( hermes::HermesType::kServer, hermes_config); + + hermes->mdm_.PrintDeviceInfo(); + hermes->RunDaemon(); hermes->Finalize(); MPI_Finalize(); diff --git a/src/config_server.h b/src/config_server.h index d42bc2408..49854387c 100644 --- a/src/config_server.h +++ b/src/config_server.h @@ -63,6 +63,10 @@ struct DeviceInfo : public lipc::ShmContainer { /** The file to create on the device */ lipc::mptr mount_point_; + /** Default Constructor */ + DeviceInfo() = default; + + /** Default SHM Constructor */ void shm_init_main(ShmHeader *header, lipc::Allocator *alloc) { shm_init_allocator(alloc); @@ -74,6 +78,7 @@ struct DeviceInfo : public lipc::ShmContainer { shm_serialize_main(); } + /** Free shared memory */ void shm_destroy_main() { dev_name_.shm_destroy(); slab_sizes_.shm_destroy(); @@ -81,6 +86,7 @@ struct DeviceInfo : public lipc::ShmContainer { mount_point_.shm_destroy(); } + /** Serialize into SHM */ void shm_serialize_main() const { dev_name_ >> header_->dev_name_; slab_sizes_ >> header_->slab_sizes_; @@ -88,6 +94,7 @@ struct DeviceInfo : public lipc::ShmContainer { mount_point_ >> header_->mount_point_; } + /** Deserialize from SHM */ void shm_deserialize_main() { dev_name_ << header_->dev_name_; slab_sizes_ << header_->slab_sizes_; @@ -95,6 +102,7 @@ struct DeviceInfo : public lipc::ShmContainer { mount_point_ << header_->mount_point_; } + /** Move another object into this object. */ void shm_weak_move_main(ShmHeader *header, lipc::Allocator *alloc, DeviceInfo &other) { @@ -107,6 +115,7 @@ struct DeviceInfo : public lipc::ShmContainer { (*mount_point_) = std::move(*other.mount_point_); } + /** Copy another object into this object */ void shm_strong_copy_main(ShmHeader *header, lipc::Allocator *alloc, const DeviceInfo &other) { diff --git a/src/io_clients/posix.h b/src/io_clients/posix.h index f10932420..929bd0994 100644 --- a/src/io_clients/posix.h +++ b/src/io_clients/posix.h @@ -19,8 +19,9 @@ class PosixIoClient : public IoClient { public: bool Init(DeviceInfo &dev_info) override { auto api = HERMES_POSIX_API; - (*dev_info.mount_point_) = (*dev_info.mount_dir_) + - "/" + "slab_" + (*dev_info.dev_name_); + lipc::string text = (*dev_info.mount_dir_) + + "/" + "slab_" + (*dev_info.dev_name_); + (*dev_info.mount_point_) = std::move(text); int fd = api->open((*dev_info.mount_point_).c_str(), O_TRUNC | O_CREAT, 0666); if (fd < 0) { return false; } diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 7628fe76b..231e0d8a9 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -29,7 +29,7 @@ void MetadataManager::shm_init(ServerConfig *config, // Create the DeviceInfo vector devices_ = lipc::make_mptr>( - HERMES->main_alloc_, HERMES->server_config_.devices_); + HERMES->main_alloc_, config->devices_); targets_ = lipc::make_mptr>(); // Create the TargetInfo vector @@ -93,6 +93,7 @@ void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { vbkt_map_ << header_->vbkt_map_ar_; targets_ << header_->targets_; devices_ << header_->devices_; + PrintDeviceInfo(); } /** diff --git a/src/metadata_manager.h b/src/metadata_manager.h index b17c77ac7..f385561c5 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -310,9 +310,29 @@ class MetadataManager { return {}; } - public: - RPC_AUTOGEN_START - RPC_AUTOGEN_END + // TODO(llogan): remove + void PrintDeviceInfo() { + for (lipc::ShmRef target : (*targets_)) { + lipc::Pointer p; + lipc::ShmRef dev_info = + (*devices_)[target->id_.GetDeviceId()]; + + std::cout << dev_info->dev_name_->str() << std::endl; + + *devices_ >> p; + std::cout << "devices_->header_ = " << p.off_.load() << std::endl; + + *dev_info >> p; + std::cout << "dev_info->header_ = " << p.off_.load() << std::endl; + + dev_info->mount_point_ >> p; + std::cout << "mount_point_->header_ = " << p.off_.load() << std::endl; + + p = dev_info->mount_point_->header_->text_; + std::cout << "mount_point_->header_->text_ = " << p.off_.load() + << std::endl; + } + } }; } // namespace hermes diff --git a/src/metadata_types.h b/src/metadata_types.h index e63a8abf4..e4d7eba6f 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -244,6 +244,7 @@ struct BucketInfo : public lipc::ShmContainer { name_ << header_->name_ar_; } + /** Move other object into this one */ void shm_weak_move_main(ShmHeader *header, lipc::Allocator *alloc, BucketInfo &other) { @@ -254,6 +255,7 @@ struct BucketInfo : public lipc::ShmContainer { shm_serialize_main(); } + /** Copy other object into this one */ void shm_strong_copy_main(ShmHeader *header, lipc::Allocator *alloc, const BucketInfo &other) { @@ -282,8 +284,10 @@ struct VBucketInfo : public lipc::ShmContainer { lipc::mptr> blobs_; public: + /** Default constructor. */ VBucketInfo() = default; + /** Default SHM Constructor */ void shm_init_main(ShmHeader *header, lipc::Allocator *alloc) { shm_init_allocator(alloc); @@ -292,21 +296,25 @@ struct VBucketInfo : public lipc::ShmContainer { blobs_ = lipc::make_mptr>(alloc_); } - void shm_destroy_main(bool destroy_header = true) { + /** Free shared memory */ + void shm_destroy_main() { name_.shm_destroy(); blobs_.shm_destroy(); } + /** Serialize into SHM */ void shm_serialize_main() const { name_ >> header_->name_; blobs_ >> header_->blobs_; } + /** Deserialize from SHM */ void shm_deserialize_main() { name_ << header_->name_; blobs_ << header_->blobs_; } + /** Move other object into this one */ void shm_weak_move_main(ShmHeader *header, lipc::Allocator *alloc, VBucketInfo &other) { @@ -318,6 +326,7 @@ struct VBucketInfo : public lipc::ShmContainer { shm_serialize_main(); } + /** Copy other object into this one */ void shm_strong_copy_main(ShmHeader *header, lipc::Allocator *alloc, const VBucketInfo &other) { From 4de8ebf946275b70cb2e19a3496ad503057fd401 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 30 Jan 2023 06:16:02 -0600 Subject: [PATCH 090/511] Put/Get work again. Need to fix mdm lock. --- benchmarks/put_get_bench.cc | 2 +- src/api/hermes.cc | 5 ++--- src/api/hermes_daemon.cc | 2 -- src/buffer_pool.cc | 2 +- src/buffer_pool.h | 15 +++++++++++++-- src/config_server.h | 2 ++ src/data_structures.h | 1 + src/metadata_manager.cc | 5 ++--- src/metadata_manager.h | 27 +-------------------------- 9 files changed, 23 insertions(+), 38 deletions(-) diff --git a/benchmarks/put_get_bench.cc b/benchmarks/put_get_bench.cc index 26b945e11..89514ef19 100644 --- a/benchmarks/put_get_bench.cc +++ b/benchmarks/put_get_bench.cc @@ -75,7 +75,7 @@ int main(int argc, char **argv) { MPI_Barrier(MPI_COMM_WORLD); PutTest(hermes, rank, 1, blobs_per_rank, blob_size); MPI_Barrier(MPI_COMM_WORLD); - // GetTest(hermes, rank, 1, blobs_per_rank, blob_size); + GetTest(hermes, rank, 1, blobs_per_rank, blob_size); hermes->Finalize(); MPI_Finalize(); } \ No newline at end of file diff --git a/src/api/hermes.cc b/src/api/hermes.cc index ef409aba0..57bd9558d 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -74,7 +74,6 @@ void Hermes::InitClient(std::string server_config_path, mdm_.shm_deserialize(&header_->mdm_); bpm_.shm_deserialize(&header_->bpm_); borg_.shm_deserialize(); - mdm_.PrintDeviceInfo(); } void Hermes::InitColocated(std::string server_config_path, @@ -127,8 +126,8 @@ void Hermes::LoadSharedMemory() { void Hermes::FinalizeServer() { // NOTE(llogan): rpc_.Finalize() is called internally by daemon in this case - bpm_.shm_destroy(); - mdm_.shm_destroy(); + // bpm_.shm_destroy(); + // mdm_.shm_destroy(); } void Hermes::FinalizeClient() { diff --git a/src/api/hermes_daemon.cc b/src/api/hermes_daemon.cc index 8a8513277..656a73765 100644 --- a/src/api/hermes_daemon.cc +++ b/src/api/hermes_daemon.cc @@ -30,8 +30,6 @@ int main(int argc, char* argv[]) { hermes::HermesType::kServer, hermes_config); - hermes->mdm_.PrintDeviceInfo(); - hermes->RunDaemon(); hermes->Finalize(); MPI_Finalize(); diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index f3bdfc168..65e769397 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -57,7 +57,7 @@ BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, lipc::ShmRef alloc = (*target_allocs_)[plcmnt.tid_.GetDeviceId()]; BufferInfo info; - info.t_off_ = alloc->cur_off_; + info.t_off_ = alloc->cur_off_.load(); alloc->cur_off_ += plcmnt.size_; // NOTE(llogan): allocate emulation info.t_size_ = plcmnt.size_; info.blob_off_ = blob_off_; diff --git a/src/buffer_pool.h b/src/buffer_pool.h index dabab5b75..debe55cb2 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -14,8 +14,19 @@ class MetadataManager; class BufferOrganizer; struct BufferPoolAllocator { - std::atomic max_size_; - std::atomic cur_off_; + lipc::atomic max_size_; + lipc::atomic cur_off_; + + /** Default constructor */ + BufferPoolAllocator() = default; + + /** Copy Constructor */ + BufferPoolAllocator(const BufferPoolAllocator &other) + : max_size_(other.max_size_.load()), cur_off_(other.cur_off_.load()) {} + + /** Move Constructor */ + BufferPoolAllocator(BufferPoolAllocator &&other) + : max_size_(other.max_size_.load()), cur_off_(other.cur_off_.load()) {} }; /** diff --git a/src/config_server.h b/src/config_server.h index 49854387c..4c2c74074 100644 --- a/src/config_server.h +++ b/src/config_server.h @@ -113,6 +113,7 @@ struct DeviceInfo : public lipc::ShmContainer { (*slab_sizes_) = std::move(*other.slab_sizes_); (*mount_dir_) = std::move(*other.mount_dir_); (*mount_point_) = std::move(*other.mount_point_); + shm_serialize_main(); } /** Copy another object into this object */ @@ -126,6 +127,7 @@ struct DeviceInfo : public lipc::ShmContainer { (*slab_sizes_) = (*other.slab_sizes_); (*mount_dir_) = (*other.mount_dir_); (*mount_point_) = (*other.mount_point_); + shm_serialize_main(); } }; diff --git a/src/data_structures.h b/src/data_structures.h index 362d77a28..5e097415e 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace lipc = labstor::ipc; diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 231e0d8a9..43f54b4b9 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -30,7 +30,8 @@ void MetadataManager::shm_init(ServerConfig *config, // Create the DeviceInfo vector devices_ = lipc::make_mptr>( HERMES->main_alloc_, config->devices_); - targets_ = lipc::make_mptr>(); + targets_ = lipc::make_mptr>( + HERMES->main_alloc_); // Create the TargetInfo vector targets_->reserve(devices_->size()); @@ -93,7 +94,6 @@ void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { vbkt_map_ << header_->vbkt_map_ar_; targets_ << header_->targets_; devices_ << header_->devices_; - PrintDeviceInfo(); } /** @@ -216,7 +216,6 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, (*blob_info.name_) = std::move(internal_blob_name); (*blob_info.buffers_) = std::move(buffers); blob_map_->emplace(blob_id, std::move(blob_info)); - std::cout << "HERE" << std::endl; } else { blob_id = *(*blob_id_map_)[internal_blob_name]; auto iter = blob_map_->find(blob_id); diff --git a/src/metadata_manager.h b/src/metadata_manager.h index f385561c5..dbbeebbd4 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -308,32 +308,7 @@ class MetadataManager { * */ lipc::vector GetGlobalTargetInfo() { return {}; - } - - // TODO(llogan): remove - void PrintDeviceInfo() { - for (lipc::ShmRef target : (*targets_)) { - lipc::Pointer p; - lipc::ShmRef dev_info = - (*devices_)[target->id_.GetDeviceId()]; - - std::cout << dev_info->dev_name_->str() << std::endl; - - *devices_ >> p; - std::cout << "devices_->header_ = " << p.off_.load() << std::endl; - - *dev_info >> p; - std::cout << "dev_info->header_ = " << p.off_.load() << std::endl; - - dev_info->mount_point_ >> p; - std::cout << "mount_point_->header_ = " << p.off_.load() << std::endl; - - p = dev_info->mount_point_->header_->text_; - std::cout << "mount_point_->header_->text_ = " << p.off_.load() - << std::endl; - } - } -}; + }}; } // namespace hermes From a1ea38bbf2402e6c34bfffd6bac2ca32f56e5104 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Tue, 31 Jan 2023 06:25:32 -0600 Subject: [PATCH 091/511] Move away from lipc for Hermes blob. Document fs adapter further. --- adapter/adapter_factory/abstract_adapter.h | 57 +++++++++ adapter/adapter_factory/adapter_factory.h | 56 ++++++++ adapter/{utils.h => adapter_utils.h} | 4 +- adapter/filesystem/filesystem.cc | 64 ++++----- adapter/filesystem/filesystem.h | 121 +++--------------- ...leton.cc => metadata_manager_singleton.cc} | 2 +- ....h => metadata_manager_singleton_macros.h} | 2 +- adapter/mapper/abstract_mapper.h | 74 +++++++++++ adapter/mapper/balanced_mapper.cc | 43 +++++++ adapter/mapper/balanced_mapper.h | 34 +++++ adapter/mapper/mapper_factory.h | 46 +++++++ adapter/posix/CMakeLists.txt | 11 +- adapter/posix/posix.cc | 48 ++++--- adapter/posix/{real_api.h => posix_api.h} | 0 .../{singleton.cc => posix_singleton.cc} | 2 +- ...eton_macros.h => posix_singleton_macros.h} | 0 code_generators/.idea/.gitignore | 3 - code_generators/.idea/code_generators.iml | 12 -- .../inspectionProfiles/Project_Default.xml | 21 --- .../inspectionProfiles/profiles_settings.xml | 6 - code_generators/.idea/misc.xml | 4 - code_generators/.idea/modules.xml | 8 -- code_generators/.idea/vcs.xml | 6 - config/hermes_client_default.yaml | 2 +- src/api/bucket.cc | 7 +- src/api/bucket.h | 75 +++++++++-- src/buffer_organizer.cc | 13 +- src/buffer_organizer.h | 11 +- src/buffer_pool.cc | 2 +- src/buffer_pool.h | 3 +- src/config.h | 4 +- src/config_client.cc | 4 + src/config_client.h | 1 + src/config_client_default.h | 2 +- src/config_server_default.h | 2 +- src/hermes_types.cc | 86 +++++++++++++ src/hermes_types.h | 73 ++++++++++- src/io_clients/io_client.h | 8 +- src/io_clients/posix.h | 8 +- src/io_clients/ram.h | 8 +- src/metadata_manager.cc | 4 +- src/metadata_manager.h | 2 +- src/metadata_types.h | 7 +- 43 files changed, 666 insertions(+), 280 deletions(-) create mode 100644 adapter/adapter_factory/abstract_adapter.h create mode 100644 adapter/adapter_factory/adapter_factory.h rename adapter/{utils.h => adapter_utils.h} (90%) rename adapter/filesystem/{singleton.cc => metadata_manager_singleton.cc} (60%) rename adapter/filesystem/{singleton_macros.h => metadata_manager_singleton_macros.h} (76%) create mode 100644 adapter/mapper/abstract_mapper.h create mode 100644 adapter/mapper/balanced_mapper.cc create mode 100644 adapter/mapper/balanced_mapper.h create mode 100644 adapter/mapper/mapper_factory.h rename adapter/posix/{real_api.h => posix_api.h} (100%) rename adapter/posix/{singleton.cc => posix_singleton.cc} (87%) rename adapter/posix/{singleton_macros.h => posix_singleton_macros.h} (100%) delete mode 100644 code_generators/.idea/.gitignore delete mode 100644 code_generators/.idea/code_generators.iml delete mode 100644 code_generators/.idea/inspectionProfiles/Project_Default.xml delete mode 100644 code_generators/.idea/inspectionProfiles/profiles_settings.xml delete mode 100644 code_generators/.idea/misc.xml delete mode 100644 code_generators/.idea/modules.xml delete mode 100644 code_generators/.idea/vcs.xml diff --git a/adapter/adapter_factory/abstract_adapter.h b/adapter/adapter_factory/abstract_adapter.h new file mode 100644 index 000000000..8905ad97a --- /dev/null +++ b/adapter/adapter_factory/abstract_adapter.h @@ -0,0 +1,57 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// +// Created by manihariharan on 12/23/20. +// + +#ifndef HERMES_ABSTRACT_ADAPTER_H +#define HERMES_ABSTRACT_ADAPTER_H + +#include "utils.h" +#include "hermes_types.h" + +namespace hermes::adapter { + +/** Adapter types */ +enum class AdapterType { + kPosix, + kStdio, + kMpiio, + kPubsub, + kVfd +}; + +/** A class to represent abstract adapter */ +class AbstractAdapter { + public: + /**< */ + virtual void PutFallback(const Blob &blob, + size_t blob_off, + size_t backend_off, + size_t backend_size, + IoContext &io_ctx) = 0; + + virtual void GetFallback(Blob &blob, + size_t blob_off, + size_t backend_off, + size_t backend_size, + IoContext &io_ctx) = 0; + + virtual void LoadBlobFromBackend(size_t backend_off, + size_t backend_size, + IoContext &io_ctx) = 0; +}; + +} // namespace hermes::adapter + +#endif // HERMES_ABSTRACT_ADAPTER_H diff --git a/adapter/adapter_factory/adapter_factory.h b/adapter/adapter_factory/adapter_factory.h new file mode 100644 index 000000000..89e2305d8 --- /dev/null +++ b/adapter/adapter_factory/adapter_factory.h @@ -0,0 +1,56 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_ADAPTER_FACTORY_H +#define HERMES_ADAPTER_FACTORY_H + +#include "abstract_adapter.h" +#include "singleton.h" + +namespace hermes::adapter { +/** + A class to represent adapter factory pattern +*/ +class AdapterFactory { + public: + /** + * Return the instance of adapter given a type. Uses factory pattern. + * + * @param[in] type type of mapper to be used by the POSIX adapter. + * @return Instance of mapper given a type. + */ + std::unique_ptr Get(const AdapterType& type) { + switch (type) { + case AdapterType::kPosix: { + return HERMES_POSIX_FS; + } + case AdapterType::kStdio: { + return nullptr; + } + case AdapterType::kMpiio: { + return nullptr; + } + case AdapterType::kPubsub: { + return nullptr; + } + case AdapterType::kVfd: { + return nullptr; + } + default: { + // TODO(llogan): @error_handling Mapper not implemented + } + } + return NULL; + } +}; +} // namespace hermes::adapter +#endif // HERMES_ADAPTER_FACTORY_H diff --git a/adapter/utils.h b/adapter/adapter_utils.h similarity index 90% rename from adapter/utils.h rename to adapter/adapter_utils.h index 5ab017e47..c3dcc1865 100644 --- a/adapter/utils.h +++ b/adapter/adapter_utils.h @@ -5,10 +5,10 @@ #ifndef HERMES_ADAPTER_UTILS_H_ #define HERMES_ADAPTER_UTILS_H_ -#define HERMES_DECL - namespace hermes::adapter { +#define HERMES_DECL(F) F + bool IsTracked(int fd) { } diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index da12d1f60..9a6223f25 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -10,11 +10,13 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include "metadata_manager_singleton_macros.h" #include "filesystem.h" #include "constants.h" #include "singleton.h" #include "metadata_manager.h" #include "vbucket.h" +#include "mapper/mapper_factory.h" #include #include @@ -32,7 +34,7 @@ File Filesystem::Open(AdapterStat &stat, const std::string &path) { void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { _InitFile(f); - auto mdm = HERMES_FILESYSTEM_ADAPTER_METADTA_MANAGER; + auto mdm = HERMES_FS_METADATA_MANAGER; stat.bkt_id_ = HERMES->GetBucket(path); LOG(INFO) << "File not opened before by adapter" << std::endl; _OpenInitStats(f, stat); @@ -42,7 +44,7 @@ void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { void Filesystem::_PutWithFallback(AdapterStat &stat, const std::string &blob_name, const std::string &filename, - hapi::Blob blob, + const hapi::Blob &blob, size_t offset, IoStatus &io_status, IoOptions &opts) { hapi::Context ctx; @@ -52,7 +54,7 @@ void Filesystem::_PutWithFallback(AdapterStat &stat, if (opts.with_fallback_) { LOG(WARNING) << "Failed to Put Blob " << blob_name << " to Bucket " << filename << ". Falling back to posix I/O." << std::endl; - _RealWrite(filename, offset, size, data, io_status, opts); + _RealWrite(filename, offset, blob.size(), blob.data(), io_status, opts); } } } @@ -61,29 +63,27 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { (void) f; - std::shared_ptr &bkt = stat.st_bkid; + std::shared_ptr &bkt = stat.st_bkid_; std::string filename = bkt->GetName(); LOG(INFO) << "Write called for filename: " << filename << " on offset: " << off << " and size: " << total_size << std::endl; size_t ret; - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; BlobPlacements mapping; auto mapper = MapperFactory().Get(kMapperType); mapper->map(off, total_size, mapping); size_t data_offset = 0; for (const auto &p : mapping) { - BlobPlacementIter wi(f, stat, filename, p, bkt, io_status, opts); - wi.blob_name_ = wi.p_.CreateBlobName(); - wi.blob_exists_ = wi.bkt_->ContainsBlob(wi.blob_name_); + lipc::charbuf blob_name(p.CreateBlobName()); + wi.blob_start_ = p.page_ * kPageSize; wi.mem_ptr_ = (u8 *)ptr + data_offset; data_offset += p.blob_size_; } off_t f_offset = off + data_offset; - if (opts.seek_) { stat.st_ptr = f_offset; } - stat.st_size = std::max(stat.st_size, static_cast(f_offset)); + if (opts.seek_) { stat.st_ptr_ = f_offset; } struct timespec ts; timespec_get(&ts, TIME_UTC); @@ -98,7 +98,7 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, IoOptions opts) { - (void) io_status; + /*(void) io_status; LOG(INFO) << "Starting an asynchronous write" << std::endl; auto pool = Singleton::GetInstance(kNumThreads); @@ -111,15 +111,15 @@ HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, auto func = std::bind(lambda, this, f, stat, ptr, off, total_size, hreq->io_status, opts); hreq->return_future = pool->run(func); - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; mdm->request_map.emplace(req_id, hreq); - return hreq; + return hreq;*/ } HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, IoOptions opts) { - (void) io_status; + /*(void) io_status; auto pool = Singleton::GetInstance(kNumThreads); HermesRequest *hreq = new HermesRequest(); @@ -131,13 +131,13 @@ HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, auto func = std::bind(lambda, this, f, stat, ptr, off, total_size, hreq->io_status, opts); hreq->return_future = pool->run(func); - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; mdm->request_map.emplace(req_id, hreq); - return hreq; + return hreq;*/ } size_t Filesystem::Wait(uint64_t req_id) { - auto mdm = Singleton::GetInstance(); + /*auto mdm = HERMES_FS_METADATA_MANAGER; auto req_iter = mdm->request_map.find(req_id); if (req_iter == mdm->request_map.end()) { return 0; @@ -145,7 +145,7 @@ size_t Filesystem::Wait(uint64_t req_id) { HermesRequest *req = (*req_iter).second; size_t ret = req->return_future.get(); delete req; - return ret; + return ret;*/ } void Filesystem::Wait(std::vector &req_ids, @@ -163,7 +163,7 @@ off_t Filesystem::Seek(File &f, AdapterStat &stat, << std::endl; return -1; } - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; switch (whence) { case SeekMode::kSet: { stat.st_ptr_ = offset; @@ -174,7 +174,7 @@ off_t Filesystem::Seek(File &f, AdapterStat &stat, break; } case SeekMode::kEnd: { - stat.st_ptr_ = stat.st_size + offset; + stat.st_ptr_ = stat.st_bkt_-> + offset; break; } default: { @@ -239,7 +239,7 @@ HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, size_t total_size, IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); if (!exists) { stat_exists = false; @@ -252,7 +252,7 @@ size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, size_t total_size, IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); if (!exists) { stat_exists = false; @@ -265,7 +265,7 @@ size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); if (!exists) { stat_exists = false; @@ -279,7 +279,7 @@ size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); if (!exists) { stat_exists = false; @@ -293,7 +293,7 @@ size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, size_t total_size, size_t req_id, IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); if (!exists) { stat_exists = false; @@ -306,7 +306,7 @@ HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, size_t total_size, size_t req_id, IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); if (!exists) { stat_exists = false; @@ -319,7 +319,7 @@ HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); if (!exists) { stat_exists = false; @@ -333,7 +333,7 @@ HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, IoOptions opts) { - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); if (!exists) { stat_exists = false; @@ -346,7 +346,7 @@ HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, off_t Filesystem::Seek(File &f, bool &stat_exists, SeekMode whence, off_t offset) { - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); if (!exists) { stat_exists = false; @@ -357,7 +357,7 @@ off_t Filesystem::Seek(File &f, bool &stat_exists, } off_t Filesystem::Tell(File &f, bool &stat_exists) { - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); if (!exists) { stat_exists = false; @@ -368,7 +368,7 @@ off_t Filesystem::Tell(File &f, bool &stat_exists) { } int Filesystem::Sync(File &f, bool &stat_exists) { - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); if (!exists) { stat_exists = false; @@ -379,7 +379,7 @@ int Filesystem::Sync(File &f, bool &stat_exists) { } int Filesystem::Close(File &f, bool &stat_exists, bool destroy) { - auto mdm = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); if (!exists) { stat_exists = false; diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index 439f939cb..356fdb14d 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -24,6 +24,8 @@ #include #include +#include "metadata_manager_singleton_macros.h" + namespace hapi = hermes::api; namespace hermes::adapter::fs { @@ -45,13 +47,13 @@ struct AdapterStat { int flags_; /**< open() flags for POSIX */ mode_t st_mode_; /**< protection */ off64_t st_ptr_; /**< Current ptr of FILE */ - timespec st_atim_; /**< time of last access */ - timespec st_mtim_; /**< time of last modification */ - timespec st_ctim_; /**< time of last status change */ + timespec st_atime_; /**< time of last access */ + timespec st_mtime_; /**< time of last modification */ + timespec st_ctime_; /**< time of last status change */ std::string mode_str_; /**< mode used for fopen() */ bool is_append_; /**< File is in append mode */ - int amode_; /**< access mode */ + int amode_; /**< access mode (MPI) */ MPI_Info info_; /**< Info object (handle) */ MPI_Comm comm_; /**< Communicator for the file.*/ bool atomicity_; /**< Consistency semantics for data-access */ @@ -62,9 +64,9 @@ struct AdapterStat { flags_(0), st_mode_(), st_ptr_(0), - st_atim_(), - st_mtim_(), - st_ctim_(), + st_atime_(), + st_mtime_(), + st_ctime_(), is_append_(false), amode_(0), comm_(MPI_COMM_SELF), @@ -139,25 +141,24 @@ struct File { A structure to represent IO options */ struct IoOptions { - PlacementPolicy dpe_; /**< data placement policy */ - bool coordinate_; /**< use coordinate? */ + hapi::PlacementPolicy dpe_; /**< data placement policy */ bool seek_; /**< use seek? */ bool with_fallback_; /**< use fallback? */ MPI_Datatype mpi_type_; /**< MPI data type */ int count_; /**< option count */ + + /** Default constructor */ IoOptions() - : dpe_(PlacementPolicy::kNone), - coordinate_(true), + : dpe_(hapi::PlacementPolicy::kNone), seek_(true), with_fallback_(true), mpi_type_(MPI_CHAR), count_(0) {} /** return options with \a dpe parallel data placement engine */ - static IoOptions WithParallelDpe(PlacementPolicy dpe) { + static IoOptions WithParallelDpe(hapi::PlacementPolicy dpe) { IoOptions opts; opts.dpe_ = dpe; - opts.coordinate_ = true; return opts; } @@ -165,7 +166,7 @@ struct IoOptions { static IoOptions DirectIo(IoOptions &cur_opts) { IoOptions opts(cur_opts); opts.seek_ = false; - opts.dpe_ = PlacementPolicy::kNone; + opts.dpe_ = hapi::PlacementPolicy::kNone; opts.with_fallback_ = true; return opts; } @@ -210,42 +211,6 @@ struct HermesRequest { IoStatus io_status; /**< IO status */ }; -/** - A structure to represent BLOB placement iterator -*/ -struct BlobPlacementIter { - File &f_; /**< file */ - AdapterStat &stat_; /**< adapter stat */ - const std::string &filename_; /**< file name */ - const BlobPlacement &p_; /**< BLOB placement */ - std::shared_ptr &bkt_; /**< bucket*/ - IoStatus &io_status_; /**< IO status */ - IoOptions &opts_; /**< IO options */ - - std::string blob_name_; /**< BLOB name */ - u8 *mem_ptr_; /**< pointer to memory */ - size_t blob_start_; /**< BLOB start */ - hapi::Context ctx_; /**< context */ - hapi::Blob blob_; /**< BLOB */ - int rank_; /**< MPI rank */ - int nprocs_; /**< number of processes */ - bool blob_exists_; /**< Does BLOB exist? */ - - /** iterate \a p BLOB placement */ - explicit BlobPlacementIter(File &f, AdapterStat &stat, - const std::string &filename, - const BlobPlacement &p, - std::shared_ptr &bkt, - IoStatus &io_status, IoOptions &opts) - : f_(f), - stat_(stat), - filename_(filename), - p_(p), - bkt_(bkt), - io_status_(io_status), - opts_(opts) {} -}; - /** A class to represent file system */ @@ -284,59 +249,7 @@ class Filesystem { /** close */ int Close(File &f, AdapterStat &stat, bool destroy = true); - /* - * APIs used internally - * */ - private: - /** coordinated put */ - void _CoordinatedPut(BlobPlacementIter &wi); - /** uncoordinated put */ - void _UncoordinatedPut(BlobPlacementIter &wi); - /** write to a new aligned buffer */ - void _WriteToNewAligned(BlobPlacementIter &write_iter); - /** write to a new unaligned buffer */ - void _WriteToNewUnaligned(BlobPlacementIter &write_iter); - /** write to an existing aligned buffer */ - void _WriteToExistingAligned(BlobPlacementIter &write_iter); - /** write to an existing unaligned buffer */ - void _WriteToExistingUnaligned(BlobPlacementIter &write_iter); - /** put with fallback */ - void _PutWithFallback(AdapterStat &stat, const std::string &blob_name, - const std::string &filename, u8 *data, size_t size, - size_t offset, IoStatus &io_status_, IoOptions &opts); - /** read existing contained buffer */ - size_t _ReadExistingContained(BlobPlacementIter &read_iter); - /** read existing partial buffer */ - size_t _ReadExistingPartial(BlobPlacementIter &read_iter); - /** read new buffer */ - size_t _ReadNew(BlobPlacementIter &read_iter); - - void _OpenInitStatsInternal(AdapterStat &stat, bool bucket_exists) { - // TODO(llogan): This isn't really parallel-safe. - /** - * Here we assume that the file size can only be growing. - * If the bucket already exists and has content not already in - * the file (e.g., when using ADAPTER_MODE=SCRATCH), we should - * use the size of the bucket instead. - * - * There are other concerns with what happens during multi-tenancy. - * What happens if one process is opening a file, while another - * process is adding content? The mechanics here aren't - * well-defined. - * */ - if (bucket_exists) { - size_t orig = stat.st_size; - size_t bkt_size = stat.st_bkid->GetTotalBlobSize(); - stat.st_size = std::max(bkt_size, orig); - LOG(INFO) << "Since bucket exists, should reset its size to: " - << bkt_size << " or " << orig - << ", winner: " << stat.st_size << std::endl; - } - if (stat.is_append) { - stat.st_ptr = stat.st_size; - } - } /* * The APIs to overload @@ -437,9 +350,7 @@ class Filesystem { } // namespace hermes::adapter::fs namespace std { -/** - A structure to represent hash -*/ +/** A structure to represent hash */ template <> struct hash { /** hash creator functor */ diff --git a/adapter/filesystem/singleton.cc b/adapter/filesystem/metadata_manager_singleton.cc similarity index 60% rename from adapter/filesystem/singleton.cc rename to adapter/filesystem/metadata_manager_singleton.cc index b12c6bf23..871b3ed22 100644 --- a/adapter/filesystem/singleton.cc +++ b/adapter/filesystem/metadata_manager_singleton.cc @@ -1,4 +1,4 @@ #include "singleton.h" #include "filesystem.h" -template<> std::unique_ptr hermes::Singleton::obj_ = nullptr; +template<> std::unique_ptr hermes::Singleton::obj_ = nullptr; diff --git a/adapter/filesystem/singleton_macros.h b/adapter/filesystem/metadata_manager_singleton_macros.h similarity index 76% rename from adapter/filesystem/singleton_macros.h rename to adapter/filesystem/metadata_manager_singleton_macros.h index e868fdaa1..3571b97c9 100644 --- a/adapter/filesystem/singleton_macros.h +++ b/adapter/filesystem/metadata_manager_singleton_macros.h @@ -4,6 +4,6 @@ #include "singleton.h" #define HERMES_FS_METADATA_MANAGER hermes::Singleton::GetInstance() -#define HERMES_FS_METADATA_MANAGER_T hermes::adapter::posix::fs::MetadataManager* +#define HERMES_FS_METADATA_MANAGER_T hermes::adapter::fs::MetadataManager* #endif // HERMES_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/mapper/abstract_mapper.h b/adapter/mapper/abstract_mapper.h new file mode 100644 index 000000000..43cd43b40 --- /dev/null +++ b/adapter/mapper/abstract_mapper.h @@ -0,0 +1,74 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// +// Created by manihariharan on 12/23/20. +// + +#ifndef HERMES_ABSTRACT_ADAPTER_H +#define HERMES_ABSTRACT_ADAPTER_H + +#include "utils.h" + +namespace hermes::adapter { + +/** + * Define different types of mappers supported by POSIX Adapter. + * Also define its construction in the MapperFactory. + */ +enum MapperType { + BALANCED = 0 /* Balanced Mapping */ +}; + +/** + A structure to represent BLOB placement +*/ +struct BlobPlacement { + size_t page_; /**< The index in the array placements */ + size_t bucket_off_; /**< Offset from file start (for FS) */ + size_t blob_off_; /**< Offset from BLOB start */ + size_t blob_size_; /**< Size after offset to read */ + int time_; /**< The order of the blob in a list of blobs */ + + /** create a BLOB name from index. */ + lipc::charbuf CreateBlobName() const { + lipc::charbuf buf(sizeof(page_)); + memcpy(buf.data_mutable(), &page_, sizeof(page_)); + return buf; + } + + /** decode \a blob_name BLOB name to index. */ + void DecodeBlobName(const lipc::charbuf &blob_name) { + memcpy(&page_, blob_name.data(), sizeof(page_)); + } +}; + +typedef std::vector BlobPlacements; + +/** + A class to represent abstract mapper +*/ +class AbstractMapper { + public: + /** + * This method maps the current operation to Hermes data structures. + * + * @param off offset + * @param size size + * @param ps BLOB placement + * + */ + virtual void map(size_t off, size_t size, BlobPlacements &ps) = 0; +}; +} // namespace hermes::adapter + +#endif // HERMES_ABSTRACT_ADAPTER_H diff --git a/adapter/mapper/balanced_mapper.cc b/adapter/mapper/balanced_mapper.cc new file mode 100644 index 000000000..0e0041639 --- /dev/null +++ b/adapter/mapper/balanced_mapper.cc @@ -0,0 +1,43 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "balanced_mapper.h" +#include "constants.h" +#include "api/hermes.h" + +namespace hermes::adapter { + + /** + * Convert a range defined by \a off and \a size into specific + * blob placements. + */ + void BalancedMapper::map(size_t off, size_t size, BlobPlacements &ps) { + VLOG(1) << "Mapping File with offset:" << off << " and size:" << size << "." + << std::endl; + + size_t kPageSize = HERMES->client_config_.file_page_size_; + size_t size_mapped = 0; + while (size > size_mapped) { + BlobPlacement p; + p.bucket_off_ = off + size_mapped; + p.page_ = p.bucket_off_ / kPageSize; + p.blob_off_ = p.bucket_off_ % kPageSize; + auto left_size_page = kPageSize - p.blob_off_; + p.blob_size_ = left_size_page < size - size_mapped ? left_size_page + : size - size_mapped; + ps.emplace_back(p); + size_mapped += p.blob_size_; + } + } + + +} // namespace hermes::adapter diff --git a/adapter/mapper/balanced_mapper.h b/adapter/mapper/balanced_mapper.h new file mode 100644 index 000000000..343efc50c --- /dev/null +++ b/adapter/mapper/balanced_mapper.h @@ -0,0 +1,34 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_BALANCED_MAPPER_H +#define HERMES_BALANCED_MAPPER_H + +#include + +#include "abstract_mapper.h" + +namespace hermes::adapter { +/** + * Implement balanced mapping + */ +class BalancedMapper : public AbstractMapper { + public: + /** + * This method maps the current Operation to Hermes data structures. + * + */ + void map(size_t off, size_t size, BlobPlacements &ps) override; +}; +} // namespace hermes::adapter + +#endif // HERMES_BALANCED_MAPPER_H diff --git a/adapter/mapper/mapper_factory.h b/adapter/mapper/mapper_factory.h new file mode 100644 index 000000000..ca8d8d88d --- /dev/null +++ b/adapter/mapper/mapper_factory.h @@ -0,0 +1,46 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_ADAPTER_FACTORY_H +#define HERMES_ADAPTER_FACTORY_H + +#include "abstract_mapper.h" +#include "balanced_mapper.cc" +#include "balanced_mapper.h" +#include "singleton.h" + +namespace hermes::adapter { +/** + A class to represent mapper factory pattern +*/ +class MapperFactory { + public: + /** + * Return the instance of mapper given a type. Uses factory pattern. + * + * @param[in] type type of mapper to be used by the POSIX adapter. + * @return Instance of mapper given a type. + */ + AbstractMapper* Get(const MapperType& type) { + switch (type) { + case MapperType::BALANCED: { + return hermes::Singleton::GetInstance(); + } + default: { + // TODO(llogan): @error_handling Mapper not implemented + } + } + return NULL; + } +}; +} // namespace hermes::adapter +#endif // HERMES_ADAPTER_FACTORY_H diff --git a/adapter/posix/CMakeLists.txt b/adapter/posix/CMakeLists.txt index dd71ff5fb..7b8e0573b 100644 --- a/adapter/posix/CMakeLists.txt +++ b/adapter/posix/CMakeLists.txt @@ -3,16 +3,23 @@ include_directories( ${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) -# Create the hermes_posix_singleton -add_library(hermes_posix_singleton SHARED ${CMAKE_CURRENT_SOURCE_DIR}/singleton.cc) +# Create the POSIX Real API singleton +add_library(hermes_posix_singleton SHARED ${CMAKE_CURRENT_SOURCE_DIR}/posix_singleton.cc) target_compile_options(hermes_posix_singleton PUBLIC -fPIC) +# Create the POSIX interceptor +add_library(hermes_posix SHARED ${CMAKE_CURRENT_SOURCE_DIR}/posix.cc) +add_dependencies(hermes_posix hermes hermes_posix_singleton) +target_link_libraries(hermes_posix hermes hermes_posix_singleton) +target_compile_options(hermes_posix PUBLIC -fPIC) + #----------------------------------------------------------------------------- # Add Target(s) to CMake Install #----------------------------------------------------------------------------- install( TARGETS hermes_posix_singleton + hermes_posix EXPORT ${HERMES_EXPORTED_TARGETS} LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} diff --git a/adapter/posix/posix.cc b/adapter/posix/posix.cc index 037fbbfe2..7cc69ed5d 100644 --- a/adapter/posix/posix.cc +++ b/adapter/posix/posix.cc @@ -19,11 +19,17 @@ bool posix_intercepted = true; #include #include +#include "hermes_types.h" #include "singleton.h" -#include "utils.h" -#include "posix/real_api.h" +#include "adapter_utils.h" +#include "posix_api.h" +#include "posix_singleton_macros.h" +#include "filesystem/filesystem.h" using hermes::Singleton; +using hermes::adapter::fs::AdapterStat; +using hermes::adapter::fs::IoStatus; +using hermes::adapter::fs::File; namespace hapi = hermes::api; namespace stdfs = std::experimental::filesystem; @@ -47,8 +53,8 @@ int HERMES_DECL(open)(const char *path, int flags, ...) { LOG(INFO) << "Intercept open for filename: " << path << " and mode: " << flags << " is tracked." << std::endl; AdapterStat stat; - stat.flags = flags; - stat.st_mode = mode; + stat.flags_ = flags; + stat.st_mode_ = mode; return fs_api->Open(stat, path).fd_; } if (flags & O_CREAT || flags & O_TMPFILE) { @@ -71,8 +77,8 @@ int HERMES_DECL(open64)(const char *path, int flags, ...) { LOG(INFO) << "Intercept open64 for filename: " << path << " and mode: " << flags << " is tracked." << std::endl; AdapterStat stat; - stat.flags = flags; - stat.st_mode = mode; + stat.flags_ = flags; + stat.st_mode_ = mode; return fs_api->Open(stat, path).fd_; } if (flags & O_CREAT) { @@ -88,8 +94,8 @@ int HERMES_DECL(__open_2)(const char *path, int oflag) { LOG(INFO) << "Intercept __open_2 for filename: " << path << " and mode: " << oflag << " is tracked." << std::endl; AdapterStat stat; - stat.flags = oflag; - stat.st_mode = 0; + stat.flags_ = oflag; + stat.st_mode_ = 0; return fs_api->Open(stat, path).fd_; } return real_api->__open_2(path, oflag); @@ -103,8 +109,8 @@ int HERMES_DECL(creat)(const char *path, mode_t mode) { LOG(INFO) << "Intercept creat for filename: " << path << " and mode: " << mode << " is tracked." << std::endl; AdapterStat stat; - stat.flags = O_CREAT; - stat.st_mode = mode; + stat.flags_ = O_CREAT; + stat.st_mode_ = mode; return fs_api->Open(stat, path).fd_; } return real_api->creat(path, mode); @@ -118,8 +124,8 @@ int HERMES_DECL(creat64)(const char *path, mode_t mode) { LOG(INFO) << "Intercept creat64 for filename: " << path << " and mode: " << mode << " is tracked." << std::endl; AdapterStat stat; - stat.flags = O_CREAT; - stat.st_mode = mode; + stat.flags_ = O_CREAT; + stat.st_mode_ = mode; return fs_api->Open(stat, path).fd_; } return real_api->creat64(path, mode); @@ -240,7 +246,7 @@ int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { if (hermes::adapter::IsTracked(fd)) { File f; f.fd_ = fd; fs_api->_InitFile(f); LOG(INFO) << "Intercepted fstat." << std::endl; - auto mdm = hermes::Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; auto existing = mdm->Find(f); if (existing.second) { AdapterStat &astat = existing.first; @@ -248,17 +254,17 @@ int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { // currently we get them by calling the real fstat on open. buf->st_dev = 0; buf->st_ino = 0; - buf->st_mode = astat.st_mode; + buf->st_mode = astat.st_mode_; buf->st_nlink = 0; - buf->st_uid = astat.st_uid; - buf->st_gid = astat.st_gid; + buf->st_uid = astat.st_uid_; + buf->st_gid = astat.st_gid_; buf->st_rdev = 0; - buf->st_size = astat.st_size; - buf->st_blksize = astat.st_blksize; + buf->st_size = astat.st_size_; + buf->st_blksize = astat.st_blksize_; buf->st_blocks = 0; - buf->st_atime = astat.st_atime; - buf->st_mtime = astat.st_mtime; - buf->st_ctime = astat.st_ctime; + buf->st_atime = astat.st_atime_; + buf->st_mtime = astat.st_mtime_; + buf->st_ctime = astat.st_ctime_; } else { result = -1; errno = EBADF; diff --git a/adapter/posix/real_api.h b/adapter/posix/posix_api.h similarity index 100% rename from adapter/posix/real_api.h rename to adapter/posix/posix_api.h diff --git a/adapter/posix/singleton.cc b/adapter/posix/posix_singleton.cc similarity index 87% rename from adapter/posix/singleton.cc rename to adapter/posix/posix_singleton.cc index a90232844..6daba4137 100644 --- a/adapter/posix/singleton.cc +++ b/adapter/posix/posix_singleton.cc @@ -1,4 +1,4 @@ #include "singleton.h" -#include "real_api.h" +#include "posix_api.h" template<> std::unique_ptr hermes::Singleton::obj_ = nullptr; diff --git a/adapter/posix/singleton_macros.h b/adapter/posix/posix_singleton_macros.h similarity index 100% rename from adapter/posix/singleton_macros.h rename to adapter/posix/posix_singleton_macros.h diff --git a/code_generators/.idea/.gitignore b/code_generators/.idea/.gitignore deleted file mode 100644 index 26d33521a..000000000 --- a/code_generators/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/code_generators/.idea/code_generators.iml b/code_generators/.idea/code_generators.iml deleted file mode 100644 index 8b8c39547..000000000 --- a/code_generators/.idea/code_generators.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/code_generators/.idea/inspectionProfiles/Project_Default.xml b/code_generators/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 7c745c6a7..000000000 --- a/code_generators/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - \ No newline at end of file diff --git a/code_generators/.idea/inspectionProfiles/profiles_settings.xml b/code_generators/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2da2..000000000 --- a/code_generators/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/code_generators/.idea/misc.xml b/code_generators/.idea/misc.xml deleted file mode 100644 index d1e22ecb8..000000000 --- a/code_generators/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/code_generators/.idea/modules.xml b/code_generators/.idea/modules.xml deleted file mode 100644 index 7ff40af9a..000000000 --- a/code_generators/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/code_generators/.idea/vcs.xml b/code_generators/.idea/vcs.xml deleted file mode 100644 index 6c0b86358..000000000 --- a/code_generators/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/config/hermes_client_default.yaml b/config/hermes_client_default.yaml index 61f5a6146..b8b208194 100644 --- a/config/hermes_client_default.yaml +++ b/config/hermes_client_default.yaml @@ -1,2 +1,2 @@ stop_daemon: true -file_page_size_kb: 1024 \ No newline at end of file +file_page_size: 1024KB \ No newline at end of file diff --git a/src/api/bucket.cc b/src/api/bucket.cc index c4e95f02b..a3b3ca6d2 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -52,7 +52,7 @@ Status Bucket::GetBlobId(std::string blob_name, /** * Put \a blob_id Blob into the bucket * */ -Status Bucket::Put(std::string blob_name, const Blob &blob, +Status Bucket::Put(std::string blob_name, ConstBlobData blob, BlobId &blob_id, Context &ctx) { // Calculate placement auto dpe = DPEFactory::Get(ctx.policy); @@ -74,9 +74,8 @@ Status Bucket::Put(std::string blob_name, const Blob &blob, /** * Get \a blob_id Blob from the bucket * */ -Status Bucket::Get(BlobId blob_id, Blob &blob, Context &ctx) { - blob = mdm_->LocalBucketGetBlob(blob_id); - return Status(); +Blob Bucket::Get(BlobId blob_id, Context &ctx) { + return mdm_->LocalBucketGetBlob(blob_id);; } /** diff --git a/src/api/bucket.h b/src/api/bucket.h index 41bcb2612..5f60d940a 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -20,7 +20,7 @@ class Bucket { Context ctx_; /////////////////////////// - ////// Bucket Operations + /// Bucket Operations ////////////////////////// public: @@ -48,6 +48,21 @@ class Bucket { return id_; } + /** + * Set the size of bucket on storage + * */ + void SetBackendSize(); + + /** + * Get the size of the data on storage + * */ + void GetBackendSize(); + + /** + * Get the current size of the bucket + * */ + size_t GetSize(); + /** * Rename this bucket * */ @@ -67,7 +82,7 @@ class Bucket { /////////////////////// - ////// Blob Operations + /// Blob Operations /////////////////////// public: @@ -82,18 +97,56 @@ class Bucket { Status GetBlobId(std::string blob_name, BlobId &blob_id, Context &ctx); /** - * Put \a blob_id Blob into the bucket + * Put \a blob_name Blob into the bucket * */ - Status Put(std::string blob_name, const Blob &blob, - BlobId &blob_id, Context &ctx); + Status Put(std::string blob_name, + ConstBlobData blob, + BlobId &blob_id, + Context &ctx); + + /** + * Put \a blob_name Blob into the bucket. Load the blob from the + * I/O backend if it does not exist. + * + * @param blob_name the semantic name of the blob + * @param blob the buffer to put final data in + * @param backend_off the offset to read from the backend if blob DNE + * @param backend_size the size to read from the backend if blob DNE + * @param backend_ctx which adapter to route I/O request if blob DNE + * @param ctx any additional information + * */ + Status PartialPutOrCreate(std::string blob_name, + ConstBlobData blob, + size_t backend_off, + size_t backend_size, + IoContext &backend_ctx, + BlobId &blob_id, + Context &ctx); /** * Get \a blob_id Blob from the bucket - * @WRAP_DEFAULT: ctx -> ctx_ - * @WRAP_PROTO: blob_id -> std::string blob_name - * @WRAP_DEFAULT: blob_id -> GetBlobId(blob_name) * */ - Status Get(BlobId blob_id, Blob &blob, Context &ctx); + Status Get(BlobId blob_id, + Blob &blob, + Context &ctx); + + /** + * Partially (or fully) Get a blob from a bucket. Load the blob from the + * I/O backend if it does not exist. + * + * @param blob_name the semantic name of the blob + * @param blob the buffer to put final data in + * @param backend_off the offset to read from the backend if blob DNE + * @param backend_size the size to read from the backend if blob DNE + * @param backend_ctx which adapter to route I/O request if blob DNE + * @param ctx any additional information + * */ + Status PartialGetOrCreate(std::string blob_name, + MutableBlobData blob, + size_t backend_off, + size_t backend_size, + IoContext &backend_ctx, + Context &ctx); /** * Rename \a blob_id blob to \a new_blob_name new name @@ -104,10 +157,6 @@ class Bucket { * Delete \a blob_id blob * */ void DestroyBlob(BlobId blob_id, Context &ctx); - - public: - RPC_AUTOGEN_START - RPC_AUTOGEN_END }; } diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index acb8c0422..e4ca24eda 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -9,14 +9,6 @@ namespace hermes { -static size_t SumBufferBlobSizes(lipc::vector &buffers) { - size_t sum = 0; - for (lipc::ShmRef buffer_ref : buffers) { - sum += (*buffer_ref).blob_size_; - } - return sum; -} - /** * Initialize the BORG * REQUIRES mdm to be initialized already. @@ -50,7 +42,7 @@ void BufferOrganizer::shm_deserialize() { /** Stores a blob into a set of buffers */ RPC void BufferOrganizer::LocalPlaceBlobInBuffers( - const Blob &blob, lipc::vector &buffers) { + ConstBlobData &blob, lipc::vector &buffers) { size_t blob_off = 0; for (lipc::ShmRef buffer_info : buffers) { if (buffer_info->tid_.GetNodeId() != mdm_->rpc_->node_id_) { @@ -59,7 +51,8 @@ RPC void BufferOrganizer::LocalPlaceBlobInBuffers( lipc::ShmRef dev_info = (*mdm_->devices_)[buffer_info->tid_.GetDeviceId()]; auto io_client = IoClientFactory::Get(dev_info->header_->io_api_); - bool ret = io_client->Write(*dev_info, blob.data() + blob_off, + bool ret = io_client->Write(*dev_info, + blob.data() + blob_off, buffer_info->t_off_, buffer_info->blob_size_); blob_off += buffer_info->blob_size_; diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index 6c60cde96..15e2a7bf4 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -11,6 +11,15 @@ namespace hermes { +/** Calculates the total size of a blob's buffers */ +static inline size_t SumBufferBlobSizes(lipc::vector &buffers) { + size_t sum = 0; + for (lipc::ShmRef buffer_ref : buffers) { + sum += (*buffer_ref).blob_size_; + } + return sum; +} + /** * Manages the organization of blobs in the hierarchy. * */ @@ -37,7 +46,7 @@ class BufferOrganizer { void shm_deserialize(); /** Stores a blob into a set of buffers */ - RPC void LocalPlaceBlobInBuffers(const Blob &blob, + RPC void LocalPlaceBlobInBuffers(ConstBlobData &blob, lipc::vector &buffers); /** Stores a blob into a set of buffers */ diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 65e769397..e0090df47 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -46,7 +46,7 @@ void BufferPool::shm_deserialize(BufferPoolShmHeader *header) { * */ lipc::vector BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, - const Blob &blob) { + ConstBlobData &blob) { lipc::vector buffers(HERMES->main_alloc_); size_t blob_off_ = 0; for (auto plcmnt : schema.plcmnts_) { diff --git a/src/buffer_pool.h b/src/buffer_pool.h index debe55cb2..14cb0a606 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -68,7 +68,8 @@ class BufferPool { * Allocate buffers from the targets according to the schema * */ RPC lipc::vector - LocalAllocateAndSetBuffers(PlacementSchema &schema, const Blob &blob); + LocalAllocateAndSetBuffers(PlacementSchema &schema, + ConstBlobData &blob); /** * Free buffers from the BufferPool diff --git a/src/config.h b/src/config.h index 989ce5e95..67ff277ca 100644 --- a/src/config.h +++ b/src/config.h @@ -127,6 +127,7 @@ static void ParseRangeList(YAML::Node list_node, std::string var, } } +/** parse the suffix of \a num_text NUMBER text */ static std::string ParseNumberSuffix(const std::string &num_text) { int i; for (i = 0; i < num_text.size(); ++i) { @@ -138,13 +139,14 @@ static std::string ParseNumberSuffix(const std::string &num_text) { return std::string(num_text.begin() + i, num_text.end());; } +/** parse the number of \a num_text NUMBER text */ static size_t ParseNumber(const std::string &num_text) { size_t size; std::stringstream(num_text) >> size; return size; } -/** Returns size (bytes) */ +/** Converts \a size_text SIZE text into a size_t */ static size_t ParseSize(const std::string &size_text) { size_t size = ParseNumber(size_text); if (size_text == "inf") { diff --git a/src/config_client.cc b/src/config_client.cc index 6e15b44ff..911adb7be 100644 --- a/src/config_client.cc +++ b/src/config_client.cc @@ -12,6 +12,10 @@ void ClientConfig::ParseYAML(YAML::Node &yaml_conf) { if (yaml_conf["stop_daemon"]) { stop_daemon_ = yaml_conf["stop_daemon"].as(); } + if (yaml_conf["file_page_size"]) { + file_page_size_ = ParseSize( + yaml_conf["file_page_size"].as()); + } } /** Load the default configuration */ diff --git a/src/config_client.h b/src/config_client.h index ef7288bbc..24cf1b9a6 100644 --- a/src/config_client.h +++ b/src/config_client.h @@ -15,6 +15,7 @@ namespace hermes::config { class ClientConfig : public BaseConfig { public: bool stop_daemon_; + size_t file_page_size_; public: ClientConfig() = default; diff --git a/src/config_client_default.h b/src/config_client_default.h index d339335ba..25b2ad580 100644 --- a/src/config_client_default.h +++ b/src/config_client_default.h @@ -2,5 +2,5 @@ #define HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ const char* kClientDefaultConfigStr = "stop_daemon: true\n" -"file_page_size_kb: 1024\n"; +"file_page_size: 1024KB\n"; #endif // HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ \ No newline at end of file diff --git a/src/config_server_default.h b/src/config_server_default.h index 1e054a364..837f7265f 100644 --- a/src/config_server_default.h +++ b/src/config_server_default.h @@ -15,7 +15,7 @@ const char* kServerDefaultConfigStr = "\n" " # The maximum buffering capacity in MiB of each device. Here we say that all 4\n" " # devices get 50 MiB of buffering capacity.\n" -" capacity: 50MB\n" +" capacity: 5000MB\n" "\n" " # The size of the smallest available buffer in KiB. In general this should be\n" " # the page size of your system for byte addressable storage, and the block size\n" diff --git a/src/hermes_types.cc b/src/hermes_types.cc index 1a81c7243..2b7ebccbd 100644 --- a/src/hermes_types.cc +++ b/src/hermes_types.cc @@ -7,6 +7,11 @@ namespace hermes::api { +//////////////////////////// +/// Context Operations +//////////////////////////// + +/** Default constructor */ Context::Context() : policy(HERMES->server_config_.dpe_.default_policy_), rr_split(HERMES->server_config_.dpe_.default_rr_split_), @@ -14,4 +19,85 @@ Context::Context() disable_swap(false), vbkt_id_({0, 0}) {} +//////////////////////////// +/// Blob Operations +//////////////////////////// + +/** Size-based constructor */ +Blob::Blob(size_t size) { + Allocate(HERMES->main_alloc_, size); +} + +/** Construct from std::string */ +Blob::Blob(const std::string &data) { + Allocate(HERMES->main_alloc_, data.size()); + memcpy(data_, data.data(), data.size()); +} + +/** Copy constructor */ +Blob::Blob(const Blob &other) { + if (!Allocate(HERMES->main_alloc_, other.size())) { + return; + } + memcpy(data_, other.data(), size()); +} + +/** Copy assignment operator */ +Blob& Blob::operator=(const Blob &other) { + if (this != &other) { + Free(); + if (!Allocate(HERMES->main_alloc_, other.size())) { + return *this; + } + memcpy(data_, other.data(), size()); + } + return *this; +} + +/** Move constructor */ +Blob::Blob(Blob &&other) { + alloc_ = other.alloc_; + data_ = other.data_; + size_ = other.size_; + destructable_ = other.destructable_; + other.destructable_ = false; +} + +/** Move assignment operator */ +Blob& Blob::operator=(Blob &other) { + if (this != &other) { + Free(); + alloc_ = other.alloc_; + data_ = other.data_; + size_ = other.size_; + destructable_ = other.destructable_; + other.destructable_ = false; + } + return *this; +} + +/** Allocate the blob */ +bool Blob::Allocate(lipc::Allocator *alloc, size_t size) { + lipc::OffsetPointer p; + if (size == 0) { + alloc_ = nullptr; + data_ = nullptr; + size_ = 0; + destructable_ = false; + return false; + } + alloc_ = alloc; + data_ = alloc->AllocatePtr(size, p); + size_ = size; + destructable_ = true; + return true; +} + +/** Deallocate this blob */ +void Blob::Free() { + if (destructable_ && data_ && size_) { + alloc_->FreePtr(data_); + } +} + } // namespace hermes::api \ No newline at end of file diff --git a/src/hermes_types.h b/src/hermes_types.h index 9cc98191d..8ebec6d3d 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -208,8 +208,62 @@ namespace hermes::api { /** * A Blob is simply an uninterpreted vector of bytes. */ -typedef lipc::charbuf Blob; +struct Blob { + lipc::Allocator *alloc_; /**< The allocator used to allocate data */ + char *data_; /**< The pointer to data */ + size_t size_; /**< The size of data */ + bool destructable_; /**< Whether or not this container owns data */ + /** Default constructor */ + Blob() : alloc_(nullptr), data_(nullptr), size_(0), destructable_(false) {} + + /** Destructor */ + ~Blob() { Free(); } + + /** Size-based constructor */ + explicit Blob(size_t size); + + /** String-based constructor */ + explicit Blob(const std::string &data); + + /** Pointer-based constructor */ + explicit Blob(char *data, size_t size) + : alloc_(nullptr), data_(data), size_(size), destructable_(false) {} + + /** Copy constructor */ + Blob(const Blob &other); + + /** Copy assignment operator */ + Blob& operator=(const Blob &other); + + /** Move constructor */ + Blob(Blob &&other); + + /** Move assignment operator */ + Blob& operator=(Blob &other); + + /** Reference data */ + char* data() { + return data_; + } + + /** Reference data */ + char* data() const { + return data_; + } + + /** Reference size */ + size_t size() const { + return size_; + } + + private: + /** Allocate blob */ + bool Allocate(lipc::Allocator *alloc, size_t size); + + /** Explicitly free the blob */ + void Free(); +}; /** Supported data placement policies */ enum class PlacementPolicy { @@ -219,9 +273,7 @@ enum class PlacementPolicy { kNone, /**< No DPE for cases we want it disabled */ }; -/** - A class to convert placement policy enum value to string -*/ +/** A class to convert placement policy enum value to string */ class PlacementPolicyConv { public: /** A function to return string representation of \a policy */ @@ -326,6 +378,19 @@ enum class TraitType : u8 { } // namespace hermes::api +namespace hermes { + +/** Namespace simplification for Blob */ +using api::Blob; + +/** Namespace simplification for MutableBlobData */ +using api::MutableBlobData; + +/** Namespace simplification for ConstBlobData */ +using api::ConstBlobData; + +} // namespace hermes + /** * HASH FUNCTIONS diff --git a/src/io_clients/io_client.h b/src/io_clients/io_client.h index 10da02aa5..79f900e3a 100644 --- a/src/io_clients/io_client.h +++ b/src/io_clients/io_client.h @@ -13,10 +13,10 @@ namespace hermes { class IoClient { public: virtual bool Init(DeviceInfo &dev_info) = 0; - virtual bool Write(DeviceInfo &dev_info, void *data, - size_t off, size_t size) = 0; - virtual bool Read(DeviceInfo &dev_info, void *data, - size_t off, size_t size) = 0; + virtual bool Write(DeviceInfo &dev_info, + const char *data, size_t off, size_t size) = 0; + virtual bool Read(DeviceInfo &dev_info, + char *data, size_t off, size_t size) = 0; }; } // namespace hermes diff --git a/src/io_clients/posix.h b/src/io_clients/posix.h index 929bd0994..06a97f729 100644 --- a/src/io_clients/posix.h +++ b/src/io_clients/posix.h @@ -6,8 +6,8 @@ #define HERMES_SRC_IO_CLIENTS_POSIX_H_ #include "io_client.h" -#include "adapter/posix/real_api.h" -#include "adapter/posix/singleton_macros.h" +#include "adapter/posix/posix_api.h" +#include "adapter/posix/posix_singleton_macros.h" #include @@ -29,7 +29,7 @@ class PosixIoClient : public IoClient { return true; } - bool Write(DeviceInfo &dev_info, void *data, + bool Write(DeviceInfo &dev_info, const char *data, size_t off, size_t size) override { auto api = HERMES_POSIX_API; int fd = api->open((*dev_info.mount_point_).c_str(), O_RDWR); @@ -43,7 +43,7 @@ class PosixIoClient : public IoClient { return count == size; } - bool Read(DeviceInfo &dev_info, void *data, + bool Read(DeviceInfo &dev_info, char *data, size_t off, size_t size) override { auto api = HERMES_POSIX_API; int fd = api->open((*dev_info.mount_point_).c_str(), O_RDWR); diff --git a/src/io_clients/ram.h b/src/io_clients/ram.h index 8ecb470a8..c1aa7cee2 100644 --- a/src/io_clients/ram.h +++ b/src/io_clients/ram.h @@ -6,8 +6,8 @@ #define HERMES_SRC_IO_CLIENTS_RAM_H_ #include "io_client.h" -#include "adapter/posix/real_api.h" -#include "adapter/posix/singleton_macros.h" +#include "adapter/posix/posix_api.h" +#include "adapter/posix/posix_singleton_macros.h" #include "hermes.h" namespace hermes { @@ -26,7 +26,7 @@ class RamIoClient : public IoClient { return true; } - bool Write(DeviceInfo &dev_info, void *data, + bool Write(DeviceInfo &dev_info, const char *data, size_t off, size_t size) override { auto &hermes_header = HERMES->header_; auto &main_alloc = HERMES->main_alloc_; @@ -35,7 +35,7 @@ class RamIoClient : public IoClient { return true; } - bool Read(DeviceInfo &dev_info, void *data, + bool Read(DeviceInfo &dev_info, char *data, size_t off, size_t size) override { auto &hermes_header = HERMES->header_; auto &main_alloc = HERMES->main_alloc_; diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 43f54b4b9..40333f569 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -202,7 +202,7 @@ bool MetadataManager::LocalDestroyBucket(BucketId bkt_id) { * */ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, const lipc::charbuf &blob_name, - const Blob &data, + ConstBlobData &data, lipc::vector &buffers) { lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); @@ -238,7 +238,7 @@ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { lipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; lipc::vector &buffers = *blob_info.buffers_; - return borg_->LocalReadBlobFromBuffers(buffers); + return borg_->LocalReadBlobFromBuffers(buffers);; } /** diff --git a/src/metadata_manager.h b/src/metadata_manager.h index dbbeebbd4..6b248cb14 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -170,7 +170,7 @@ class MetadataManager { * */ RPC BlobId LocalBucketPutBlob(BucketId bkt_id, const lipc::charbuf &blob_name, - const Blob &data, + ConstBlobData &data, lipc::vector &buffers); /** diff --git a/src/metadata_types.h b/src/metadata_types.h index e4d7eba6f..4afd92ed2 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -185,8 +185,9 @@ struct BlobInfo : public lipc::ShmContainer { shm_init_header(header); (*header_) = (*other.header_); bkt_id_ = other.bkt_id_; - (name_) = std::move(other.name_); - (buffers_) = std::move(other.buffers_); + (*name_) = std::move(*other.name_); + (*buffers_) = std::move(*other.buffers_); + shm_serialize_main(); } /** Deep copy data into another BlobInfo */ @@ -199,6 +200,7 @@ struct BlobInfo : public lipc::ShmContainer { bkt_id_ = other.bkt_id_; (*name_) = (*other.name_); (*buffers_) = (*other.buffers_); + shm_serialize_main(); } }; @@ -207,6 +209,7 @@ template<> struct ShmHeader : public lipc::ShmBaseHeader { lipc::TypedPointer name_ar_; size_t num_blobs_; + size_t true_size_; }; /** Metadata for a Bucket */ From a38bbc36847b8ce8bcce937d1f82454f980c4f85 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 1 Feb 2023 00:38:50 -0600 Subject: [PATCH 092/511] Restructure I/O clients to reduce duplication --- CMakeLists.txt | 2 +- adapter/CMakeLists.txt | 2 + adapter/adapter_factory/abstract_adapter.h | 57 ------- adapter/adapter_utils.h | 2 + adapter/filesystem/CMakeLists.txt | 41 +++++ adapter/filesystem/filesystem.cc | 68 ++++---- adapter/filesystem/filesystem.h | 151 ++++------------- adapter/filesystem/filesystem_io_client.h | 37 +++++ ...data_manager.cc => fs_metadata_manager.cc} | 18 +- ...tadata_manager.h => fs_metadata_manager.h} | 20 +-- ...on.cc => fs_metadata_manager_singleton.cc} | 2 +- ...=> fs_metadata_manager_singleton_macros.h} | 0 adapter/io_client/CMakeLists.txt | 37 +++++ adapter/io_client/empty.cc | 3 + adapter/io_client/io_client.h | 155 ++++++++++++++++++ .../io_client_factory.h} | 27 ++- adapter/mapper/abstract_mapper.h | 10 +- adapter/mapper/mapper_factory.h | 2 +- adapter/posix/CMakeLists.txt | 20 ++- adapter/posix/posix.cc | 1 + adapter/posix/posix_fs_api.h | 38 +++++ adapter/posix/posix_io_client.cc | 85 ++++++++++ adapter/posix/posix_io_client.h | 68 ++++++++ adapter/posix/posix_singleton_macros.h | 6 +- benchmarks/CMakeLists.txt | 1 + src/CMakeLists.txt | 2 +- src/api/bucket.cc | 19 ++- src/api/bucket.h | 39 ++--- src/api/vbucket.cc | 1 + src/api/vbucket.h | 2 +- .../borg_io_client.h} | 8 +- .../borg_io_client_factory.h} | 18 +- .../borg_posix_client.h} | 12 +- .../borg_ram_client.h} | 12 +- src/buffer_organizer.cc | 12 +- src/buffer_organizer.h | 2 +- src/buffer_pool.cc | 2 +- src/buffer_pool.h | 2 +- src/data_structures.h | 1 + src/hermes_types.cc | 81 --------- src/hermes_types.h | 69 +------- src/metadata_manager.cc | 54 +++++- src/metadata_manager.h | 49 +++++- src/metadata_types.h | 4 + src/singleton.h | 27 +++ test/CMakeLists.txt | 1 + test/test_bucket.cc | 6 +- 47 files changed, 805 insertions(+), 471 deletions(-) delete mode 100644 adapter/adapter_factory/abstract_adapter.h create mode 100644 adapter/filesystem/CMakeLists.txt create mode 100644 adapter/filesystem/filesystem_io_client.h rename adapter/filesystem/{metadata_manager.cc => fs_metadata_manager.cc} (84%) rename adapter/filesystem/{metadata_manager.h => fs_metadata_manager.h} (89%) rename adapter/filesystem/{metadata_manager_singleton.cc => fs_metadata_manager_singleton.cc} (83%) rename adapter/filesystem/{metadata_manager_singleton_macros.h => fs_metadata_manager_singleton_macros.h} (100%) create mode 100644 adapter/io_client/CMakeLists.txt create mode 100644 adapter/io_client/empty.cc create mode 100644 adapter/io_client/io_client.h rename adapter/{adapter_factory/adapter_factory.h => io_client/io_client_factory.h} (74%) create mode 100644 adapter/posix/posix_fs_api.h create mode 100644 adapter/posix/posix_io_client.cc create mode 100644 adapter/posix/posix_io_client.h rename src/{io_clients/io_client.h => borg_io_clients/borg_io_client.h} (72%) rename src/{io_clients/io_client_factory.h => borg_io_clients/borg_io_client_factory.h} (54%) rename src/{io_clients/posix.h => borg_io_clients/borg_posix_client.h} (87%) rename src/{io_clients/ram.h => borg_io_clients/borg_ram_client.h} (84%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1430282e5..4ad54a3d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Release") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") message("This IS a release build") else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -v") message("This is NOT a release build") endif() diff --git a/adapter/CMakeLists.txt b/adapter/CMakeLists.txt index e88b353a3..3482b29ce 100644 --- a/adapter/CMakeLists.txt +++ b/adapter/CMakeLists.txt @@ -6,5 +6,7 @@ set(HERMES_ADAPTER_DIR ${CMAKE_SOURCE_DIR}/adapter) include_directories(${CMAKE_SOURCE_DIR}/src) if(HERMES_ENABLE_POSIX_ADAPTER) + add_subdirectory(filesystem) add_subdirectory(posix) + add_subdirectory(adapter_factory) endif() diff --git a/adapter/adapter_factory/abstract_adapter.h b/adapter/adapter_factory/abstract_adapter.h deleted file mode 100644 index 8905ad97a..000000000 --- a/adapter/adapter_factory/abstract_adapter.h +++ /dev/null @@ -1,57 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -// -// Created by manihariharan on 12/23/20. -// - -#ifndef HERMES_ABSTRACT_ADAPTER_H -#define HERMES_ABSTRACT_ADAPTER_H - -#include "utils.h" -#include "hermes_types.h" - -namespace hermes::adapter { - -/** Adapter types */ -enum class AdapterType { - kPosix, - kStdio, - kMpiio, - kPubsub, - kVfd -}; - -/** A class to represent abstract adapter */ -class AbstractAdapter { - public: - /**< */ - virtual void PutFallback(const Blob &blob, - size_t blob_off, - size_t backend_off, - size_t backend_size, - IoContext &io_ctx) = 0; - - virtual void GetFallback(Blob &blob, - size_t blob_off, - size_t backend_off, - size_t backend_size, - IoContext &io_ctx) = 0; - - virtual void LoadBlobFromBackend(size_t backend_off, - size_t backend_size, - IoContext &io_ctx) = 0; -}; - -} // namespace hermes::adapter - -#endif // HERMES_ABSTRACT_ADAPTER_H diff --git a/adapter/adapter_utils.h b/adapter/adapter_utils.h index c3dcc1865..e2ee22ac4 100644 --- a/adapter/adapter_utils.h +++ b/adapter/adapter_utils.h @@ -5,6 +5,8 @@ #ifndef HERMES_ADAPTER_UTILS_H_ #define HERMES_ADAPTER_UTILS_H_ +namespace stdfs = std::experimental::filesystem; + namespace hermes::adapter { #define HERMES_DECL(F) F diff --git a/adapter/filesystem/CMakeLists.txt b/adapter/filesystem/CMakeLists.txt new file mode 100644 index 000000000..e44f79bdf --- /dev/null +++ b/adapter/filesystem/CMakeLists.txt @@ -0,0 +1,41 @@ +include_directories( + ${CMAKE_SOURCE_DIR} + ${HERMES_SRC_DIR} + ${HERMES_ADAPTER_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}) + +# Create the POSIX Real API singleton +add_library(hermes_fs_mdm_singleton SHARED + ${CMAKE_CURRENT_SOURCE_DIR}/fs_metadata_manager_singleton.cc) +add_dependencies(hermes_fs_mdm_singleton hermes) +target_link_libraries(hermes_fs_mdm_singleton + MPI::MPI_CXX hermes) +target_compile_options(hermes_fs_mdm_singleton PUBLIC -fPIC) + +#----------------------------------------------------------------------------- +# Add Target(s) to CMake Install +#----------------------------------------------------------------------------- +install( + TARGETS + hermes_fs_mdm_singleton + EXPORT + ${HERMES_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} +) + +#----------------------------------------------------------------------------- +# Export all exported targets to the build tree for use by parent project +#----------------------------------------------------------------------------- +set(HERMES_EXPORTED_LIBS + hermes_fs_mdm_singleton + ${HERMES_EXPORTED_LIBS}) +if(NOT HERMES_EXTERNALLY_CONFIGURED) +EXPORT ( + TARGETS + ${HERMES_EXPORTED_LIBS} + FILE + ${HERMES_EXPORTED_TARGETS}.cmake +) +endif() \ No newline at end of file diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 9a6223f25..f657bcbe5 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -10,13 +10,14 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "metadata_manager_singleton_macros.h" +#include "fs_metadata_manager_singleton_macros.h" #include "filesystem.h" #include "constants.h" #include "singleton.h" -#include "metadata_manager.h" +#include "fs_metadata_manager.h" #include "vbucket.h" #include "mapper/mapper_factory.h" +#include "io_client/io_client_factory.h" #include #include @@ -33,68 +34,63 @@ File Filesystem::Open(AdapterStat &stat, const std::string &path) { } void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { + auto io_client = IoClientFactory::Get(io_client_); + IoStatus status; _InitFile(f); auto mdm = HERMES_FS_METADATA_MANAGER; stat.bkt_id_ = HERMES->GetBucket(path); LOG(INFO) << "File not opened before by adapter" << std::endl; - _OpenInitStats(f, stat); + io_client->StatObject(f, stat, status); mdm->Create(f, stat); } -void Filesystem::_PutWithFallback(AdapterStat &stat, - const std::string &blob_name, - const std::string &filename, - const hapi::Blob &blob, - size_t offset, - IoStatus &io_status, IoOptions &opts) { - hapi::Context ctx; - hermes::BlobId blob_id; - hapi::Status put_status = stat.bkt_id_->Put(blob_name, blob, blob_id, ctx); - if (put_status.Fail()) { - if (opts.with_fallback_) { - LOG(WARNING) << "Failed to Put Blob " << blob_name << " to Bucket " - << filename << ". Falling back to posix I/O." << std::endl; - _RealWrite(filename, offset, blob.size(), blob.data(), io_status, opts); - } - } -} - size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { (void) f; - std::shared_ptr &bkt = stat.st_bkid_; + std::shared_ptr &bkt = stat.bkt_id_; std::string filename = bkt->GetName(); LOG(INFO) << "Write called for filename: " << filename << " on offset: " << off << " and size: " << total_size << std::endl; size_t ret; - auto mdm = HERMES_FS_METADATA_MANAGER; BlobPlacements mapping; - auto mapper = MapperFactory().Get(kMapperType); + auto mapper = MapperFactory().Get(MapperType::kBalancedMapper); mapper->map(off, total_size, mapping); size_t data_offset = 0; + size_t kPageSize = HERMES->client_config_.file_page_size_; for (const auto &p : mapping) { + const Blob blob_wrap((const char*)ptr + data_offset, off); lipc::charbuf blob_name(p.CreateBlobName()); - - wi.blob_start_ = p.page_ * kPageSize; - wi.mem_ptr_ = (u8 *)ptr + data_offset; + BlobId blob_id; + size_t backend_start = p.page_ * kPageSize; + IoClientContext backend_ctx; + Context ctx; + backend_ctx.filename_ = filename; + bkt->PartialPutOrCreate(blob_name.str(), + blob_wrap, + p.blob_off_, + backend_start, + kPageSize, + blob_id, + backend_ctx, + ctx); data_offset += p.blob_size_; } off_t f_offset = off + data_offset; if (opts.seek_) { stat.st_ptr_ = f_offset; } - - struct timespec ts; - timespec_get(&ts, TIME_UTC); - stat.st_mtim = ts; - stat.st_ctim = ts; + stat.UpdateTime(); ret = data_offset; - _IoStats(data_offset, io_status, opts); return ret; } +size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, + size_t off, size_t total_size, + IoStatus &io_status, IoOptions opts) { +} + HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, IoOptions opts) { @@ -174,11 +170,13 @@ off_t Filesystem::Seek(File &f, AdapterStat &stat, break; } case SeekMode::kEnd: { - stat.st_ptr_ = stat.st_bkt_-> + offset; + //TODO(llogan): Fix seek end + // stat.st_ptr_ = stat.bkt_id_-> + offset; + stat.st_ptr_ = 0 + offset; break; } default: { - // TODO(hari): throw not implemented error. + // TODO(llogan): throw not implemented error. } } mdm->Update(f, stat); diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index 356fdb14d..effaa97e0 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -13,23 +13,23 @@ #ifndef HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_H_ #define HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_H_ -#include -#include #include -#include #include -#include -#include - +#include #include #include -#include "metadata_manager_singleton_macros.h" +#include "traits.h" +#include "bucket.h" +#include "vbucket.h" +#include "adapter/io_client/io_client.h" +#include "fs_metadata_manager_singleton_macros.h" namespace hapi = hermes::api; namespace hermes::adapter::fs { +/** The type of seek to perform */ enum class SeekMode { kNone = -1, kSet = SEEK_SET, @@ -40,37 +40,15 @@ enum class SeekMode { /** A structure to represent adapter stat. */ -struct AdapterStat { +struct AdapterStat : public IoClientStat { std::shared_ptr bkt_id_; /**< bucket associated with the file */ /** VBucket for persisting data asynchronously. */ std::shared_ptr vbkt_id_; - int flags_; /**< open() flags for POSIX */ - mode_t st_mode_; /**< protection */ - off64_t st_ptr_; /**< Current ptr of FILE */ - timespec st_atime_; /**< time of last access */ - timespec st_mtime_; /**< time of last modification */ - timespec st_ctime_; /**< time of last status change */ - std::string mode_str_; /**< mode used for fopen() */ - - bool is_append_; /**< File is in append mode */ - int amode_; /**< access mode (MPI) */ - MPI_Info info_; /**< Info object (handle) */ - MPI_Comm comm_; /**< Communicator for the file.*/ - bool atomicity_; /**< Consistency semantics for data-access */ + /** Default constructor. */ AdapterStat() : bkt_id_(), - vbkt_id_(), - flags_(0), - st_mode_(), - st_ptr_(0), - st_atime_(), - st_mtime_(), - st_ctime_(), - is_append_(false), - amode_(0), - comm_(MPI_COMM_SELF), - atomicity_(false) {} + vbkt_id_() {} /** compare \a a BLOB and \a b BLOB.*/ static bool CompareBlobs(const std::string &a, const std::string &b) { @@ -78,29 +56,8 @@ struct AdapterStat { } }; -/** - A structure to represent file -*/ -struct File { - int fd_; /**< file descriptor */ - FILE *fh_; /**< file handler */ - MPI_File mpi_fh_; /**< MPI file handler */ - - dev_t st_dev; /**< device */ - ino_t st_ino; /**< inode */ - bool status_; /**< status */ - int mpi_status_; /**< MPI status */ - - /** default file constructor */ - File() - : fd_(-1), - fh_(nullptr), - mpi_fh_(nullptr), - st_dev(-1), - st_ino(-1), - status_(true), - mpi_status_(MPI_SUCCESS) {} - +/** A structure to represent file */ +struct File : public IoClientContext { /** file constructor that copies \a old file */ File(const File &old) { Copy(old); } @@ -137,23 +94,17 @@ struct File { } }; -/** - A structure to represent IO options -*/ -struct IoOptions { - hapi::PlacementPolicy dpe_; /**< data placement policy */ - bool seek_; /**< use seek? */ - bool with_fallback_; /**< use fallback? */ - MPI_Datatype mpi_type_; /**< MPI data type */ - int count_; /**< option count */ +/** A structure to represent IO options */ +struct IoOptions : public IoClientOptions { + hapi::PlacementPolicy dpe_; /**< data placement policy */ + bool seek_; /**< use seek? */ + bool with_fallback_; /**< use fallback? */ /** Default constructor */ IoOptions() : dpe_(hapi::PlacementPolicy::kNone), seek_(true), - with_fallback_(true), - mpi_type_(MPI_CHAR), - count_(0) {} + with_fallback_(true) {} /** return options with \a dpe parallel data placement engine */ static IoOptions WithParallelDpe(hapi::PlacementPolicy dpe) { @@ -192,42 +143,35 @@ struct IoOptions { } }; -/** - A structure to represent IO status -*/ -struct IoStatus { - int mpi_ret_; /**< MPI return value */ - MPI_Status mpi_status_; /**< MPI status */ - MPI_Status *mpi_status_ptr_; /**< MPI status pointer */ - - IoStatus() : mpi_ret_(MPI_SUCCESS), mpi_status_ptr_(&mpi_status_) {} -}; - -/** - A structure to represent Hermes request -*/ +/** A structure to represent Hermes request */ struct HermesRequest { std::future return_future; /**< future result of async op. */ IoStatus io_status; /**< IO status */ }; -/** - A class to represent file system -*/ +/** A class to represent file system */ class Filesystem { public: + IoClientType io_client_; /**< The I/O client to use for I/O */ + + public: + /** Constructor */ + explicit Filesystem(IoClientType io_client) : io_client_(io_client) {} + /** open \a path */ File Open(AdapterStat &stat, const std::string &path); /** open \a f File in \a path*/ void Open(AdapterStat &stat, File &f, const std::string &path); + /** write */ size_t Write(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, IoStatus &io_status, IoOptions opts = IoOptions()); /** read */ - size_t Read(File &f, AdapterStat &stat, void *ptr, size_t off, - size_t total_size, IoStatus &io_status, - IoOptions opts = IoOptions()); + size_t Read(File &f, AdapterStat &stat, void *ptr, + size_t off, size_t total_size, + IoStatus &io_status, IoOptions opts = IoOptions()); + /** write asynchronously */ HermesRequest *AWrite(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, @@ -249,39 +193,6 @@ class Filesystem { /** close */ int Close(File &f, AdapterStat &stat, bool destroy = true); - private: - - /* - * The APIs to overload - */ - public: - /** initialize file */ - virtual void _InitFile(File &f) = 0; - - private: - /** open initial status */ - virtual void _OpenInitStats(File &f, AdapterStat &stat) = 0; - /** real open */ - virtual File _RealOpen(AdapterStat &stat, const std::string &path) = 0; - /** real write */ - virtual size_t _RealWrite(const std::string &filename, off_t offset, - size_t size, const u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) = 0; - /** real read */ - virtual size_t _RealRead(const std::string &filename, off_t offset, - size_t size, u8 *data_ptr, IoStatus &io_status, - IoOptions &opts) = 0; - /** io status */ - virtual void _IoStats(size_t count, IoStatus &io_status, IoOptions &opts) { - (void)count; - (void)io_status; - (void)opts; - } - /** real sync */ - virtual int _RealSync(File &f) = 0; - /** real close */ - virtual int _RealClose(File &f) = 0; - /* * I/O APIs which seek based on the internal AdapterStat st_ptr, * instead of taking an offset as input. diff --git a/adapter/filesystem/filesystem_io_client.h b/adapter/filesystem/filesystem_io_client.h new file mode 100644 index 000000000..4000b8a1b --- /dev/null +++ b/adapter/filesystem/filesystem_io_client.h @@ -0,0 +1,37 @@ +// +// Created by lukemartinlogan on 2/1/23. +// + +#ifndef HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_IO_CLIENT_H_ +#define HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_IO_CLIENT_H_ + +#include "io_client/io_client.h" + +namespace hermes::adapter::fs { + +class FilesystemIoClient : public IoClient { + public: + virtual ~FilesystemIoClient() = default; + + public: + /** initialize file */ + virtual void _InitFile(IoClientContext &f) = 0; + + private: + /** Initialize an opened file's statistics */ + virtual void _OpenInitStats(IoClientContext &f, IoClientStat &stat) = 0; + + /** real open */ + virtual IoClientContext _RealOpen(IoClientStat &stat, + const std::string &path) = 0; + + /** real sync */ + virtual int _RealSync(IoClientContext &f) = 0; + + /** real close */ + virtual int _RealClose(IoClientContext &f) = 0; +}; + +} // namespace hermes::adapter::fs + +#endif // HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_IO_CLIENT_H_ diff --git a/adapter/filesystem/metadata_manager.cc b/adapter/filesystem/fs_metadata_manager.cc similarity index 84% rename from adapter/filesystem/metadata_manager.cc rename to adapter/filesystem/fs_metadata_manager.cc index 9c151ccc0..3882d12b3 100644 --- a/adapter/filesystem/metadata_manager.cc +++ b/adapter/filesystem/fs_metadata_manager.cc @@ -10,7 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "metadata_manager.h" +#include "fs_metadata_manager.h" +#include "hermes.h" /** * Namespace declarations for cleaner code. @@ -18,6 +19,21 @@ using hermes::adapter::fs::AdapterStat; using hermes::adapter::fs::MetadataManager; +void MetadataManager::InitializeHermes() { + if (!is_init_) { + lock_.lock(); + if (!is_init_) { + HERMES->Init(HermesType::kClient); + is_init_ = true; + } + lock_.unlock(); + } + + // TODO(llogan): Recycle old fds + hermes_fd_min_ = 8192; // TODO(llogan): don't assume 8192 + hermes_fd_max_ = INT_MAX; +} + bool MetadataManager::Create(const File &f, const AdapterStat &stat) { VLOG(1) << "Create metadata for file handler." << std::endl; auto ret = metadata.emplace(f, stat); diff --git a/adapter/filesystem/metadata_manager.h b/adapter/filesystem/fs_metadata_manager.h similarity index 89% rename from adapter/filesystem/metadata_manager.h rename to adapter/filesystem/fs_metadata_manager.h index af506bae2..c207859db 100644 --- a/adapter/filesystem/metadata_manager.h +++ b/adapter/filesystem/fs_metadata_manager.h @@ -13,13 +13,8 @@ #ifndef HERMES_ADAPTER_METADATA_MANAGER_H #define HERMES_ADAPTER_METADATA_MANAGER_H -#include -#include - #include #include - -#include "constants.h" #include "filesystem.h" namespace hermes::adapter::fs { @@ -43,20 +38,7 @@ class MetadataManager { : metadata(), is_init_(false) {} /** Initialize Hermes (thread-safe) */ - void InitializeHermes() { - if (!is_init_) { - lock_.lock(); - if (!is_init_) { - HERMES->Init(HermesType::kClient); - is_init_ = true; - } - lock_.unlock(); - } - - // TODO(llogan): Recycle old fds - hermes_fd_min_ = 8192; // TODO(llogan): don't assume 8192 - hermes_fd_max_ = INT_MAX; - } + void InitializeHermes(); /** * Create a metadata entry for POSIX adapter for a given file handler. diff --git a/adapter/filesystem/metadata_manager_singleton.cc b/adapter/filesystem/fs_metadata_manager_singleton.cc similarity index 83% rename from adapter/filesystem/metadata_manager_singleton.cc rename to adapter/filesystem/fs_metadata_manager_singleton.cc index 871b3ed22..4aad8d872 100644 --- a/adapter/filesystem/metadata_manager_singleton.cc +++ b/adapter/filesystem/fs_metadata_manager_singleton.cc @@ -1,4 +1,4 @@ #include "singleton.h" -#include "filesystem.h" +#include "fs_metadata_manager.h" template<> std::unique_ptr hermes::Singleton::obj_ = nullptr; diff --git a/adapter/filesystem/metadata_manager_singleton_macros.h b/adapter/filesystem/fs_metadata_manager_singleton_macros.h similarity index 100% rename from adapter/filesystem/metadata_manager_singleton_macros.h rename to adapter/filesystem/fs_metadata_manager_singleton_macros.h diff --git a/adapter/io_client/CMakeLists.txt b/adapter/io_client/CMakeLists.txt new file mode 100644 index 000000000..1b4a1dc31 --- /dev/null +++ b/adapter/io_client/CMakeLists.txt @@ -0,0 +1,37 @@ +# Add library to wrap around all adapter native APIs for use internally in Hermes +add_library(hermes_adapter_native + ${CMAKE_CURRENT_SOURCE_DIR}/empty.cc) +target_compile_options(hermes_adapter_native PUBLIC -fPIC) +add_dependencies(hermes_adapter_native + hermes_posix_fs) +target_link_libraries(hermes_adapter_native + hermes_posix_fs + MPI::MPI_CXX glog::glog stdc++fs dl) + +#----------------------------------------------------------------------------- +# Add Target(s) to CMake Install +#----------------------------------------------------------------------------- +install( + TARGETS + hermes_adapter_native + EXPORT + ${HERMES_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} +) + +#----------------------------------------------------------------------------- +# Export all exported targets to the build tree for use by parent project +#----------------------------------------------------------------------------- +set(HERMES_EXPORTED_LIBS + hermes_adapter_native + ${HERMES_EXPORTED_LIBS}) +if(NOT HERMES_EXTERNALLY_CONFIGURED) + EXPORT ( + TARGETS + ${HERMES_EXPORTED_LIBS} + FILE + ${HERMES_EXPORTED_TARGETS}.cmake + ) +endif() \ No newline at end of file diff --git a/adapter/io_client/empty.cc b/adapter/io_client/empty.cc new file mode 100644 index 000000000..6a1a31054 --- /dev/null +++ b/adapter/io_client/empty.cc @@ -0,0 +1,3 @@ +// +// Created by lukemartinlogan on 1/31/23. +// diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h new file mode 100644 index 000000000..f2daff8df --- /dev/null +++ b/adapter/io_client/io_client.h @@ -0,0 +1,155 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// +// Created by manihariharan on 12/23/20. +// + +#ifndef HERMES_ABSTRACT_ADAPTER_H +#define HERMES_ABSTRACT_ADAPTER_H + +#include "utils.h" +#include "hermes_types.h" +#include + +namespace hermes::adapter { + +/** Adapter types */ +enum class IoClientType { + kNone, + kPosix, + kStdio, + kMpiio, + kVfd +}; + +/** Represents an object in the I/O client (e.g., a file) */ +struct IoClientContext { + IoClientType type_; /**< Client to forward I/O request to */ + std::string filename_; /**< Filename to read from */ + int fd_; /**< file descriptor */ + FILE *fh_; /**< file handler */ + MPI_File mpi_fh_; /**< MPI file handler */ + + dev_t st_dev; /**< device */ + ino_t st_ino; /**< inode */ + bool status_; /**< status */ + int mpi_status_; /**< MPI status */ + + /** Default constructor */ + IoClientContext() + : type_(IoClientType::kNone), + filename_(), + fd_(-1), + fh_(nullptr), + mpi_fh_(nullptr), + st_dev(-1), + st_ino(-1), + status_(true), + mpi_status_(MPI_SUCCESS) {} +}; + +/** Represents any relevant settings for an I/O client operation */ +struct IoClientOptions { + MPI_Datatype mpi_type_; /**< MPI data type */ + int mpi_count_; /**< The number of types */ + + /** Default constructor */ + IoClientOptions() : mpi_type_(MPI_CHAR), + mpi_count_(0) {} +}; + +/** Any relevant statistics from the I/O client */ +struct IoClientStat { + int flags_; /**< open() flags for POSIX */ + mode_t st_mode_; /**< protection */ + uid_t st_uid_; /**< user ID of owner */ + gid_t st_gid_; /**< group ID of owner */ + off64_t st_ptr_; /**< Current ptr of FILE */ + timespec st_atim_; /**< time of last access */ + timespec st_mtim_; /**< time of last modification */ + timespec st_ctim_; /**< time of last status change */ + std::string mode_str_; /**< mode used for fopen() */ + + bool is_append_; /**< File is in append mode */ + int amode_; /**< access mode (MPI) */ + MPI_Info info_; /**< Info object (handle) */ + MPI_Comm comm_; /**< Communicator for the file.*/ + bool atomicity_; /**< Consistency semantics for data-access */ + + /** Default constructor */ + IoClientStat() + : flags_(0), + st_mode_(), + st_ptr_(0), + st_atim_(), + st_mtim_(), + st_ctim_(), + is_append_(false), + amode_(0), + comm_(MPI_COMM_SELF), + atomicity_(false) {} + + /** Update to the current time */ + void UpdateTime() { + struct timespec ts; + timespec_get(&ts, TIME_UTC); + st_mtim_ = ts; + st_ctim_ = ts; + } +}; + +/** A structure to represent IO status */ +struct IoStatus { + size_t posix_ret_; /**< POSIX/STDIO return value */ + int mpi_ret_; /**< MPI return value */ + MPI_Status mpi_status_; /**< MPI status */ + MPI_Status *mpi_status_ptr_; /**< MPI status pointer */ + + /** Default constructor */ + IoStatus() : posix_ret_(0), + mpi_ret_(MPI_SUCCESS), + mpi_status_ptr_(&mpi_status_) {} +}; + +/** + * A class to represent abstract I/O client. + * Used internally by BORG and certain adapter classes. + * */ +class IoClient { + public: + /** Default constructor */ + IoClient() = default; + + /** Virtual destructor */ + virtual ~IoClient() = default; + + /** Write blob to backend */ + virtual void WriteBlob(const Blob &full_blob, + size_t backend_off, + size_t backend_size, + const IoClientContext &io_ctx, + const IoClientOptions &opts, + IoStatus &status) = 0; + + /** Read blob from the backend */ + virtual void ReadBlob(Blob &full_blob, + size_t backend_off, + size_t backend_size, + const IoClientContext &io_ctx, + const IoClientOptions &opts, + IoStatus &status) = 0; +}; + +} // namespace hermes::adapter + +#endif // HERMES_ABSTRACT_ADAPTER_H diff --git a/adapter/adapter_factory/adapter_factory.h b/adapter/io_client/io_client_factory.h similarity index 74% rename from adapter/adapter_factory/adapter_factory.h rename to adapter/io_client/io_client_factory.h index 89e2305d8..141dd69f2 100644 --- a/adapter/adapter_factory/adapter_factory.h +++ b/adapter/io_client/io_client_factory.h @@ -10,39 +10,38 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_ADAPTER_FACTORY_H -#define HERMES_ADAPTER_FACTORY_H +#ifndef HERMES_IO_CLIENT_FACTORY_H +#define HERMES_IO_CLIENT_FACTORY_H -#include "abstract_adapter.h" +#include "io_client.h" #include "singleton.h" +#include "adapter/posix/posix_fs_api.h" + namespace hermes::adapter { /** A class to represent adapter factory pattern */ -class AdapterFactory { +class IoClientFactory { public: /** * Return the instance of adapter given a type. Uses factory pattern. * - * @param[in] type type of mapper to be used by the POSIX adapter. + * @param[in] type type of adapter. * @return Instance of mapper given a type. */ - std::unique_ptr Get(const AdapterType& type) { + static IoClient* Get(const IoClientType& type) { switch (type) { - case AdapterType::kPosix: { + case IoClientType::kPosix: { return HERMES_POSIX_FS; } - case AdapterType::kStdio: { - return nullptr; - } - case AdapterType::kMpiio: { + case IoClientType::kStdio: { return nullptr; } - case AdapterType::kPubsub: { + case IoClientType::kMpiio: { return nullptr; } - case AdapterType::kVfd: { + case IoClientType::kVfd: { return nullptr; } default: { @@ -53,4 +52,4 @@ class AdapterFactory { } }; } // namespace hermes::adapter -#endif // HERMES_ADAPTER_FACTORY_H +#endif // HERMES_IO_CLIENT_FACTORY_H diff --git a/adapter/mapper/abstract_mapper.h b/adapter/mapper/abstract_mapper.h index 43cd43b40..241f750bb 100644 --- a/adapter/mapper/abstract_mapper.h +++ b/adapter/mapper/abstract_mapper.h @@ -14,8 +14,8 @@ // Created by manihariharan on 12/23/20. // -#ifndef HERMES_ABSTRACT_ADAPTER_H -#define HERMES_ABSTRACT_ADAPTER_H +#ifndef HERMES_ABSTRACT_MAPPER_H +#define HERMES_ABSTRACT_MAPPER_H #include "utils.h" @@ -25,8 +25,8 @@ namespace hermes::adapter { * Define different types of mappers supported by POSIX Adapter. * Also define its construction in the MapperFactory. */ -enum MapperType { - BALANCED = 0 /* Balanced Mapping */ +enum class MapperType { + kBalancedMapper }; /** @@ -71,4 +71,4 @@ class AbstractMapper { }; } // namespace hermes::adapter -#endif // HERMES_ABSTRACT_ADAPTER_H +#endif // HERMES_ABSTRACT_MAPPER_H diff --git a/adapter/mapper/mapper_factory.h b/adapter/mapper/mapper_factory.h index ca8d8d88d..12a3f4754 100644 --- a/adapter/mapper/mapper_factory.h +++ b/adapter/mapper/mapper_factory.h @@ -32,7 +32,7 @@ class MapperFactory { */ AbstractMapper* Get(const MapperType& type) { switch (type) { - case MapperType::BALANCED: { + case MapperType::kBalancedMapper: { return hermes::Singleton::GetInstance(); } default: { diff --git a/adapter/posix/CMakeLists.txt b/adapter/posix/CMakeLists.txt index 7b8e0573b..56ca14ea7 100644 --- a/adapter/posix/CMakeLists.txt +++ b/adapter/posix/CMakeLists.txt @@ -1,4 +1,5 @@ include_directories( + ${CMAKE_SOURCE_DIR} ${HERMES_SRC_DIR} ${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) @@ -7,10 +8,20 @@ include_directories( add_library(hermes_posix_singleton SHARED ${CMAKE_CURRENT_SOURCE_DIR}/posix_singleton.cc) target_compile_options(hermes_posix_singleton PUBLIC -fPIC) +# Add library hermes_posix_fs +add_library(hermes_posix_fs ${CMAKE_CURRENT_SOURCE_DIR}/posix_fs_api.cc) +target_compile_options(hermes_posix_fs PUBLIC -fPIC) +add_dependencies(hermes_posix_fs + hermes hermes_posix_singleton hermes_fs_mdm_singleton) +target_link_libraries(hermes_posix_fs + hermes hermes_posix_singleton hermes_fs_mdm_singleton + MPI::MPI_CXX glog::glog stdc++fs dl) + # Create the POSIX interceptor add_library(hermes_posix SHARED ${CMAKE_CURRENT_SOURCE_DIR}/posix.cc) add_dependencies(hermes_posix hermes hermes_posix_singleton) -target_link_libraries(hermes_posix hermes hermes_posix_singleton) +target_link_libraries(hermes_posix + hermes hermes_posix_singleton hermes_posix_fs) target_compile_options(hermes_posix PUBLIC -fPIC) #----------------------------------------------------------------------------- @@ -19,6 +30,7 @@ target_compile_options(hermes_posix PUBLIC -fPIC) install( TARGETS hermes_posix_singleton + hermes_posix_fs hermes_posix EXPORT ${HERMES_EXPORTED_TARGETS} @@ -30,7 +42,11 @@ install( #----------------------------------------------------------------------------- # Export all exported targets to the build tree for use by parent project #----------------------------------------------------------------------------- -set(HERMES_EXPORTED_LIBS hermes_posix_singleton ${HERMES_EXPORTED_LIBS}) +set(HERMES_EXPORTED_LIBS + hermes_posix_singleton + hermes_posix_fs + hermes_posix + ${HERMES_EXPORTED_LIBS}) if(NOT HERMES_EXTERNALLY_CONFIGURED) EXPORT ( TARGETS diff --git a/adapter/posix/posix.cc b/adapter/posix/posix.cc index 7cc69ed5d..6fbf45b82 100644 --- a/adapter/posix/posix.cc +++ b/adapter/posix/posix.cc @@ -23,6 +23,7 @@ bool posix_intercepted = true; #include "singleton.h" #include "adapter_utils.h" #include "posix_api.h" +#include "posix_fs_api.h" #include "posix_singleton_macros.h" #include "filesystem/filesystem.h" diff --git a/adapter/posix/posix_fs_api.h b/adapter/posix/posix_fs_api.h new file mode 100644 index 000000000..6bed31448 --- /dev/null +++ b/adapter/posix/posix_fs_api.h @@ -0,0 +1,38 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_ADAPTER_POSIX_NATIVE_H_ +#define HERMES_ADAPTER_POSIX_NATIVE_H_ + +#include + +#include "adapter/filesystem/filesystem.h" +#include "adapter/filesystem/fs_metadata_manager.h" +#include "posix_singleton_macros.h" +#include "posix_api.h" +#include "posix_io_client.h" + +namespace hermes::adapter::posix { + +/** A class to represent POSIX IO file system */ +class PosixFs : public hermes::adapter::fs::Filesystem { + public: + PosixFs() : hermes::adapter::fs::Filesystem(IoClientType::kPosix) {} +}; + +/** Simplify access to the stateless PosixFs Singleton */ +#define HERMES_POSIX_FS hermes::EasySingleton::GetInstance() +#define HERMES_POSIX_FS_T hermes::adapter::posix::PosixFs* + +} // namespace hermes::adapter::posix + +#endif // HERMES_ADAPTER_POSIX_NATIVE_H_ diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc new file mode 100644 index 000000000..41072fa88 --- /dev/null +++ b/adapter/posix/posix_io_client.cc @@ -0,0 +1,85 @@ +// +// Created by lukemartinlogan on 1/31/23. +// + +#include "posix_io_client.h" + +namespace hermes::adapter::posix { + +IoClientContext PosixIoClient::_RealOpen(IoClientStat &stat, + const std::string &path) { + IoClientContext f; + if (stat.flags_ & O_CREAT || stat.flags_ & O_TMPFILE) { + f.fd_ = real_api->open(path.c_str(), stat.flags_, stat.st_mode_); + } else { + f.fd_ = real_api->open(path.c_str(), stat.flags_); + } + if (f.fd_ < 0) { + f.status_ = false; + } + _InitFile(f); + return f; +} + +void PosixIoClient::_InitFile(IoClientContext &f) { + struct stat st; + real_api->__fxstat(_STAT_VER, f.fd_, &st); + f.st_dev = st.st_dev; + f.st_ino = st.st_ino; +} + +void PosixIoClient::_OpenInitStats(IoClientContext &f, IoClientStat &stat) { + struct stat st; + real_api->__fxstat(_STAT_VER, f.fd_, &st); + stat.st_mode_ = st.st_mode; + stat.st_uid_ = st.st_uid; + stat.st_gid_ = st.st_gid; + // stat.st_size_ = st.st_size; + // stat.st_blksize_ = st.st_blksize; + stat.st_atim_ = st.st_atim; + stat.st_mtim_ = st.st_mtim; + stat.st_ctim_ = st.st_ctim; + if (stat.flags_ & O_APPEND) { + stat.is_append_ = true; + } +} + +size_t PosixIoClient::WriteBlob(const std::string &filename, off_t offset, + size_t size, const u8 *data_ptr, + IoStatus &io_status, IoOptions &opts) { + (void) opts; (void) io_status; + LOG(INFO) << "Writing to file: " << filename + << " offset: " << offset + << " size:" << size << "." + << " file_size:" << stdfs::file_size(filename) << std::endl; + int fd = real_api->open(filename.c_str(), O_RDWR | O_CREAT); + if (fd < 0) { return 0; } + size_t write_size = real_api->pwrite(fd, data_ptr, size, offset); + real_api->close(fd); + return write_size; +} + +size_t PosixIoClient::ReadBlob(const std::string &filename, off_t offset, + size_t size, u8 *data_ptr, + IoStatus &io_status, IoOptions &opts) { + (void) opts; (void) io_status; + LOG(INFO) << "Read called for filename from destination: " << filename + << " on offset: " << offset + << " and size: " << size << "." + << " file_size:" << stdfs::file_size(filename) << std::endl; + int fd = real_api->open(filename.c_str(), O_RDONLY); + if (fd < 0) { return 0; } + size_t read_size = real_api->pread(fd, data_ptr, size, offset); + real_api->close(fd); + return read_size; +} + +int PosixIoClient::_RealSync(IoClientContext &f) { + return real_api->fsync(f.fd_); +} + +int PosixIoClient::_RealClose(IoClientContext &f) { + return real_api->close(f.fd_); +} + +} // namespace hermes::adapter::posix diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h new file mode 100644 index 000000000..477a53628 --- /dev/null +++ b/adapter/posix/posix_io_client.h @@ -0,0 +1,68 @@ +// +// Created by lukemartinlogan on 1/31/23. +// + +#ifndef HERMES_ADAPTER_POSIX_POSIX_IO_CLIENT_H_ +#define HERMES_ADAPTER_POSIX_POSIX_IO_CLIENT_H_ + +#include + +#include "filesystem/filesystem_io_client.h" +#include "posix_singleton_macros.h" +#include "posix_api.h" + +using hermes::Singleton; +using hermes::adapter::IoClientStat; +using hermes::adapter::IoClientOptions; +using hermes::adapter::IoStatus; +using hermes::adapter::posix::PosixApi; + +namespace hermes::adapter::posix { + +/** A class to represent POSIX IO file system */ +class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { + private: + HERMES_POSIX_API_T real_api; /**< pointer to real APIs */ + + public: + /** Default constructor */ + PosixIoClient() { real_api = HERMES_POSIX_API; } + + /** Virtual destructor */ + virtual ~PosixIoClient() = default; + + public: + /** Initialize a file whose fd has already been allocated */ + void _InitFile(IoClientContext &f) override; + + /** Write blob to backend */ + void WriteBlob(const Blob &full_blob, + size_t backend_off, + size_t backend_size, + const IoClientContext &io_ctx, + const IoClientOptions &opts, + IoStatus &status) override; + + /** Read blob from the backend */ + void ReadBlob(Blob &full_blob, + size_t backend_off, + size_t backend_size, + const IoClientContext &io_ctx, + const IoClientOptions &opts, + IoStatus &status) override; + + private: + void _OpenInitStats(IoClientContext &f, IoClientStat &stat) override; + IoClientContext _RealOpen(IoClientStat &stat, + const std::string &path) override; + int _RealSync(IoClientContext &f) override; + int _RealClose(IoClientContext &f) override; +}; + +} // namespace hermes::adapter::posix + +/** Simplify access to the stateless PosixFs Singleton */ +#define HERMES_POSIX_FS hermes::EasySingleton::GetInstance() +#define HERMES_POSIX_FS_T hermes::adapter::posix::PosixFs* + +#endif // HERMES_ADAPTER_POSIX_POSIX_IO_CLIENT_H_ diff --git a/adapter/posix/posix_singleton_macros.h b/adapter/posix/posix_singleton_macros.h index 72f6167e7..5e4a2f148 100644 --- a/adapter/posix/posix_singleton_macros.h +++ b/adapter/posix/posix_singleton_macros.h @@ -1,9 +1,9 @@ -#ifndef HERMES_SINGLETON_ADAPTER_MACROS_H -#define HERMES_SINGLETON_ADAPTER_MACROS_H +#ifndef HERMES_POSIX_SINGLETON_ADAPTER_MACROS_H +#define HERMES_POSIX_SINGLETON_ADAPTER_MACROS_H #include "singleton.h" #define HERMES_POSIX_API hermes::Singleton::GetInstance() #define HERMES_POSIX_API_T hermes::adapter::posix::PosixApi* -#endif // HERMES_SINGLETON_ADAPTER_MACROS_H +#endif // HERMES_POSIX_SINGLETON_ADAPTER_MACROS_H diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index ffb042438..627d478b7 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,4 +1,5 @@ include_directories( + ${CMAKE_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/src/api ${PROJECT_SOURCE_DIR}/test ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7878793bc..173a48349 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -87,7 +87,7 @@ target_include_directories(hermes add_dependencies(hermes hermes_posix_singleton) target_link_libraries(hermes - PUBLIC hermes_posix_singleton + PUBLIC hermes_adapter_native PUBLIC ${GLPK_LIBRARIES} PUBLIC ${CMAKE_HERMES_COMMUNICATION_TYPE_LIB} PUBLIC ${CMAKE_HERMES_RPC_TYPE_LIB} diff --git a/src/api/bucket.cc b/src/api/bucket.cc index a3b3ca6d2..0ea67b4e6 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -20,6 +20,14 @@ Bucket::Bucket(std::string name, Context &ctx) id_ = mdm_->LocalGetOrCreateBucket(lname); } +/** + * Get \a bkt_id bucket, which is known to exist. + * + * Used internally by Hermes. + * */ +Bucket::Bucket(BucketId bkt_id, Context &ctx) +: id_(bkt_id) {} + /** * Rename this bucket * */ @@ -52,7 +60,7 @@ Status Bucket::GetBlobId(std::string blob_name, /** * Put \a blob_id Blob into the bucket * */ -Status Bucket::Put(std::string blob_name, ConstBlobData blob, +Status Bucket::Put(std::string blob_name, const Blob blob, BlobId &blob_id, Context &ctx) { // Calculate placement auto dpe = DPEFactory::Get(ctx.policy); @@ -74,15 +82,18 @@ Status Bucket::Put(std::string blob_name, ConstBlobData blob, /** * Get \a blob_id Blob from the bucket * */ -Blob Bucket::Get(BlobId blob_id, Context &ctx) { - return mdm_->LocalBucketGetBlob(blob_id);; +Status Bucket::Get(BlobId blob_id, Blob &blob, Context &ctx) { + Blob b = mdm_->LocalBucketGetBlob(blob_id); + blob = std::move(b); + return Status(); } /** * Rename \a blob_id blob to \a new_blob_name new name * */ void Bucket::RenameBlob(BlobId blob_id, - std::string new_blob_name, Context &ctx) { + std::string new_blob_name, + Context &ctx) { lipc::string lnew_blob_name(new_blob_name); mdm_->LocalRenameBlob(id_, blob_id, lnew_blob_name); } diff --git a/src/api/bucket.h b/src/api/bucket.h index 5f60d940a..efa808dd4 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -7,10 +7,13 @@ #include "hermes_types.h" #include "status.h" -#include "hermes.h" +#include "buffer_pool.h" +#include "adapter/adapter_factory/abstract_adapter.h" namespace hermes::api { +using hermes::adapter::IoClientContext; + class Bucket { private: MetadataManager *mdm_; @@ -33,6 +36,14 @@ class Bucket { Bucket(std::string bkt_name, Context &ctx); + /** + * Get \a bkt_id bucket, which is known to exist. + * + * Used internally by Hermes. + * */ + Bucket(BucketId bkt_id, Context &ctx); + + public: /** * Get the name of this bucket. Name is cached instead of * making an RPC. Not coherent if Rename is called. @@ -100,7 +111,7 @@ class Bucket { * Put \a blob_name Blob into the bucket * */ Status Put(std::string blob_name, - ConstBlobData blob, + const Blob blob, BlobId &blob_id, Context &ctx); @@ -110,17 +121,19 @@ class Bucket { * * @param blob_name the semantic name of the blob * @param blob the buffer to put final data in + * @param blob_off the offset within the blob to begin the Put * @param backend_off the offset to read from the backend if blob DNE * @param backend_size the size to read from the backend if blob DNE * @param backend_ctx which adapter to route I/O request if blob DNE * @param ctx any additional information * */ Status PartialPutOrCreate(std::string blob_name, - ConstBlobData blob, + const Blob &blob, + size_t blob_off, size_t backend_off, size_t backend_size, - IoContext &backend_ctx, BlobId &blob_id, + IoClientContext &backend_ctx, Context &ctx); /** @@ -130,24 +143,6 @@ class Bucket { Blob &blob, Context &ctx); - /** - * Partially (or fully) Get a blob from a bucket. Load the blob from the - * I/O backend if it does not exist. - * - * @param blob_name the semantic name of the blob - * @param blob the buffer to put final data in - * @param backend_off the offset to read from the backend if blob DNE - * @param backend_size the size to read from the backend if blob DNE - * @param backend_ctx which adapter to route I/O request if blob DNE - * @param ctx any additional information - * */ - Status PartialGetOrCreate(std::string blob_name, - MutableBlobData blob, - size_t backend_off, - size_t backend_size, - IoContext &backend_ctx, - Context &ctx); - /** * Rename \a blob_id blob to \a new_blob_name new name * */ diff --git a/src/api/vbucket.cc b/src/api/vbucket.cc index 9c85fee46..ae9b49500 100644 --- a/src/api/vbucket.cc +++ b/src/api/vbucket.cc @@ -3,6 +3,7 @@ // #include "vbucket.h" +#include "hermes.h" namespace hermes::api { diff --git a/src/api/vbucket.h b/src/api/vbucket.h index da62d7b57..8fae0ada0 100644 --- a/src/api/vbucket.h +++ b/src/api/vbucket.h @@ -7,7 +7,7 @@ #include "hermes_types.h" #include "status.h" -#include "hermes.h" +#include "metadata_manager.h" namespace hermes::api { diff --git a/src/io_clients/io_client.h b/src/borg_io_clients/borg_io_client.h similarity index 72% rename from src/io_clients/io_client.h rename to src/borg_io_clients/borg_io_client.h index 79f900e3a..0e47881fa 100644 --- a/src/io_clients/io_client.h +++ b/src/borg_io_clients/borg_io_client.h @@ -2,15 +2,15 @@ // Created by lukemartinlogan on 12/22/22. // -#ifndef HERMES_SRC_IO_CLIENTS_IO_CLIENT_H_ -#define HERMES_SRC_IO_CLIENTS_IO_CLIENT_H_ +#ifndef HERMES_SRC_BORG_IO_CLIENTS_IO_CLIENT_H +#define HERMES_SRC_BORG_IO_CLIENTS_IO_CLIENT_H #include "hermes_types.h" #include "metadata_types.h" namespace hermes { -class IoClient { +class BorgIoClient { public: virtual bool Init(DeviceInfo &dev_info) = 0; virtual bool Write(DeviceInfo &dev_info, @@ -21,4 +21,4 @@ class IoClient { } // namespace hermes -#endif // HERMES_SRC_IO_CLIENTS_IO_CLIENT_H_ +#endif // HERMES_SRC_BORG_IO_CLIENTS_IO_CLIENT_H diff --git a/src/io_clients/io_client_factory.h b/src/borg_io_clients/borg_io_client_factory.h similarity index 54% rename from src/io_clients/io_client_factory.h rename to src/borg_io_clients/borg_io_client_factory.h index 836436f56..4e6adc1ab 100644 --- a/src/io_clients/io_client_factory.h +++ b/src/borg_io_clients/borg_io_client_factory.h @@ -2,25 +2,25 @@ // Created by lukemartinlogan on 12/22/22. // -#ifndef HERMES_SRC_IO_CLIENTS_IO_CLIENT_FACTORY_H_ -#define HERMES_SRC_IO_CLIENTS_IO_CLIENT_FACTORY_H_ +#ifndef HERMES_SRC_BORG_IO_CLIENTS_IO_CLIENT_FACTORY_H +#define HERMES_SRC_BORG_IO_CLIENTS_IO_CLIENT_FACTORY_H -#include "io_client.h" +#include "borg_io_client.h" #include "metadata_types.h" -#include "posix.h" -#include "ram.h" +#include "borg_posix_client.h" +#include "borg_ram_client.h" -namespace hermes { +namespace hermes::borg { /** A class to represent I/O Client Factory */ -class IoClientFactory { +class BorgIoClientFactory { public: /** * Get the I/O api implementation * */ - static std::unique_ptr Get(IoInterface type) { + static std::unique_ptr Get(IoInterface type) { switch (type) { case IoInterface::kPosix: { return std::make_unique(); @@ -35,4 +35,4 @@ class IoClientFactory { } // namespace hermes -#endif // HERMES_SRC_IO_CLIENTS_IO_CLIENT_FACTORY_H_ +#endif // HERMES_SRC_BORG_IO_CLIENTS_IO_CLIENT_FACTORY_H diff --git a/src/io_clients/posix.h b/src/borg_io_clients/borg_posix_client.h similarity index 87% rename from src/io_clients/posix.h rename to src/borg_io_clients/borg_posix_client.h index 06a97f729..1bc82d921 100644 --- a/src/io_clients/posix.h +++ b/src/borg_io_clients/borg_posix_client.h @@ -2,10 +2,10 @@ // Created by lukemartinlogan on 12/22/22. // -#ifndef HERMES_SRC_IO_CLIENTS_POSIX_H_ -#define HERMES_SRC_IO_CLIENTS_POSIX_H_ +#ifndef HERMES_SRC_BORG_IO_CLIENTS_POSIX_H +#define HERMES_SRC_BORG_IO_CLIENTS_POSIX_H -#include "io_client.h" +#include "borg_io_client.h" #include "adapter/posix/posix_api.h" #include "adapter/posix/posix_singleton_macros.h" @@ -13,9 +13,9 @@ namespace stdfs = std::experimental::filesystem; -namespace hermes { +namespace hermes::borg { -class PosixIoClient : public IoClient { +class PosixIoClient : public BorgIoClient { public: bool Init(DeviceInfo &dev_info) override { auto api = HERMES_POSIX_API; @@ -60,4 +60,4 @@ class PosixIoClient : public IoClient { } // namespace hermes -#endif // HERMES_SRC_IO_CLIENTS_POSIX_H_ +#endif // HERMES_SRC_BORG_IO_CLIENTS_POSIX_H diff --git a/src/io_clients/ram.h b/src/borg_io_clients/borg_ram_client.h similarity index 84% rename from src/io_clients/ram.h rename to src/borg_io_clients/borg_ram_client.h index c1aa7cee2..d72ba6664 100644 --- a/src/io_clients/ram.h +++ b/src/borg_io_clients/borg_ram_client.h @@ -2,17 +2,17 @@ // Created by lukemartinlogan on 12/22/22. // -#ifndef HERMES_SRC_IO_CLIENTS_RAM_H_ -#define HERMES_SRC_IO_CLIENTS_RAM_H_ +#ifndef HERMES_SRC_BORG_IO_CLIENTS_RAM_H_ +#define HERMES_SRC_BORG_IO_CLIENTS_RAM_H_ -#include "io_client.h" +#include "borg_io_client.h" #include "adapter/posix/posix_api.h" #include "adapter/posix/posix_singleton_macros.h" #include "hermes.h" -namespace hermes { +namespace hermes::borg { -class RamIoClient : public IoClient { +class RamIoClient : public BorgIoClient { public: bool Init(DeviceInfo &dev_info) override { auto &hermes_header = HERMES->header_; @@ -47,4 +47,4 @@ class RamIoClient : public IoClient { } // namespace hermes -#endif // HERMES_SRC_IO_CLIENTS_RAM_H_ +#endif // HERMES_SRC_BORG_IO_CLIENTS_RAM_H_ diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index e4ca24eda..3793d3b9d 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -4,7 +4,7 @@ #include "buffer_organizer.h" #include "metadata_manager.h" -#include "io_clients/io_client_factory.h" +#include "borg_io_clients/borg_io_client_factory.h" #include "hermes.h" namespace hermes { @@ -23,7 +23,7 @@ void BufferOrganizer::shm_init() { } else { dev_info->header_->io_api_ = IoInterface::kPosix; } - auto io_client = IoClientFactory::Get(dev_info->header_->io_api_); + auto io_client = borg::BorgIoClientFactory::Get(dev_info->header_->io_api_); io_client->Init(*dev_info); } } @@ -42,7 +42,7 @@ void BufferOrganizer::shm_deserialize() { /** Stores a blob into a set of buffers */ RPC void BufferOrganizer::LocalPlaceBlobInBuffers( - ConstBlobData &blob, lipc::vector &buffers) { + const Blob &blob, lipc::vector &buffers) { size_t blob_off = 0; for (lipc::ShmRef buffer_info : buffers) { if (buffer_info->tid_.GetNodeId() != mdm_->rpc_->node_id_) { @@ -50,7 +50,7 @@ RPC void BufferOrganizer::LocalPlaceBlobInBuffers( } lipc::ShmRef dev_info = (*mdm_->devices_)[buffer_info->tid_.GetDeviceId()]; - auto io_client = IoClientFactory::Get(dev_info->header_->io_api_); + auto io_client = borg::BorgIoClientFactory::Get(dev_info->header_->io_api_); bool ret = io_client->Write(*dev_info, blob.data() + blob_off, buffer_info->t_off_, @@ -73,8 +73,8 @@ RPC Blob BufferOrganizer::LocalReadBlobFromBuffers( } lipc::ShmRef dev_info = (*mdm_->devices_)[buffer_info->tid_.GetDeviceId()]; - auto io_client = IoClientFactory::Get(dev_info->header_->io_api_); - bool ret = io_client->Read(*dev_info, blob.data_mutable() + blob_off, + auto io_client = borg::BorgIoClientFactory::Get(dev_info->header_->io_api_); + bool ret = io_client->Read(*dev_info, blob.data() + blob_off, buffer_info->t_off_, buffer_info->blob_size_); blob_off += buffer_info->blob_size_; diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index 15e2a7bf4..adf376e0a 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -46,7 +46,7 @@ class BufferOrganizer { void shm_deserialize(); /** Stores a blob into a set of buffers */ - RPC void LocalPlaceBlobInBuffers(ConstBlobData &blob, + RPC void LocalPlaceBlobInBuffers(const Blob &blob, lipc::vector &buffers); /** Stores a blob into a set of buffers */ diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index e0090df47..65e769397 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -46,7 +46,7 @@ void BufferPool::shm_deserialize(BufferPoolShmHeader *header) { * */ lipc::vector BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, - ConstBlobData &blob) { + const Blob &blob) { lipc::vector buffers(HERMES->main_alloc_); size_t blob_off_ = 0; for (auto plcmnt : schema.plcmnts_) { diff --git a/src/buffer_pool.h b/src/buffer_pool.h index 14cb0a606..f688df993 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -69,7 +69,7 @@ class BufferPool { * */ RPC lipc::vector LocalAllocateAndSetBuffers(PlacementSchema &schema, - ConstBlobData &blob); + const Blob &blob); /** * Free buffers from the BufferPool diff --git a/src/data_structures.h b/src/data_structures.h index 5e097415e..fc0814b12 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace lipc = labstor::ipc; diff --git a/src/hermes_types.cc b/src/hermes_types.cc index 2b7ebccbd..44e6de92b 100644 --- a/src/hermes_types.cc +++ b/src/hermes_types.cc @@ -19,85 +19,4 @@ Context::Context() disable_swap(false), vbkt_id_({0, 0}) {} -//////////////////////////// -/// Blob Operations -//////////////////////////// - -/** Size-based constructor */ -Blob::Blob(size_t size) { - Allocate(HERMES->main_alloc_, size); -} - -/** Construct from std::string */ -Blob::Blob(const std::string &data) { - Allocate(HERMES->main_alloc_, data.size()); - memcpy(data_, data.data(), data.size()); -} - -/** Copy constructor */ -Blob::Blob(const Blob &other) { - if (!Allocate(HERMES->main_alloc_, other.size())) { - return; - } - memcpy(data_, other.data(), size()); -} - -/** Copy assignment operator */ -Blob& Blob::operator=(const Blob &other) { - if (this != &other) { - Free(); - if (!Allocate(HERMES->main_alloc_, other.size())) { - return *this; - } - memcpy(data_, other.data(), size()); - } - return *this; -} - -/** Move constructor */ -Blob::Blob(Blob &&other) { - alloc_ = other.alloc_; - data_ = other.data_; - size_ = other.size_; - destructable_ = other.destructable_; - other.destructable_ = false; -} - -/** Move assignment operator */ -Blob& Blob::operator=(Blob &other) { - if (this != &other) { - Free(); - alloc_ = other.alloc_; - data_ = other.data_; - size_ = other.size_; - destructable_ = other.destructable_; - other.destructable_ = false; - } - return *this; -} - -/** Allocate the blob */ -bool Blob::Allocate(lipc::Allocator *alloc, size_t size) { - lipc::OffsetPointer p; - if (size == 0) { - alloc_ = nullptr; - data_ = nullptr; - size_ = 0; - destructable_ = false; - return false; - } - alloc_ = alloc; - data_ = alloc->AllocatePtr(size, p); - size_ = size; - destructable_ = true; - return true; -} - -/** Deallocate this blob */ -void Blob::Free() { - if (destructable_ && data_ && size_) { - alloc_->FreePtr(data_); - } -} - } // namespace hermes::api \ No newline at end of file diff --git a/src/hermes_types.h b/src/hermes_types.h index 8ebec6d3d..ad1c12c3d 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -112,6 +112,7 @@ struct UniqueId { typedef UniqueId<0> BucketId; typedef UniqueId<1> VBucketId; typedef UniqueId<2> BlobId; +typedef UniqueId<3> TransactionId; /** A definition for logging something that is not yet implemented */ #define HERMES_NOT_IMPLEMENTED_YET \ @@ -205,65 +206,8 @@ struct TraitId { namespace hermes::api { -/** - * A Blob is simply an uninterpreted vector of bytes. - */ -struct Blob { - lipc::Allocator *alloc_; /**< The allocator used to allocate data */ - char *data_; /**< The pointer to data */ - size_t size_; /**< The size of data */ - bool destructable_; /**< Whether or not this container owns data */ - - /** Default constructor */ - Blob() : alloc_(nullptr), data_(nullptr), size_(0), destructable_(false) {} - - /** Destructor */ - ~Blob() { Free(); } - - /** Size-based constructor */ - explicit Blob(size_t size); - - /** String-based constructor */ - explicit Blob(const std::string &data); - - /** Pointer-based constructor */ - explicit Blob(char *data, size_t size) - : alloc_(nullptr), data_(data), size_(size), destructable_(false) {} - - /** Copy constructor */ - Blob(const Blob &other); - - /** Copy assignment operator */ - Blob& operator=(const Blob &other); - - /** Move constructor */ - Blob(Blob &&other); - - /** Move assignment operator */ - Blob& operator=(Blob &other); - - /** Reference data */ - char* data() { - return data_; - } - - /** Reference data */ - char* data() const { - return data_; - } - - /** Reference size */ - size_t size() const { - return size_; - } - - private: - /** Allocate blob */ - bool Allocate(lipc::Allocator *alloc, size_t size); - - /** Explicitly free the blob */ - void Free(); -}; +/** A blob is an uniterpreted array of bytes */ +typedef labstor::charbuf Blob; /** Supported data placement policies */ enum class PlacementPolicy { @@ -383,11 +327,8 @@ namespace hermes { /** Namespace simplification for Blob */ using api::Blob; -/** Namespace simplification for MutableBlobData */ -using api::MutableBlobData; - -/** Namespace simplification for ConstBlobData */ -using api::ConstBlobData; +/** Namespace simplification for Context */ +using api::Context; } // namespace hermes diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 40333f569..585dbe096 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -5,9 +5,17 @@ #include "hermes.h" #include "metadata_manager.h" #include "buffer_organizer.h" +#include "api/bucket.h" +#include "adapter/adapter_factory/adapter_factory.h" namespace hermes { +/** Namespace simplification for AdapterFactory */ +using hermes::adapter::AdapterFactory; + +/** Namespace simplification for Bucket */ +using api::Bucket; + /** * Explicitly initialize the MetadataManager * Doesn't require anything to be initialized. @@ -202,7 +210,7 @@ bool MetadataManager::LocalDestroyBucket(BucketId bkt_id) { * */ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, const lipc::charbuf &blob_name, - ConstBlobData &data, + const Blob &data, lipc::vector &buffers) { lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); @@ -227,6 +235,50 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, return blob_id; } +/** + * Partially (or fully) Put a blob from a bucket. Load the blob from the + * I/O backend if it does not exist. + * + * @param blob_name the semantic name of the blob + * @param blob the buffer to put final data in + * @param blob_off the offset within the blob to begin the Put + * @param backend_off the offset to read from the backend if blob DNE + * @param backend_size the size to read from the backend if blob DNE + * @param backend_ctx which adapter to route I/O request if blob DNE + * @param ctx any additional information + * */ +Status MetadataManager::LocalPartialPutOrCreateBlob(BucketId bkt_id, + lipc::string blob_name, + Blob &blob, + size_t blob_off, + size_t backend_off, + size_t backend_size, + BlobId &blob_id, + IoClientContext &backend_ctx, + Context &ctx) { + Blob full_blob; + Bucket bkt(bkt_id, ctx); + lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); + auto iter = blob_id_map_->find(internal_blob_name); + if (blob_off == 0 && blob.size() == backend_size) { + // Put the entire blob, no need to load from storage + return bkt.Put(blob_name.str(), blob, blob_id, ctx); + } + if (iter != blob_id_map_->end()) { + // Read blob from Hermes + bkt.Get(blob_id, full_blob, ctx); + } else { + // Read blob using adapter + auto adapter = AdapterFactory::Get(backend_ctx.type_); + adapter->ReadBlobFromBackend(full_blob, backend_off, + backend_size, backend_ctx); + } + // Modify the blob + memcpy(full_blob.data() + blob_off, blob.data(), blob.size()); + // Re-put the blob + bkt.Put(blob_name.str(), full_blob, blob_id, ctx); +} + /** * Get \a blob_name blob from \a bkt_id bucket * diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 6b248cb14..8dc8f9731 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -11,9 +11,16 @@ #include "rpc.h" #include "metadata_types.h" #include "rpc_thallium_serialization.h" +#include "adapter/adapter_factory/abstract_adapter.h" namespace hermes { +/** Namespace simplification for IoClientContext */ +using hermes::adapter::IoClientContext; + +/** Namespace simplification for AbstractAdapter */ +using hermes::adapter::AbstractAdapter; + /** Forward declaration of borg */ class BufferOrganizer; @@ -170,9 +177,49 @@ class MetadataManager { * */ RPC BlobId LocalBucketPutBlob(BucketId bkt_id, const lipc::charbuf &blob_name, - ConstBlobData &data, + const Blob &data, lipc::vector &buffers); + /** + * Partially (or fully) Put a blob from a bucket. Load the blob from the + * I/O backend if it does not exist. + * + * @param blob_name the semantic name of the blob + * @param blob the buffer to put final data in + * @param blob_off the offset within the blob to begin the Put + * @param backend_off the offset to read from the backend if blob DNE + * @param backend_size the size to read from the backend if blob DNE + * @param backend_ctx which adapter to route I/O request if blob DNE + * @param ctx any additional information + * */ + Status LocalPartialPutOrCreateBlob(BucketId bkt_id, + lipc::string blob_name, + Blob &blob, + size_t blob_off, + size_t backend_off, + size_t backend_size, + BlobId &blob_id, + IoClientContext &backend_ctx, + Context &ctx); + + /** + * Modify part of a blob. Load the blob from a backend if it does not + * exist. + * + * @param bkt_id id of the bucket + * @param blob_name semantic blob name + * @param data the data being placed + * @param buffers the buffers to place data in + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ + RPC BlobId LocalBucketPartialPutOrCreateBlob( + BucketId bkt_id, + const lipc::charbuf &blob_name, + const Blob &data, + lipc::vector &buffers); + /** * Get a blob from a bucket * diff --git a/src/metadata_types.h b/src/metadata_types.h index 4afd92ed2..56b612397 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -143,6 +143,10 @@ struct BlobInfo : public lipc::ShmContainer { lipc::mptr name_; /// The BufferInfo vector lipc::mptr> buffers_; + /// Synchronize access to blob + Mutex lock_; + /// Ensure that operations belonging to a transaction are not locked forever + TransactionId transaction_; /** Default constructor. Does nothing. */ BlobInfo() = default; diff --git a/src/singleton.h b/src/singleton.h index 5a287f727..8e62acd76 100644 --- a/src/singleton.h +++ b/src/singleton.h @@ -39,5 +39,32 @@ class Singleton { } }; +/** + * A class to represent singleton pattern + * Does not require specific initialization of the static veraible + * */ +template +class EasySingleton { + protected: + /** static instance. */ + static std::unique_ptr instance; + + public: + /** + * Uses unique pointer to build a static global instance of variable. + * @tparam T + * @return instance of T + */ + static T* GetInstance() { + if (instance == nullptr) { + instance = std::make_unique(); + } + return instance.get(); + } +}; + +template +std::unique_ptr EasySingleton::instance = nullptr; + } // namespace hermes #endif // HERMES_ADAPTER_SINGLETON_H diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e4b833c93..0c2b524e1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,6 +5,7 @@ include_directories( ${PROJECT_SOURCE_DIR}/src/api ${PROJECT_SOURCE_DIR}/gotcha_intercept ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR} ${HERMES_INCLUDES_BUILD_TIME} ) diff --git a/test/test_bucket.cc b/test/test_bucket.cc index a015969dc..51fa0d534 100644 --- a/test/test_bucket.cc +++ b/test/test_bucket.cc @@ -41,7 +41,7 @@ void TestManyPuts(hapi::Hermes *hermes) { hermes::Blob blob(blob_size); std::string name = std::to_string(i); char nonce = i % 256; - memset(blob.data_mutable(), nonce, blob_size); + memset(blob.data(), nonce, blob_size); bkt->Put(name, std::move(blob), blob_id, ctx); } @@ -63,7 +63,7 @@ void TestBlobOverride(hapi::Hermes *hermes) { hermes::BlobId blob_id; hermes::Blob blob(1024); for (size_t i = 0; i < 1024; ++i) { - memset(blob.data_mutable(), 10, 1024); + memset(blob.data(), 10, 1024); bkt2->Put("0", std::move(blob), blob_id, ctx); hermes::Blob ret; bkt->Get(blob_id, ret, ctx); @@ -94,7 +94,7 @@ void TestBucketDestroy(hapi::Hermes *hermes) { hermes::Blob blob(blob_size); std::string name = std::to_string(i); char nonce = i % 256; - memset(blob.data_mutable(), nonce, blob_size); + memset(blob.data(), nonce, blob_size); bkt->Put(name, std::move(blob), blob_id, ctx); } From 3558b705c90790854852a77da5fbb9f08ef2041f Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 1 Feb 2023 23:26:48 -0600 Subject: [PATCH 093/511] Begin fixing singleton compile issues --- CMakeLists.txt | 2 +- adapter/CMakeLists.txt | 37 ++++- adapter/adapter_init.cc | 24 ++++ adapter/adapter_utils.h | 20 --- adapter/filesystem/CMakeLists.txt | 24 +++- adapter/filesystem/file.h | 66 +++++++++ adapter/filesystem/filesystem.cc | 57 ++++---- adapter/filesystem/filesystem.h | 125 +++++++++-------- adapter/filesystem/filesystem_io_client.h | 75 ++++++++-- ..._metadata_manager.cc => filesystem_mdm.cc} | 33 ++--- ...fs_metadata_manager.h => filesystem_mdm.h} | 30 ++-- .../filesystem/filesystem_mdm_singleton.cc | 5 + ...os.h => filesystem_mdm_singleton_macros.h} | 2 +- .../fs_metadata_manager_singleton.cc | 4 - adapter/interceptor.h | 35 +++++ adapter/io_client/CMakeLists.txt | 18 +-- adapter/io_client/io_client.h | 33 +++-- adapter/io_client/io_client_factory.h | 4 +- adapter/mpiio/fs_api.cc | 10 +- adapter/mpiio/fs_api.h | 16 +-- adapter/mpiio/mpiio.cc | 48 +++---- adapter/posix/CMakeLists.txt | 34 ++--- adapter/posix/posix.cc | 87 ++++++------ adapter/posix/posix_api.h | 4 +- adapter/posix/posix_api_singleton.cc | 4 + ..._macros.h => posix_api_singleton_macros.h} | 4 +- adapter/posix/posix_fs_api.h | 36 ++++- adapter/posix/posix_io_client.cc | 131 ++++++++++-------- adapter/posix/posix_io_client.h | 47 ++++--- adapter/posix/posix_singleton.cc | 4 - adapter/stdio/fs_api.cc | 12 +- adapter/stdio/fs_api.h | 14 +- adapter/stdio/stdio.cc | 46 +++--- adapter/test/posix/posix_adapter_mpi_test.cpp | 8 +- adapter/test/posix/posix_adapter_test.cpp | 8 +- code_generators/singleton.py | 2 +- data_stager/stagers/posix_stager.cc | 2 +- src/CMakeLists.txt | 4 +- src/api/bucket.cc | 33 +++++ src/api/bucket.h | 5 +- src/api/hermes.cc | 1 + src/api/hermes.h | 36 ++++- src/borg_io_clients/borg_posix_client.h | 2 +- src/borg_io_clients/borg_ram_client.h | 2 +- src/config_client.h | 2 + src/hermes_types.h | 1 - src/metadata_manager.cc | 45 +++--- src/metadata_manager.h | 45 ++---- src/rpc_factory.h.in | 2 + src/singleton.cc | 2 +- src/singleton.h | 42 +++++- src/singleton_macros.h | 2 +- 52 files changed, 842 insertions(+), 493 deletions(-) create mode 100644 adapter/adapter_init.cc delete mode 100644 adapter/adapter_utils.h create mode 100644 adapter/filesystem/file.h rename adapter/filesystem/{fs_metadata_manager.cc => filesystem_mdm.cc} (70%) rename adapter/filesystem/{fs_metadata_manager.h => filesystem_mdm.h} (73%) create mode 100644 adapter/filesystem/filesystem_mdm_singleton.cc rename adapter/filesystem/{fs_metadata_manager_singleton_macros.h => filesystem_mdm_singleton_macros.h} (67%) delete mode 100644 adapter/filesystem/fs_metadata_manager_singleton.cc create mode 100644 adapter/interceptor.h create mode 100644 adapter/posix/posix_api_singleton.cc rename adapter/posix/{posix_singleton_macros.h => posix_api_singleton_macros.h} (53%) delete mode 100644 adapter/posix/posix_singleton.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ad54a3d6..1430282e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Release") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") message("This IS a release build") else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -v") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") message("This is NOT a release build") endif() diff --git a/adapter/CMakeLists.txt b/adapter/CMakeLists.txt index 3482b29ce..e7685540f 100644 --- a/adapter/CMakeLists.txt +++ b/adapter/CMakeLists.txt @@ -3,10 +3,43 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHERMES_PRELOAD -DHERMES_RPC_THALLIUM") set(HERMES_SRC_DIR ${CMAKE_SOURCE_DIR}/src) set(HERMES_ADAPTER_DIR ${CMAKE_SOURCE_DIR}/adapter) -include_directories(${CMAKE_SOURCE_DIR}/src) +include_directories(${CMAKE_SOURCE_DIR} HERMES_SRC_DIR HERMES_ADAPTER_DIR) if(HERMES_ENABLE_POSIX_ADAPTER) + add_subdirectory(io_client) add_subdirectory(filesystem) add_subdirectory(posix) - add_subdirectory(adapter_factory) endif() + +# Transparently Start Hermes in Client Mode +add_library(adapter_init ${CMAKE_CURRENT_SOURCE_DIR}/adapter_init.cc) +add_dependencies(adapter_init hermes) +target_link_libraries(adapter_init hermes) + +#----------------------------------------------------------------------------- +# Add Target(s) to CMake Install +#----------------------------------------------------------------------------- +install( + TARGETS + adapter_init + EXPORT + ${HERMES_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} +) + +#----------------------------------------------------------------------------- +# Export all exported targets to the build tree for use by parent project +#----------------------------------------------------------------------------- +set(HERMES_EXPORTED_LIBS + adapter_init + ${HERMES_EXPORTED_LIBS}) +if(NOT HERMES_EXTERNALLY_CONFIGURED) + EXPORT ( + TARGETS + ${HERMES_EXPORTED_LIBS} + FILE + ${HERMES_EXPORTED_TARGETS}.cmake + ) +endif() \ No newline at end of file diff --git a/adapter/adapter_init.cc b/adapter/adapter_init.cc new file mode 100644 index 000000000..99ce7cb81 --- /dev/null +++ b/adapter/adapter_init.cc @@ -0,0 +1,24 @@ +// +// Created by lukemartinlogan on 2/1/23. +// + +#ifndef HERMES_ADAPTER_GLOBAL_INIT_HERMES_H_ +#define HERMES_ADAPTER_GLOBAL_INIT_HERMES_H_ + +#include "hermes.h" + +/** Use C++ runtime to ensure Hermes starts and finalizes */ +struct TransparentInitHermes { + TransparentInitHermes() { + HERMES->Create(hermes::HermesType::kClient); + } + + ~TransparentInitHermes() { + HERMES->Finalize(); + } +}; + +/** Initialize Hermes transparently */ +TransparentInitHermes x; + +#endif // HERMES_ADAPTER_GLOBAL_INIT_HERMES_H_ diff --git a/adapter/adapter_utils.h b/adapter/adapter_utils.h deleted file mode 100644 index e2ee22ac4..000000000 --- a/adapter/adapter_utils.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// Created by lukemartinlogan on 1/19/23. -// - -#ifndef HERMES_ADAPTER_UTILS_H_ -#define HERMES_ADAPTER_UTILS_H_ - -namespace stdfs = std::experimental::filesystem; - -namespace hermes::adapter { - -#define HERMES_DECL(F) F - -bool IsTracked(int fd) { - -} - -} // namespace hermes::adapter - -#endif // HERMES_ADAPTER_UTILS_H_ diff --git a/adapter/filesystem/CMakeLists.txt b/adapter/filesystem/CMakeLists.txt index e44f79bdf..fbeb6c4be 100644 --- a/adapter/filesystem/CMakeLists.txt +++ b/adapter/filesystem/CMakeLists.txt @@ -4,20 +4,35 @@ include_directories( ${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) -# Create the POSIX Real API singleton +# Create the metadata manager singleton + FS base class add_library(hermes_fs_mdm_singleton SHARED - ${CMAKE_CURRENT_SOURCE_DIR}/fs_metadata_manager_singleton.cc) -add_dependencies(hermes_fs_mdm_singleton hermes) + ${CMAKE_CURRENT_SOURCE_DIR}/filesystem_mdm_singleton.cc) +add_dependencies(hermes_fs_mdm_singleton + hermes) target_link_libraries(hermes_fs_mdm_singleton - MPI::MPI_CXX hermes) + hermes + MPI::MPI_CXX) target_compile_options(hermes_fs_mdm_singleton PUBLIC -fPIC) +# Create the metadata manager singleton + FS base class +add_library(hermes_fs_base SHARED + ${CMAKE_CURRENT_SOURCE_DIR}/filesystem.cc) +add_dependencies(hermes_fs_base + hermes + hermes_fs_mdm_singleton) +target_link_libraries(hermes_fs_base + MPI::MPI_CXX + hermes + hermes_fs_mdm_singleton) +target_compile_options(hermes_fs_base PUBLIC -fPIC) + #----------------------------------------------------------------------------- # Add Target(s) to CMake Install #----------------------------------------------------------------------------- install( TARGETS hermes_fs_mdm_singleton + hermes_fs_base EXPORT ${HERMES_EXPORTED_TARGETS} LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} @@ -30,6 +45,7 @@ install( #----------------------------------------------------------------------------- set(HERMES_EXPORTED_LIBS hermes_fs_mdm_singleton + hermes_fs_base ${HERMES_EXPORTED_LIBS}) if(NOT HERMES_EXTERNALLY_CONFIGURED) EXPORT ( diff --git a/adapter/filesystem/file.h b/adapter/filesystem/file.h new file mode 100644 index 000000000..10a4c4ac1 --- /dev/null +++ b/adapter/filesystem/file.h @@ -0,0 +1,66 @@ +// +// Created by lukemartinlogan on 2/1/23. +// + +#ifndef HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_TYPES_H_ +#define HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_TYPES_H_ + +#include "adapter/io_client/io_client.h" + +namespace hermes::adapter::fs { + +/** A structure to represent file */ +struct File : public IoClientContext { + /** default constructor */ + File() = default; + + /** file constructor that copies \a old file */ + File(const File &old) { Copy(old); } + + /** file assignment operator that copies \a old file */ + File &operator=(const File &old) { + Copy(old); + return *this; + } + + /** copy \a old file */ + void Copy(const File &old) { + filename_ = old.filename_; + hermes_fd_ = old.hermes_fd_; + hermes_fh_ = old.hermes_fh_; + hermes_mpi_fh_ = old.hermes_mpi_fh_; + status_ = old.status_; + } + + /** file comparison operator */ + bool operator==(const File &other) const { + return (hermes_fd_ == other.hermes_fd_) && + (hermes_fh_ == other.hermes_fh_) && + (hermes_mpi_fh_ == other.hermes_mpi_fh_); + } + + /** return hash value of this class */ + std::size_t hash() const { + std::size_t result; + std::size_t h1 = std::hash{}(hermes_fd_); + std::size_t h2 = std::hash{}(hermes_fh_); + std::size_t h3 = std::hash{}(hermes_mpi_fh_); + result = h1 ^ h2 ^ h3; + return result; + } +}; + +} // hermes::adapter::fs + +namespace std { +/** A structure to represent hash */ +template <> +struct hash { + /** hash creator functor */ + std::size_t operator()(const hermes::adapter::fs::File &key) const { + return key.hash(); + } +}; +} // namespace std + +#endif // HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_TYPES_H_ diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index f657bcbe5..b38991796 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -10,14 +10,13 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "fs_metadata_manager_singleton_macros.h" +#include "filesystem_mdm_singleton_macros.h" #include "filesystem.h" #include "constants.h" #include "singleton.h" -#include "fs_metadata_manager.h" +#include "filesystem_mdm.h" #include "vbucket.h" #include "mapper/mapper_factory.h" -#include "io_client/io_client_factory.h" #include #include @@ -27,21 +26,27 @@ namespace stdfs = std::experimental::filesystem; namespace hermes::adapter::fs { File Filesystem::Open(AdapterStat &stat, const std::string &path) { - File f = _RealOpen(stat, path); + File f; + io_client_->RealOpen(f, stat, path); if (!f.status_) { return f; } Open(stat, f, path); return f; } void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { - auto io_client = IoClientFactory::Get(io_client_); - IoStatus status; - _InitFile(f); auto mdm = HERMES_FS_METADATA_MANAGER; stat.bkt_id_ = HERMES->GetBucket(path); - LOG(INFO) << "File not opened before by adapter" << std::endl; - io_client->StatObject(f, stat, status); - mdm->Create(f, stat); + std::pair exists = mdm->Find(f); + if (!exists.second) { + LOG(INFO) << "File not opened before by adapter" << std::endl; + auto stat_ptr = std::make_unique(stat); + FilesystemIoClientContext fs_ctx(&mdm->fs_mdm_, (void*)stat_ptr.get()); + io_client_->HermesOpen(f, stat, fs_ctx); + mdm->Create(f, stat_ptr); + } else { + LOG(INFO) << "File opened by adapter" << std::endl; + exists.first->UpdateTime(); + } } size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, @@ -65,16 +70,17 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, lipc::charbuf blob_name(p.CreateBlobName()); BlobId blob_id; size_t backend_start = p.page_ * kPageSize; - IoClientContext backend_ctx; + IoClientContext io_ctx; Context ctx; - backend_ctx.filename_ = filename; + io_ctx.filename_ = filename; bkt->PartialPutOrCreate(blob_name.str(), blob_wrap, p.blob_off_, backend_start, kPageSize, blob_id, - backend_ctx, + io_ctx, + opts, ctx); data_offset += p.blob_size_; } @@ -142,6 +148,7 @@ size_t Filesystem::Wait(uint64_t req_id) { size_t ret = req->return_future.get(); delete req; return ret;*/ + return 0; } void Filesystem::Wait(std::vector &req_ids, @@ -244,7 +251,7 @@ size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, return 0; } stat_exists = true; - return Write(f, stat, ptr, total_size, io_status, opts); + return Write(f, *stat, ptr, total_size, io_status, opts); } size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, @@ -257,7 +264,7 @@ size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, return 0; } stat_exists = true; - return Read(f, stat, ptr, total_size, io_status, opts); + return Read(f, *stat, ptr, total_size, io_status, opts); } size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, @@ -271,7 +278,7 @@ size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, } stat_exists = true; opts.seek_ = false; - return Write(f, stat, ptr, off, total_size, io_status, opts); + return Write(f, *stat, ptr, off, total_size, io_status, opts); } size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, @@ -285,7 +292,7 @@ size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, } stat_exists = true; opts.seek_ = false; - return Read(f, stat, ptr, off, total_size, io_status, opts); + return Read(f, *stat, ptr, off, total_size, io_status, opts); } HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, @@ -298,7 +305,7 @@ HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, return 0; } stat_exists = true; - return AWrite(f, stat, ptr, total_size, req_id, io_status, opts); + return AWrite(f, *stat, ptr, total_size, req_id, io_status, opts); } HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, @@ -311,7 +318,7 @@ HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, return 0; } stat_exists = true; - return ARead(f, stat, ptr, total_size, req_id, io_status, opts); + return ARead(f, *stat, ptr, total_size, req_id, io_status, opts); } HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, @@ -325,7 +332,7 @@ HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, } stat_exists = true; opts.seek_ = false; - return AWrite(f, stat, ptr, off, total_size, req_id, io_status, opts); + return AWrite(f, *stat, ptr, off, total_size, req_id, io_status, opts); } HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, @@ -339,7 +346,7 @@ HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, } stat_exists = true; opts.seek_ = false; - return ARead(f, stat, ptr, off, total_size, req_id, io_status, opts); + return ARead(f, *stat, ptr, off, total_size, req_id, io_status, opts); } off_t Filesystem::Seek(File &f, bool &stat_exists, @@ -351,7 +358,7 @@ off_t Filesystem::Seek(File &f, bool &stat_exists, return -1; } stat_exists = true; - return Seek(f, stat, whence, offset); + return Seek(f, *stat, whence, offset); } off_t Filesystem::Tell(File &f, bool &stat_exists) { @@ -362,7 +369,7 @@ off_t Filesystem::Tell(File &f, bool &stat_exists) { return -1; } stat_exists = true; - return Tell(f, stat); + return Tell(f, *stat); } int Filesystem::Sync(File &f, bool &stat_exists) { @@ -373,7 +380,7 @@ int Filesystem::Sync(File &f, bool &stat_exists) { return -1; } stat_exists = true; - return Sync(f, stat); + return Sync(f, *stat); } int Filesystem::Close(File &f, bool &stat_exists, bool destroy) { @@ -384,7 +391,7 @@ int Filesystem::Close(File &f, bool &stat_exists, bool destroy) { return -1; } stat_exists = true; - return Close(f, stat, destroy); + return Close(f, *stat, destroy); } } // namespace hermes::adapter::fs diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index effaa97e0..3553f375c 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -22,13 +22,19 @@ #include "traits.h" #include "bucket.h" #include "vbucket.h" +#include "hermes.h" + #include "adapter/io_client/io_client.h" -#include "fs_metadata_manager_singleton_macros.h" +#include "filesystem_io_client.h" +#include "file.h" namespace hapi = hermes::api; namespace hermes::adapter::fs { +/** The maximum length of a posix path */ +static inline const int kMaxPathLen = 4096; + /** The type of seek to perform */ enum class SeekMode { kNone = -1, @@ -37,9 +43,7 @@ enum class SeekMode { kEnd = SEEK_END }; -/** - A structure to represent adapter stat. -*/ +/** A structure to represent adapter statistics */ struct AdapterStat : public IoClientStat { std::shared_ptr bkt_id_; /**< bucket associated with the file */ /** VBucket for persisting data asynchronously. */ @@ -56,44 +60,6 @@ struct AdapterStat : public IoClientStat { } }; -/** A structure to represent file */ -struct File : public IoClientContext { - /** file constructor that copies \a old file */ - File(const File &old) { Copy(old); } - - /** file assignment operator that copies \a old file */ - File &operator=(const File &old) { - Copy(old); - return *this; - } - - /** copy \a old file */ - void Copy(const File &old) { - fd_ = old.fd_; - fh_ = old.fh_; - mpi_fh_ = old.mpi_fh_; - st_dev = old.st_dev; - st_ino = old.st_ino; - status_ = old.status_; - } - - /** file comparison operator */ - bool operator==(const File &old) const { - return (st_dev == old.st_dev) && (st_ino == old.st_ino) && - (mpi_fh_ == old.mpi_fh_); - } - - /** return hash value of this class */ - std::size_t hash() const { - std::size_t result; - std::size_t h1 = std::hash{}(st_dev); - std::size_t h2 = std::hash{}(st_ino); - std::size_t h3 = std::hash{}(mpi_fh_); - result = h1 ^ h2 ^ h3; - return result; - } -}; - /** A structure to represent IO options */ struct IoOptions : public IoClientOptions { hapi::PlacementPolicy dpe_; /**< data placement policy */ @@ -143,20 +109,14 @@ struct IoOptions : public IoClientOptions { } }; -/** A structure to represent Hermes request */ -struct HermesRequest { - std::future return_future; /**< future result of async op. */ - IoStatus io_status; /**< IO status */ -}; - /** A class to represent file system */ class Filesystem { public: - IoClientType io_client_; /**< The I/O client to use for I/O */ + FilesystemIoClient *io_client_; public: /** Constructor */ - explicit Filesystem(IoClientType io_client) : io_client_(io_client) {} + explicit Filesystem(FilesystemIoClient *io_client) : io_client_(io_client) {} /** open \a path */ File Open(AdapterStat &stat, const std::string &path); @@ -256,19 +216,64 @@ class Filesystem { int Sync(File &f, bool &stat_exists); /** close */ int Close(File &f, bool &stat_exists, bool destroy = true); -}; -} // namespace hermes::adapter::fs + public: + /** real open */ + void RealOpen(IoClientContext &f, + IoClientStat &stat, + const std::string &path) { + io_client_->RealOpen(f, stat, path); + } + + /** + * Called after real open. Allocates the Hermes representation of + * identifying file information, such as a hermes file descriptor + * and hermes file handler. These are not the same as POSIX file + * descriptor and STDIO file handler. + * */ + virtual void HermesOpen(IoClientContext &f, + IoClientStat &stat, + FilesystemIoClientContext &fs_mdm) { + io_client_->HermesOpen(f, stat, fs_mdm); + } -namespace std { -/** A structure to represent hash */ -template <> -struct hash { - /** hash creator functor */ - std::size_t operator()(const hermes::adapter::fs::File &key) const { - return key.hash(); + /** real sync */ + int RealSync(const IoClientContext &f, const AdapterStat &stat) { + return io_client_->RealSync(f, stat); + } + + /** real close */ + int RealClose(const IoClientContext &f, const AdapterStat &stat) { + return io_client_->RealClose(f, stat); + } + + public: + /** Whether or not \a path PATH is tracked by Hermes */ + static bool IsTracked(const std::string &path) { + if (!HERMES->IsInitialized()) { + return false; + } + stdfs::path stdfs_path(path); + // TODO(llogan): use weak_canonical for performance reasons + std::string abs_path = stdfs::canonical(stdfs_path); + auto &path_inclusions = HERMES->client_config_.path_inclusions_; + auto &path_exclusions = HERMES->client_config_.path_exclusions_; + // Check if path is included + for (const std::string &pth : path_inclusions) { + if (abs_path.rfind(pth) != std::string::npos) { + return true; + } + } + // Check if path is excluded + for (const std::string &pth : path_exclusions) { + if (abs_path.rfind(pth) != std::string::npos) { + return false; + } + } + return true; } }; -} // namespace std + +} // namespace hermes::adapter::fs #endif // HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_H_ diff --git a/adapter/filesystem/filesystem_io_client.h b/adapter/filesystem/filesystem_io_client.h index 4000b8a1b..f1b0bc3ca 100644 --- a/adapter/filesystem/filesystem_io_client.h +++ b/adapter/filesystem/filesystem_io_client.h @@ -5,31 +5,80 @@ #ifndef HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_IO_CLIENT_H_ #define HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_IO_CLIENT_H_ -#include "io_client/io_client.h" +#include "adapter/io_client/io_client.h" +#include +#include + +namespace stdfs = std::experimental::filesystem; namespace hermes::adapter::fs { +/** + * Metadta required by Filesystem I/O clients to perform a HermesOpen + * */ +struct FsIoClientMetadata { + int hermes_fd_min_, hermes_fd_max_; /**< Min and max fd values (inclusive)*/ + std::atomic hermes_fd_cur_; /**< Current fd */ + + /** Default constructor */ + FsIoClientMetadata() { + // TODO(llogan): Recycle old fds + hermes_fd_min_ = 8192; // TODO(llogan): don't assume 8192 + hermes_fd_max_ = std::numeric_limits::max(); + } +}; + +/** + * State required by Filesystem I/O clients to perform a HermesOpen + * */ +struct FilesystemIoClientContext { + /** + * A pointer to the FsIoClientMetadata stored in the Filesystem + * */ + FsIoClientMetadata *mdm_; + + /** + * A pointer to the Adapter Stat object. Used by STDIO + MPI-IO to + * represent the hermes_fh_ and hermes_mpi_fh_ fields. + * */ + void *stat_; + + /** Default constructor */ + FilesystemIoClientContext(FsIoClientMetadata *mdm, void *stat) + : mdm_(mdm), stat_(stat) {} +}; + +/** + * Defines I/O clients which are compatible with the filesystem + * base class. + * */ class FilesystemIoClient : public IoClient { public: + /** virtual destructor */ virtual ~FilesystemIoClient() = default; - public: - /** initialize file */ - virtual void _InitFile(IoClientContext &f) = 0; - - private: - /** Initialize an opened file's statistics */ - virtual void _OpenInitStats(IoClientContext &f, IoClientStat &stat) = 0; - /** real open */ - virtual IoClientContext _RealOpen(IoClientStat &stat, - const std::string &path) = 0; + virtual void RealOpen(IoClientContext &f, + IoClientStat &stat, + const std::string &path) = 0; + + /** + * Called after real open. Allocates the Hermes representation of + * identifying file information, such as a hermes file descriptor + * and hermes file handler. These are not the same as POSIX file + * descriptor and STDIO file handler. + * */ + virtual void HermesOpen(IoClientContext &f, + const IoClientStat &stat, + FilesystemIoClientContext &fs_mdm) = 0; /** real sync */ - virtual int _RealSync(IoClientContext &f) = 0; + virtual int RealSync(const IoClientContext &f, + const IoClientStat &stat) = 0; /** real close */ - virtual int _RealClose(IoClientContext &f) = 0; + virtual int RealClose(const IoClientContext &f, + const IoClientStat &stat) = 0; }; } // namespace hermes::adapter::fs diff --git a/adapter/filesystem/fs_metadata_manager.cc b/adapter/filesystem/filesystem_mdm.cc similarity index 70% rename from adapter/filesystem/fs_metadata_manager.cc rename to adapter/filesystem/filesystem_mdm.cc index 3882d12b3..fe0538d0c 100644 --- a/adapter/filesystem/fs_metadata_manager.cc +++ b/adapter/filesystem/filesystem_mdm.cc @@ -10,7 +10,7 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "fs_metadata_manager.h" +#include "filesystem_mdm.h" #include "hermes.h" /** @@ -19,24 +19,10 @@ using hermes::adapter::fs::AdapterStat; using hermes::adapter::fs::MetadataManager; -void MetadataManager::InitializeHermes() { - if (!is_init_) { - lock_.lock(); - if (!is_init_) { - HERMES->Init(HermesType::kClient); - is_init_ = true; - } - lock_.unlock(); - } - - // TODO(llogan): Recycle old fds - hermes_fd_min_ = 8192; // TODO(llogan): don't assume 8192 - hermes_fd_max_ = INT_MAX; -} - -bool MetadataManager::Create(const File &f, const AdapterStat &stat) { +bool MetadataManager::Create(const File &f, + std::unique_ptr &stat) { VLOG(1) << "Create metadata for file handler." << std::endl; - auto ret = metadata.emplace(f, stat); + auto ret = metadata.emplace(f, std::move(stat)); return ret.second; } @@ -44,21 +30,20 @@ bool MetadataManager::Update(const File &f, const AdapterStat &stat) { VLOG(1) << "Update metadata for file handler." << std::endl; auto iter = metadata.find(f); if (iter != metadata.end()) { - metadata.erase(iter); - auto ret = metadata.emplace(f, stat); - return ret.second; + *(*iter).second = stat; + return true; } else { return false; } } -std::pair MetadataManager::Find(const File &f) { +std::pair MetadataManager::Find(const File &f) { typedef std::pair MetadataReturn; auto iter = metadata.find(f); if (iter == metadata.end()) - return MetadataReturn(AdapterStat(), false); + return std::pair(nullptr, false); else - return MetadataReturn(iter->second, true); + return std::pair(iter->second.get(), true); } bool MetadataManager::Delete(const File &f) { diff --git a/adapter/filesystem/fs_metadata_manager.h b/adapter/filesystem/filesystem_mdm.h similarity index 73% rename from adapter/filesystem/fs_metadata_manager.h rename to adapter/filesystem/filesystem_mdm.h index c207859db..1e496fd41 100644 --- a/adapter/filesystem/fs_metadata_manager.h +++ b/adapter/filesystem/filesystem_mdm.h @@ -15,43 +15,41 @@ #include #include +#include "file.h" +#include "filesystem_io_client.h" #include "filesystem.h" namespace hermes::adapter::fs { + /** * Metadata manager for POSIX adapter */ class MetadataManager { private: - std::unordered_map metadata; /**< Map for metadata*/ - int hermes_fd_min_, hermes_fd_max_; /**< Min and max fd values (inclusive)*/ - std::atomic hermes_fd_cur_; /**< Current fd */ - bool is_init_; /**< Whether hermes is initialized yet */ - std::mutex lock_; /**< Lock for init and metadata */ + std::unordered_map> + metadata; /**< Map for metadata*/ public: /** map for Hermes request */ std::unordered_map request_map; + std::mutex lock_; /**< Lock for metadata updates */ + FsIoClientMetadata fs_mdm_; /**< Context needed for I/O clients */ /** Constructor */ - MetadataManager() - : metadata(), is_init_(false) {} - - /** Initialize Hermes (thread-safe) */ - void InitializeHermes(); + MetadataManager() = default; /** - * Create a metadata entry for POSIX adapter for a given file handler. + * Create a metadata entry for filesystem adapters given File handler. * @param f original file handler of the file on the destination * filesystem. * @param stat POSIX Adapter version of Stat data structure. * @return true, if operation was successful. * false, if operation was unsuccessful. */ - bool Create(const File& f, const AdapterStat& stat); + bool Create(const File& f, std::unique_ptr &stat); /** - * Update existing metadata entry for POSIX adapter for a given file handler. + * Update existing metadata entry for filesystem adapters. * @param f original file handler of the file on the destination. * @param stat POSIX Adapter version of Stat data structure. * @return true, if operation was successful. @@ -60,7 +58,7 @@ class MetadataManager { bool Update(const File& f, const AdapterStat& stat); /** - * Delete existing metadata entry for POSIX adapter for a given file handler. + * Delete existing metadata entry for for filesystem adapters. * @param f original file handler of the file on the destination. * @return true, if operation was successful. * false, if operation was unsuccessful. @@ -68,12 +66,12 @@ class MetadataManager { bool Delete(const File& f); /** - * Find existing metadata entry for POSIX adapter for a given file handler. + * Find existing metadata entry for filesystem adapters. * @param f original file handler of the file on the destination. * @return The metadata entry if exist. * The bool in pair indicated whether metadata entry exists. */ - std::pair Find(const File& f); + std::pair Find(const File& f); }; } // namespace hermes::adapter::fs diff --git a/adapter/filesystem/filesystem_mdm_singleton.cc b/adapter/filesystem/filesystem_mdm_singleton.cc new file mode 100644 index 000000000..84f2de8ee --- /dev/null +++ b/adapter/filesystem/filesystem_mdm_singleton.cc @@ -0,0 +1,5 @@ +#include "singleton.h" + +#include "filesystem_mdm.h" +template<> hermes::adapter::fs::MetadataManager +hermes::GlobalSingleton::obj_; diff --git a/adapter/filesystem/fs_metadata_manager_singleton_macros.h b/adapter/filesystem/filesystem_mdm_singleton_macros.h similarity index 67% rename from adapter/filesystem/fs_metadata_manager_singleton_macros.h rename to adapter/filesystem/filesystem_mdm_singleton_macros.h index 3571b97c9..e2fd8fa82 100644 --- a/adapter/filesystem/fs_metadata_manager_singleton_macros.h +++ b/adapter/filesystem/filesystem_mdm_singleton_macros.h @@ -3,7 +3,7 @@ #include "singleton.h" -#define HERMES_FS_METADATA_MANAGER hermes::Singleton::GetInstance() +#define HERMES_FS_METADATA_MANAGER hermes::GlobalSingleton::GetInstance() #define HERMES_FS_METADATA_MANAGER_T hermes::adapter::fs::MetadataManager* #endif // HERMES_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/filesystem/fs_metadata_manager_singleton.cc b/adapter/filesystem/fs_metadata_manager_singleton.cc deleted file mode 100644 index 4aad8d872..000000000 --- a/adapter/filesystem/fs_metadata_manager_singleton.cc +++ /dev/null @@ -1,4 +0,0 @@ -#include "singleton.h" - -#include "fs_metadata_manager.h" -template<> std::unique_ptr hermes::Singleton::obj_ = nullptr; diff --git a/adapter/interceptor.h b/adapter/interceptor.h new file mode 100644 index 000000000..818bfcbbd --- /dev/null +++ b/adapter/interceptor.h @@ -0,0 +1,35 @@ +// +// Created by lukemartinlogan on 1/19/23. +// + +#ifndef HERMES_ADAPTER_UTILS_H_ +#define HERMES_ADAPTER_UTILS_H_ + +#include "hermes.h" +#include "adapter/filesystem/filesystem_mdm.h" +#include "adapter/filesystem/filesystem_mdm_singleton_macros.h" + +namespace stdfs = std::experimental::filesystem; + +namespace hermes::adapter { + +#define HERMES_DECL(F) F + +/** The maximum length of a POSIX path */ +static inline const int kMaxPathLen = 4096; + + +/** get the file name from \a fp file pointer */ +inline std::string GetFilenameFromFP(FILE* fp) { + char proclnk[kMaxPathLen]; + char filename[kMaxPathLen]; + int fno = fileno(fp); + snprintf(proclnk, kMaxPathLen, "/proc/self/fd/%d", fno); + size_t r = readlink(proclnk, filename, kMaxPathLen); + filename[r] = '\0'; + return filename; +} + +} // namespace hermes::adapter + +#endif // HERMES_ADAPTER_UTILS_H_ diff --git a/adapter/io_client/CMakeLists.txt b/adapter/io_client/CMakeLists.txt index 1b4a1dc31..0068a4664 100644 --- a/adapter/io_client/CMakeLists.txt +++ b/adapter/io_client/CMakeLists.txt @@ -1,11 +1,13 @@ # Add library to wrap around all adapter native APIs for use internally in Hermes -add_library(hermes_adapter_native +set(IO_CLIENT_LIBS + hermes_posix_io_client) +add_library(hermes_adapter_io_clients ${CMAKE_CURRENT_SOURCE_DIR}/empty.cc) -target_compile_options(hermes_adapter_native PUBLIC -fPIC) -add_dependencies(hermes_adapter_native - hermes_posix_fs) -target_link_libraries(hermes_adapter_native - hermes_posix_fs +target_compile_options(hermes_adapter_io_clients PUBLIC -fPIC) +add_dependencies(hermes_adapter_io_clients + ${IO_CLIENT_LIBS}) +target_link_libraries(hermes_adapter_io_clients + ${IO_CLIENT_LIBS} MPI::MPI_CXX glog::glog stdc++fs dl) #----------------------------------------------------------------------------- @@ -13,7 +15,7 @@ target_link_libraries(hermes_adapter_native #----------------------------------------------------------------------------- install( TARGETS - hermes_adapter_native + hermes_adapter_io_clients EXPORT ${HERMES_EXPORTED_TARGETS} LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} @@ -25,7 +27,7 @@ install( # Export all exported targets to the build tree for use by parent project #----------------------------------------------------------------------------- set(HERMES_EXPORTED_LIBS - hermes_adapter_native + hermes_adapter_io_clients ${HERMES_EXPORTED_LIBS}) if(NOT HERMES_EXTERNALLY_CONFIGURED) EXPORT ( diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index f2daff8df..81dd5686e 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -17,9 +17,9 @@ #ifndef HERMES_ABSTRACT_ADAPTER_H #define HERMES_ABSTRACT_ADAPTER_H -#include "utils.h" -#include "hermes_types.h" #include +#include "hermes_types.h" +#include namespace hermes::adapter { @@ -36,12 +36,11 @@ enum class IoClientType { struct IoClientContext { IoClientType type_; /**< Client to forward I/O request to */ std::string filename_; /**< Filename to read from */ - int fd_; /**< file descriptor */ - FILE *fh_; /**< file handler */ - MPI_File mpi_fh_; /**< MPI file handler */ - dev_t st_dev; /**< device */ - ino_t st_ino; /**< inode */ + int hermes_fd_; /**< fake file descriptor (SCRATCH MODE) */ + FILE *hermes_fh_; /**< fake file handler (SCRATCH MODE) */ + MPI_File hermes_mpi_fh_; /**< fake MPI file handler (SCRATCH MODE) */ + bool status_; /**< status */ int mpi_status_; /**< MPI status */ @@ -49,11 +48,9 @@ struct IoClientContext { IoClientContext() : type_(IoClientType::kNone), filename_(), - fd_(-1), - fh_(nullptr), - mpi_fh_(nullptr), - st_dev(-1), - st_ino(-1), + hermes_fd_(-1), + hermes_fh_(nullptr), + hermes_mpi_fh_(nullptr), status_(true), mpi_status_(MPI_SUCCESS) {} }; @@ -80,6 +77,10 @@ struct IoClientStat { timespec st_ctim_; /**< time of last status change */ std::string mode_str_; /**< mode used for fopen() */ + int fd_; /**< real file descriptor */ + FILE *fh_; /**< real STDIO file handler */ + MPI_File mpi_fh_; /**< real MPI file handler */ + bool is_append_; /**< File is in append mode */ int amode_; /**< access mode (MPI) */ MPI_Info info_; /**< Info object (handle) */ @@ -121,6 +122,12 @@ struct IoStatus { mpi_status_ptr_(&mpi_status_) {} }; +/** A structure to represent Hermes request */ +struct HermesRequest { + std::future return_future; /**< future result of async op. */ + IoStatus io_status; /**< IO status */ +}; + /** * A class to represent abstract I/O client. * Used internally by BORG and certain adapter classes. @@ -136,7 +143,6 @@ class IoClient { /** Write blob to backend */ virtual void WriteBlob(const Blob &full_blob, size_t backend_off, - size_t backend_size, const IoClientContext &io_ctx, const IoClientOptions &opts, IoStatus &status) = 0; @@ -144,7 +150,6 @@ class IoClient { /** Read blob from the backend */ virtual void ReadBlob(Blob &full_blob, size_t backend_off, - size_t backend_size, const IoClientContext &io_ctx, const IoClientOptions &opts, IoStatus &status) = 0; diff --git a/adapter/io_client/io_client_factory.h b/adapter/io_client/io_client_factory.h index 141dd69f2..1b32908aa 100644 --- a/adapter/io_client/io_client_factory.h +++ b/adapter/io_client/io_client_factory.h @@ -16,7 +16,7 @@ #include "io_client.h" #include "singleton.h" -#include "adapter/posix/posix_fs_api.h" +#include "adapter/posix/posix_io_client.h" namespace hermes::adapter { /** @@ -33,7 +33,7 @@ class IoClientFactory { static IoClient* Get(const IoClientType& type) { switch (type) { case IoClientType::kPosix: { - return HERMES_POSIX_FS; + return HERMES_POSIX_IO_CLIENT; } case IoClientType::kStdio: { return nullptr; diff --git a/adapter/mpiio/fs_api.cc b/adapter/mpiio/fs_api.cc index aff31e030..ff23a8f0d 100644 --- a/adapter/mpiio/fs_api.cc +++ b/adapter/mpiio/fs_api.cc @@ -500,7 +500,7 @@ int MpiioFS::SeekShared(File &f, bool &stat_exists, * Internal overrides * */ -File MpiioFS::_RealOpen(AdapterStat &stat, const std::string &path) { +File MpiioFS::RealOpen(AdapterStat &stat, const std::string &path) { File f; f.mpi_status_ = real_api->MPI_File_open(stat.comm, path.c_str(), stat.amode, stat.info, &f.mpi_fh_); @@ -516,7 +516,7 @@ File MpiioFS::_RealOpen(AdapterStat &stat, const std::string &path) { return f; } -void MpiioFS::_InitFile(File &f) { +void MpiioFS::InitFile(File &f) { // NOTE(llogan): MPI_Info_get does not behave well, so removing (void) f; /*struct stat st; @@ -528,7 +528,7 @@ void MpiioFS::_InitFile(File &f) { posix_api->close(fd);*/ } -void MpiioFS::_OpenInitStats(File &f, AdapterStat &stat) { +void MpiioFS::OpenInitStat(File &f, AdapterStat &stat) { MPI_Offset size = static_cast(stat.st_size); MPI_File_get_size(f.mpi_fh_, &size); stat.st_size = size; @@ -611,11 +611,11 @@ void MpiioFS::_IoStats(size_t count, IoStatus &io_status, IoOptions &opts) { io_status.mpi_status_ptr_->count_lo = count; } -int MpiioFS::_RealSync(File &f) { +int MpiioFS::RealSync(File &f) { return real_api->MPI_File_sync(f.mpi_fh_); } -int MpiioFS::_RealClose(File &f) { +int MpiioFS::RealClose(File &f) { return real_api->MPI_File_close(&f.mpi_fh_); } diff --git a/adapter/mpiio/fs_api.h b/adapter/mpiio/fs_api.h index 4819bafb3..bdf3245a0 100644 --- a/adapter/mpiio/fs_api.h +++ b/adapter/mpiio/fs_api.h @@ -63,16 +63,16 @@ class MpiioSeekModeConv { class MpiioFS : public hermes::adapter::fs::Filesystem { private: API *real_api; /**< pointer to real APIs */ - hermes::adapter::posix::API *posix_api; /**< pointer to POSIX APIs */ + hermes::adapter::fs::API *posix_api; /**< pointer to POSIX APIs */ public: MpiioFS() { real_api = Singleton::GetInstance(); - posix_api = Singleton::GetInstance(); + posix_api = Singleton::GetInstance(); } ~MpiioFS() = default; - void _InitFile(File &f) override; + void InitFile(File &f) override; public: /** get file name from \a fh MPI file pointer */ @@ -217,10 +217,10 @@ class MpiioFS : public hermes::adapter::fs::Filesystem { */ private: - /** OpenInitStats */ - void _OpenInitStats(File &f, AdapterStat &stat) override; + /** OpenInitStat */ + void OpenInitStat(File &f, AdapterStat &stat) override; /** RealOpen */ - File _RealOpen(AdapterStat &stat, const std::string &path) override; + File RealOpen(AdapterStat &stat, const std::string &path) override; /** RealWrite */ size_t _RealWrite(const std::string &filename, off_t offset, size_t size, const u8 *data_ptr, IoStatus &io_status, @@ -231,9 +231,9 @@ class MpiioFS : public hermes::adapter::fs::Filesystem { /** IoStats */ void _IoStats(size_t count, IoStatus &io_status, IoOptions &opts) override; /** RealSync */ - int _RealSync(File &f) override; + int RealSync(File &f) override; /** RealClose */ - int _RealClose(File &f) override; + int RealClose(File &f) override; }; } // namespace hermes::adapter::mpiio diff --git a/adapter/mpiio/mpiio.cc b/adapter/mpiio/mpiio.cc index 91c77f747..675c11dc4 100644 --- a/adapter/mpiio/mpiio.cc +++ b/adapter/mpiio/mpiio.cc @@ -50,7 +50,7 @@ inline bool IsTracked(MPI_File *fh) { if (hermes::adapter::exit) return false; auto mdm = Singleton::GetInstance(); auto fs_api = Singleton::GetInstance(); - File f; f.mpi_fh_ = (*fh); fs_api->_InitFile(f); + File f; f.mpi_fh_ = (*fh); fs_api->InitFile(f); auto [stat, exists] = mdm->Find(f); return exists; } @@ -119,7 +119,7 @@ int HERMES_DECL(MPI_File_close)(MPI_File *fh) { if (IsTracked(fh)) { File f; f.mpi_fh_ = *fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); return fs_api->Close(f, stat_exists); } return real_api->MPI_File_close(fh); @@ -132,7 +132,7 @@ int HERMES_DECL(MPI_File_seek)(MPI_File fh, MPI_Offset offset, int whence) { if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); return fs_api->Seek(f, stat_exists, offset, whence); } return real_api->MPI_File_seek(fh, offset, whence); @@ -148,7 +148,7 @@ int HERMES_DECL(MPI_File_seek_shared)(MPI_File fh, MPI_Offset offset, << " whence:" << whence << "." << std::endl; File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); return fs_api->SeekShared(f, stat_exists, offset, whence); } return real_api->MPI_File_seek_shared(fh, offset, whence); @@ -161,7 +161,7 @@ int HERMES_DECL(MPI_File_get_position)(MPI_File fh, MPI_Offset *offset) { if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); (*offset) = static_cast(fs_api->Tell(f, stat_exists)); return MPI_SUCCESS; } @@ -177,7 +177,7 @@ int HERMES_DECL(MPI_File_read_all)(MPI_File fh, void *buf, int count, LOG(INFO) << "Intercept MPI_File_read_all." << std::endl; File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); return fs_api->ReadAll(f, stat_exists, buf, count, datatype, status); } return real_api->MPI_File_read_all(fh, buf, count, datatype, status); @@ -191,7 +191,7 @@ int HERMES_DECL(MPI_File_read_at_all)(MPI_File fh, MPI_Offset offset, void *buf, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); return fs_api->ReadAll(f, stat_exists, buf, offset, count, datatype, status); } @@ -207,7 +207,7 @@ int HERMES_DECL(MPI_File_read_at)(MPI_File fh, MPI_Offset offset, void *buf, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); return fs_api->Read(f, stat_exists, buf, offset, count, datatype, status); } return real_api->MPI_File_read_at(fh, offset, buf, count, datatype, status); @@ -220,7 +220,7 @@ int HERMES_DECL(MPI_File_read)(MPI_File fh, void *buf, int count, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); int ret = fs_api->Read(f, stat_exists, buf, count, datatype, status); if (stat_exists) return ret; } @@ -235,7 +235,7 @@ int HERMES_DECL(MPI_File_read_ordered)(MPI_File fh, void *buf, int count, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); return fs_api->ReadOrdered(f, stat_exists, buf, count, datatype, status); } return real_api->MPI_File_read_ordered(fh, buf, count, datatype, status); @@ -250,7 +250,7 @@ int HERMES_DECL(MPI_File_read_shared)(MPI_File fh, void *buf, int count, LOG(INFO) << "Intercept MPI_File_read_shared." << std::endl; File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); return fs_api->Read(f, stat_exists, buf, count, datatype, status); } return real_api->MPI_File_read_shared(fh, buf, count, datatype, status); @@ -264,7 +264,7 @@ int HERMES_DECL(MPI_File_write_all)(MPI_File fh, const void *buf, int count, LOG(INFO) << "Intercept MPI_File_write_all." << std::endl; File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); int ret = fs_api->WriteAll(f, stat_exists, buf, count, datatype, status); if (stat_exists) return ret; } @@ -280,7 +280,7 @@ int HERMES_DECL(MPI_File_write_at_all)(MPI_File fh, MPI_Offset offset, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); int ret = fs_api->WriteAll(f, stat_exists, buf, offset, count, datatype, status); if (stat_exists) return ret; @@ -298,7 +298,7 @@ int HERMES_DECL(MPI_File_write_at)(MPI_File fh, MPI_Offset offset, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); return fs_api->Write(f, stat_exists, buf, offset, count, datatype, status); } return real_api->MPI_File_write_at(fh, offset, buf, count, datatype, status); @@ -312,7 +312,7 @@ int HERMES_DECL(MPI_File_write)(MPI_File fh, const void *buf, int count, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); int ret = fs_api->Write(f, stat_exists, buf, count, datatype, status); if (stat_exists) return ret; } @@ -327,7 +327,7 @@ int HERMES_DECL(MPI_File_write_ordered)(MPI_File fh, const void *buf, int count, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); return fs_api->WriteOrdered(f, stat_exists, buf, count, datatype, status); } return real_api->MPI_File_write_ordered(fh, buf, count, datatype, status); @@ -342,7 +342,7 @@ int HERMES_DECL(MPI_File_write_shared)(MPI_File fh, const void *buf, int count, // NOTE(llogan): originally WriteOrdered File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); return fs_api->WriteOrdered(f, stat_exists, buf, count, datatype, status); } return real_api->MPI_File_write_shared(fh, buf, count, datatype, status); @@ -360,7 +360,7 @@ int HERMES_DECL(MPI_File_iread_at)(MPI_File fh, MPI_Offset offset, void *buf, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); fs_api->ARead(f, stat_exists, buf, offset, count, datatype, request); return MPI_SUCCESS; } @@ -374,7 +374,7 @@ int HERMES_DECL(MPI_File_iread)(MPI_File fh, void *buf, int count, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); fs_api->ARead(f, stat_exists, buf, count, datatype, request); } return real_api->MPI_File_iread(fh, buf, count, datatype, request); @@ -388,7 +388,7 @@ int HERMES_DECL(MPI_File_iread_shared)(MPI_File fh, void *buf, int count, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); fs_api->ARead(f, stat_exists, buf, count, datatype, request); return MPI_SUCCESS; } @@ -404,7 +404,7 @@ int HERMES_DECL(MPI_File_iwrite_at)(MPI_File fh, MPI_Offset offset, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); fs_api->AWrite(f, stat_exists, buf, offset, count, datatype, request); return MPI_SUCCESS; } @@ -420,7 +420,7 @@ int HERMES_DECL(MPI_File_iwrite)(MPI_File fh, const void *buf, int count, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); fs_api->AWrite(f, stat_exists, buf, count, datatype, request); return MPI_SUCCESS; } @@ -435,7 +435,7 @@ int HERMES_DECL(MPI_File_iwrite_shared)(MPI_File fh, const void *buf, int count, if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); fs_api->AWriteOrdered(f, stat_exists, buf, count, datatype, request); return MPI_SUCCESS; } @@ -452,7 +452,7 @@ int HERMES_DECL(MPI_File_sync)(MPI_File fh) { if (IsTracked(&fh)) { File f; f.mpi_fh_ = fh; - fs_api->_InitFile(f); + fs_api->InitFile(f); fs_api->Sync(f, stat_exists); return 0; } diff --git a/adapter/posix/CMakeLists.txt b/adapter/posix/CMakeLists.txt index 56ca14ea7..3d6ee71d3 100644 --- a/adapter/posix/CMakeLists.txt +++ b/adapter/posix/CMakeLists.txt @@ -4,24 +4,26 @@ include_directories( ${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) -# Create the POSIX Real API singleton -add_library(hermes_posix_singleton SHARED ${CMAKE_CURRENT_SOURCE_DIR}/posix_singleton.cc) -target_compile_options(hermes_posix_singleton PUBLIC -fPIC) - -# Add library hermes_posix_fs -add_library(hermes_posix_fs ${CMAKE_CURRENT_SOURCE_DIR}/posix_fs_api.cc) -target_compile_options(hermes_posix_fs PUBLIC -fPIC) -add_dependencies(hermes_posix_fs - hermes hermes_posix_singleton hermes_fs_mdm_singleton) -target_link_libraries(hermes_posix_fs - hermes hermes_posix_singleton hermes_fs_mdm_singleton +# Creates the POSIX I/O client and singleton +add_library(hermes_posix_io_client + ${CMAKE_CURRENT_SOURCE_DIR}/posix_api_singleton.cc + ${CMAKE_CURRENT_SOURCE_DIR}/posix_io_client.cc) +target_compile_options(hermes_posix_io_client PUBLIC -fPIC) +target_link_libraries(hermes_posix_io_client MPI::MPI_CXX glog::glog stdc++fs dl) # Create the POSIX interceptor add_library(hermes_posix SHARED ${CMAKE_CURRENT_SOURCE_DIR}/posix.cc) -add_dependencies(hermes_posix hermes hermes_posix_singleton) +add_dependencies(hermes_posix + hermes + hermes_posix_io_client + hermes_fs_base + adapter_init) target_link_libraries(hermes_posix - hermes hermes_posix_singleton hermes_posix_fs) + hermes + hermes_posix_io_client + hermes_fs_base + adapter_init) target_compile_options(hermes_posix PUBLIC -fPIC) #----------------------------------------------------------------------------- @@ -29,8 +31,7 @@ target_compile_options(hermes_posix PUBLIC -fPIC) #----------------------------------------------------------------------------- install( TARGETS - hermes_posix_singleton - hermes_posix_fs + hermes_posix_io_client hermes_posix EXPORT ${HERMES_EXPORTED_TARGETS} @@ -43,8 +44,7 @@ install( # Export all exported targets to the build tree for use by parent project #----------------------------------------------------------------------------- set(HERMES_EXPORTED_LIBS - hermes_posix_singleton - hermes_posix_fs + hermes_posix_io_client hermes_posix ${HERMES_EXPORTED_LIBS}) if(NOT HERMES_EXTERNALLY_CONFIGURED) diff --git a/adapter/posix/posix.cc b/adapter/posix/posix.cc index 6fbf45b82..f60c48e15 100644 --- a/adapter/posix/posix.cc +++ b/adapter/posix/posix.cc @@ -21,16 +21,17 @@ bool posix_intercepted = true; #include "hermes_types.h" #include "singleton.h" -#include "adapter_utils.h" +#include "interceptor.h" + #include "posix_api.h" #include "posix_fs_api.h" -#include "posix_singleton_macros.h" +#include "posix_api_singleton_macros.h" #include "filesystem/filesystem.h" -using hermes::Singleton; using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::IoStatus; +using hermes::adapter::IoStatus; using hermes::adapter::fs::File; +using hermes::adapter::fs::SeekMode; namespace hapi = hermes::api; namespace stdfs = std::experimental::filesystem; @@ -50,13 +51,13 @@ int HERMES_DECL(open)(const char *path, int flags, ...) { mode = va_arg(arg, int); va_end(arg); } - if (hermes::adapter::IsTracked(path)) { + if (fs_api->IsTracked(path)) { LOG(INFO) << "Intercept open for filename: " << path << " and mode: " << flags << " is tracked." << std::endl; AdapterStat stat; stat.flags_ = flags; stat.st_mode_ = mode; - return fs_api->Open(stat, path).fd_; + return fs_api->Open(stat, path).hermes_fd_; } if (flags & O_CREAT || flags & O_TMPFILE) { return real_api->open(path, flags, mode); @@ -74,13 +75,13 @@ int HERMES_DECL(open64)(const char *path, int flags, ...) { mode = va_arg(arg, int); va_end(arg); } - if (hermes::adapter::IsTracked(path)) { + if (fs_api->IsTracked(path)) { LOG(INFO) << "Intercept open64 for filename: " << path << " and mode: " << flags << " is tracked." << std::endl; AdapterStat stat; stat.flags_ = flags; stat.st_mode_ = mode; - return fs_api->Open(stat, path).fd_; + return fs_api->Open(stat, path).hermes_fd_; } if (flags & O_CREAT) { return real_api->open64(path, flags, mode); @@ -91,13 +92,13 @@ int HERMES_DECL(open64)(const char *path, int flags, ...) { int HERMES_DECL(__open_2)(const char *path, int oflag) { auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(path)) { + if (fs_api->IsTracked(path)) { LOG(INFO) << "Intercept __open_2 for filename: " << path << " and mode: " << oflag << " is tracked." << std::endl; AdapterStat stat; stat.flags_ = oflag; stat.st_mode_ = 0; - return fs_api->Open(stat, path).fd_; + return fs_api->Open(stat, path).hermes_fd_; } return real_api->__open_2(path, oflag); } @@ -106,13 +107,13 @@ int HERMES_DECL(creat)(const char *path, mode_t mode) { std::string path_str(path); auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(path)) { + if (fs_api->IsTracked(path)) { LOG(INFO) << "Intercept creat for filename: " << path << " and mode: " << mode << " is tracked." << std::endl; AdapterStat stat; stat.flags_ = O_CREAT; stat.st_mode_ = mode; - return fs_api->Open(stat, path).fd_; + return fs_api->Open(stat, path).hermes_fd_; } return real_api->creat(path, mode); } @@ -121,13 +122,13 @@ int HERMES_DECL(creat64)(const char *path, mode_t mode) { std::string path_str(path); auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(path)) { + if (fs_api->IsTracked(path)) { LOG(INFO) << "Intercept creat64 for filename: " << path << " and mode: " << mode << " is tracked." << std::endl; AdapterStat stat; stat.flags_ = O_CREAT; stat.st_mode_ = mode; - return fs_api->Open(stat, path).fd_; + return fs_api->Open(stat, path).hermes_fd_; } return real_api->creat64(path, mode); } @@ -136,9 +137,9 @@ ssize_t HERMES_DECL(read)(int fd, void *buf, size_t count) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(fd)) { + if (fs_api->IsTracked(fd)) { LOG(INFO) << "Intercept read." << std::endl; - File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; + File f; f.hermes_fd_ = fd; IoStatus io_status; size_t ret = fs_api->Read(f, stat_exists, buf, count, io_status); if (stat_exists) return ret; } @@ -149,9 +150,9 @@ ssize_t HERMES_DECL(write)(int fd, const void *buf, size_t count) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(fd)) { + if (fs_api->IsTracked(fd)) { LOG(INFO) << "Intercept write." << std::endl; - File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; + File f; f.hermes_fd_ = fd; IoStatus io_status; size_t ret = fs_api->Write(f, stat_exists, buf, count, io_status); if (stat_exists) return ret; } @@ -162,9 +163,9 @@ ssize_t HERMES_DECL(pread)(int fd, void *buf, size_t count, off_t offset) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(fd)) { + if (fs_api->IsTracked(fd)) { LOG(INFO) << "Intercept pread." << std::endl; - File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; + File f; f.hermes_fd_ = fd; IoStatus io_status; size_t ret = fs_api->Read(f, stat_exists, buf, offset, count, io_status); if (stat_exists) return ret; } @@ -176,8 +177,8 @@ ssize_t HERMES_DECL(pwrite)(int fd, const void *buf, size_t count, bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(fd)) { - File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; + if (fs_api->IsTracked(fd)) { + File f; f.hermes_fd_ = fd; IoStatus io_status; LOG(INFO) << "Intercept pwrite." << std::endl; size_t ret = fs_api->Write(f, stat_exists, buf, offset, count, io_status); if (stat_exists) return ret; @@ -189,8 +190,8 @@ ssize_t HERMES_DECL(pread64)(int fd, void *buf, size_t count, off64_t offset) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(fd)) { - File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; + if (fs_api->IsTracked(fd)) { + File f; f.hermes_fd_ = fd; IoStatus io_status; LOG(INFO) << "Intercept pread64." << std::endl; size_t ret = fs_api->Read(f, stat_exists, buf, offset, count, io_status); if (stat_exists) return ret; @@ -203,8 +204,8 @@ ssize_t HERMES_DECL(pwrite64)(int fd, const void *buf, size_t count, bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(fd)) { - File f; f.fd_ = fd; fs_api->_InitFile(f); IoStatus io_status; + if (fs_api->IsTracked(fd)) { + File f; f.hermes_fd_ = fd; IoStatus io_status; LOG(INFO) << "Intercept pwrite." << std::endl; size_t ret = fs_api->Write(f, stat_exists, buf, offset, count, io_status); if (stat_exists) return ret; @@ -216,8 +217,8 @@ off_t HERMES_DECL(lseek)(int fd, off_t offset, int whence) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(fd)) { - File f; f.fd_ = fd; fs_api->_InitFile(f); + if (fs_api->IsTracked(fd)) { + File f; f.hermes_fd_ = fd; LOG(INFO) << "Intercept lseek offset:" << offset << " whence:" << whence << "." << std::endl; return fs_api->Seek(f, stat_exists, @@ -230,8 +231,8 @@ off64_t HERMES_DECL(lseek64)(int fd, off64_t offset, int whence) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(fd)) { - File f; f.fd_ = fd; fs_api->_InitFile(f); + if (fs_api->IsTracked(fd)) { + File f; f.hermes_fd_ = fd; LOG(INFO) << "Intercept lseek64 offset:" << offset << " whence:" << whence << "." << std::endl; return fs_api->Seek(f, stat_exists, @@ -244,13 +245,13 @@ int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { int result = 0; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(fd)) { - File f; f.fd_ = fd; fs_api->_InitFile(f); + if (fs_api->IsTracked(fd)) { + File f; f.hermes_fd_ = fd; LOG(INFO) << "Intercepted fstat." << std::endl; auto mdm = HERMES_FS_METADATA_MANAGER; auto existing = mdm->Find(f); if (existing.second) { - AdapterStat &astat = existing.first; + AdapterStat &astat = *existing.first; // TODO(chogan): st_dev and st_ino need to be assigned by us, but // currently we get them by calling the real fstat on open. buf->st_dev = 0; @@ -260,12 +261,12 @@ int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { buf->st_uid = astat.st_uid_; buf->st_gid = astat.st_gid_; buf->st_rdev = 0; - buf->st_size = astat.st_size_; - buf->st_blksize = astat.st_blksize_; + // buf->st_size = astat.st_size_; + // buf->st_blksize = astat.st_blksize_; buf->st_blocks = 0; - buf->st_atime = astat.st_atime_; - buf->st_mtime = astat.st_mtime_; - buf->st_ctime = astat.st_ctime_; + buf->st_atime = astat.st_atim_.tv_sec; + buf->st_mtime = astat.st_mtim_.tv_sec; + buf->st_ctime = astat.st_ctim_.tv_sec; } else { result = -1; errno = EBADF; @@ -282,8 +283,8 @@ int HERMES_DECL(fsync)(int fd) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(fd)) { - File f; f.fd_ = fd; fs_api->_InitFile(f); + if (fs_api->IsTracked(fd)) { + File f; f.hermes_fd_ = fd; LOG(INFO) << "Intercept fsync." << std::endl; return fs_api->Sync(f, stat_exists); } @@ -294,12 +295,12 @@ int HERMES_DECL(close)(int fd) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (hermes::adapter::IsTracked(fd)) { + if (fs_api->IsTracked(fd)) { LOG(INFO) << "Intercept close(" << std::to_string(fd) << ")"; - DLOG(INFO) << " -> " << hermes::adapter::GetFilenameFromFD(fd); + DLOG(INFO) << " -> " << fs_api->GetFilenameFromFD(fd); LOG(INFO) << std::endl; - File f; f.fd_ = fd; fs_api->_InitFile(f); + File f; f.hermes_fd_ = fd; return fs_api->Close(f, stat_exists); } return real_api->close(fd); diff --git a/adapter/posix/posix_api.h b/adapter/posix/posix_api.h index 1f22b94fa..6206d962c 100644 --- a/adapter/posix/posix_api.h +++ b/adapter/posix/posix_api.h @@ -47,7 +47,7 @@ typedef int (*fsync_t)(int fd); typedef int (*close_t)(int fd); } -namespace hermes::adapter::posix { +namespace hermes::adapter::fs { /** Pointers to the real posix API */ class PosixApi { @@ -185,7 +185,7 @@ class PosixApi { REQUIRE_API(close) } }; -} // namespace hermes::adapter::posix +} // namespace hermes::adapter::fs #undef REQUIRE_API diff --git a/adapter/posix/posix_api_singleton.cc b/adapter/posix/posix_api_singleton.cc new file mode 100644 index 000000000..139142750 --- /dev/null +++ b/adapter/posix/posix_api_singleton.cc @@ -0,0 +1,4 @@ +#include "singleton.h" + +#include "posix_api.h" +template<> hermes::adapter::fs::PosixApi hermes::GlobalSingleton::obj_; diff --git a/adapter/posix/posix_singleton_macros.h b/adapter/posix/posix_api_singleton_macros.h similarity index 53% rename from adapter/posix/posix_singleton_macros.h rename to adapter/posix/posix_api_singleton_macros.h index 5e4a2f148..4270c444a 100644 --- a/adapter/posix/posix_singleton_macros.h +++ b/adapter/posix/posix_api_singleton_macros.h @@ -3,7 +3,7 @@ #include "singleton.h" -#define HERMES_POSIX_API hermes::Singleton::GetInstance() -#define HERMES_POSIX_API_T hermes::adapter::posix::PosixApi* +#define HERMES_POSIX_API hermes::GlobalSingleton::GetInstance() +#define HERMES_POSIX_API_T hermes::adapter::fs::PosixApi* #endif // HERMES_POSIX_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/posix/posix_fs_api.h b/adapter/posix/posix_fs_api.h index 6bed31448..46fd7cff0 100644 --- a/adapter/posix/posix_fs_api.h +++ b/adapter/posix/posix_fs_api.h @@ -16,23 +16,45 @@ #include #include "adapter/filesystem/filesystem.h" -#include "adapter/filesystem/fs_metadata_manager.h" -#include "posix_singleton_macros.h" +#include "adapter/filesystem/filesystem_mdm.h" +#include "posix_api_singleton_macros.h" #include "posix_api.h" #include "posix_io_client.h" -namespace hermes::adapter::posix { +namespace hermes::adapter::fs { /** A class to represent POSIX IO file system */ class PosixFs : public hermes::adapter::fs::Filesystem { public: - PosixFs() : hermes::adapter::fs::Filesystem(IoClientType::kPosix) {} + PosixFs() : hermes::adapter::fs::Filesystem(HERMES_POSIX_IO_CLIENT) {} + + /** Whether or not \a fd FILE DESCRIPTOR was generated by Hermes */ + bool IsTracked(int fd) { + if (!HERMES->IsInitialized()) { + return false; + } + hermes::adapter::fs::File f; + f.hermes_fd_ = fd; + std::pair stat_pair = + HERMES_FS_METADATA_MANAGER->Find(f); + return stat_pair.second; + } + + /** get the file name from \a fd file descriptor */ + inline std::string GetFilenameFromFD(int fd) { + char proclnk[kMaxPathLen]; + char filename[kMaxPathLen]; + snprintf(proclnk, kMaxPathLen, "/proc/self/fd/%d", fd); + size_t r = readlink(proclnk, filename, kMaxPathLen); + filename[r] = '\0'; + return filename; + } }; /** Simplify access to the stateless PosixFs Singleton */ -#define HERMES_POSIX_FS hermes::EasySingleton::GetInstance() -#define HERMES_POSIX_FS_T hermes::adapter::posix::PosixFs* +#define HERMES_POSIX_FS hermes::EasySingleton::GetInstance() +#define HERMES_POSIX_FS_T hermes::adapter::fs::PosixFs* -} // namespace hermes::adapter::posix +} // namespace hermes::adapter::fs #endif // HERMES_ADAPTER_POSIX_NATIVE_H_ diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 41072fa88..74178e049 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -4,82 +4,97 @@ #include "posix_io_client.h" -namespace hermes::adapter::posix { +namespace hermes::adapter::fs { -IoClientContext PosixIoClient::_RealOpen(IoClientStat &stat, - const std::string &path) { - IoClientContext f; +/** Allocate an fd for the file f */ +void PosixIoClient::RealOpen(IoClientContext &f, + IoClientStat &stat, + const std::string &path) { if (stat.flags_ & O_CREAT || stat.flags_ & O_TMPFILE) { - f.fd_ = real_api->open(path.c_str(), stat.flags_, stat.st_mode_); + stat.fd_ = real_api->open(path.c_str(), stat.flags_, stat.st_mode_); } else { - f.fd_ = real_api->open(path.c_str(), stat.flags_); + stat.fd_ = real_api->open(path.c_str(), stat.flags_); } - if (f.fd_ < 0) { + if (stat.fd_ < 0) { f.status_ = false; } - _InitFile(f); - return f; -} - -void PosixIoClient::_InitFile(IoClientContext &f) { - struct stat st; - real_api->__fxstat(_STAT_VER, f.fd_, &st); - f.st_dev = st.st_dev; - f.st_ino = st.st_ino; -} - -void PosixIoClient::_OpenInitStats(IoClientContext &f, IoClientStat &stat) { - struct stat st; - real_api->__fxstat(_STAT_VER, f.fd_, &st); - stat.st_mode_ = st.st_mode; - stat.st_uid_ = st.st_uid; - stat.st_gid_ = st.st_gid; - // stat.st_size_ = st.st_size; - // stat.st_blksize_ = st.st_blksize; - stat.st_atim_ = st.st_atim; - stat.st_mtim_ = st.st_mtim; - stat.st_ctim_ = st.st_ctim; if (stat.flags_ & O_APPEND) { stat.is_append_ = true; } } -size_t PosixIoClient::WriteBlob(const std::string &filename, off_t offset, - size_t size, const u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) { - (void) opts; (void) io_status; - LOG(INFO) << "Writing to file: " << filename - << " offset: " << offset - << " size:" << size << "." - << " file_size:" << stdfs::file_size(filename) << std::endl; - int fd = real_api->open(filename.c_str(), O_RDWR | O_CREAT); - if (fd < 0) { return 0; } - size_t write_size = real_api->pwrite(fd, data_ptr, size, offset); +/** + * Called after real open. Allocates the Hermes representation of + * identifying file information, such as a hermes file descriptor + * and hermes file handler. These are not the same as POSIX file + * descriptor and STDIO file handler. + * */ +void PosixIoClient::HermesOpen(IoClientContext &f, + const IoClientStat &stat, + FilesystemIoClientContext &fs_mdm) { + +} + +/** Write blob to backend */ +void PosixIoClient::WriteBlob(const Blob &full_blob, + size_t backend_off, + const IoClientContext &io_ctx, + const IoClientOptions &opts, + IoStatus &status) { + (void) opts; + LOG(INFO) << "Writing to file: " << io_ctx.filename_ + << " offset: " << backend_off + << " size:" << full_blob.size() << "." + << " file_size:" << stdfs::file_size(io_ctx.filename_) + << std::endl; + int fd = real_api->open(io_ctx.filename_.c_str(), O_RDWR | O_CREAT); + if (fd < 0) { + status.posix_ret_ =0; + return; + } + status.posix_ret_ = real_api->pwrite(fd, + full_blob.data(), + full_blob.size(), + backend_off); real_api->close(fd); - return write_size; } -size_t PosixIoClient::ReadBlob(const std::string &filename, off_t offset, - size_t size, u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) { - (void) opts; (void) io_status; - LOG(INFO) << "Read called for filename from destination: " << filename - << " on offset: " << offset - << " and size: " << size << "." - << " file_size:" << stdfs::file_size(filename) << std::endl; - int fd = real_api->open(filename.c_str(), O_RDONLY); - if (fd < 0) { return 0; } - size_t read_size = real_api->pread(fd, data_ptr, size, offset); +/** Read blob from the backend */ +void PosixIoClient::ReadBlob(Blob &full_blob, + size_t backend_off, + const IoClientContext &io_ctx, + const IoClientOptions &opts, + IoStatus &status) { + (void) opts; + LOG(INFO) << "Writing to file: " << io_ctx.filename_ + << " offset: " << backend_off + << " size:" << full_blob.size() << "." + << " file_size:" << stdfs::file_size(io_ctx.filename_) + << std::endl; + int fd = real_api->open(io_ctx.filename_.c_str(), O_RDONLY); + if (fd < 0) { + status.posix_ret_ =0; + return; + } + status.posix_ret_ = real_api->pread(fd, + full_blob.data(), + full_blob.size(), + backend_off); real_api->close(fd); - return read_size; } -int PosixIoClient::_RealSync(IoClientContext &f) { - return real_api->fsync(f.fd_); +/** Synchronize \a file FILE f */ +int PosixIoClient::RealSync(const IoClientContext &f, + const IoClientStat &stat) { + (void) f; + return real_api->fsync(stat.fd_); } -int PosixIoClient::_RealClose(IoClientContext &f) { - return real_api->close(f.fd_); +/** Close \a file FILE f */ +int PosixIoClient::RealClose(const IoClientContext &f, + const IoClientStat &stat) { + (void) f; + return real_api->close(stat.fd_); } -} // namespace hermes::adapter::posix +} // namespace hermes::adapter::fs diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h index 477a53628..f8e816066 100644 --- a/adapter/posix/posix_io_client.h +++ b/adapter/posix/posix_io_client.h @@ -7,17 +7,17 @@ #include -#include "filesystem/filesystem_io_client.h" -#include "posix_singleton_macros.h" +#include "adapter/filesystem/filesystem_io_client.h" +#include "posix_api_singleton_macros.h" #include "posix_api.h" using hermes::Singleton; using hermes::adapter::IoClientStat; using hermes::adapter::IoClientOptions; using hermes::adapter::IoStatus; -using hermes::adapter::posix::PosixApi; +using hermes::adapter::fs::PosixApi; -namespace hermes::adapter::posix { +namespace hermes::adapter::fs { /** A class to represent POSIX IO file system */ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { @@ -32,13 +32,24 @@ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { virtual ~PosixIoClient() = default; public: - /** Initialize a file whose fd has already been allocated */ - void _InitFile(IoClientContext &f) override; + /** Allocate an fd for the file f */ + void RealOpen(IoClientContext &f, + IoClientStat &stat, + const std::string &path) override; + + /** + * Called after real open. Allocates the Hermes representation of + * identifying file information, such as a hermes file descriptor + * and hermes file handler. These are not the same as POSIX file + * descriptor and STDIO file handler. + * */ + void HermesOpen(IoClientContext &f, + const IoClientStat &stat, + FilesystemIoClientContext &fs_mdm) override; /** Write blob to backend */ void WriteBlob(const Blob &full_blob, size_t backend_off, - size_t backend_size, const IoClientContext &io_ctx, const IoClientOptions &opts, IoStatus &status) override; @@ -46,23 +57,23 @@ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { /** Read blob from the backend */ void ReadBlob(Blob &full_blob, size_t backend_off, - size_t backend_size, const IoClientContext &io_ctx, const IoClientOptions &opts, IoStatus &status) override; - private: - void _OpenInitStats(IoClientContext &f, IoClientStat &stat) override; - IoClientContext _RealOpen(IoClientStat &stat, - const std::string &path) override; - int _RealSync(IoClientContext &f) override; - int _RealClose(IoClientContext &f) override; + /** Synchronize \a file FILE f */ + int RealSync(const IoClientContext &f, + const IoClientStat &stat) override; + + /** Close \a file FILE f */ + int RealClose(const IoClientContext &f, + const IoClientStat &stat) override; }; -} // namespace hermes::adapter::posix +} // namespace hermes::adapter::fs -/** Simplify access to the stateless PosixFs Singleton */ -#define HERMES_POSIX_FS hermes::EasySingleton::GetInstance() -#define HERMES_POSIX_FS_T hermes::adapter::posix::PosixFs* +/** Simplify access to the stateless PosixIoClient Singleton */ +#define HERMES_POSIX_IO_CLIENT hermes::EasySingleton::GetInstance() +#define HERMES_POSIX_IO_CLIENT_T hermes::adapter::fs::PosixIoClient* #endif // HERMES_ADAPTER_POSIX_POSIX_IO_CLIENT_H_ diff --git a/adapter/posix/posix_singleton.cc b/adapter/posix/posix_singleton.cc deleted file mode 100644 index 6daba4137..000000000 --- a/adapter/posix/posix_singleton.cc +++ /dev/null @@ -1,4 +0,0 @@ -#include "singleton.h" - -#include "posix_api.h" -template<> std::unique_ptr hermes::Singleton::obj_ = nullptr; diff --git a/adapter/stdio/fs_api.cc b/adapter/stdio/fs_api.cc index 855bc6ad7..c386c294c 100644 --- a/adapter/stdio/fs_api.cc +++ b/adapter/stdio/fs_api.cc @@ -17,17 +17,17 @@ namespace hermes::adapter::stdio { -File StdioFS::_RealOpen(AdapterStat &stat, const std::string &path) { +File StdioFS::RealOpen(AdapterStat &stat, const std::string &path) { File f; f.fh_ = real_api->fopen(path.c_str(), stat.mode_str.c_str()); if (f.fh_ == nullptr) { f.status_ = false; } - _InitFile(f); + InitFile(f); return f; } -void StdioFS::_InitFile(File &f) { +void StdioFS::InitFile(File &f) { struct stat st; if (f.fh_ == nullptr) { f.fd_ = -1; @@ -39,7 +39,7 @@ void StdioFS::_InitFile(File &f) { f.st_ino = st.st_ino; } -void StdioFS::_OpenInitStats(File &f, AdapterStat &stat) { +void StdioFS::OpenInitStat(File &f, AdapterStat &stat) { struct stat st; posix_api->__fxstat(_STAT_VER, f.fd_, &st); stat.st_mode = st.st_mode; @@ -91,11 +91,11 @@ size_t StdioFS::_RealRead(const std::string &filename, off_t offset, return read_size; } -int StdioFS::_RealSync(File &f) { +int StdioFS::RealSync(File &f) { return real_api->fflush(f.fh_); } -int StdioFS::_RealClose(File &f) { +int StdioFS::RealClose(File &f) { return real_api->fclose(f.fh_); } diff --git a/adapter/stdio/fs_api.h b/adapter/stdio/fs_api.h index a10f3f418..a689b8e51 100644 --- a/adapter/stdio/fs_api.h +++ b/adapter/stdio/fs_api.h @@ -36,27 +36,27 @@ namespace hermes::adapter::stdio { class StdioFS : public hermes::adapter::fs::Filesystem { private: API *real_api; /**< pointer to real APIs */ - hermes::adapter::posix::API *posix_api; /**< pointer to POSIX APIs */ + hermes::adapter::fs::API *posix_api; /**< pointer to POSIX APIs */ public: StdioFS() { real_api = Singleton::GetInstance(); - posix_api = Singleton::GetInstance(); + posix_api = Singleton::GetInstance(); } ~StdioFS() = default; - void _InitFile(File &f) override; + void InitFile(File &f) override; private: - void _OpenInitStats(File &f, AdapterStat &stat) override; - File _RealOpen(AdapterStat &stat, const std::string &path) override; + void OpenInitStat(File &f, AdapterStat &stat) override; + File RealOpen(AdapterStat &stat, const std::string &path) override; size_t _RealWrite(const std::string &filename, off_t offset, size_t size, const u8 *data_ptr, IoStatus &io_status, IoOptions &opts) override; size_t _RealRead(const std::string &filename, off_t offset, size_t size, u8 *data_ptr, IoStatus &io_status, IoOptions &opts) override; - int _RealSync(File &f) override; - int _RealClose(File &f) override; + int RealSync(File &f) override; + int RealClose(File &f) override; }; } // namespace hermes::adapter::stdio diff --git a/adapter/stdio/stdio.cc b/adapter/stdio/stdio.cc index 4805cd5e4..a8e5d8305 100644 --- a/adapter/stdio/stdio.cc +++ b/adapter/stdio/stdio.cc @@ -77,7 +77,7 @@ FILE *reopen_internal(const std::string &user_path, const char *mode, File f; f.fh_ = ret; - fs_api->_InitFile(f); + fs_api->InitFile(f); std::string path_str = WeaklyCanonical(user_path).string(); LOG(INFO) << "Reopen file for filename " << path_str << " in mode " << mode << std::endl; @@ -131,7 +131,7 @@ FILE *HERMES_DECL(fdopen)(int fd, const char *mode) { std::string path_str = hermes::adapter::GetFilenameFromFD(fd); File f; f.fh_ = ret; - fs_api->_InitFile(f); + fs_api->InitFile(f); AdapterStat stat; stat.mode_str = mode; fs_api->Open(stat, f, path_str); @@ -166,7 +166,7 @@ int HERMES_DECL(fflush)(FILE *fp) { if (fp && hermes::adapter::IsTracked(fp)) { File f; f.fh_ = fp; - fs_api->_InitFile(f); + fs_api->InitFile(f); return fs_api->Sync(f, stat_exists); } return real_api->fflush(fp); @@ -180,7 +180,7 @@ int HERMES_DECL(fclose)(FILE *fp) { LOG(INFO) << "Intercepting fclose(" << fp << ")\n"; File f; f.fh_ = fp; - fs_api->_InitFile(f); + fs_api->InitFile(f); int ret = fs_api->Close(f, stat_exists); if (stat_exists) return ret; } @@ -197,7 +197,7 @@ size_t HERMES_DECL(fwrite)(const void *ptr, size_t size, size_t nmemb, << ", " << fp << ")\n"; File f; f.fh_ = fp; - fs_api->_InitFile(f); + fs_api->InitFile(f); IoStatus io_status; size_t ret = fs_api->Write(f, stat_exists, ptr, size * nmemb, io_status); if (stat_exists) { @@ -215,7 +215,7 @@ int HERMES_DECL(fputc)(int c, FILE *fp) { LOG(INFO) << "Intercepting fputc(" << c << ", " << fp << ")\n"; File f; f.fh_ = fp; - fs_api->_InitFile(f); + fs_api->InitFile(f); IoStatus io_status; fs_api->Write(f, stat_exists, &c, 1, io_status); if (stat_exists) { @@ -232,7 +232,7 @@ int HERMES_DECL(fgetpos)(FILE *fp, fpos_t *pos) { if (hermes::adapter::IsTracked(fp) && pos) { File f; f.fh_ = fp; - fs_api->_InitFile(f); + fs_api->InitFile(f); LOG(INFO) << "Intercept fgetpos." << std::endl; // TODO(chogan): @portability In the GNU C Library, fpos_t is an opaque // data structure that contains internal data to represent file offset and @@ -254,7 +254,7 @@ int HERMES_DECL(fgetpos64)(FILE *fp, fpos64_t *pos) { if (hermes::adapter::IsTracked(fp) && pos) { File f; f.fh_ = fp; - fs_api->_InitFile(f); + fs_api->InitFile(f); LOG(INFO) << "Intercept fgetpos64." << std::endl; // TODO(chogan): @portability In the GNU C Library, fpos_t is an opaque // data structure that contains internal data to represent file offset and @@ -276,7 +276,7 @@ int HERMES_DECL(putc)(int c, FILE *fp) { if (hermes::adapter::IsTracked(fp)) { File f; f.fh_ = fp; - fs_api->_InitFile(f); + fs_api->InitFile(f); IoStatus io_status; LOG(INFO) << "Intercept putc." << std::endl; fs_api->Write(f, stat_exists, &c, 1, io_status); @@ -295,7 +295,7 @@ int HERMES_DECL(putw)(int w, FILE *fp) { LOG(INFO) << "Intercept putw." << std::endl; File f; f.fh_ = fp; - fs_api->_InitFile(f); + fs_api->InitFile(f); IoStatus io_status; int ret = fs_api->Write(f, stat_exists, &w, sizeof(w), io_status); if (ret == sizeof(w)) { @@ -315,7 +315,7 @@ int HERMES_DECL(fputs)(const char *s, FILE *stream) { LOG(INFO) << "Intercept fputs." << std::endl; File f; f.fh_ = stream; - fs_api->_InitFile(f); + fs_api->InitFile(f); IoStatus io_status; int ret = fs_api->Write(f, stat_exists, s, strlen(s), io_status); if (stat_exists) { @@ -333,7 +333,7 @@ size_t HERMES_DECL(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream) { LOG(INFO) << "Intercept fread with size: " << size << "." << std::endl; File f; f.fh_ = stream; - fs_api->_InitFile(f); + fs_api->InitFile(f); IoStatus io_status; size_t ret = fs_api->Read(f, stat_exists, ptr, size * nmemb, io_status); if (stat_exists) { @@ -351,7 +351,7 @@ int HERMES_DECL(fgetc)(FILE *stream) { LOG(INFO) << "Intercept fgetc." << std::endl; File f; f.fh_ = stream; - fs_api->_InitFile(f); + fs_api->InitFile(f); IoStatus io_status; u8 value; fs_api->Read(f, stat_exists, &value, sizeof(u8), io_status); @@ -370,7 +370,7 @@ int HERMES_DECL(getc)(FILE *stream) { LOG(INFO) << "Intercept getc." << std::endl; File f; f.fh_ = stream; - fs_api->_InitFile(f); + fs_api->InitFile(f); IoStatus io_status; u8 value; fs_api->Read(f, stat_exists, &value, sizeof(u8), io_status); @@ -389,7 +389,7 @@ int HERMES_DECL(getw)(FILE *stream) { LOG(INFO) << "Intercept getw." << std::endl; File f; f.fh_ = stream; - fs_api->_InitFile(f); + fs_api->InitFile(f); IoStatus io_status; int value; fs_api->Read(f, stat_exists, &value, sizeof(int), io_status); @@ -408,7 +408,7 @@ char *HERMES_DECL(fgets)(char *s, int size, FILE *stream) { LOG(INFO) << "Intercept fgets." << std::endl; File f; f.fh_ = stream; - fs_api->_InitFile(f); + fs_api->InitFile(f); IoStatus io_status; size_t read_size = size - 1; size_t ret_size = fs_api->Read(f, stat_exists, s, read_size, io_status); @@ -443,7 +443,7 @@ void HERMES_DECL(rewind)(FILE *stream) { LOG(INFO) << "Intercept rewind." << std::endl; File f; f.fh_ = stream; - fs_api->_InitFile(f); + fs_api->InitFile(f); fs_api->Seek(f, stat_exists, SeekMode::kSet, 0); if (stat_exists) { return; @@ -461,7 +461,7 @@ int HERMES_DECL(fseek)(FILE *stream, long offset, int whence) { << "." << std::endl; File f; f.fh_ = stream; - fs_api->_InitFile(f); + fs_api->InitFile(f); off_t ret = fs_api->Seek(f, stat_exists, static_cast(whence), offset); if (stat_exists && ret > 0) { @@ -480,7 +480,7 @@ int HERMES_DECL(fseeko)(FILE *stream, off_t offset, int whence) { << "." << std::endl; File f; f.fh_ = stream; - fs_api->_InitFile(f); + fs_api->InitFile(f); off_t ret = fs_api->Seek(f, stat_exists, static_cast(whence), offset); if (stat_exists && ret > 0) { @@ -499,7 +499,7 @@ int HERMES_DECL(fseeko64)(FILE *stream, off64_t offset, int whence) { << "." << std::endl; File f; f.fh_ = stream; - fs_api->_InitFile(f); + fs_api->InitFile(f); off_t ret = fs_api->Seek(f, stat_exists, static_cast(whence), offset); if (stat_exists && ret > 0) { @@ -518,7 +518,7 @@ int HERMES_DECL(fsetpos)(FILE *stream, const fpos_t *pos) { LOG(INFO) << "Intercept fsetpos offset:" << offset << "." << std::endl; File f; f.fh_ = stream; - fs_api->_InitFile(f); + fs_api->InitFile(f); off_t ret = fs_api->Seek(f, stat_exists, SeekMode::kSet, offset); if (stat_exists && ret > 0) { return 0; @@ -536,7 +536,7 @@ int HERMES_DECL(fsetpos64)(FILE *stream, const fpos64_t *pos) { LOG(INFO) << "Intercept fsetpos64 offset:" << offset << "." << std::endl; File f; f.fh_ = stream; - fs_api->_InitFile(f); + fs_api->InitFile(f); off_t ret = fs_api->Seek(f, stat_exists, SeekMode::kSet, offset); if (stat_exists && ret > 0) { return 0; @@ -553,7 +553,7 @@ long int HERMES_DECL(ftell)(FILE *fp) { LOG(INFO) << "Intercept ftell." << std::endl; File f; f.fh_ = fp; - fs_api->_InitFile(f); + fs_api->InitFile(f); off_t ret = fs_api->Tell(f, stat_exists); if (stat_exists) { return ret; diff --git a/adapter/test/posix/posix_adapter_mpi_test.cpp b/adapter/test/posix/posix_adapter_mpi_test.cpp index 2dbdeeec0..cee4db946 100644 --- a/adapter/test/posix/posix_adapter_mpi_test.cpp +++ b/adapter/test/posix/posix_adapter_mpi_test.cpp @@ -31,7 +31,7 @@ namespace stdfs = std::experimental::filesystem; -namespace hermes::adapter::posix::test { +namespace hermes::adapter::fs::test { struct Arguments { std::string filename = "test.dat"; std::string directory = "/tmp"; @@ -63,10 +63,10 @@ struct Info { size_t medium_min = 4 * 1024 + 1, medium_max = 512 * 1024; size_t large_min = 512 * 1024 + 1, large_max = 3 * 1024 * 1024; }; -} // namespace hermes::adapter::posix::test +} // namespace hermes::adapter::fs::test -hermes::adapter::posix::test::Arguments args; -hermes::adapter::posix::test::Info info; +hermes::adapter::fs::test::Arguments args; +hermes::adapter::fs::test::Info info; std::vector gen_random(const int len) { std::vector tmp_s(len); static const char alphanum[] = diff --git a/adapter/test/posix/posix_adapter_test.cpp b/adapter/test/posix/posix_adapter_test.cpp index c57c0a402..c3db44787 100644 --- a/adapter/test/posix/posix_adapter_test.cpp +++ b/adapter/test/posix/posix_adapter_test.cpp @@ -30,7 +30,7 @@ namespace stdfs = std::experimental::filesystem; -namespace hermes::adapter::posix::test { +namespace hermes::adapter::fs::test { struct Arguments { std::string filename = "test.dat"; std::string directory = "/tmp"; @@ -57,9 +57,9 @@ struct Info { size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; }; -} // namespace hermes::adapter::posix::test -hermes::adapter::posix::test::Arguments args; -hermes::adapter::posix::test::Info info; +} // namespace hermes::adapter::fs::test +hermes::adapter::fs::test::Arguments args; +hermes::adapter::fs::test::Info info; std::vector gen_random(const int len) { auto tmp_s = std::vector(len); static const char alphanum[] = diff --git a/code_generators/singleton.py b/code_generators/singleton.py index 1b3695c9e..3c0705a3f 100644 --- a/code_generators/singleton.py +++ b/code_generators/singleton.py @@ -18,6 +18,6 @@ # POSIX RealAPI singleton gen = SingletonGenerator("ADAPTER", "\"singleton.h\"") -gen.add("hermes::adapter::posix", "PosixApi", "\"real_api.h\"") +gen.add("hermes::adapter::fs", "PosixApi", "\"real_api.h\"") gen.generate(f"{HERMES_ROOT}/adapter/posix/singleton.cc", f"{HERMES_ROOT}/adapter/posix/singleton_macros.h") \ No newline at end of file diff --git a/data_stager/stagers/posix_stager.cc b/data_stager/stagers/posix_stager.cc index 3c857e598..ee92b9d91 100644 --- a/data_stager/stagers/posix_stager.cc +++ b/data_stager/stagers/posix_stager.cc @@ -12,7 +12,7 @@ #include "posix_stager.h" -using hermes::adapter::posix::PosixFS; +using hermes::adapter::fs::PosixFS; using hermes::api::PlacementPolicyConv; using hermes::api::PlacementPolicy; using hermes::adapter::fs::IoOptions; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 173a48349..f69807ea1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -84,10 +84,10 @@ target_include_directories(hermes SYSTEM PUBLIC ${HERMES_EXT_INCLUDE_DEPENDENCIES} ) -add_dependencies(hermes hermes_posix_singleton) +add_dependencies(hermes hermes_adapter_io_clients) target_link_libraries(hermes - PUBLIC hermes_adapter_native + PUBLIC hermes_adapter_io_clients PUBLIC ${GLPK_LIBRARIES} PUBLIC ${CMAKE_HERMES_COMMUNICATION_TYPE_LIB} PUBLIC ${CMAKE_HERMES_RPC_TYPE_LIB} diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 0ea67b4e6..5fe707796 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -79,6 +79,39 @@ Status Bucket::Put(std::string blob_name, const Blob blob, return Status(); } +/** + * Put \a blob_name Blob into the bucket. Load the blob from the + * I/O backend if it does not exist. + * + * @param blob_name the semantic name of the blob + * @param blob the buffer to put final data in + * @param blob_off the offset within the blob to begin the Put + * @param backend_off the offset to read from the backend if blob DNE + * @param backend_size the size to read from the backend if blob DNE + * @param backend_ctx which adapter to route I/O request if blob DNE + * @param ctx any additional information + * */ +Status Bucket::PartialPutOrCreate(std::string blob_name, + const Blob &blob, + size_t blob_off, + size_t backend_off, + size_t backend_size, + BlobId &blob_id, + const IoClientContext &io_ctx, + const IoClientOptions &opts, + Context &ctx) { + mdm_->LocalBucketPartialPutOrCreateBlob( + id_, + lipc::string(blob_name), + blob, + blob_off, + backend_off, + backend_size, + io_ctx, + opts, + ctx); +} + /** * Get \a blob_id Blob from the bucket * */ diff --git a/src/api/bucket.h b/src/api/bucket.h index efa808dd4..f89dcfea3 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -8,7 +8,7 @@ #include "hermes_types.h" #include "status.h" #include "buffer_pool.h" -#include "adapter/adapter_factory/abstract_adapter.h" +#include "adapter/io_client/io_client_factory.h" namespace hermes::api { @@ -133,7 +133,8 @@ class Bucket { size_t backend_off, size_t backend_size, BlobId &blob_id, - IoClientContext &backend_ctx, + const IoClientContext &io_ctx, + const IoClientOptions &opts, Context &ctx); /** diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 57bd9558d..127c7a863 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -28,6 +28,7 @@ void Hermes::Init(HermesType mode, break; } } + is_initialized_ = true; } void Hermes::Finalize() { diff --git a/src/api/hermes.h b/src/api/hermes.h index d1d1101dc..98d6351f6 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -46,12 +46,19 @@ class Hermes { COMM_TYPE comm_; RPC_TYPE rpc_; lipc::Allocator *main_alloc_; + bool is_initialized_; public: - Hermes() = default; + /** Default constructor */ + Hermes() : is_initialized_(false) {} + /** Destructor */ ~Hermes() = default; + /** Whether or not Hermes is initialized */ + bool IsInitialized() { return is_initialized_; } + + /** Initialize Hermes explicitly */ static Hermes* Create(HermesType mode = HermesType::kClient, std::string server_config_path = "", std::string client_config_path = "") { @@ -60,46 +67,65 @@ class Hermes { return hermes; } - void Init(HermesType mode = HermesType::kClient, - std::string server_config_path = "", - std::string client_config_path = ""); - + public: + /** Finalize Hermes explicitly */ void Finalize(); + /** Run the Hermes core Daemon */ void RunDaemon(); + /** Stop the Hermes core Daemon */ void StopDaemon(); public: + /** Create a Bucket in Hermes */ std::shared_ptr GetBucket(std::string name, Context ctx = Context()); + + /** Create a VBucket in Hermes */ std::shared_ptr GetVBucket(std::string name, Context ctx = Context()); private: + /** Internal initialization of Hermes */ + void Init(HermesType mode = HermesType::kClient, + std::string server_config_path = "", + std::string client_config_path = ""); + + /** Initialize Hermes as a server */ void InitServer(std::string server_config_path); + /** Initialize Hermes as both a server and a daemon */ void InitColocated(std::string server_config_path, std::string client_config_path); + /** Initialize Hermes as a client to the daemon */ void InitClient(std::string server_config_path, std::string client_config_path); + /** Load the server-side configuration */ void LoadServerConfig(std::string config_path); + /** Load the client-side configuration */ void LoadClientConfig(std::string config_path); + /** Initialize shared-memory between daemon and client */ void InitSharedMemory(); + /** Connect to a Daemon's shared memory */ void LoadSharedMemory(); + /** Finalize Daemon mode */ void FinalizeServer(); + /** Finalize client mode */ void FinalizeClient(); + /** Finalize colocated mode */ void FinalizeColocated(); private: + /** Get an environment variable with null safety. */ inline std::string GetEnvSafe(const char *env_name) { char *val = getenv(env_name); if (val == nullptr){ diff --git a/src/borg_io_clients/borg_posix_client.h b/src/borg_io_clients/borg_posix_client.h index 1bc82d921..0a88c4a35 100644 --- a/src/borg_io_clients/borg_posix_client.h +++ b/src/borg_io_clients/borg_posix_client.h @@ -7,7 +7,7 @@ #include "borg_io_client.h" #include "adapter/posix/posix_api.h" -#include "adapter/posix/posix_singleton_macros.h" +#include "adapter/posix/posix_api_singleton_macros.h" #include diff --git a/src/borg_io_clients/borg_ram_client.h b/src/borg_io_clients/borg_ram_client.h index d72ba6664..29e69ef70 100644 --- a/src/borg_io_clients/borg_ram_client.h +++ b/src/borg_io_clients/borg_ram_client.h @@ -7,7 +7,7 @@ #include "borg_io_client.h" #include "adapter/posix/posix_api.h" -#include "adapter/posix/posix_singleton_macros.h" +#include "adapter/posix/posix_api_singleton_macros.h" #include "hermes.h" namespace hermes::borg { diff --git a/src/config_client.h b/src/config_client.h index 24cf1b9a6..bd21c71d9 100644 --- a/src/config_client.h +++ b/src/config_client.h @@ -16,6 +16,8 @@ class ClientConfig : public BaseConfig { public: bool stop_daemon_; size_t file_page_size_; + std::vector path_inclusions_; + std::vector path_exclusions_; public: ClientConfig() = default; diff --git a/src/hermes_types.h b/src/hermes_types.h index ad1c12c3d..5cce95b59 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -21,7 +21,6 @@ #include #include -#include "hermes_version.h" #include "data_structures.h" #include "constants.h" #include "singleton_macros.h" diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 585dbe096..9c346f89e 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -6,13 +6,9 @@ #include "metadata_manager.h" #include "buffer_organizer.h" #include "api/bucket.h" -#include "adapter/adapter_factory/adapter_factory.h" namespace hermes { -/** Namespace simplification for AdapterFactory */ -using hermes::adapter::AdapterFactory; - /** Namespace simplification for Bucket */ using api::Bucket; @@ -247,36 +243,53 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, * @param backend_ctx which adapter to route I/O request if blob DNE * @param ctx any additional information * */ -Status MetadataManager::LocalPartialPutOrCreateBlob(BucketId bkt_id, - lipc::string blob_name, - Blob &blob, - size_t blob_off, - size_t backend_off, - size_t backend_size, - BlobId &blob_id, - IoClientContext &backend_ctx, - Context &ctx) { +Status MetadataManager::LocalBucketPartialPutOrCreateBlob( + BucketId bkt_id, + const lipc::string &blob_name, + const Blob &blob, + size_t blob_off, + size_t backend_off, + size_t backend_size, + const IoClientContext &io_ctx, + const IoClientOptions &opts, + Context &ctx) { + + // Determine if the blob exists + BlobId blob_id; Blob full_blob; Bucket bkt(bkt_id, ctx); lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); auto iter = blob_id_map_->find(internal_blob_name); + + // Put the blob if (blob_off == 0 && blob.size() == backend_size) { + // Case 1: We're overriding the entire blob // Put the entire blob, no need to load from storage return bkt.Put(blob_name.str(), blob, blob_id, ctx); } if (iter != blob_id_map_->end()) { + // Case 2: The blob already exists (read from hermes) // Read blob from Hermes bkt.Get(blob_id, full_blob, ctx); } else { + // Case 3: The blob did not exist (need to read from backend) // Read blob using adapter - auto adapter = AdapterFactory::Get(backend_ctx.type_); - adapter->ReadBlobFromBackend(full_blob, backend_off, - backend_size, backend_ctx); + IoStatus status; + auto io_client = IoClientFactory::Get(io_ctx.type_); + full_blob.resize(backend_size); + io_client->ReadBlob(full_blob, + backend_off, + io_ctx, + opts, + status); } + // Ensure the blob can hold the update + full_blob.resize(std::max(full_blob.size(), blob_off + blob.size())); // Modify the blob memcpy(full_blob.data() + blob_off, blob.data(), blob.size()); // Re-put the blob bkt.Put(blob_name.str(), full_blob, blob_id, ctx); + return Status(); } /** diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 8dc8f9731..7ee58060a 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -11,15 +11,18 @@ #include "rpc.h" #include "metadata_types.h" #include "rpc_thallium_serialization.h" -#include "adapter/adapter_factory/abstract_adapter.h" +#include "adapter/io_client/io_client_factory.h" namespace hermes { +/** Namespace simplification for AdapterFactory */ +using hermes::adapter::IoClientFactory; + /** Namespace simplification for IoClientContext */ using hermes::adapter::IoClientContext; /** Namespace simplification for AbstractAdapter */ -using hermes::adapter::AbstractAdapter; +using hermes::adapter::IoClientOptions; /** Forward declaration of borg */ class BufferOrganizer; @@ -192,33 +195,15 @@ class MetadataManager { * @param backend_ctx which adapter to route I/O request if blob DNE * @param ctx any additional information * */ - Status LocalPartialPutOrCreateBlob(BucketId bkt_id, - lipc::string blob_name, - Blob &blob, - size_t blob_off, - size_t backend_off, - size_t backend_size, - BlobId &blob_id, - IoClientContext &backend_ctx, - Context &ctx); - - /** - * Modify part of a blob. Load the blob from a backend if it does not - * exist. - * - * @param bkt_id id of the bucket - * @param blob_name semantic blob name - * @param data the data being placed - * @param buffers the buffers to place data in - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm - * */ - RPC BlobId LocalBucketPartialPutOrCreateBlob( - BucketId bkt_id, - const lipc::charbuf &blob_name, - const Blob &data, - lipc::vector &buffers); + RPC Status LocalBucketPartialPutOrCreateBlob(BucketId bkt_id, + const lipc::string &blob_name, + const Blob &blob, + size_t blob_off, + size_t backend_off, + size_t backend_size, + const IoClientContext &io_ctx, + const IoClientOptions &opts, + Context &ctx); /** * Get a blob from a bucket @@ -229,7 +214,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - Blob LocalBucketGetBlob(BlobId blob_id); + RPC Blob LocalBucketGetBlob(BlobId blob_id); /** * Get \a blob_name blob from \a bkt_id bucket diff --git a/src/rpc_factory.h.in b/src/rpc_factory.h.in index 9f848ba47..76cc7ae74 100644 --- a/src/rpc_factory.h.in +++ b/src/rpc_factory.h.in @@ -5,7 +5,9 @@ #ifndef HERMES_SRC_RPC_FACTORY_H_ #define HERMES_SRC_RPC_FACTORY_H_ +#ifndef @CMAKE_HERMES_RPC_TYPE@ #define @CMAKE_HERMES_RPC_TYPE@ +#endif #if defined(HERMES_RPC_THALLIUM) #include "rpc_thallium.h" diff --git a/src/singleton.cc b/src/singleton.cc index 836f05fe3..38dd6dfdd 100644 --- a/src/singleton.cc +++ b/src/singleton.cc @@ -1,4 +1,4 @@ #include "singleton.h" #include -template<> std::unique_ptr hermes::Singleton::obj_ = nullptr; +template<> hermes::api::Hermes hermes::GlobalSingleton::obj_; diff --git a/src/singleton.h b/src/singleton.h index 8e62acd76..c434f754a 100644 --- a/src/singleton.h +++ b/src/singleton.h @@ -18,12 +18,12 @@ #include namespace hermes { + /** - * Make a class singleton when used with the class. format for class name T - * Singleton::GetInstance() + * Makes a singleton. Constructs the first time GetInstance is called. + * Requires user to define the static storage of obj_ in separate file. * @tparam T */ - template class Singleton { private: @@ -39,9 +39,24 @@ class Singleton { } }; +/** + * Makes a singleton. Constructs during initialization of program. + * Requires user to define the static storage of obj_ in separate file. + * */ +template +class GlobalSingleton { + private: + static T obj_; + public: + GlobalSingleton() = default; + static T* GetInstance() { + return &obj_; + } +}; + /** * A class to represent singleton pattern - * Does not require specific initialization of the static veraible + * Does not require specific initialization of the static variable * */ template class EasySingleton { @@ -62,9 +77,26 @@ class EasySingleton { return instance.get(); } }; - template std::unique_ptr EasySingleton::instance = nullptr; +/** + * Makes a singleton. Constructs during initialization of program. + * Does not require specific initialization of the static variable. + * */ +template +class EasyGlobalSingleton { + private: + static T obj_; + public: + EasyGlobalSingleton() = default; + static T* GetInstance() { + return &obj_; + } +}; +template +T EasyGlobalSingleton::obj_; + + } // namespace hermes #endif // HERMES_ADAPTER_SINGLETON_H diff --git a/src/singleton_macros.h b/src/singleton_macros.h index 221c7b84d..1095adf7b 100644 --- a/src/singleton_macros.h +++ b/src/singleton_macros.h @@ -3,7 +3,7 @@ #include "singleton.h" -#define HERMES hermes::Singleton::GetInstance() +#define HERMES hermes::GlobalSingleton::GetInstance() #define HERMES_T hermes::api::Hermes* #endif // HERMES_SINGLETON_SRC_MACROS_H From 57b600cb3ecc306f70f6f94df08991cffee34d6d Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 1 Feb 2023 23:48:54 -0600 Subject: [PATCH 094/511] adapters compiling again --- adapter/filesystem/filesystem.h | 2 +- .../filesystem/filesystem_mdm_singleton.cc | 2 +- adapter/posix/posix.cc | 32 +++++++++---------- adapter/posix/posix_api_singleton.cc | 2 +- adapter/posix/posix_fs_api.h | 4 +-- benchmarks/CMakeLists.txt | 1 + src/CMakeLists.txt | 2 +- src/{singleton.cc => api/hermes_singleton.cc} | 4 +-- .../hermes_singleton_macros.h} | 0 src/hermes_types.h | 2 +- test/CMakeLists.txt | 9 ++++-- 11 files changed, 33 insertions(+), 27 deletions(-) rename src/{singleton.cc => api/hermes_singleton.cc} (58%) rename src/{singleton_macros.h => api/hermes_singleton_macros.h} (100%) diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index 3553f375c..b44bb424c 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -249,7 +249,7 @@ class Filesystem { public: /** Whether or not \a path PATH is tracked by Hermes */ - static bool IsTracked(const std::string &path) { + static bool IsPathTracked(const std::string &path) { if (!HERMES->IsInitialized()) { return false; } diff --git a/adapter/filesystem/filesystem_mdm_singleton.cc b/adapter/filesystem/filesystem_mdm_singleton.cc index 84f2de8ee..42bfc8cdc 100644 --- a/adapter/filesystem/filesystem_mdm_singleton.cc +++ b/adapter/filesystem/filesystem_mdm_singleton.cc @@ -2,4 +2,4 @@ #include "filesystem_mdm.h" template<> hermes::adapter::fs::MetadataManager -hermes::GlobalSingleton::obj_; +hermes::GlobalSingleton::obj_ = hermes::adapter::fs::MetadataManager(); diff --git a/adapter/posix/posix.cc b/adapter/posix/posix.cc index f60c48e15..1dfe5ab22 100644 --- a/adapter/posix/posix.cc +++ b/adapter/posix/posix.cc @@ -51,7 +51,7 @@ int HERMES_DECL(open)(const char *path, int flags, ...) { mode = va_arg(arg, int); va_end(arg); } - if (fs_api->IsTracked(path)) { + if (fs_api->IsPathTracked(path)) { LOG(INFO) << "Intercept open for filename: " << path << " and mode: " << flags << " is tracked." << std::endl; AdapterStat stat; @@ -75,7 +75,7 @@ int HERMES_DECL(open64)(const char *path, int flags, ...) { mode = va_arg(arg, int); va_end(arg); } - if (fs_api->IsTracked(path)) { + if (fs_api->IsPathTracked(path)) { LOG(INFO) << "Intercept open64 for filename: " << path << " and mode: " << flags << " is tracked." << std::endl; AdapterStat stat; @@ -92,7 +92,7 @@ int HERMES_DECL(open64)(const char *path, int flags, ...) { int HERMES_DECL(__open_2)(const char *path, int oflag) { auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(path)) { + if (fs_api->IsPathTracked(path)) { LOG(INFO) << "Intercept __open_2 for filename: " << path << " and mode: " << oflag << " is tracked." << std::endl; AdapterStat stat; @@ -107,7 +107,7 @@ int HERMES_DECL(creat)(const char *path, mode_t mode) { std::string path_str(path); auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(path)) { + if (fs_api->IsPathTracked(path)) { LOG(INFO) << "Intercept creat for filename: " << path << " and mode: " << mode << " is tracked." << std::endl; AdapterStat stat; @@ -122,7 +122,7 @@ int HERMES_DECL(creat64)(const char *path, mode_t mode) { std::string path_str(path); auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(path)) { + if (fs_api->IsPathTracked(path)) { LOG(INFO) << "Intercept creat64 for filename: " << path << " and mode: " << mode << " is tracked." << std::endl; AdapterStat stat; @@ -137,7 +137,7 @@ ssize_t HERMES_DECL(read)(int fd, void *buf, size_t count) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(fd)) { + if (fs_api->IsFdTracked(fd)) { LOG(INFO) << "Intercept read." << std::endl; File f; f.hermes_fd_ = fd; IoStatus io_status; size_t ret = fs_api->Read(f, stat_exists, buf, count, io_status); @@ -150,7 +150,7 @@ ssize_t HERMES_DECL(write)(int fd, const void *buf, size_t count) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(fd)) { + if (fs_api->IsFdTracked(fd)) { LOG(INFO) << "Intercept write." << std::endl; File f; f.hermes_fd_ = fd; IoStatus io_status; size_t ret = fs_api->Write(f, stat_exists, buf, count, io_status); @@ -163,7 +163,7 @@ ssize_t HERMES_DECL(pread)(int fd, void *buf, size_t count, off_t offset) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(fd)) { + if (fs_api->IsFdTracked(fd)) { LOG(INFO) << "Intercept pread." << std::endl; File f; f.hermes_fd_ = fd; IoStatus io_status; size_t ret = fs_api->Read(f, stat_exists, buf, offset, count, io_status); @@ -177,7 +177,7 @@ ssize_t HERMES_DECL(pwrite)(int fd, const void *buf, size_t count, bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(fd)) { + if (fs_api->IsFdTracked(fd)) { File f; f.hermes_fd_ = fd; IoStatus io_status; LOG(INFO) << "Intercept pwrite." << std::endl; size_t ret = fs_api->Write(f, stat_exists, buf, offset, count, io_status); @@ -190,7 +190,7 @@ ssize_t HERMES_DECL(pread64)(int fd, void *buf, size_t count, off64_t offset) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(fd)) { + if (fs_api->IsFdTracked(fd)) { File f; f.hermes_fd_ = fd; IoStatus io_status; LOG(INFO) << "Intercept pread64." << std::endl; size_t ret = fs_api->Read(f, stat_exists, buf, offset, count, io_status); @@ -204,7 +204,7 @@ ssize_t HERMES_DECL(pwrite64)(int fd, const void *buf, size_t count, bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(fd)) { + if (fs_api->IsFdTracked(fd)) { File f; f.hermes_fd_ = fd; IoStatus io_status; LOG(INFO) << "Intercept pwrite." << std::endl; size_t ret = fs_api->Write(f, stat_exists, buf, offset, count, io_status); @@ -217,7 +217,7 @@ off_t HERMES_DECL(lseek)(int fd, off_t offset, int whence) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(fd)) { + if (fs_api->IsFdTracked(fd)) { File f; f.hermes_fd_ = fd; LOG(INFO) << "Intercept lseek offset:" << offset << " whence:" << whence << "." << std::endl; @@ -231,7 +231,7 @@ off64_t HERMES_DECL(lseek64)(int fd, off64_t offset, int whence) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(fd)) { + if (fs_api->IsFdTracked(fd)) { File f; f.hermes_fd_ = fd; LOG(INFO) << "Intercept lseek64 offset:" << offset << " whence:" << whence << "." << std::endl; @@ -245,7 +245,7 @@ int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { int result = 0; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(fd)) { + if (fs_api->IsFdTracked(fd)) { File f; f.hermes_fd_ = fd; LOG(INFO) << "Intercepted fstat." << std::endl; auto mdm = HERMES_FS_METADATA_MANAGER; @@ -283,7 +283,7 @@ int HERMES_DECL(fsync)(int fd) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(fd)) { + if (fs_api->IsFdTracked(fd)) { File f; f.hermes_fd_ = fd; LOG(INFO) << "Intercept fsync." << std::endl; return fs_api->Sync(f, stat_exists); @@ -295,7 +295,7 @@ int HERMES_DECL(close)(int fd) { bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; - if (fs_api->IsTracked(fd)) { + if (fs_api->IsFdTracked(fd)) { LOG(INFO) << "Intercept close(" << std::to_string(fd) << ")"; DLOG(INFO) << " -> " << fs_api->GetFilenameFromFD(fd); LOG(INFO) << std::endl; diff --git a/adapter/posix/posix_api_singleton.cc b/adapter/posix/posix_api_singleton.cc index 139142750..bc0aa4a29 100644 --- a/adapter/posix/posix_api_singleton.cc +++ b/adapter/posix/posix_api_singleton.cc @@ -1,4 +1,4 @@ #include "singleton.h" #include "posix_api.h" -template<> hermes::adapter::fs::PosixApi hermes::GlobalSingleton::obj_; +template<> hermes::adapter::fs::PosixApi hermes::GlobalSingleton::obj_ = hermes::adapter::fs::PosixApi(); diff --git a/adapter/posix/posix_fs_api.h b/adapter/posix/posix_fs_api.h index 46fd7cff0..34b5a0b0c 100644 --- a/adapter/posix/posix_fs_api.h +++ b/adapter/posix/posix_fs_api.h @@ -29,7 +29,7 @@ class PosixFs : public hermes::adapter::fs::Filesystem { PosixFs() : hermes::adapter::fs::Filesystem(HERMES_POSIX_IO_CLIENT) {} /** Whether or not \a fd FILE DESCRIPTOR was generated by Hermes */ - bool IsTracked(int fd) { + static bool IsFdTracked(int fd) { if (!HERMES->IsInitialized()) { return false; } @@ -41,7 +41,7 @@ class PosixFs : public hermes::adapter::fs::Filesystem { } /** get the file name from \a fd file descriptor */ - inline std::string GetFilenameFromFD(int fd) { + std::string GetFilenameFromFD(int fd) { char proclnk[kMaxPathLen]; char filename[kMaxPathLen]; snprintf(proclnk, kMaxPathLen, "/proc/self/fd/%d", fd); diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 627d478b7..afce2039b 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -8,6 +8,7 @@ set(BENCHMARKS put_get_bench) foreach(benchmark ${BENCHMARKS}) add_executable(${benchmark} ${benchmark}.cc) + add_dependencies(${benchmark} hermes) target_link_libraries(${benchmark} hermes MPI::MPI_CXX $<$:thallium> glog::glog) endforeach() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f69807ea1..535f8ef1b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,7 +39,7 @@ endif() # Set sources #------------------------------------------------------------------------------ set(HERMES_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/singleton.cc + ${CMAKE_CURRENT_SOURCE_DIR}/api/hermes_singleton.cc ${CMAKE_CURRENT_SOURCE_DIR}/config_client.cc ${CMAKE_CURRENT_SOURCE_DIR}/config_server.cc ${CMAKE_CURRENT_SOURCE_DIR}/hermes_types.cc diff --git a/src/singleton.cc b/src/api/hermes_singleton.cc similarity index 58% rename from src/singleton.cc rename to src/api/hermes_singleton.cc index 38dd6dfdd..b3948d2b7 100644 --- a/src/singleton.cc +++ b/src/api/hermes_singleton.cc @@ -1,4 +1,4 @@ #include "singleton.h" -#include -template<> hermes::api::Hermes hermes::GlobalSingleton::obj_; +#include "hermes.h" +template<> hermes::api::Hermes hermes::GlobalSingleton::obj_ = hermes::api::Hermes(); diff --git a/src/singleton_macros.h b/src/api/hermes_singleton_macros.h similarity index 100% rename from src/singleton_macros.h rename to src/api/hermes_singleton_macros.h diff --git a/src/hermes_types.h b/src/hermes_types.h index 5cce95b59..35aef3e3c 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -23,7 +23,7 @@ #include "data_structures.h" #include "constants.h" -#include "singleton_macros.h" +#include "api/hermes_singleton_macros.h" #include "statuses.h" /** diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0c2b524e1..2ceee255f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,8 +19,13 @@ set(API_TESTS foreach(program ${API_TESTS}) add_executable(${program} ${program}.cc main_mpi.cc) - target_link_libraries(${program} ${LIBRT} hermes MPI::MPI_CXX - $<$:thallium> glog::glog Catch2::Catch2) + add_dependencies(${program} hermes) + target_link_libraries(${program} ${LIBRT} + hermes + MPI::MPI_CXX + $<$:thallium> + glog::glog + Catch2::Catch2) add_test(NAME "Test${program}" COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2 "${CMAKE_BINARY_DIR}/bin/${program}") From 94c364bb61161960fa6564826cc3cebc9cd34718 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 2 Feb 2023 07:38:47 -0600 Subject: [PATCH 095/511] posix adapter compiling again --- adapter/filesystem/filesystem.cc | 11 +- adapter/filesystem/filesystem.h | 4 +- adapter/filesystem/filesystem_io_client.h | 13 +- adapter/io_client/io_client.h | 37 ++++- adapter/io_client/io_client_factory.h | 16 +-- adapter/posix/posix_fs_api.h | 3 +- adapter/posix/posix_io_client.cc | 54 ++++--- adapter/posix/posix_io_client.h | 27 ++-- adapter/test/posix/simple_posix.cc | 3 + ci/lint.sh | 3 +- code_generators/preamble.py | 51 +++++++ src/api/bucket.cc | 114 +++++++++++---- src/api/bucket.h | 58 ++++---- src/api/hermes.cc | 10 +- src/api/hermes.h | 6 +- src/api/vbucket.cc | 7 +- src/api/vbucket.h | 5 +- src/metadata_manager.cc | 168 ++++++++++++---------- src/metadata_manager.h | 61 ++++---- src/metadata_types.h | 16 ++- 20 files changed, 444 insertions(+), 223 deletions(-) create mode 100644 adapter/test/posix/simple_posix.cc create mode 100644 code_generators/preamble.py diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index b38991796..a30f01360 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -39,6 +39,12 @@ void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { std::pair exists = mdm->Find(f); if (!exists.second) { LOG(INFO) << "File not opened before by adapter" << std::endl; + // Create the new bucket + Context ctx; + IoOptions opts; + opts.type_ = type_; + stat.bkt_id_ = HERMES->GetBucket(path, ctx, opts); + // Allocate internal hermes data auto stat_ptr = std::make_unique(stat); FilesystemIoClientContext fs_ctx(&mdm->fs_mdm_, (void*)stat_ptr.get()); io_client_->HermesOpen(f, stat, fs_ctx); @@ -69,15 +75,14 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, const Blob blob_wrap((const char*)ptr + data_offset, off); lipc::charbuf blob_name(p.CreateBlobName()); BlobId blob_id; - size_t backend_start = p.page_ * kPageSize; IoClientContext io_ctx; Context ctx; io_ctx.filename_ = filename; + opts.backend_off_ = p.page_ * kPageSize; + opts.backend_size_ = kPageSize; bkt->PartialPutOrCreate(blob_name.str(), blob_wrap, p.blob_off_, - backend_start, - kPageSize, blob_id, io_ctx, opts, diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index b44bb424c..ae43defce 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -113,10 +113,12 @@ struct IoOptions : public IoClientOptions { class Filesystem { public: FilesystemIoClient *io_client_; + AdapterType type_; public: /** Constructor */ - explicit Filesystem(FilesystemIoClient *io_client) : io_client_(io_client) {} + explicit Filesystem(FilesystemIoClient *io_client, AdapterType type) + : io_client_(io_client), type_(type) {} /** open \a path */ File Open(AdapterStat &stat, const std::string &path); diff --git a/adapter/filesystem/filesystem_io_client.h b/adapter/filesystem/filesystem_io_client.h index f1b0bc3ca..0da2ca6ea 100644 --- a/adapter/filesystem/filesystem_io_client.h +++ b/adapter/filesystem/filesystem_io_client.h @@ -22,10 +22,21 @@ struct FsIoClientMetadata { /** Default constructor */ FsIoClientMetadata() { - // TODO(llogan): Recycle old fds hermes_fd_min_ = 8192; // TODO(llogan): don't assume 8192 hermes_fd_max_ = std::numeric_limits::max(); } + + /** Allocate a Hermes FD */ + int AllocateFd() { + int cur = hermes_fd_cur_.fetch_add(1); + return cur; + } + + /** Release a Hermes FD */ + void ReleaseFd(int hermes_fd) { + // TODO(llogan): recycle instead of ignore + (void) hermes_fd; + } }; /** diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index 81dd5686e..9dd1591cc 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -24,17 +24,18 @@ namespace hermes::adapter { /** Adapter types */ -enum class IoClientType { +enum class AdapterType { kNone, kPosix, kStdio, kMpiio, + kPubsub, kVfd }; /** Represents an object in the I/O client (e.g., a file) */ struct IoClientContext { - IoClientType type_; /**< Client to forward I/O request to */ + AdapterType type_; /**< Client to forward I/O request to */ std::string filename_; /**< Filename to read from */ int hermes_fd_; /**< fake file descriptor (SCRATCH MODE) */ @@ -46,7 +47,7 @@ struct IoClientContext { /** Default constructor */ IoClientContext() - : type_(IoClientType::kNone), + : type_(AdapterType::kNone), filename_(), hermes_fd_(-1), hermes_fh_(nullptr), @@ -57,21 +58,28 @@ struct IoClientContext { /** Represents any relevant settings for an I/O client operation */ struct IoClientOptions { + AdapterType type_; /**< Client to forward I/O request to */ MPI_Datatype mpi_type_; /**< MPI data type */ int mpi_count_; /**< The number of types */ + size_t backend_off_; /**< Offset in the backend to begin I/O */ + size_t backend_size_; /**< Size of I/O to perform at backend */ /** Default constructor */ IoClientOptions() : mpi_type_(MPI_CHAR), - mpi_count_(0) {} + mpi_count_(0), + backend_off_(0), + backend_size_(0) {} }; /** Any relevant statistics from the I/O client */ struct IoClientStat { int flags_; /**< open() flags for POSIX */ mode_t st_mode_; /**< protection */ + size_t backend_size_; /**< size of the object in the backend */ + size_t bkt_size_; /**< size of the object in Hermes */ uid_t st_uid_; /**< user ID of owner */ gid_t st_gid_; /**< group ID of owner */ - off64_t st_ptr_; /**< Current ptr of FILE */ + off64_t st_ptr_; /**< current ptr of FILE */ timespec st_atim_; /**< time of last access */ timespec st_mtim_; /**< time of last modification */ timespec st_ctim_; /**< time of last status change */ @@ -109,6 +117,11 @@ struct IoClientStat { } }; +/** Any statistics which need to be globally maintained across ranks */ +struct GlobalIoClientState { + size_t true_size_; +}; + /** A structure to represent IO status */ struct IoStatus { size_t posix_ret_; /**< POSIX/STDIO return value */ @@ -140,16 +153,26 @@ class IoClient { /** Virtual destructor */ virtual ~IoClient() = default; + /** Get initial statistics from the backend */ + virtual void InitBucketState(const lipc::charbuf &bkt_name, + const IoClientOptions &opts, + GlobalIoClientState &stat) = 0; + + /** + * What the statistics would be if all blobs were flushed from Hermes + * to the backing storage system. + * */ + virtual void UpdateBucketState(const IoClientOptions &opts, + GlobalIoClientState &stat) = 0; + /** Write blob to backend */ virtual void WriteBlob(const Blob &full_blob, - size_t backend_off, const IoClientContext &io_ctx, const IoClientOptions &opts, IoStatus &status) = 0; /** Read blob from the backend */ virtual void ReadBlob(Blob &full_blob, - size_t backend_off, const IoClientContext &io_ctx, const IoClientOptions &opts, IoStatus &status) = 0; diff --git a/adapter/io_client/io_client_factory.h b/adapter/io_client/io_client_factory.h index 1b32908aa..22c3a8f54 100644 --- a/adapter/io_client/io_client_factory.h +++ b/adapter/io_client/io_client_factory.h @@ -30,25 +30,23 @@ class IoClientFactory { * @param[in] type type of adapter. * @return Instance of mapper given a type. */ - static IoClient* Get(const IoClientType& type) { + static IoClient* Get(const AdapterType& type) { switch (type) { - case IoClientType::kPosix: { + case AdapterType::kPosix: { return HERMES_POSIX_IO_CLIENT; } - case IoClientType::kStdio: { + case AdapterType::kStdio: { return nullptr; } - case IoClientType::kMpiio: { - return nullptr; - } - case IoClientType::kVfd: { + case AdapterType::kMpiio: { return nullptr; } + case AdapterType::kPubsub: + case AdapterType::kVfd: default: { - // TODO(llogan): @error_handling Mapper not implemented + return nullptr; } } - return NULL; } }; } // namespace hermes::adapter diff --git a/adapter/posix/posix_fs_api.h b/adapter/posix/posix_fs_api.h index 34b5a0b0c..f05633a45 100644 --- a/adapter/posix/posix_fs_api.h +++ b/adapter/posix/posix_fs_api.h @@ -26,7 +26,8 @@ namespace hermes::adapter::fs { /** A class to represent POSIX IO file system */ class PosixFs : public hermes::adapter::fs::Filesystem { public: - PosixFs() : hermes::adapter::fs::Filesystem(HERMES_POSIX_IO_CLIENT) {} + PosixFs() : hermes::adapter::fs::Filesystem(HERMES_POSIX_IO_CLIENT, + AdapterType::kPosix) {} /** Whether or not \a fd FILE DESCRIPTOR was generated by Hermes */ static bool IsFdTracked(int fd) { diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 74178e049..5ce9ff6c7 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -35,39 +35,65 @@ void PosixIoClient::HermesOpen(IoClientContext &f, } +/** Synchronize \a file FILE f */ +int PosixIoClient::RealSync(const IoClientContext &f, + const IoClientStat &stat) { + (void) f; + return real_api->fsync(stat.fd_); +} + +/** Close \a file FILE f */ +int PosixIoClient::RealClose(const IoClientContext &f, + const IoClientStat &stat) { + (void) f; + return real_api->close(stat.fd_); +} + +/** Get initial statistics from the backend */ +void PosixIoClient::InitBucketState(const lipc::charbuf &bkt_name, + const IoClientOptions &opts, + GlobalIoClientState &stat) { + // real_api->__fxstat(); + stat.true_size_ = 0; +} + +/** Update backend statistics */ +void PosixIoClient::UpdateBucketState(const IoClientOptions &opts, + GlobalIoClientState &stat) { + stat.true_size_; +} + /** Write blob to backend */ void PosixIoClient::WriteBlob(const Blob &full_blob, - size_t backend_off, const IoClientContext &io_ctx, const IoClientOptions &opts, IoStatus &status) { (void) opts; LOG(INFO) << "Writing to file: " << io_ctx.filename_ - << " offset: " << backend_off + << " offset: " << opts.backend_off_ << " size:" << full_blob.size() << "." << " file_size:" << stdfs::file_size(io_ctx.filename_) << std::endl; int fd = real_api->open(io_ctx.filename_.c_str(), O_RDWR | O_CREAT); if (fd < 0) { - status.posix_ret_ =0; + status.posix_ret_ = 0; return; } status.posix_ret_ = real_api->pwrite(fd, full_blob.data(), full_blob.size(), - backend_off); + opts.backend_off_); real_api->close(fd); } /** Read blob from the backend */ void PosixIoClient::ReadBlob(Blob &full_blob, - size_t backend_off, const IoClientContext &io_ctx, const IoClientOptions &opts, IoStatus &status) { (void) opts; LOG(INFO) << "Writing to file: " << io_ctx.filename_ - << " offset: " << backend_off + << " offset: " << opts.backend_off_ << " size:" << full_blob.size() << "." << " file_size:" << stdfs::file_size(io_ctx.filename_) << std::endl; @@ -79,22 +105,8 @@ void PosixIoClient::ReadBlob(Blob &full_blob, status.posix_ret_ = real_api->pread(fd, full_blob.data(), full_blob.size(), - backend_off); + opts.backend_off_); real_api->close(fd); } -/** Synchronize \a file FILE f */ -int PosixIoClient::RealSync(const IoClientContext &f, - const IoClientStat &stat) { - (void) f; - return real_api->fsync(stat.fd_); -} - -/** Close \a file FILE f */ -int PosixIoClient::RealClose(const IoClientContext &f, - const IoClientStat &stat) { - (void) f; - return real_api->close(stat.fd_); -} - } // namespace hermes::adapter::fs diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h index f8e816066..3ecd5c8b1 100644 --- a/adapter/posix/posix_io_client.h +++ b/adapter/posix/posix_io_client.h @@ -47,27 +47,34 @@ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { const IoClientStat &stat, FilesystemIoClientContext &fs_mdm) override; + /** Synchronize \a file FILE f */ + int RealSync(const IoClientContext &f, + const IoClientStat &stat) override; + + /** Close \a file FILE f */ + int RealClose(const IoClientContext &f, + const IoClientStat &stat) override; + + /** Get initial statistics from the backend */ + void InitBucketState(const lipc::charbuf &bkt_name, + const IoClientOptions &opts, + GlobalIoClientState &stat) override; + + /** Update backend statistics */ + void UpdateBucketState(const IoClientOptions &opts, + GlobalIoClientState &stat) override; + /** Write blob to backend */ void WriteBlob(const Blob &full_blob, - size_t backend_off, const IoClientContext &io_ctx, const IoClientOptions &opts, IoStatus &status) override; /** Read blob from the backend */ void ReadBlob(Blob &full_blob, - size_t backend_off, const IoClientContext &io_ctx, const IoClientOptions &opts, IoStatus &status) override; - - /** Synchronize \a file FILE f */ - int RealSync(const IoClientContext &f, - const IoClientStat &stat) override; - - /** Close \a file FILE f */ - int RealClose(const IoClientContext &f, - const IoClientStat &stat) override; }; } // namespace hermes::adapter::fs diff --git a/adapter/test/posix/simple_posix.cc b/adapter/test/posix/simple_posix.cc new file mode 100644 index 000000000..777f5ee56 --- /dev/null +++ b/adapter/test/posix/simple_posix.cc @@ -0,0 +1,3 @@ +// +// Created by lukemartinlogan on 2/1/23. +// diff --git a/ci/lint.sh b/ci/lint.sh index 19e5db779..327aa51e5 100644 --- a/ci/lint.sh +++ b/ci/lint.sh @@ -3,7 +3,8 @@ HERMES_ROOT=$1 ADAPTER=${HERMES_ROOT}/adapter cpplint --recursive \ ---exclude="${HERMES_ROOT}/src/stb_ds.h" \ +--exclude="${HERMES_ROOT}/src/config_server_default.h" \ +--exclude="${HERMES_ROOT}/src/config_client_default.h" \ --exclude="${ADAPTER}/posix/real_api.h" \ --exclude="${ADAPTER}/stdio/real_api.h" \ --exclude="${ADAPTER}/mpiio/real_api.h" \ diff --git a/code_generators/preamble.py b/code_generators/preamble.py new file mode 100644 index 000000000..4affef61f --- /dev/null +++ b/code_generators/preamble.py @@ -0,0 +1,51 @@ +""" +Prepends the preabmle to all files in the repo + +USAGE: + python3 scripts/preamble.py ${HERMES_ROOT} +""" + +import sys,os,re +import pathlib + +preamble = """ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +""" + +def PrependPreamble(path): + text = "" + with open(path, 'r') as fp: + text = fp.read() + if "Copyright (C) 2022 SCS Lab " in text: + text = text.replace(preamble, "") + text = text.strip() + text = re.sub("//\n// Created by [^\n]*\n//\n", "", text) + text = preamble.strip() + text + "\n" + + with open(path, 'w') as fp: + fp.write(text) + + +def LocateCppFiles(root): + for entry in os.listdir(root): + full_path = os.path.join(root, entry) + if os.path.isdir(full_path): + LocateCppFiles(full_path) + elif os.path.isfile(full_path): + file_ext = pathlib.Path(full_path).suffix + if file_ext == '.cc' or file_ext == '.h': + PrependPreamble(full_path) + + +root = sys.argv[1] +LocateCppFiles(root) \ No newline at end of file diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 5fe707796..8710b6c34 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -14,20 +14,14 @@ namespace hermes::api { /** * Either initialize or fetch the bucket. * */ -Bucket::Bucket(std::string name, Context &ctx) +Bucket::Bucket(const std::string &bkt_name, + Context &ctx, + const IoClientOptions &opts) : mdm_(&HERMES->mdm_), bpm_(&HERMES->bpm_) { - lipc::string lname(name); - id_ = mdm_->LocalGetOrCreateBucket(lname); + lipc::string lname(bkt_name); + id_ = mdm_->LocalGetOrCreateBucket(lname, opts); } -/** - * Get \a bkt_id bucket, which is known to exist. - * - * Used internally by Hermes. - * */ -Bucket::Bucket(BucketId bkt_id, Context &ctx) -: id_(bkt_id) {} - /** * Rename this bucket * */ @@ -50,7 +44,8 @@ void Bucket::Destroy() { * Get the id of a blob from the blob name * */ Status Bucket::GetBlobId(std::string blob_name, - BlobId &blob_id, Context &ctx) { + BlobId &blob_id, + Context &ctx) { lipc::string lblob_name(blob_name); blob_id = mdm_->LocalGetBlobId(GetId(), lblob_name); return Status(); @@ -60,8 +55,11 @@ Status Bucket::GetBlobId(std::string blob_name, /** * Put \a blob_id Blob into the bucket * */ -Status Bucket::Put(std::string blob_name, const Blob blob, - BlobId &blob_id, Context &ctx) { +Status Bucket::Put(std::string blob_name, + const Blob blob, + BlobId &blob_id, + Context &ctx, + IoClientOptions opts) { // Calculate placement auto dpe = DPEFactory::Get(ctx.policy); std::vector blob_sizes(1, blob.size()); @@ -72,8 +70,17 @@ Status Bucket::Put(std::string blob_name, const Blob blob, for (auto &schema : schemas) { // TODO(llogan): rpcify auto buffers = bpm_->LocalAllocateAndSetBuffers(schema, blob); - blob_id = mdm_->LocalBucketPutBlob(id_, lipc::string(blob_name), - blob, buffers); + auto put_ret = mdm_->LocalBucketPutBlob(id_, lipc::string(blob_name), + blob.size(), buffers); + blob_id = std::get<0>(put_ret); + bool did_create = std::get<1>(put_ret); + size_t orig_blob_size = std::get<2>(put_ret); + mdm_->LocalBucketRegisterBlobId(id_, + blob_id, + orig_blob_size, + blob.size(), + did_create, + opts); } return Status(); @@ -86,30 +93,46 @@ Status Bucket::Put(std::string blob_name, const Blob blob, * @param blob_name the semantic name of the blob * @param blob the buffer to put final data in * @param blob_off the offset within the blob to begin the Put - * @param backend_off the offset to read from the backend if blob DNE - * @param backend_size the size to read from the backend if blob DNE - * @param backend_ctx which adapter to route I/O request if blob DNE + * @param io_ctx which adapter to route I/O request if blob DNE + * @param opts which adapter to route I/O request if blob DNE * @param ctx any additional information * */ Status Bucket::PartialPutOrCreate(std::string blob_name, const Blob &blob, size_t blob_off, - size_t backend_off, - size_t backend_size, BlobId &blob_id, const IoClientContext &io_ctx, const IoClientOptions &opts, Context &ctx) { - mdm_->LocalBucketPartialPutOrCreateBlob( - id_, - lipc::string(blob_name), - blob, - blob_off, - backend_off, - backend_size, - io_ctx, - opts, - ctx); + Blob full_blob; + // Put the blob + if (blob_off == 0 && blob.size() == opts.backend_size_) { + // Case 1: We're overriding the entire blob + // Put the entire blob, no need to load from storage + return Put(blob_name, blob, blob_id, ctx); + } + if (ContainsBlob(blob_id)) { + // Case 2: The blob already exists (read from hermes) + // Read blob from Hermes + Get(blob_id, full_blob, ctx); + } else { + // Case 3: The blob did not exist (need to read from backend) + // Read blob using adapter + IoStatus status; + auto io_client = IoClientFactory::Get(io_ctx.type_); + full_blob.resize(opts.backend_size_); + io_client->ReadBlob(full_blob, + io_ctx, + opts, + status); + } + // Ensure the blob can hold the update + full_blob.resize(std::max(full_blob.size(), blob_off + blob.size())); + // Modify the blob + memcpy(full_blob.data() + blob_off, blob.data(), blob.size()); + // Re-put the blob + Put(blob_name, full_blob, blob_id, ctx); + return Status(); } /** @@ -121,6 +144,35 @@ Status Bucket::Get(BlobId blob_id, Blob &blob, Context &ctx) { return Status(); } +/** + * Load \a blob_name Blob from the bucket. Load the blob from the + * I/O backend if it does not exist. + * + * @param blob_name the semantic name of the blob + * @param blob the buffer to put final data in + * @param blob_off the offset within the blob to begin the Put + * @param blob_id [out] the blob id corresponding to blob_name + * @param io_ctx information required to perform I/O to the backend + * @param opts specific configuration of the I/O to perform + * @param ctx any additional information + * */ +Status PartialGetOrCreate(std::string blob_name, + const Blob &blob, + size_t blob_off, + BlobId &blob_id, + const IoClientContext &io_ctx, + const IoClientOptions &opts, + Context &ctx) { + return Status(); +} + +/** + * Determine if the bucket contains \a blob_id BLOB + * */ +bool Bucket::ContainsBlob(BlobId blob_id) { + return mdm_->LocalBucketContainsBlob(id_, blob_id); +} + /** * Rename \a blob_id blob to \a new_blob_name new name * */ diff --git a/src/api/bucket.h b/src/api/bucket.h index f89dcfea3..4085705f5 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -33,15 +33,9 @@ class Bucket { * Called from hermes.h in GetBucket(). Should not * be used directly. * */ - Bucket(std::string bkt_name, - Context &ctx); - - /** - * Get \a bkt_id bucket, which is known to exist. - * - * Used internally by Hermes. - * */ - Bucket(BucketId bkt_id, Context &ctx); + Bucket(const std::string &bkt_name, + Context &ctx, + const IoClientOptions &opts); public: /** @@ -59,16 +53,6 @@ class Bucket { return id_; } - /** - * Set the size of bucket on storage - * */ - void SetBackendSize(); - - /** - * Get the size of the data on storage - * */ - void GetBackendSize(); - /** * Get the current size of the bucket * */ @@ -113,7 +97,8 @@ class Bucket { Status Put(std::string blob_name, const Blob blob, BlobId &blob_id, - Context &ctx); + Context &ctx, + IoClientOptions opts = IoClientOptions()); /** * Put \a blob_name Blob into the bucket. Load the blob from the @@ -122,16 +107,14 @@ class Bucket { * @param blob_name the semantic name of the blob * @param blob the buffer to put final data in * @param blob_off the offset within the blob to begin the Put - * @param backend_off the offset to read from the backend if blob DNE - * @param backend_size the size to read from the backend if blob DNE - * @param backend_ctx which adapter to route I/O request if blob DNE + * @param blob_id [out] the blob id corresponding to blob_name + * @param io_ctx information required to perform I/O to the backend + * @param opts specific configuration of the I/O to perform * @param ctx any additional information * */ Status PartialPutOrCreate(std::string blob_name, const Blob &blob, size_t blob_off, - size_t backend_off, - size_t backend_size, BlobId &blob_id, const IoClientContext &io_ctx, const IoClientOptions &opts, @@ -144,6 +127,31 @@ class Bucket { Blob &blob, Context &ctx); + /** + * Load \a blob_name Blob from the bucket. Load the blob from the + * I/O backend if it does not exist. + * + * @param blob_name the semantic name of the blob + * @param blob the buffer to put final data in + * @param blob_off the offset within the blob to begin the Put + * @param blob_id [out] the blob id corresponding to blob_name + * @param io_ctx information required to perform I/O to the backend + * @param opts specific configuration of the I/O to perform + * @param ctx any additional information + * */ + Status PartialGetOrCreate(std::string blob_name, + const Blob &blob, + size_t blob_off, + BlobId &blob_id, + const IoClientContext &io_ctx, + const IoClientOptions &opts, + Context &ctx); + + /** + * Determine if the bucket contains \a blob_id BLOB + * */ + bool ContainsBlob(BlobId blob_id); + /** * Rename \a blob_id blob to \a new_blob_name new name * */ diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 127c7a863..a266b88a7 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -143,13 +143,15 @@ void Hermes::FinalizeColocated() { } std::shared_ptr Hermes::GetBucket(std::string name, - Context ctx) { - return std::make_shared(name, ctx); + Context ctx, + IoClientOptions opts) { + return std::make_shared(name, ctx, opts); } std::shared_ptr Hermes::GetVBucket(std::string name, - Context ctx) { - return std::make_shared(name, ctx); + Context ctx, + IoClientOptions opts) { + return std::make_shared(name, ctx, opts); } } // namespace hermes::api \ No newline at end of file diff --git a/src/api/hermes.h b/src/api/hermes.h index 98d6351f6..2e1f9edcc 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -80,11 +80,13 @@ class Hermes { public: /** Create a Bucket in Hermes */ std::shared_ptr GetBucket(std::string name, - Context ctx = Context()); + Context ctx = Context(), + IoClientOptions = IoClientOptions()); /** Create a VBucket in Hermes */ std::shared_ptr GetVBucket(std::string name, - Context ctx = Context()); + Context ctx = Context(), + IoClientOptions = IoClientOptions()); private: /** Internal initialization of Hermes */ diff --git a/src/api/vbucket.cc b/src/api/vbucket.cc index ae9b49500..13694a657 100644 --- a/src/api/vbucket.cc +++ b/src/api/vbucket.cc @@ -13,10 +13,13 @@ namespace hermes::api { * @param name the name of the vbucket * @param ctx any additional information * */ -VBucket::VBucket(std::string name, Context &ctx) : mdm_(&HERMES->mdm_) { +VBucket::VBucket(const std::string &name, + Context &ctx, + const IoClientOptions &opts) +: mdm_(&HERMES->mdm_), ctx_(ctx) { lipc::string lname(name); // TODO(llogan): rpcify - id_ = mdm_->LocalGetOrCreateVBucket(lname); + id_ = mdm_->LocalGetOrCreateVBucket(lname, opts); } /** diff --git a/src/api/vbucket.h b/src/api/vbucket.h index 8fae0ada0..c21cabebc 100644 --- a/src/api/vbucket.h +++ b/src/api/vbucket.h @@ -15,6 +15,7 @@ class VBucket { private: MetadataManager *mdm_; VBucketId id_; + Context ctx_; public: /** @@ -23,7 +24,9 @@ class VBucket { * @param name the name of the vbucket * @param ctx any additional information * */ - VBucket(std::string name, Context &ctx); + VBucket(const std::string &name, + Context &ctx, + const IoClientOptions &opts); /** * Rename a VBucket. diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 9c346f89e..7fbb1fd15 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -106,7 +106,9 @@ void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -BucketId MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { +BucketId MetadataManager::LocalGetOrCreateBucket( + lipc::charbuf &bkt_name, + const IoClientOptions &opts) { // Create unique ID for the Bucket BucketId bkt_id; bkt_id.unique_ = header_->id_alloc_.fetch_add(1); @@ -116,6 +118,13 @@ BucketId MetadataManager::LocalGetOrCreateBucket(lipc::charbuf &bkt_name) { if (bkt_id_map_->try_emplace(bkt_name, bkt_id)) { BucketInfo info(HERMES->main_alloc_); (*info.name_) = bkt_name; + info.header_->internal_size_ = 0; + auto io_client = IoClientFactory::Get(opts.type_); + if (io_client) { + io_client->InitBucketState(bkt_name, + opts, + info.header_->client_state_); + } bkt_map_->emplace(bkt_id, std::move(info)); } else { auto iter = bkt_id_map_->find(bkt_name); @@ -145,6 +154,29 @@ BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { return bkt_id; } +/** + * Get the size of the bucket. May consider the impact the bucket has + * on the backing storage system's statistics using the io_ctx. + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ +size_t MetadataManager::LocalGetBucketSize(BucketId bkt_id, + IoClientContext &io_ctx) { + auto iter = bkt_map_->find(bkt_id); + if (iter == bkt_map_->end()) { + return 0; + } + lipc::ShmRef> info = (*iter); + BucketInfo &bkt_info = *info->second_; + auto io_client = IoClientFactory::Get(io_ctx.type_); + if (io_client) { + return bkt_info.header_->client_state_.true_size_; + } else { + return bkt_info.header_->internal_size_; + } +} + /** * Check whether or not \a bkt_id bucket contains * \a blob_id blob @@ -193,8 +225,42 @@ bool MetadataManager::LocalDestroyBucket(BucketId bkt_id) { return true; } +/** Registers a blob with the bucket */ +Status MetadataManager::LocalBucketRegisterBlobId( + BucketId bkt_id, + BlobId blob_id, + size_t orig_blob_size, + size_t new_blob_size, + bool did_create, + const IoClientOptions &opts) { + auto iter = bkt_map_->find(bkt_id); + if (iter == bkt_map_->end()) { + return Status(); + } + lipc::ShmRef> info = (*iter); + BucketInfo &bkt_info = *info->second_; + // Update I/O client bucket stats + auto io_client = IoClientFactory::Get(opts.type_); + if (io_client) { + io_client->UpdateBucketState(opts, bkt_info.header_->client_state_); + } + // Update internal bucket size + bkt_info.header_->internal_size_ += new_blob_size - orig_blob_size; + // Add blob to ID vector if it didn't already exist + if (!did_create) { return Status(); } + // TODO(llogan): add blob id + return Status(); +} + +/** Unregister a blob from a bucket */ +Status MetadataManager::LocalBucketUnregisterBlobId( + BucketId bkt_id, BlobId blob_id, + const IoClientContext &io_ctx) { + // TODO(llogan) +} + /** - * Put a blob in a bucket + * Creates the blob metadata * * @param bkt_id id of the bucket * @param blob_name semantic blob name @@ -204,21 +270,27 @@ bool MetadataManager::LocalDestroyBucket(BucketId bkt_id) { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, - const lipc::charbuf &blob_name, - const Blob &data, - lipc::vector &buffers) { +std::tuple MetadataManager::LocalBucketPutBlob( + BucketId bkt_id, + const lipc::charbuf &blob_name, + size_t blob_size, + lipc::vector &buffers) { + size_t orig_blob_size = 0; + + // Get internal blob name lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); // Create unique ID for the Blob BlobId blob_id; blob_id.unique_ = header_->id_alloc_.fetch_add(1); blob_id.node_id_ = rpc_->node_id_; - if (blob_id_map_->try_emplace(internal_blob_name, blob_id)) { + bool did_create = blob_id_map_->try_emplace(internal_blob_name, blob_id); + if (did_create) { BlobInfo blob_info(HERMES->main_alloc_); blob_info.bkt_id_ = bkt_id; (*blob_info.name_) = std::move(internal_blob_name); (*blob_info.buffers_) = std::move(buffers); + blob_info.header_->blob_size_ = blob_size; blob_map_->emplace(blob_id, std::move(blob_info)); } else { blob_id = *(*blob_id_map_)[internal_blob_name]; @@ -227,69 +299,7 @@ BlobId MetadataManager::LocalBucketPutBlob(BucketId bkt_id, BlobInfo &blob_info = *info->second_; (*blob_info.buffers_) = std::move(buffers); } - - return blob_id; -} - -/** - * Partially (or fully) Put a blob from a bucket. Load the blob from the - * I/O backend if it does not exist. - * - * @param blob_name the semantic name of the blob - * @param blob the buffer to put final data in - * @param blob_off the offset within the blob to begin the Put - * @param backend_off the offset to read from the backend if blob DNE - * @param backend_size the size to read from the backend if blob DNE - * @param backend_ctx which adapter to route I/O request if blob DNE - * @param ctx any additional information - * */ -Status MetadataManager::LocalBucketPartialPutOrCreateBlob( - BucketId bkt_id, - const lipc::string &blob_name, - const Blob &blob, - size_t blob_off, - size_t backend_off, - size_t backend_size, - const IoClientContext &io_ctx, - const IoClientOptions &opts, - Context &ctx) { - - // Determine if the blob exists - BlobId blob_id; - Blob full_blob; - Bucket bkt(bkt_id, ctx); - lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); - auto iter = blob_id_map_->find(internal_blob_name); - - // Put the blob - if (blob_off == 0 && blob.size() == backend_size) { - // Case 1: We're overriding the entire blob - // Put the entire blob, no need to load from storage - return bkt.Put(blob_name.str(), blob, blob_id, ctx); - } - if (iter != blob_id_map_->end()) { - // Case 2: The blob already exists (read from hermes) - // Read blob from Hermes - bkt.Get(blob_id, full_blob, ctx); - } else { - // Case 3: The blob did not exist (need to read from backend) - // Read blob using adapter - IoStatus status; - auto io_client = IoClientFactory::Get(io_ctx.type_); - full_blob.resize(backend_size); - io_client->ReadBlob(full_blob, - backend_off, - io_ctx, - opts, - status); - } - // Ensure the blob can hold the update - full_blob.resize(std::max(full_blob.size(), blob_off + blob.size())); - // Modify the blob - memcpy(full_blob.data() + blob_off, blob.data(), blob.size()); - // Re-put the blob - bkt.Put(blob_name.str(), full_blob, blob_id, ctx); - return Status(); + return std::tuple(blob_id, did_create, orig_blob_size); } /** @@ -329,14 +339,21 @@ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -lipc::vector MetadataManager::LocalGetBlobBuffers(BlobId blob_id) { +std::vector MetadataManager::LocalGetBlobBuffers(BlobId blob_id) { auto iter = blob_map_->find(blob_id); if (iter == blob_map_->end()) { - return lipc::vector(); + return std::vector(); } lipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; - return (*blob_info.buffers_); + + // TODO(llogan): make this internal to the lipc::vec + std::vector v; + v.reserve(blob_info.buffers_->size()); + for (lipc::ShmRef buffer_info : *blob_info.buffers_) { + v.emplace_back(*buffer_info); + } + return v; } /** @@ -388,7 +405,10 @@ bool MetadataManager::LocalDestroyBlob(BucketId bkt_id, * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -VBucketId MetadataManager::LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name) { +VBucketId MetadataManager::LocalGetOrCreateVBucket( + lipc::charbuf &vbkt_name, + const IoClientOptions &opts) { + (void) opts; // Create unique ID for the Bucket VBucketId vbkt_id; vbkt_id.unique_ = header_->id_alloc_.fetch_add(1); diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 7ee58060a..ea82a760d 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -131,7 +131,8 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BucketId LocalGetOrCreateBucket(lipc::charbuf &bkt_name); + RPC BucketId LocalGetOrCreateBucket(lipc::charbuf &bkt_name, + const IoClientOptions &opts); /** * Get the BucketId with \a bkt_name bucket name @@ -150,6 +151,15 @@ class MetadataManager { * */ RPC bool LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id); + /** + * Get the size of a bucket (depends on the IoClient used). + * + * @RPC_TARGET_NODE rpc_->node_id_ + * @RPC_CLASS_INSTANCE mdm + * */ + RPC size_t LocalGetBucketSize(BucketId bkt_id, + IoClientContext &io_ctx); + /** * Rename \a bkt_id bucket to \a new_bkt_name new name * @@ -178,32 +188,30 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BlobId LocalBucketPutBlob(BucketId bkt_id, - const lipc::charbuf &blob_name, - const Blob &data, - lipc::vector &buffers); + RPC std::tuple LocalBucketPutBlob( + BucketId bkt_id, + const lipc::charbuf &blob_name, + size_t blob_size, + lipc::vector &buffers); /** - * Partially (or fully) Put a blob from a bucket. Load the blob from the - * I/O backend if it does not exist. - * - * @param blob_name the semantic name of the blob - * @param blob the buffer to put final data in - * @param blob_off the offset within the blob to begin the Put - * @param backend_off the offset to read from the backend if blob DNE - * @param backend_size the size to read from the backend if blob DNE - * @param backend_ctx which adapter to route I/O request if blob DNE - * @param ctx any additional information + * Registers the existence of a Blob with the Bucket. Required for + * deletion and statistics. + * */ + Status LocalBucketRegisterBlobId(BucketId bkt_id, + BlobId blob_id, + size_t orig_blob_size, + size_t new_blob_size, + bool did_create, + const IoClientOptions &opts); + + /** + * Registers the existence of a Blob with the Bucket. Required for + * deletion and statistics. * */ - RPC Status LocalBucketPartialPutOrCreateBlob(BucketId bkt_id, - const lipc::string &blob_name, - const Blob &blob, - size_t blob_off, - size_t backend_off, - size_t backend_size, - const IoClientContext &io_ctx, - const IoClientOptions &opts, - Context &ctx); + Status LocalBucketUnregisterBlobId(BucketId bkt_id, + BlobId blob_id, + const IoClientContext &io_ctx); /** * Get a blob from a bucket @@ -230,7 +238,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC lipc::vector LocalGetBlobBuffers(BlobId blob_id); + RPC std::vector LocalGetBlobBuffers(BlobId blob_id); /** * Rename \a blob_id blob to \a new_blob_name new blob name @@ -256,7 +264,8 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC VBucketId LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name); + RPC VBucketId LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name, + const IoClientOptions &opts); /** * Get the VBucketId of \a vbkt_name VBucket diff --git a/src/metadata_types.h b/src/metadata_types.h index 56b612397..dc7fa4748 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -7,9 +7,11 @@ #include "hermes_types.h" #include "config_server.h" +#include "adapter/io_client/io_client.h" namespace hermes { +using adapter::GlobalIoClientState; using api::Blob; struct BucketInfo; /** Forward declaration of BucketInfo */ struct BlobInfo; /** Forward declaration of BlobInfo */ @@ -92,8 +94,9 @@ struct ShmHeader : public lipc::ShmBaseHeader { BucketId bkt_id_; /**< The bucket containing the blob */ lipc::TypedPointer name_ar_; /**< SHM pointer to string */ lipc::TypedPointer> - buffers_ar_; /**< SHM pointer to BufferInfo vector */ - RwLock rwlock_; /**< Ensures BlobInfo access is synchronized */ + buffers_ar_; /**< SHM pointer to BufferInfo vector */ + size_t blob_size_; /**< The overall size of the blob */ + RwLock rwlock_; /**< Ensures BlobInfo access is synchronized */ /** Default constructor */ ShmHeader() = default; @@ -102,12 +105,14 @@ struct ShmHeader : public lipc::ShmBaseHeader { ShmHeader(const ShmHeader &other) noexcept : bkt_id_(other.bkt_id_), name_ar_(other.name_ar_), buffers_ar_(other.buffers_ar_), + blob_size_(other.blob_size_), rwlock_() {} /** Move constructor */ ShmHeader(ShmHeader &&other) noexcept : bkt_id_(std::move(other.bkt_id_)), name_ar_(std::move(other.name_ar_)), buffers_ar_(std::move(other.buffers_ar_)), + blob_size_(other.blob_size_), rwlock_() {} /** Copy assignment */ @@ -116,6 +121,7 @@ struct ShmHeader : public lipc::ShmBaseHeader { bkt_id_ = other.bkt_id_; name_ar_ = other.name_ar_; buffers_ar_ = other.buffers_ar_; + blob_size_ = other.blob_size_; } return *this; } @@ -126,6 +132,7 @@ struct ShmHeader : public lipc::ShmBaseHeader { bkt_id_ = std::move(other.bkt_id_); name_ar_ = std::move(other.name_ar_); buffers_ar_ = std::move(other.buffers_ar_); + blob_size_ = other.blob_size_; } return *this; } @@ -212,8 +219,9 @@ struct BlobInfo : public lipc::ShmContainer { template<> struct ShmHeader : public lipc::ShmBaseHeader { lipc::TypedPointer name_ar_; - size_t num_blobs_; - size_t true_size_; + lipc::TypedPointer> blobs_ar_; + size_t internal_size_; + GlobalIoClientState client_state_; }; /** Metadata for a Bucket */ From 92e7a87eb608058b3a8c1f2c8c22cc85eabcaa59 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 2 Feb 2023 08:11:47 -0600 Subject: [PATCH 096/511] Put get native still work --- src/api/bucket.cc | 48 ++++++++++++++++++++++++++++++++++------- src/api/bucket.h | 5 +++-- src/metadata_manager.cc | 4 ++-- src/metadata_manager.h | 12 +++++------ src/statuses.h | 3 +++ 5 files changed, 54 insertions(+), 18 deletions(-) diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 8710b6c34..0bc1c75f6 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -17,11 +17,18 @@ namespace hermes::api { Bucket::Bucket(const std::string &bkt_name, Context &ctx, const IoClientOptions &opts) - : mdm_(&HERMES->mdm_), bpm_(&HERMES->bpm_) { +: mdm_(&HERMES->mdm_), bpm_(&HERMES->bpm_) { lipc::string lname(bkt_name); id_ = mdm_->LocalGetOrCreateBucket(lname, opts); } +/** + * Get the current size of the bucket + * */ +size_t Bucket::GetSize(IoClientOptions opts) { + return mdm_->LocalGetBucketSize(id_, opts); +} + /** * Rename this bucket * */ @@ -156,13 +163,38 @@ Status Bucket::Get(BlobId blob_id, Blob &blob, Context &ctx) { * @param opts specific configuration of the I/O to perform * @param ctx any additional information * */ -Status PartialGetOrCreate(std::string blob_name, - const Blob &blob, - size_t blob_off, - BlobId &blob_id, - const IoClientContext &io_ctx, - const IoClientOptions &opts, - Context &ctx) { +Status Bucket::PartialGetOrCreate(std::string blob_name, + Blob &blob, + size_t blob_off, + size_t blob_size, + BlobId &blob_id, + const IoClientContext &io_ctx, + const IoClientOptions &opts, + Context &ctx) { + Blob full_blob; + if (ContainsBlob(blob_id)) { + // Case 1: The blob already exists (read from hermes) + // Read blob from Hermes + Get(blob_id, full_blob, ctx); + } else { + // Case 2: The blob did not exist (need to read from backend) + // Read blob using adapter + IoStatus status; + auto io_client = IoClientFactory::Get(io_ctx.type_); + full_blob.resize(opts.backend_size_); + io_client->ReadBlob(full_blob, + io_ctx, + opts, + status); + } + // Ensure the blob can hold the update + if (full_blob.size() < blob_off + blob_size) { + return PARTIAL_GET_OR_CREATE_OVERFLOW; + } + // Modify the blob + // TODO(llogan): we can avoid a copy here + blob.resize(blob_size); + memcpy(blob.data() + blob_off, full_blob.data() + blob_off, blob.size()); return Status(); } diff --git a/src/api/bucket.h b/src/api/bucket.h index 4085705f5..b8ea24201 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -56,7 +56,7 @@ class Bucket { /** * Get the current size of the bucket * */ - size_t GetSize(); + size_t GetSize(IoClientOptions opts = IoClientOptions()); /** * Rename this bucket @@ -140,8 +140,9 @@ class Bucket { * @param ctx any additional information * */ Status PartialGetOrCreate(std::string blob_name, - const Blob &blob, + Blob &blob, size_t blob_off, + size_t blob_size, BlobId &blob_id, const IoClientContext &io_ctx, const IoClientOptions &opts, diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 7fbb1fd15..7239079e3 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -162,14 +162,14 @@ BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { * @RPC_CLASS_INSTANCE mdm * */ size_t MetadataManager::LocalGetBucketSize(BucketId bkt_id, - IoClientContext &io_ctx) { + const IoClientOptions &opts) { auto iter = bkt_map_->find(bkt_id); if (iter == bkt_map_->end()) { return 0; } lipc::ShmRef> info = (*iter); BucketInfo &bkt_info = *info->second_; - auto io_client = IoClientFactory::Get(io_ctx.type_); + auto io_client = IoClientFactory::Get(opts.type_); if (io_client) { return bkt_info.header_->client_state_.true_size_; } else { diff --git a/src/metadata_manager.h b/src/metadata_manager.h index ea82a760d..882de0ebd 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -143,22 +143,22 @@ class MetadataManager { RPC BucketId LocalGetBucketId(lipc::charbuf &bkt_name); /** - * Check whether or not \a bkt_id bucket contains - * \a blob_id blob + * Get the size of a bucket (depends on the IoClient used). * * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id); + RPC size_t LocalGetBucketSize(BucketId bkt_id, + const IoClientOptions &opts); /** - * Get the size of a bucket (depends on the IoClient used). + * Check whether or not \a bkt_id bucket contains + * \a blob_id blob * * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC size_t LocalGetBucketSize(BucketId bkt_id, - IoClientContext &io_ctx); + RPC bool LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id); /** * Rename \a bkt_id bucket to \a new_bkt_name new name diff --git a/src/statuses.h b/src/statuses.h index 233e58b25..5ae250539 100644 --- a/src/statuses.h +++ b/src/statuses.h @@ -18,6 +18,9 @@ const Status DPE_MIN_IO_TIME_NO_SOLUTION( "DPE could not find solution for the minimize I/O time DPE"); const Status BUFFER_POOL_OUT_OF_RAM( "Could not allocate the ram tier of storage in BPM"); +const Status PARTIAL_GET_OR_CREATE_OVERFLOW( + "The read exceeds the size of the backend's data"); + } #endif // HERMES_SRC_STATUSES_H_ From 0f024ae019bdd1610d789116938101c1938ecb2e Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 2 Feb 2023 08:29:20 -0600 Subject: [PATCH 097/511] Begin partial put/get tests --- benchmarks/put_get_bench.cc | 2 +- src/api/bucket.cc | 18 +++++++++++++----- src/api/bucket.h | 13 +++++++++---- src/hermes_types.h | 9 ++++++--- src/metadata_manager.cc | 3 ++- src/metadata_manager.h | 2 +- test/test_bucket.cc | 8 ++++---- 7 files changed, 36 insertions(+), 19 deletions(-) diff --git a/benchmarks/put_get_bench.cc b/benchmarks/put_get_bench.cc index 89514ef19..66bbe5f9d 100644 --- a/benchmarks/put_get_bench.cc +++ b/benchmarks/put_get_bench.cc @@ -56,7 +56,7 @@ void GetTest(hapi::Hermes *hermes, size_t blob_name_int = rank * blobs_per_rank + i; std::string name = std::to_string(blob_name_int); hermes::Blob ret; - bkt->GetBlobId(name, blob_id, ctx); + bkt->GetBlobId(name, blob_id); bkt->Get(blob_id, ret, ctx); } } diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 0bc1c75f6..0695171f7 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -51,8 +51,7 @@ void Bucket::Destroy() { * Get the id of a blob from the blob name * */ Status Bucket::GetBlobId(std::string blob_name, - BlobId &blob_id, - Context &ctx) { + BlobId &blob_id) { lipc::string lblob_name(blob_name); blob_id = mdm_->LocalGetBlobId(GetId(), lblob_name); return Status(); @@ -104,7 +103,7 @@ Status Bucket::Put(std::string blob_name, * @param opts which adapter to route I/O request if blob DNE * @param ctx any additional information * */ -Status Bucket::PartialPutOrCreate(std::string blob_name, +Status Bucket::PartialPutOrCreate(const std::string &blob_name, const Blob &blob, size_t blob_off, BlobId &blob_id, @@ -163,7 +162,7 @@ Status Bucket::Get(BlobId blob_id, Blob &blob, Context &ctx) { * @param opts specific configuration of the I/O to perform * @param ctx any additional information * */ -Status Bucket::PartialGetOrCreate(std::string blob_name, +Status Bucket::PartialGetOrCreate(const std::string &blob_name, Blob &blob, size_t blob_off, size_t blob_size, @@ -172,7 +171,7 @@ Status Bucket::PartialGetOrCreate(std::string blob_name, const IoClientOptions &opts, Context &ctx) { Blob full_blob; - if (ContainsBlob(blob_id)) { + if (ContainsBlob(blob_name, blob_id)) { // Case 1: The blob already exists (read from hermes) // Read blob from Hermes Get(blob_id, full_blob, ctx); @@ -198,6 +197,15 @@ Status Bucket::PartialGetOrCreate(std::string blob_name, return Status(); } +/** + * Determine if the bucket contains \a blob_id BLOB + * */ +bool Bucket::ContainsBlob(const std::string &blob_name, + BlobId &blob_id) { + GetBlobId(blob_name, blob_id); + return blob_id.IsNull(); +} + /** * Determine if the bucket contains \a blob_id BLOB * */ diff --git a/src/api/bucket.h b/src/api/bucket.h index b8ea24201..3b15772f2 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -86,10 +86,9 @@ class Bucket { * * @param blob_name the name of the blob * @param blob_id (output) the returned blob_id - * @param ctx any additional information * @return The Status of the operation * */ - Status GetBlobId(std::string blob_name, BlobId &blob_id, Context &ctx); + Status GetBlobId(std::string blob_name, BlobId &blob_id); /** * Put \a blob_name Blob into the bucket @@ -112,7 +111,7 @@ class Bucket { * @param opts specific configuration of the I/O to perform * @param ctx any additional information * */ - Status PartialPutOrCreate(std::string blob_name, + Status PartialPutOrCreate(const std::string &blob_name, const Blob &blob, size_t blob_off, BlobId &blob_id, @@ -139,7 +138,7 @@ class Bucket { * @param opts specific configuration of the I/O to perform * @param ctx any additional information * */ - Status PartialGetOrCreate(std::string blob_name, + Status PartialGetOrCreate(const std::string &blob_name, Blob &blob, size_t blob_off, size_t blob_size, @@ -148,6 +147,12 @@ class Bucket { const IoClientOptions &opts, Context &ctx); + /** + * Determine if the bucket contains \a blob_id BLOB + * */ + bool ContainsBlob(const std::string &blob_name, + BlobId &blob_id); + /** * Determine if the bucket contains \a blob_id BLOB * */ diff --git a/src/hermes_types.h b/src/hermes_types.h index 35aef3e3c..dba485f59 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -92,9 +92,12 @@ struct UniqueId { bool IsNull() const { return unique_ == 0; } - static UniqueId GetNull() { - UniqueId id; - id.unique_ = 0; + UniqueId() = default; + + UniqueId(u64 unique, i32 node_id) : unique_(unique), node_id_(node_id) {} + + static inline UniqueId GetNull() { + static const UniqueId id(0, 0); return id; } diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 7239079e3..b2382d137 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -184,7 +184,8 @@ size_t MetadataManager::LocalGetBucketSize(BucketId bkt_id, * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ -bool MetadataManager::LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id) { +bool MetadataManager::LocalBucketContainsBlob(BucketId bkt_id, + BlobId blob_id) { auto iter = blob_map_->find(blob_id); if (iter == blob_map_->end()) { return false; diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 882de0ebd..7cea2168f 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -158,7 +158,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC bool LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id); + bool LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id); /** * Rename \a bkt_id bucket to \a new_bkt_name new name diff --git a/test/test_bucket.cc b/test/test_bucket.cc index 51fa0d534..476300158 100644 --- a/test/test_bucket.cc +++ b/test/test_bucket.cc @@ -49,7 +49,7 @@ void TestManyPuts(hapi::Hermes *hermes) { std::string name = std::to_string(i); char nonce = i % 256; hermes::Blob blob; - bkt->GetBlobId(name, blob_id, ctx); + bkt->GetBlobId(name, blob_id); bkt->Get(blob_id, blob, ctx); REQUIRE(blob.size() == blob_size); REQUIRE(VerifyBuffer(blob.data(), blob_size, nonce)); @@ -111,13 +111,13 @@ void TestBlobRename(hapi::Hermes *hermes) { { hermes::BlobId blob_get_id; - bkt->GetBlobId("0", blob_get_id, ctx); + bkt->GetBlobId("0", blob_get_id); REQUIRE(blob_get_id.IsNull()); } { hermes::BlobId blob_get_id; - bkt->GetBlobId("1", blob_get_id, ctx); + bkt->GetBlobId("1", blob_get_id); REQUIRE(!blob_get_id.IsNull()); REQUIRE(blob_get_id == blob_id); } @@ -132,7 +132,7 @@ void TestBlobDestroy(hapi::Hermes *hermes) { bkt->DestroyBlob(blob_id, ctx); { hermes::BlobId blob_id_get; - bkt->GetBlobId("0", blob_id_get, ctx); + bkt->GetBlobId("0", blob_id_get); REQUIRE(blob_id_get.IsNull()); } } From 0c0cb636ada5c7aa8d5b1e8ca133d8f6283594af Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 2 Feb 2023 08:37:06 -0600 Subject: [PATCH 098/511] preamble --- code_generators/preamble.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/code_generators/preamble.py b/code_generators/preamble.py index 4affef61f..9ae7470b9 100644 --- a/code_generators/preamble.py +++ b/code_generators/preamble.py @@ -8,7 +8,7 @@ import sys,os,re import pathlib -preamble = """ +hermes_preamble = """ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Distributed under BSD 3-Clause license. * * Copyright by The HDF Group. * @@ -20,14 +20,41 @@ * the COPYING file, which can be found at the top directory. If you do not * * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -""" +""".strip() + +labstor_preamble = """ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of LabStor + * + * LabStor 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 Lesser 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 + * . + */ +""".strip() def PrependPreamble(path): text = "" with open(path, 'r') as fp: text = fp.read() - if "Copyright (C) 2022 SCS Lab " in text: - text = text.replace(preamble, "") + text = text.replace(hermes_preamble, "") + text = text.replace(labstor_preamble, "") text = text.strip() text = re.sub("//\n// Created by [^\n]*\n//\n", "", text) text = preamble.strip() + text + "\n" From 65edff3a88265cfc7e3ec62678a95c4924ffc053 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 2 Feb 2023 08:41:34 -0600 Subject: [PATCH 099/511] preamble --- code_generators/preamble.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code_generators/preamble.py b/code_generators/preamble.py index 9ae7470b9..571fe0c63 100644 --- a/code_generators/preamble.py +++ b/code_generators/preamble.py @@ -55,9 +55,9 @@ def PrependPreamble(path): text = fp.read() text = text.replace(hermes_preamble, "") text = text.replace(labstor_preamble, "") - text = text.strip() text = re.sub("//\n// Created by [^\n]*\n//\n", "", text) - text = preamble.strip() + text + "\n" + text = text.strip() + text = hermes_preamble + "\n" + text + "\n" with open(path, 'w') as fp: fp.write(text) From 6deee81f063198ea6cded56b49c79d8067832f10 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 2 Feb 2023 08:47:22 -0600 Subject: [PATCH 100/511] preamble test_bucket --- code_generators/preamble.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/code_generators/preamble.py b/code_generators/preamble.py index 571fe0c63..a27987418 100644 --- a/code_generators/preamble.py +++ b/code_generators/preamble.py @@ -22,6 +22,20 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ """.strip() +preamble2 = """ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +""".strip() + labstor_preamble = """ /* * Copyright (C) 2022 SCS Lab , @@ -54,6 +68,7 @@ def PrependPreamble(path): with open(path, 'r') as fp: text = fp.read() text = text.replace(hermes_preamble, "") + text = text.replace(preamble2, "") text = text.replace(labstor_preamble, "") text = re.sub("//\n// Created by [^\n]*\n//\n", "", text) text = text.strip() From aac76f8966783d6555a0d17dc5644213eae23041 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 2 Feb 2023 08:48:40 -0600 Subject: [PATCH 101/511] Preamble mostly works --- code_generators/preamble.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code_generators/preamble.py b/code_generators/preamble.py index a27987418..f728bfc0c 100644 --- a/code_generators/preamble.py +++ b/code_generators/preamble.py @@ -72,7 +72,7 @@ def PrependPreamble(path): text = text.replace(labstor_preamble, "") text = re.sub("//\n// Created by [^\n]*\n//\n", "", text) text = text.strip() - text = hermes_preamble + "\n" + text + "\n" + text = hermes_preamble + "\n\n" + text + "\n" with open(path, 'w') as fp: fp.write(text) From 6fb9febad8d714b9a7e0181a108778fdef31ae65 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 2 Feb 2023 08:49:37 -0600 Subject: [PATCH 102/511] Comitting preamble --- adapter/adapter_init.cc | 14 ++++++-- adapter/filesystem/file.h | 14 ++++++-- adapter/filesystem/filesystem.cc | 20 +++++------ adapter/filesystem/filesystem_io_client.h | 14 ++++++-- .../filesystem/filesystem_mdm_singleton.cc | 12 +++++++ .../filesystem_mdm_singleton_macros.h | 12 +++++++ adapter/interceptor.h | 14 ++++++-- adapter/io_client/empty.cc | 16 +++++++-- adapter/io_client/io_client.h | 4 --- adapter/mapper/abstract_mapper.h | 4 --- adapter/mpiio/fs_api.cc | 20 +++++------ adapter/posix/posix_api_singleton.cc | 12 +++++++ adapter/posix/posix_api_singleton_macros.h | 12 +++++++ adapter/posix/posix_io_client.cc | 14 ++++++-- adapter/posix/posix_io_client.h | 14 ++++++-- adapter/stdio/fs_api.cc | 20 +++++------ adapter/test/mpiio/parallel.cc | 20 +++++------ adapter/test/posix/simple_io.cc | 20 +++++------ adapter/test/posix/simple_posix.cc | 16 +++++++-- adapter/vfd/H5FDhermes.h | 12 +++++++ adapter/vfd/H5FDhermes_err.h | 12 +++++++ benchmarks/put_get_bench.cc | 16 ++++++--- code_generators/unit/api/apis.h | 16 ++++++--- code_generators/unit/api/rpcs.cc | 14 +++++++- data_stager/finalize_hermes.cc | 20 +++++------ data_stager/stage_in.cc | 20 +++++------ data_stager/stage_out.cc | 20 +++++------ data_stager/stagers/posix_stager.cc | 20 +++++------ src/api/bucket.cc | 16 ++++++--- src/api/bucket.h | 14 ++++++-- src/api/hermes.cc | 16 ++++++--- src/api/hermes.h | 14 ++++++-- src/api/hermes_singleton.cc | 12 +++++++ src/api/hermes_singleton_macros.h | 12 +++++++ src/api/traits.h | 14 ++++++-- src/api/vbucket.cc | 16 ++++++--- src/api/vbucket.h | 14 ++++++-- src/borg_io_clients/borg_io_client.h | 14 ++++++-- src/borg_io_clients/borg_io_client_factory.h | 14 ++++++-- src/borg_io_clients/borg_posix_client.h | 14 ++++++-- src/borg_io_clients/borg_ram_client.h | 14 ++++++-- src/buffer_organizer.cc | 16 ++++++--- src/buffer_organizer.h | 14 ++++++-- src/buffer_pool.cc | 16 ++++++--- src/buffer_pool.h | 14 ++++++-- src/config_client.cc | 16 ++++++--- src/config_client.h | 14 ++++++-- src/config_client_default.h | 14 +++++++- src/config_server.cc | 14 ++++++-- src/config_server.h | 14 ++++++-- src/config_server_default.h | 14 +++++++- src/constants.h | 14 ++++++-- src/data_structures.h | 14 ++++++-- src/decorator.h | 14 ++++++-- src/dpe/minimize_io_time.cc | 20 +++++------ src/dpe/random.cc | 20 +++++------ src/dpe/round_robin.cc | 20 +++++------ src/hermes_types.cc | 16 ++++++--- src/metadata_manager.cc | 16 ++++++--- src/metadata_manager.h | 16 ++++++--- src/metadata_types.h | 14 ++++++-- src/prefetcher.cc | 20 +++++------ src/prefetcher.h | 20 +++++------ src/prefetcher_factory.h | 20 +++++------ src/prefetchers/apriori.cc | 20 +++++------ src/prefetchers/apriori.h | 20 +++++------ src/prefetchers/sequential.cc | 20 +++++------ src/prefetchers/sequential.h | 20 +++++------ src/rpc.cc | 16 ++++++--- src/rpc_thallium.cc | 2 +- src/rpc_thallium_defs.cc | 16 ++++++--- src/rpc_thallium_serialization.h | 14 ++++++-- src/status.cc | 16 ++++++--- src/statuses.h | 14 ++++++-- test/basic_test.h | 35 ++++++------------ test/main.cc | 36 ++++++------------- test/main_mpi.cc | 36 ++++++------------- test/test_bucket.cc | 22 ++++++------ test/test_rpc.cc | 22 ++++++------ test/test_vbucket.cc | 16 ++++++--- 80 files changed, 862 insertions(+), 439 deletions(-) diff --git a/adapter/adapter_init.cc b/adapter/adapter_init.cc index 99ce7cb81..1283177af 100644 --- a/adapter/adapter_init.cc +++ b/adapter/adapter_init.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 2/1/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_ADAPTER_GLOBAL_INIT_HERMES_H_ #define HERMES_ADAPTER_GLOBAL_INIT_HERMES_H_ diff --git a/adapter/filesystem/file.h b/adapter/filesystem/file.h index 10a4c4ac1..0665fd77e 100644 --- a/adapter/filesystem/file.h +++ b/adapter/filesystem/file.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 2/1/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_TYPES_H_ #define HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_TYPES_H_ diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index a30f01360..5faea0857 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "filesystem_mdm_singleton_macros.h" #include "filesystem.h" diff --git a/adapter/filesystem/filesystem_io_client.h b/adapter/filesystem/filesystem_io_client.h index 0da2ca6ea..81f88e141 100644 --- a/adapter/filesystem/filesystem_io_client.h +++ b/adapter/filesystem/filesystem_io_client.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 2/1/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_IO_CLIENT_H_ #define HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_IO_CLIENT_H_ diff --git a/adapter/filesystem/filesystem_mdm_singleton.cc b/adapter/filesystem/filesystem_mdm_singleton.cc index 42bfc8cdc..18f792c9b 100644 --- a/adapter/filesystem/filesystem_mdm_singleton.cc +++ b/adapter/filesystem/filesystem_mdm_singleton.cc @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "singleton.h" #include "filesystem_mdm.h" diff --git a/adapter/filesystem/filesystem_mdm_singleton_macros.h b/adapter/filesystem/filesystem_mdm_singleton_macros.h index e2fd8fa82..89ef94bd4 100644 --- a/adapter/filesystem/filesystem_mdm_singleton_macros.h +++ b/adapter/filesystem/filesystem_mdm_singleton_macros.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef HERMES_SINGLETON_ADAPTER_MACROS_H #define HERMES_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/interceptor.h b/adapter/interceptor.h index 818bfcbbd..fa58be973 100644 --- a/adapter/interceptor.h +++ b/adapter/interceptor.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/19/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_ADAPTER_UTILS_H_ #define HERMES_ADAPTER_UTILS_H_ diff --git a/adapter/io_client/empty.cc b/adapter/io_client/empty.cc index 6a1a31054..9d87bd5e7 100644 --- a/adapter/io_client/empty.cc +++ b/adapter/io_client/empty.cc @@ -1,3 +1,13 @@ -// -// Created by lukemartinlogan on 1/31/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index 9dd1591cc..111d03f7a 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -10,10 +10,6 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -// -// Created by manihariharan on 12/23/20. -// - #ifndef HERMES_ABSTRACT_ADAPTER_H #define HERMES_ABSTRACT_ADAPTER_H diff --git a/adapter/mapper/abstract_mapper.h b/adapter/mapper/abstract_mapper.h index 241f750bb..dd352b225 100644 --- a/adapter/mapper/abstract_mapper.h +++ b/adapter/mapper/abstract_mapper.h @@ -10,10 +10,6 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -// -// Created by manihariharan on 12/23/20. -// - #ifndef HERMES_ABSTRACT_MAPPER_H #define HERMES_ABSTRACT_MAPPER_H diff --git a/adapter/mpiio/fs_api.cc b/adapter/mpiio/fs_api.cc index ff23a8f0d..8429e8294 100644 --- a/adapter/mpiio/fs_api.cc +++ b/adapter/mpiio/fs_api.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "fs_api.h" diff --git a/adapter/posix/posix_api_singleton.cc b/adapter/posix/posix_api_singleton.cc index bc0aa4a29..72176fbcd 100644 --- a/adapter/posix/posix_api_singleton.cc +++ b/adapter/posix/posix_api_singleton.cc @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "singleton.h" #include "posix_api.h" diff --git a/adapter/posix/posix_api_singleton_macros.h b/adapter/posix/posix_api_singleton_macros.h index 4270c444a..d41d6a488 100644 --- a/adapter/posix/posix_api_singleton_macros.h +++ b/adapter/posix/posix_api_singleton_macros.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef HERMES_POSIX_SINGLETON_ADAPTER_MACROS_H #define HERMES_POSIX_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 5ce9ff6c7..d52d81e0f 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/31/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "posix_io_client.h" diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h index 3ecd5c8b1..a33befbfc 100644 --- a/adapter/posix/posix_io_client.h +++ b/adapter/posix/posix_io_client.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/31/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_ADAPTER_POSIX_POSIX_IO_CLIENT_H_ #define HERMES_ADAPTER_POSIX_POSIX_IO_CLIENT_H_ diff --git a/adapter/stdio/fs_api.cc b/adapter/stdio/fs_api.cc index c386c294c..ed8a92881 100644 --- a/adapter/stdio/fs_api.cc +++ b/adapter/stdio/fs_api.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "real_api.h" diff --git a/adapter/test/mpiio/parallel.cc b/adapter/test/mpiio/parallel.cc index 9f91a59b5..6187ddb92 100644 --- a/adapter/test/mpiio/parallel.cc +++ b/adapter/test/mpiio/parallel.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "mpi.h" #include diff --git a/adapter/test/posix/simple_io.cc b/adapter/test/posix/simple_io.cc index 78db64ab9..662da85e2 100644 --- a/adapter/test/posix/simple_io.cc +++ b/adapter/test/posix/simple_io.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "mpi.h" #include diff --git a/adapter/test/posix/simple_posix.cc b/adapter/test/posix/simple_posix.cc index 777f5ee56..9d87bd5e7 100644 --- a/adapter/test/posix/simple_posix.cc +++ b/adapter/test/posix/simple_posix.cc @@ -1,3 +1,13 @@ -// -// Created by lukemartinlogan on 2/1/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + diff --git a/adapter/vfd/H5FDhermes.h b/adapter/vfd/H5FDhermes.h index fb347273a..1f2edeca6 100644 --- a/adapter/vfd/H5FDhermes.h +++ b/adapter/vfd/H5FDhermes.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * Copyright by the Board of Trustees of the University of Illinois. * diff --git a/adapter/vfd/H5FDhermes_err.h b/adapter/vfd/H5FDhermes_err.h index 3d910b670..adc9fb550 100644 --- a/adapter/vfd/H5FDhermes_err.h +++ b/adapter/vfd/H5FDhermes_err.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * All rights reserved. * diff --git a/benchmarks/put_get_bench.cc b/benchmarks/put_get_bench.cc index 66bbe5f9d..92fa16e2c 100644 --- a/benchmarks/put_get_bench.cc +++ b/benchmarks/put_get_bench.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/27/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include @@ -78,4 +86,4 @@ int main(int argc, char **argv) { GetTest(hermes, rank, 1, blobs_per_rank, blob_size); hermes->Finalize(); MPI_Finalize(); -} \ No newline at end of file +} diff --git a/code_generators/unit/api/apis.h b/code_generators/unit/api/apis.h index 28e9b29bc..0205d5c3e 100644 --- a/code_generators/unit/api/apis.h +++ b/code_generators/unit/api/apis.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/6/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ namespace hello::hi { } // namespace hello::hi @@ -229,4 +237,4 @@ WRAP std::vector& f6(int a, std::vector b, Ctx) { } RPC_AUTOGEN_END -#endif // HERMES_CODE_GENERATORS_CODE_GENERATORS_UNIT_PROTOS_H_ \ No newline at end of file +#endif // HERMES_CODE_GENERATORS_CODE_GENERATORS_UNIT_PROTOS_H_ diff --git a/code_generators/unit/api/rpcs.cc b/code_generators/unit/api/rpcs.cc index 5f7acbb43..1163f2226 100644 --- a/code_generators/unit/api/rpcs.cc +++ b/code_generators/unit/api/rpcs.cc @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + int main() { RPC_AUTOGEN_START auto remote_f2 = @@ -53,4 +65,4 @@ server_engine_->define("f102", remote_f102); auto result = mdm->Localf101(); req.respond(result); }; - server_engine_->define("f101", remote_f101); \ No newline at end of file + server_engine_->define("f101", remote_f101); diff --git a/data_stager/finalize_hermes.cc b/data_stager/finalize_hermes.cc index 37086e6dd..087b6cf35 100644 --- a/data_stager/finalize_hermes.cc +++ b/data_stager/finalize_hermes.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "filesystem/metadata_manager.h" #include "singleton.h" diff --git a/data_stager/stage_in.cc b/data_stager/stage_in.cc index 9fa7468fa..b6ee81817 100644 --- a/data_stager/stage_in.cc +++ b/data_stager/stage_in.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "posix/fs_api.h" diff --git a/data_stager/stage_out.cc b/data_stager/stage_out.cc index 537654066..c67faf0e1 100644 --- a/data_stager/stage_out.cc +++ b/data_stager/stage_out.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "posix/fs_api.h" diff --git a/data_stager/stagers/posix_stager.cc b/data_stager/stagers/posix_stager.cc index ee92b9d91..eee0695bf 100644 --- a/data_stager/stagers/posix_stager.cc +++ b/data_stager/stagers/posix_stager.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "posix_stager.h" diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 0695171f7..9a98fe528 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/4/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "bucket.h" #include "data_placement_engine_factory.h" @@ -230,4 +238,4 @@ void Bucket::DestroyBlob(BlobId blob_id, Context &ctx) { mdm_->LocalDestroyBlob(id_, blob_id); } -} // namespace hermes::api \ No newline at end of file +} // namespace hermes::api diff --git a/src/api/bucket.h b/src/api/bucket.h index 3b15772f2..80ac580a5 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/4/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_API_BUCKET_H_ #define HERMES_SRC_API_BUCKET_H_ diff --git a/src/api/hermes.cc b/src/api/hermes.cc index a266b88a7..ba6815869 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/3/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "hermes.h" #include "bucket.h" @@ -154,4 +162,4 @@ std::shared_ptr Hermes::GetVBucket(std::string name, return std::make_shared(name, ctx, opts); } -} // namespace hermes::api \ No newline at end of file +} // namespace hermes::api diff --git a/src/api/hermes.h b/src/api/hermes.h index 2e1f9edcc..c0c676dab 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/2/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_API_HERMES_H_ #define HERMES_SRC_API_HERMES_H_ diff --git a/src/api/hermes_singleton.cc b/src/api/hermes_singleton.cc index b3948d2b7..39d012038 100644 --- a/src/api/hermes_singleton.cc +++ b/src/api/hermes_singleton.cc @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "singleton.h" #include "hermes.h" diff --git a/src/api/hermes_singleton_macros.h b/src/api/hermes_singleton_macros.h index 1095adf7b..51da6d3a2 100644 --- a/src/api/hermes_singleton_macros.h +++ b/src/api/hermes_singleton_macros.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef HERMES_SINGLETON_SRC_MACROS_H #define HERMES_SINGLETON_SRC_MACROS_H diff --git a/src/api/traits.h b/src/api/traits.h index c3e6aa933..e5bebb489 100644 --- a/src/api/traits.h +++ b/src/api/traits.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/4/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_API_TRAITS_H_ #define HERMES_SRC_API_TRAITS_H_ diff --git a/src/api/vbucket.cc b/src/api/vbucket.cc index 13694a657..39e3f0758 100644 --- a/src/api/vbucket.cc +++ b/src/api/vbucket.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/4/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "vbucket.h" #include "hermes.h" @@ -70,4 +78,4 @@ bool VBucket::ContainsBlob(BlobId blob_id) { return mdm_->LocalVBucketContainsBlob(id_, blob_id); } -} // namespace hermes::api \ No newline at end of file +} // namespace hermes::api diff --git a/src/api/vbucket.h b/src/api/vbucket.h index c21cabebc..800ab3bb0 100644 --- a/src/api/vbucket.h +++ b/src/api/vbucket.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/4/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_API_VBUCKET_H_ #define HERMES_SRC_API_VBUCKET_H_ diff --git a/src/borg_io_clients/borg_io_client.h b/src/borg_io_clients/borg_io_client.h index 0e47881fa..519bd8fef 100644 --- a/src/borg_io_clients/borg_io_client.h +++ b/src/borg_io_clients/borg_io_client.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/22/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_BORG_IO_CLIENTS_IO_CLIENT_H #define HERMES_SRC_BORG_IO_CLIENTS_IO_CLIENT_H diff --git a/src/borg_io_clients/borg_io_client_factory.h b/src/borg_io_clients/borg_io_client_factory.h index 4e6adc1ab..f96c8fe25 100644 --- a/src/borg_io_clients/borg_io_client_factory.h +++ b/src/borg_io_clients/borg_io_client_factory.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/22/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_BORG_IO_CLIENTS_IO_CLIENT_FACTORY_H #define HERMES_SRC_BORG_IO_CLIENTS_IO_CLIENT_FACTORY_H diff --git a/src/borg_io_clients/borg_posix_client.h b/src/borg_io_clients/borg_posix_client.h index 0a88c4a35..3bfe45d0f 100644 --- a/src/borg_io_clients/borg_posix_client.h +++ b/src/borg_io_clients/borg_posix_client.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/22/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_BORG_IO_CLIENTS_POSIX_H #define HERMES_SRC_BORG_IO_CLIENTS_POSIX_H diff --git a/src/borg_io_clients/borg_ram_client.h b/src/borg_io_clients/borg_ram_client.h index 29e69ef70..568865d67 100644 --- a/src/borg_io_clients/borg_ram_client.h +++ b/src/borg_io_clients/borg_ram_client.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/22/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_BORG_IO_CLIENTS_RAM_H_ #define HERMES_SRC_BORG_IO_CLIENTS_RAM_H_ diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 3793d3b9d..6debd42ff 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/19/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "buffer_organizer.h" #include "metadata_manager.h" @@ -90,4 +98,4 @@ RPC void BufferOrganizer::LocalCopyBuffers(lipc::vector &dst, lipc::vector &src) { } -} // namespace hermes \ No newline at end of file +} // namespace hermes diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index adf376e0a..c1f6be58a 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/19/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_BUFFER_ORGANIZER_H_ #define HERMES_SRC_BUFFER_ORGANIZER_H_ diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 65e769397..f845a4fdb 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/19/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "buffer_pool.h" #include "metadata_manager.h" @@ -81,4 +89,4 @@ bool BufferPool::LocalReleaseBuffers(lipc::vector &buffers) { return true; } -} // namespace hermes \ No newline at end of file +} // namespace hermes diff --git a/src/buffer_pool.h b/src/buffer_pool.h index f688df993..16dc6ebec 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/19/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_BUFFER_POOL_H_ #define HERMES_SRC_BUFFER_POOL_H_ diff --git a/src/config_client.cc b/src/config_client.cc index 911adb7be..9e57ed2b4 100644 --- a/src/config_client.cc +++ b/src/config_client.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/2/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "config_client.h" #include "config_client_default.h" @@ -23,4 +31,4 @@ void ClientConfig::LoadDefault() { LoadText(kClientDefaultConfigStr, false); } -} // namespace hermes::config \ No newline at end of file +} // namespace hermes::config diff --git a/src/config_client.h b/src/config_client.h index bd21c71d9..eebfdb439 100644 --- a/src/config_client.h +++ b/src/config_client.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/19/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_CONFIG_CLIENT_H_ #define HERMES_SRC_CONFIG_CLIENT_H_ diff --git a/src/config_client_default.h b/src/config_client_default.h index 25b2ad580..f4c6e6dc8 100644 --- a/src/config_client_default.h +++ b/src/config_client_default.h @@ -1,6 +1,18 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ #define HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ const char* kClientDefaultConfigStr = "stop_daemon: true\n" "file_page_size: 1024KB\n"; -#endif // HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ \ No newline at end of file +#endif // HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ diff --git a/src/config_server.cc b/src/config_server.cc index 1b75f9e99..84cc70b68 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/2/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include diff --git a/src/config_server.h b/src/config_server.h index 4c2c74074..d0593602b 100644 --- a/src/config_server.h +++ b/src/config_server.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/19/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_CONFIG_SERVER_H_ #define HERMES_SRC_CONFIG_SERVER_H_ diff --git a/src/config_server_default.h b/src/config_server_default.h index 837f7265f..f29883f42 100644 --- a/src/config_server_default.h +++ b/src/config_server_default.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ #define HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ const char* kServerDefaultConfigStr = @@ -145,4 +157,4 @@ const char* kServerDefaultConfigStr = "#Paths which are never ignored when buffering data\n" "path_inclusions: [\"/var/opt/cray/dws/mounts/\"]\n" "\n"; -#endif // HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ \ No newline at end of file +#endif // HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ diff --git a/src/constants.h b/src/constants.h index 6da3b36e4..ade7633be 100644 --- a/src/constants.h +++ b/src/constants.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/2/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_CONSTANTS_H_ #define HERMES_SRC_CONSTANTS_H_ diff --git a/src/data_structures.h b/src/data_structures.h index fc0814b12..c5af12669 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/2/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_DATA_STRUCTURES_H_ #define HERMES_SRC_DATA_STRUCTURES_H_ diff --git a/src/decorator.h b/src/decorator.h index 1d6124cf9..4d5016e82 100644 --- a/src/decorator.h +++ b/src/decorator.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/1/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_RPC_GENERATOR_DECORATOR_H_ #define HERMES_SRC_RPC_GENERATOR_DECORATOR_H_ diff --git a/src/dpe/minimize_io_time.cc b/src/dpe/minimize_io_time.cc index 085933c88..428d5cfd0 100644 --- a/src/dpe/minimize_io_time.cc +++ b/src/dpe/minimize_io_time.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "minimize_io_time.h" #include "linprog.h" diff --git a/src/dpe/random.cc b/src/dpe/random.cc index 9d04b1dc0..92ad83960 100644 --- a/src/dpe/random.cc +++ b/src/dpe/random.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "random.h" diff --git a/src/dpe/round_robin.cc b/src/dpe/round_robin.cc index 21dd209a0..12b64ea04 100644 --- a/src/dpe/round_robin.cc +++ b/src/dpe/round_robin.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "round_robin.h" #include diff --git a/src/hermes_types.cc b/src/hermes_types.cc index 44e6de92b..f75e4de54 100644 --- a/src/hermes_types.cc +++ b/src/hermes_types.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/5/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "hermes_types.h" #include "hermes.h" @@ -19,4 +27,4 @@ Context::Context() disable_swap(false), vbkt_id_({0, 0}) {} -} // namespace hermes::api \ No newline at end of file +} // namespace hermes::api diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index b2382d137..288504bec 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/4/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "hermes.h" #include "metadata_manager.h" @@ -541,4 +549,4 @@ bool MetadataManager::LocalDestroyVBucket(VBucketId vbkt_id) { return true; } -} // namespace hermes \ No newline at end of file +} // namespace hermes diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 7cea2168f..a9ed99832 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/4/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_METADATA_MANAGER_H_ #define HERMES_SRC_METADATA_MANAGER_H_ @@ -353,4 +361,4 @@ class MetadataManager { } // namespace hermes -#endif // HERMES_SRC_METADATA_MANAGER_H_ \ No newline at end of file +#endif // HERMES_SRC_METADATA_MANAGER_H_ diff --git a/src/metadata_types.h b/src/metadata_types.h index dc7fa4748..4d69a20ad 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/7/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_METADATA_TYPES_H_ #define HERMES_SRC_METADATA_TYPES_H_ diff --git a/src/prefetcher.cc b/src/prefetcher.cc index 24f274612..2c0c22b24 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "prefetcher_factory.h" #include "metadata_manager.h" diff --git a/src/prefetcher.h b/src/prefetcher.h index 3ea3e8512..7d062e9cb 100644 --- a/src/prefetcher.h +++ b/src/prefetcher.h @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_PREFETCHER_H_ #define HERMES_SRC_PREFETCHER_H_ diff --git a/src/prefetcher_factory.h b/src/prefetcher_factory.h index ecb138f2b..d2be71a9b 100644 --- a/src/prefetcher_factory.h +++ b/src/prefetcher_factory.h @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_PREFETCHER_FACTORY_H_ #define HERMES_SRC_PREFETCHER_FACTORY_H_ diff --git a/src/prefetchers/apriori.cc b/src/prefetchers/apriori.cc index 88f58be94..710111506 100644 --- a/src/prefetchers/apriori.cc +++ b/src/prefetchers/apriori.cc @@ -1,13 +1,13 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "apriori.h" diff --git a/src/prefetchers/apriori.h b/src/prefetchers/apriori.h index 666c5d0e9..a9cdbe7dd 100644 --- a/src/prefetchers/apriori.h +++ b/src/prefetchers/apriori.h @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_PREFETCHERS_APRIORI_H_ #define HERMES_SRC_PREFETCHERS_APRIORI_H_ diff --git a/src/prefetchers/sequential.cc b/src/prefetchers/sequential.cc index a2ba1b736..c47b45bbe 100644 --- a/src/prefetchers/sequential.cc +++ b/src/prefetchers/sequential.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "sequential.h" #include "singleton.h" diff --git a/src/prefetchers/sequential.h b/src/prefetchers/sequential.h index 04405d3b8..da4fba7a3 100644 --- a/src/prefetchers/sequential.h +++ b/src/prefetchers/sequential.h @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ #define HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ diff --git a/src/rpc.cc b/src/rpc.cc index 318eacfd6..2ea7e3508 100644 --- a/src/rpc.cc +++ b/src/rpc.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/4/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "rpc.h" #include "hermes.h" @@ -126,4 +134,4 @@ std::string RpcContext::_GetIpAddress(const std::string &host_name) { return ip_address; } -} \ No newline at end of file +} diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 58dfc1234..cea60fe59 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -94,4 +94,4 @@ void ThalliumRpc::Finalize() { } } -} // namespace hermes \ No newline at end of file +} // namespace hermes diff --git a/src/rpc_thallium_defs.cc b/src/rpc_thallium_defs.cc index 00ef5027d..dc091c5fb 100644 --- a/src/rpc_thallium_defs.cc +++ b/src/rpc_thallium_defs.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/3/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "rpc_thallium.h" #include "metadata_manager.h" @@ -20,4 +28,4 @@ void ThalliumRpc::DefineRpcs() { RPC_AUTOGEN_END } -} // namespace hermes \ No newline at end of file +} // namespace hermes diff --git a/src/rpc_thallium_serialization.h b/src/rpc_thallium_serialization.h index 678bd4e83..96eca8b8c 100644 --- a/src/rpc_thallium_serialization.h +++ b/src/rpc_thallium_serialization.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/2/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_RPC_THALLIUM_SERIALIZATION_H_ #define HERMES_SRC_RPC_THALLIUM_SERIALIZATION_H_ diff --git a/src/status.cc b/src/status.cc index d0d54c652..92d9f3b9f 100644 --- a/src/status.cc +++ b/src/status.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/21/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "status.h" @@ -8,4 +16,4 @@ namespace hermes::api { int Status::code_counter_ = 0; -} // namespace hermes::api \ No newline at end of file +} // namespace hermes::api diff --git a/src/statuses.h b/src/statuses.h index 5ae250539..4d3cd6f34 100644 --- a/src/statuses.h +++ b/src/statuses.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/21/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SRC_STATUSES_H_ #define HERMES_SRC_STATUSES_H_ diff --git a/test/basic_test.h b/test/basic_test.h index d6d0fb970..02b546b05 100644 --- a/test/basic_test.h +++ b/test/basic_test.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of LabStor - * - * LabStor 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef LABSTOR_TEST_UNIT_BASIC_TEST_H_ #define LABSTOR_TEST_UNIT_BASIC_TEST_H_ diff --git a/test/main.cc b/test/main.cc index c48ca4d71..da1e76728 100644 --- a/test/main.cc +++ b/test/main.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of LabStor - * - * LabStor 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include diff --git a/test/main_mpi.cc b/test/main_mpi.cc index 9f0da40e7..c34f81eca 100644 --- a/test/main_mpi.cc +++ b/test/main_mpi.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of LabStor - * - * LabStor 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include diff --git a/test/test_bucket.cc b/test/test_bucket.cc index 476300158..8da2de77f 100644 --- a/test/test_bucket.cc +++ b/test/test_bucket.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include @@ -159,4 +159,4 @@ TEST_CASE("TestBlobRename") { TEST_CASE("TestBlobDestroy") { TestBlobDestroy(HERMES); -} \ No newline at end of file +} diff --git a/test/test_rpc.cc b/test/test_rpc.cc index 228fcbe61..a00ce09f4 100644 --- a/test/test_rpc.cc +++ b/test/test_rpc.cc @@ -1,14 +1,14 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include @@ -32,4 +32,4 @@ void MainPosttest() { TEST_CASE("TestRpc") { HERMES->Finalize(); -} \ No newline at end of file +} diff --git a/test/test_vbucket.cc b/test/test_vbucket.cc index 8e86a0a9f..4627e0edc 100644 --- a/test/test_vbucket.cc +++ b/test/test_vbucket.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/5/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include @@ -37,4 +45,4 @@ void TestVBucketCreateDestroy(hapi::Hermes *hermes) { TEST_CASE("TestVBucketCreate") { TestVBucketCreateDestroy(HERMES); -} \ No newline at end of file +} From 15847eb61769b5e903dd8aceb6822a6d66ed9737 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 2 Feb 2023 09:25:35 -0600 Subject: [PATCH 103/511] Fix lint issues --- adapter/filesystem/file.h | 2 +- adapter/filesystem/filesystem.cc | 2 +- adapter/filesystem/filesystem_mdm_singleton.cc | 3 ++- adapter/filesystem/filesystem_mdm_singleton_macros.h | 3 ++- adapter/posix/posix_api_singleton.cc | 3 ++- adapter/posix/posix_api_singleton_macros.h | 3 ++- adapter/posix/posix_fs_api.h | 3 ++- adapter/posix/posix_io_client.cc | 3 +-- adapter/posix/posix_io_client.h | 3 ++- ci/lint.sh | 2 +- src/api/bucket.h | 4 +--- src/api/hermes.h | 2 +- src/api/hermes_singleton.cc | 3 ++- src/borg_io_clients/borg_io_client_factory.h | 2 +- src/borg_io_clients/borg_posix_client.h | 2 +- src/borg_io_clients/borg_ram_client.h | 2 +- src/config.h | 5 +++-- src/config_client.h | 2 +- src/config_server.cc | 2 +- src/constants.h | 2 +- src/dpe/minimize_io_time.cc | 3 ++- src/metadata_manager.h | 3 ++- src/metadata_types.h | 2 +- src/prefetcher.cc | 4 ++-- src/rpc.cc | 2 +- src/rpc_thallium.cc | 2 +- src/rpc_thallium.h | 8 ++++---- src/singleton.h | 2 +- src/status.h | 2 +- src/statuses.h | 2 +- 30 files changed, 45 insertions(+), 38 deletions(-) diff --git a/adapter/filesystem/file.h b/adapter/filesystem/file.h index 0665fd77e..b47120e01 100644 --- a/adapter/filesystem/file.h +++ b/adapter/filesystem/file.h @@ -58,7 +58,7 @@ struct File : public IoClientContext { } }; -} // hermes::adapter::fs +} // namespace hermes::adapter::fs namespace std { /** A structure to represent hash */ diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 5faea0857..0c26f278b 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -182,7 +182,7 @@ off_t Filesystem::Seek(File &f, AdapterStat &stat, break; } case SeekMode::kEnd: { - //TODO(llogan): Fix seek end + // TODO(llogan): Fix seek end // stat.st_ptr_ = stat.bkt_id_-> + offset; stat.st_ptr_ = 0 + offset; break; diff --git a/adapter/filesystem/filesystem_mdm_singleton.cc b/adapter/filesystem/filesystem_mdm_singleton.cc index 18f792c9b..b2b004681 100644 --- a/adapter/filesystem/filesystem_mdm_singleton.cc +++ b/adapter/filesystem/filesystem_mdm_singleton.cc @@ -14,4 +14,5 @@ #include "filesystem_mdm.h" template<> hermes::adapter::fs::MetadataManager -hermes::GlobalSingleton::obj_ = hermes::adapter::fs::MetadataManager(); +hermes::GlobalSingleton::obj_ = + hermes::adapter::fs::MetadataManager(); diff --git a/adapter/filesystem/filesystem_mdm_singleton_macros.h b/adapter/filesystem/filesystem_mdm_singleton_macros.h index 89ef94bd4..25bb028af 100644 --- a/adapter/filesystem/filesystem_mdm_singleton_macros.h +++ b/adapter/filesystem/filesystem_mdm_singleton_macros.h @@ -15,7 +15,8 @@ #include "singleton.h" -#define HERMES_FS_METADATA_MANAGER hermes::GlobalSingleton::GetInstance() +#define HERMES_FS_METADATA_MANAGER \ + hermes::GlobalSingleton::GetInstance() #define HERMES_FS_METADATA_MANAGER_T hermes::adapter::fs::MetadataManager* #endif // HERMES_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/posix/posix_api_singleton.cc b/adapter/posix/posix_api_singleton.cc index 72176fbcd..3217e0567 100644 --- a/adapter/posix/posix_api_singleton.cc +++ b/adapter/posix/posix_api_singleton.cc @@ -13,4 +13,5 @@ #include "singleton.h" #include "posix_api.h" -template<> hermes::adapter::fs::PosixApi hermes::GlobalSingleton::obj_ = hermes::adapter::fs::PosixApi(); +template<> hermes::adapter::fs::PosixApi hermes::GlobalSingleton< + hermes::adapter::fs::PosixApi>::obj_ = hermes::adapter::fs::PosixApi(); diff --git a/adapter/posix/posix_api_singleton_macros.h b/adapter/posix/posix_api_singleton_macros.h index d41d6a488..e0ddb1500 100644 --- a/adapter/posix/posix_api_singleton_macros.h +++ b/adapter/posix/posix_api_singleton_macros.h @@ -15,7 +15,8 @@ #include "singleton.h" -#define HERMES_POSIX_API hermes::GlobalSingleton::GetInstance() +#define HERMES_POSIX_API \ + hermes::GlobalSingleton::GetInstance() #define HERMES_POSIX_API_T hermes::adapter::fs::PosixApi* #endif // HERMES_POSIX_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/posix/posix_fs_api.h b/adapter/posix/posix_fs_api.h index f05633a45..361ae908b 100644 --- a/adapter/posix/posix_fs_api.h +++ b/adapter/posix/posix_fs_api.h @@ -53,7 +53,8 @@ class PosixFs : public hermes::adapter::fs::Filesystem { }; /** Simplify access to the stateless PosixFs Singleton */ -#define HERMES_POSIX_FS hermes::EasySingleton::GetInstance() +#define HERMES_POSIX_FS \ + hermes::EasyGlobalSingleton::GetInstance() #define HERMES_POSIX_FS_T hermes::adapter::fs::PosixFs* } // namespace hermes::adapter::fs diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index d52d81e0f..b5fcedfea 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -40,7 +40,6 @@ void PosixIoClient::RealOpen(IoClientContext &f, void PosixIoClient::HermesOpen(IoClientContext &f, const IoClientStat &stat, FilesystemIoClientContext &fs_mdm) { - } /** Synchronize \a file FILE f */ @@ -107,7 +106,7 @@ void PosixIoClient::ReadBlob(Blob &full_blob, << std::endl; int fd = real_api->open(io_ctx.filename_.c_str(), O_RDONLY); if (fd < 0) { - status.posix_ret_ =0; + status.posix_ret_ = 0; return; } status.posix_ret_ = real_api->pread(fd, diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h index a33befbfc..67bc99c07 100644 --- a/adapter/posix/posix_io_client.h +++ b/adapter/posix/posix_io_client.h @@ -88,7 +88,8 @@ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { } // namespace hermes::adapter::fs /** Simplify access to the stateless PosixIoClient Singleton */ -#define HERMES_POSIX_IO_CLIENT hermes::EasySingleton::GetInstance() +#define HERMES_POSIX_IO_CLIENT \ + hermes::EasyGlobalSingleton::GetInstance() #define HERMES_POSIX_IO_CLIENT_T hermes::adapter::fs::PosixIoClient* #endif // HERMES_ADAPTER_POSIX_POSIX_IO_CLIENT_H_ diff --git a/ci/lint.sh b/ci/lint.sh index 327aa51e5..86fa44a0f 100644 --- a/ci/lint.sh +++ b/ci/lint.sh @@ -5,7 +5,7 @@ ADAPTER=${HERMES_ROOT}/adapter cpplint --recursive \ --exclude="${HERMES_ROOT}/src/config_server_default.h" \ --exclude="${HERMES_ROOT}/src/config_client_default.h" \ ---exclude="${ADAPTER}/posix/real_api.h" \ +--exclude="${ADAPTER}/posix/posix_api.h" \ --exclude="${ADAPTER}/stdio/real_api.h" \ --exclude="${ADAPTER}/mpiio/real_api.h" \ "${HERMES_ROOT}/adapter" "${HERMES_ROOT}/benchmarks" "${HERMES_ROOT}/data_stager" \ diff --git a/src/api/bucket.h b/src/api/bucket.h index 80ac580a5..ba04a0d2b 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -34,7 +34,6 @@ class Bucket { /// Bucket Operations ////////////////////////// public: - /** * Get or create \a bkt_name bucket. * @@ -88,7 +87,6 @@ class Bucket { /// Blob Operations /////////////////////// public: - /** * Get the id of a blob from the blob name * @@ -177,6 +175,6 @@ class Bucket { void DestroyBlob(BlobId blob_id, Context &ctx); }; -} +} // namespace hermes::api #endif // HERMES_SRC_API_BUCKET_H_ diff --git a/src/api/hermes.h b/src/api/hermes.h index c0c676dab..4fa365a51 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -138,7 +138,7 @@ class Hermes { /** Get an environment variable with null safety. */ inline std::string GetEnvSafe(const char *env_name) { char *val = getenv(env_name); - if (val == nullptr){ + if (val == nullptr) { return ""; } return val; diff --git a/src/api/hermes_singleton.cc b/src/api/hermes_singleton.cc index 39d012038..56460506d 100644 --- a/src/api/hermes_singleton.cc +++ b/src/api/hermes_singleton.cc @@ -13,4 +13,5 @@ #include "singleton.h" #include "hermes.h" -template<> hermes::api::Hermes hermes::GlobalSingleton::obj_ = hermes::api::Hermes(); +template<> hermes::api::Hermes hermes::GlobalSingleton< + hermes::api::Hermes>::obj_ = hermes::api::Hermes(); diff --git a/src/borg_io_clients/borg_io_client_factory.h b/src/borg_io_clients/borg_io_client_factory.h index f96c8fe25..d196cbc8b 100644 --- a/src/borg_io_clients/borg_io_client_factory.h +++ b/src/borg_io_clients/borg_io_client_factory.h @@ -41,6 +41,6 @@ class BorgIoClientFactory { } }; -} // namespace hermes +} // namespace hermes::borg #endif // HERMES_SRC_BORG_IO_CLIENTS_IO_CLIENT_FACTORY_H diff --git a/src/borg_io_clients/borg_posix_client.h b/src/borg_io_clients/borg_posix_client.h index 3bfe45d0f..6edcb5edd 100644 --- a/src/borg_io_clients/borg_posix_client.h +++ b/src/borg_io_clients/borg_posix_client.h @@ -66,6 +66,6 @@ class PosixIoClient : public BorgIoClient { } }; -} // namespace hermes +} // namespace hermes::borg #endif // HERMES_SRC_BORG_IO_CLIENTS_POSIX_H diff --git a/src/borg_io_clients/borg_ram_client.h b/src/borg_io_clients/borg_ram_client.h index 568865d67..6716c660c 100644 --- a/src/borg_io_clients/borg_ram_client.h +++ b/src/borg_io_clients/borg_ram_client.h @@ -53,6 +53,6 @@ class RamIoClient : public BorgIoClient { } }; -} // namespace hermes +} // namespace hermes::borg #endif // HERMES_SRC_BORG_IO_CLIENTS_RAM_H_ diff --git a/src/config.h b/src/config.h index 67ff277ca..cdd45ecb1 100644 --- a/src/config.h +++ b/src/config.h @@ -62,7 +62,8 @@ class BaseConfig { }; /** print \a expected value and fail when an error occurs */ -static void PrintExpectedAndFail(const std::string &expected, u32 line_number = 0) { +static void PrintExpectedAndFail(const std::string &expected, + u32 line_number = 0) { std::ostringstream msg; msg << "Configuration parser expected '" << expected << "'"; if (line_number > 0) { @@ -74,7 +75,7 @@ static void PrintExpectedAndFail(const std::string &expected, u32 line_number = } /** parse \a list_node vector from configuration file in YAML */ -template> +template> static void ParseVector(YAML::Node list_node, VEC_TYPE &list) { if constexpr(IS_SHM_SMART_POINTER(VEC_TYPE)) { for (auto val_node : list_node) { diff --git a/src/config_client.h b/src/config_client.h index eebfdb439..a4be3c6f6 100644 --- a/src/config_client.h +++ b/src/config_client.h @@ -35,7 +35,7 @@ class ClientConfig : public BaseConfig { void ParseYAML(YAML::Node &yaml_conf) override; }; -} // hermes::config +} // namespace hermes::config namespace hermes { using config::ClientConfig; diff --git a/src/config_server.cc b/src/config_server.cc index 84cc70b68..a8cec5681 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -161,4 +161,4 @@ void ServerConfig::LoadDefault() { LoadText(kServerDefaultConfigStr, false); } -} // hermes::config +} // namespace hermes::config diff --git a/src/constants.h b/src/constants.h index ade7633be..77e9089ef 100644 --- a/src/constants.h +++ b/src/constants.h @@ -30,6 +30,6 @@ static const char kBoPrefix[] = "BO::"; /**< buffer organizer prefix */ /** buffer organizer prefix length */ static const int kBoPrefixLength = sizeof(kBoPrefix) - 1; -} +} // namespace hermes #endif // HERMES_SRC_CONSTANTS_H_ diff --git a/src/dpe/minimize_io_time.cc b/src/dpe/minimize_io_time.cc index 428d5cfd0..1fa5b5e5c 100644 --- a/src/dpe/minimize_io_time.cc +++ b/src/dpe/minimize_io_time.cc @@ -61,7 +61,8 @@ Status MinimizeIoTime::Placement(const std::vector &blob_sizes, // Constraint #2: Capacity constraints for (size_t j = 0; j < num_targets; ++j) { double rem_cap_thresh = - static_cast((*targets[j]).rem_cap_) * (1 - minimum_remaining_capacity); + static_cast((*targets[j]).rem_cap_) * + (1 - minimum_remaining_capacity); double est_rem_cap = capacity_change_threshold * (*targets[j]).rem_cap_; double max_capacity = std::max({rem_cap_thresh, est_rem_cap}); if (max_capacity > 0) { diff --git a/src/metadata_manager.h b/src/metadata_manager.h index a9ed99832..20e4a1528 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -357,7 +357,8 @@ class MetadataManager { * */ lipc::vector GetGlobalTargetInfo() { return {}; - }}; + } +}; } // namespace hermes diff --git a/src/metadata_types.h b/src/metadata_types.h index 4d69a20ad..527d34d2f 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -62,7 +62,7 @@ struct BufferInfo { BufferInfo(TargetId tid, size_t t_off, size_t t_size, size_t blob_off, size_t blob_size) : tid_(tid), t_off_(t_off), t_size_(t_size), - blob_off_(blob_off), blob_size_(blob_size){} + blob_off_(blob_off), blob_size_(blob_size) {} /** Copy constructor */ BufferInfo(const BufferInfo &other) { diff --git a/src/prefetcher.cc b/src/prefetcher.cc index 2c0c22b24..d766b4000 100644 --- a/src/prefetcher.cc +++ b/src/prefetcher.cc @@ -97,7 +97,7 @@ bool HasOnlyDemotions(PrefetchDecision &decision, float &decay) { decay = std::min(decay, prefetch_stat.decay_); } return true; -}; +} void Prefetcher::CalculateBlobScore(struct timespec &ts, PrefetchDecision &decision) { @@ -204,7 +204,7 @@ void Prefetcher::Process() { // TODO(llogan): a hack to help BORG shuffle data struct timespec ts2; - while(PrefetchStat::DiffTimespec(&ts2, &ts) < 1) { + while (PrefetchStat::DiffTimespec(&ts2, &ts) < 1) { timespec_get(&ts2, TIME_UTC); ABT_thread_yield(); } diff --git a/src/rpc.cc b/src/rpc.cc index 2ea7e3508..3b01f7046 100644 --- a/src/rpc.cc +++ b/src/rpc.cc @@ -134,4 +134,4 @@ std::string RpcContext::_GetIpAddress(const std::string &host_name) { return ip_address; } -} +} // namespace hermes diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index cea60fe59..211f2c599 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -88,7 +88,7 @@ void ThalliumRpc::Finalize() { break; } case HermesType::kColocated: { - //TODO(llogan) + // TODO(llogan) break; } } diff --git a/src/rpc_thallium.h b/src/rpc_thallium.h index 285616053..bf0f1e58c 100644 --- a/src/rpc_thallium.h +++ b/src/rpc_thallium.h @@ -31,10 +31,10 @@ namespace hermes { class ThalliumRpc : public RpcContext { public: std::atomic kill_requested_; /**< is kill requested? */ - std::unique_ptr client_engine_; /**< pointer to engine */ - std::unique_ptr server_engine_; /**< pointer to engine */ - std::unique_ptr bo_engine_; /**< pointer to buf. org. engine */ - std::unique_ptr io_engine_; /**< pointer to engine */ + std::unique_ptr client_engine_; /**< pointer to client engine */ + std::unique_ptr server_engine_; /**< pointer to server engine */ + std::unique_ptr bo_engine_; /**< pointer to borg engine */ + std::unique_ptr io_engine_; /**< pointer to I/O engine */ ABT_xstream execution_stream_; /**< Argobots execution stream */ /** initialize RPC context */ diff --git a/src/singleton.h b/src/singleton.h index c434f754a..755bf6e81 100644 --- a/src/singleton.h +++ b/src/singleton.h @@ -34,7 +34,7 @@ class Singleton { /** Get or create an instance of type T */ template inline static T* GetInstance(Args ...args) { - if(!obj_) { obj_ = std::make_unique(args...); } + if (!obj_) { obj_ = std::make_unique(args...); } return obj_.get(); } }; diff --git a/src/status.h b/src/status.h index 23abe7f3f..e9d3f0bcf 100644 --- a/src/status.h +++ b/src/status.h @@ -51,5 +51,5 @@ class Status { } }; -} // hermes +} // namespace hermes::api #endif // HERMES_STATUS_H_ diff --git a/src/statuses.h b/src/statuses.h index 4d3cd6f34..ebcd90835 100644 --- a/src/statuses.h +++ b/src/statuses.h @@ -29,6 +29,6 @@ const Status BUFFER_POOL_OUT_OF_RAM( const Status PARTIAL_GET_OR_CREATE_OVERFLOW( "The read exceeds the size of the backend's data"); -} +} // namespace hermes #endif // HERMES_SRC_STATUSES_H_ From d6a3bea8df665abcafdb182fb13e19b580aab711 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 2 Feb 2023 23:15:00 -0600 Subject: [PATCH 104/511] Move some I/O opts back to I/O client --- adapter/filesystem/filesystem.cc | 48 +++++++++++++++++++++++---- adapter/filesystem/filesystem.h | 56 ++++++++++---------------------- adapter/io_client/io_client.h | 19 +++++++++-- src/data_structures.h | 1 + 4 files changed, 78 insertions(+), 46 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 0c26f278b..ac400dd86 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -89,8 +89,7 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, ctx); data_offset += p.blob_size_; } - off_t f_offset = off + data_offset; - if (opts.seek_) { stat.st_ptr_ = f_offset; } + if (opts.DoSeek()) { stat.st_ptr_ = off + data_offset; } stat.UpdateTime(); ret = data_offset; @@ -100,6 +99,43 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { + (void) f; + std::shared_ptr &bkt = stat.bkt_id_; + std::string filename = bkt->GetName(); + LOG(INFO) << "Read called for filename: " << filename << " on offset: " + << off << " and size: " << total_size << std::endl; + + size_t ret; + BlobPlacements mapping; + auto mapper = MapperFactory().Get(MapperType::kBalancedMapper); + mapper->map(off, total_size, mapping); + size_t data_offset = 0; + size_t kPageSize = HERMES->client_config_.file_page_size_; + + for (const auto &p : mapping) { + Blob blob_wrap((const char*)ptr + data_offset, off); + lipc::charbuf blob_name(p.CreateBlobName()); + BlobId blob_id; + IoClientContext io_ctx; + Context ctx; + io_ctx.filename_ = filename; + opts.backend_off_ = p.page_ * kPageSize; + opts.backend_size_ = kPageSize; + bkt->PartialGetOrCreate(blob_name.str(), + blob_wrap, + p.blob_off_, + p.blob_size_, + blob_id, + io_ctx, + opts, + ctx); + data_offset += p.blob_size_; + } + if (opts.DoSeek()) { stat.st_ptr_ = off + data_offset; } + stat.UpdateTime(); + + ret = data_offset; + return ret; } HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, @@ -282,7 +318,7 @@ size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, return 0; } stat_exists = true; - opts.seek_ = false; + opts.UnsetSeek(); return Write(f, *stat, ptr, off, total_size, io_status, opts); } @@ -296,7 +332,7 @@ size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, return 0; } stat_exists = true; - opts.seek_ = false; + opts.UnsetSeek(); return Read(f, *stat, ptr, off, total_size, io_status, opts); } @@ -336,7 +372,7 @@ HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, return 0; } stat_exists = true; - opts.seek_ = false; + opts.UnsetSeek(); return AWrite(f, *stat, ptr, off, total_size, req_id, io_status, opts); } @@ -350,7 +386,7 @@ HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, return 0; } stat_exists = true; - opts.seek_ = false; + opts.UnsetSeek(); return ARead(f, *stat, ptr, off, total_size, req_id, io_status, opts); } diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index ae43defce..f951e0efb 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -60,52 +60,32 @@ struct AdapterStat : public IoClientStat { } }; -/** A structure to represent IO options */ -struct IoOptions : public IoClientOptions { - hapi::PlacementPolicy dpe_; /**< data placement policy */ - bool seek_; /**< use seek? */ - bool with_fallback_; /**< use fallback? */ +/**< Whether to perform seek */ +#define HERMES_FS_SEEK (1<< (HERMES_IO_CLIENT_FLAGS_COUNT)) +/** + * A structure to represent IO options for FS adapter. + * For now, nothing additional than the typical IoClientOptions. + * */ +struct IoOptions : public IoClientOptions { /** Default constructor */ - IoOptions() - : dpe_(hapi::PlacementPolicy::kNone), - seek_(true), - with_fallback_(true) {} - - /** return options with \a dpe parallel data placement engine */ - static IoOptions WithParallelDpe(hapi::PlacementPolicy dpe) { - IoOptions opts; - opts.dpe_ = dpe; - return opts; + IoOptions() : IoClientOptions() { + flags_.SetBits(HERMES_FS_SEEK); } - /** return direct IO options by setting placement policy to none */ - static IoOptions DirectIo(IoOptions &cur_opts) { - IoOptions opts(cur_opts); - opts.seek_ = false; - opts.dpe_ = hapi::PlacementPolicy::kNone; - opts.with_fallback_ = true; - return opts; + /** Enable seek for this I/O */ + void SetSeek() { + flags_.SetBits(HERMES_FS_SEEK); } - /** return IO options with \a mpi_type MPI data type */ - static IoOptions DataType(MPI_Datatype mpi_type, bool seek = true) { - IoOptions opts; - opts.mpi_type_ = mpi_type; - opts.seek_ = seek; - return opts; + /** Disable seek for this I/O */ + void UnsetSeek() { + flags_.UnsetBits(HERMES_FS_SEEK); } - /** - * Ensure that I/O goes only to Hermes, and does not fall back to PFS. - * - * @param orig_opts The original options to modify - * */ - static IoOptions PlaceInHermes(IoOptions &orig_opts) { - IoOptions opts(orig_opts); - opts.seek_ = false; - opts.with_fallback_ = false; - return opts; + /** Whether or not to perform seek in FS adapter */ + bool DoSeek() { + return flags_.OrBits(HERMES_FS_SEEK); } }; diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index 111d03f7a..bc7790b6f 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -17,6 +17,8 @@ #include "hermes_types.h" #include +namespace hapi = hermes::api; + namespace hermes::adapter { /** Adapter types */ @@ -52,16 +54,29 @@ struct IoClientContext { mpi_status_(MPI_SUCCESS) {} }; +/** Put or get data directly from I/O client */ +#define HERMES_IO_CLIENT_BYPASS (1<<0) +/** Only put or get data from a Hermes buffer; no fallback to I/O client */ +#define HERMES_IO_CLIENT_NO_FALLBACK (1<<1) +/** The number of I/O client flags (used for extending flag field) */ +#define HERMES_IO_CLIENT_FLAGS_COUNT 2 + /** Represents any relevant settings for an I/O client operation */ struct IoClientOptions { - AdapterType type_; /**< Client to forward I/O request to */ + // TODO(llogan): We should use an std::variant or union instead of large set + AdapterType type_; /**< Client to forward I/O request to */ + hapi::PlacementPolicy dpe_; /**< data placement policy */ + bitfield32_t flags_; /**< various I/O flags */ MPI_Datatype mpi_type_; /**< MPI data type */ int mpi_count_; /**< The number of types */ size_t backend_off_; /**< Offset in the backend to begin I/O */ size_t backend_size_; /**< Size of I/O to perform at backend */ /** Default constructor */ - IoClientOptions() : mpi_type_(MPI_CHAR), + IoClientOptions() : type_(AdapterType::kNone), + dpe_(hapi::PlacementPolicy::kNone), + flags_(), + mpi_type_(MPI_CHAR), mpi_count_(0), backend_off_(0), backend_size_(0) {} diff --git a/src/data_structures.h b/src/data_structures.h index c5af12669..ee1972cae 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -25,6 +25,7 @@ namespace lipc = labstor::ipc; using labstor::RwLock; using labstor::Mutex; +using labstor::bitfield32_t; #include #include From 862609a35e57886ec95afe3332f191790fa87bf3 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Thu, 2 Feb 2023 23:56:13 -0600 Subject: [PATCH 105/511] Comment interceptor-list out for now. Don't create separate binary for mdm_singleton. --- adapter/CMakeLists.txt | 1 + adapter/filesystem/CMakeLists.txt | 22 +++------- adapter/mapper/balanced_mapper.cc | 40 +++++++++---------- adapter/mapper/mapper_factory.h | 2 +- adapter/stdio/fs_api.h | 2 +- adapter/test/CMakeLists.txt | 36 +++++------------ adapter/test/mpiio/mpiio_adapter_test.cpp | 20 +++++----- adapter/test/posix/posix_adapter_mpi_test.cpp | 34 ++++++++-------- adapter/test/posix/posix_adapter_test.cpp | 21 +++++----- .../stdio_adapter_low_buffer_space_test.cpp | 16 ++++---- .../test/stdio/stdio_adapter_mode_test.cpp | 16 ++++---- adapter/test/stdio/stdio_adapter_mpi_test.cpp | 24 +++++------ adapter/test/stdio/stdio_adapter_test.cpp | 18 +++++---- 13 files changed, 117 insertions(+), 135 deletions(-) diff --git a/adapter/CMakeLists.txt b/adapter/CMakeLists.txt index e7685540f..475f3528c 100644 --- a/adapter/CMakeLists.txt +++ b/adapter/CMakeLists.txt @@ -9,6 +9,7 @@ if(HERMES_ENABLE_POSIX_ADAPTER) add_subdirectory(io_client) add_subdirectory(filesystem) add_subdirectory(posix) + add_subdirectory(test) endif() # Transparently Start Hermes in Client Mode diff --git a/adapter/filesystem/CMakeLists.txt b/adapter/filesystem/CMakeLists.txt index fbeb6c4be..0ee6cd3ff 100644 --- a/adapter/filesystem/CMakeLists.txt +++ b/adapter/filesystem/CMakeLists.txt @@ -4,26 +4,16 @@ include_directories( ${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) -# Create the metadata manager singleton + FS base class -add_library(hermes_fs_mdm_singleton SHARED - ${CMAKE_CURRENT_SOURCE_DIR}/filesystem_mdm_singleton.cc) -add_dependencies(hermes_fs_mdm_singleton - hermes) -target_link_libraries(hermes_fs_mdm_singleton - hermes - MPI::MPI_CXX) -target_compile_options(hermes_fs_mdm_singleton PUBLIC -fPIC) - # Create the metadata manager singleton + FS base class add_library(hermes_fs_base SHARED - ${CMAKE_CURRENT_SOURCE_DIR}/filesystem.cc) + ${CMAKE_CURRENT_SOURCE_DIR}/filesystem.cc + ${CMAKE_CURRENT_SOURCE_DIR}/filesystem_mdm.cc + ${CMAKE_CURRENT_SOURCE_DIR}/filesystem_mdm_singleton.cc) add_dependencies(hermes_fs_base - hermes - hermes_fs_mdm_singleton) + hermes) target_link_libraries(hermes_fs_base MPI::MPI_CXX - hermes - hermes_fs_mdm_singleton) + hermes) target_compile_options(hermes_fs_base PUBLIC -fPIC) #----------------------------------------------------------------------------- @@ -31,7 +21,6 @@ target_compile_options(hermes_fs_base PUBLIC -fPIC) #----------------------------------------------------------------------------- install( TARGETS - hermes_fs_mdm_singleton hermes_fs_base EXPORT ${HERMES_EXPORTED_TARGETS} @@ -44,7 +33,6 @@ install( # Export all exported targets to the build tree for use by parent project #----------------------------------------------------------------------------- set(HERMES_EXPORTED_LIBS - hermes_fs_mdm_singleton hermes_fs_base ${HERMES_EXPORTED_LIBS}) if(NOT HERMES_EXTERNALLY_CONFIGURED) diff --git a/adapter/mapper/balanced_mapper.cc b/adapter/mapper/balanced_mapper.cc index 0e0041639..b1e335287 100644 --- a/adapter/mapper/balanced_mapper.cc +++ b/adapter/mapper/balanced_mapper.cc @@ -16,28 +16,28 @@ namespace hermes::adapter { - /** - * Convert a range defined by \a off and \a size into specific - * blob placements. - */ - void BalancedMapper::map(size_t off, size_t size, BlobPlacements &ps) { - VLOG(1) << "Mapping File with offset:" << off << " and size:" << size << "." - << std::endl; +/** + * Convert a range defined by \a off and \a size into specific + * blob placements. + */ +void BalancedMapper::map(size_t off, size_t size, BlobPlacements &ps) { + VLOG(1) << "Mapping File with offset:" << off << " and size:" << size << "." + << std::endl; - size_t kPageSize = HERMES->client_config_.file_page_size_; - size_t size_mapped = 0; - while (size > size_mapped) { - BlobPlacement p; - p.bucket_off_ = off + size_mapped; - p.page_ = p.bucket_off_ / kPageSize; - p.blob_off_ = p.bucket_off_ % kPageSize; - auto left_size_page = kPageSize - p.blob_off_; - p.blob_size_ = left_size_page < size - size_mapped ? left_size_page - : size - size_mapped; - ps.emplace_back(p); - size_mapped += p.blob_size_; - } + size_t kPageSize = HERMES->client_config_.file_page_size_; + size_t size_mapped = 0; + while (size > size_mapped) { + BlobPlacement p; + p.bucket_off_ = off + size_mapped; + p.page_ = p.bucket_off_ / kPageSize; + p.blob_off_ = p.bucket_off_ % kPageSize; + auto left_size_page = kPageSize - p.blob_off_; + p.blob_size_ = left_size_page < size - size_mapped ? left_size_page + : size - size_mapped; + ps.emplace_back(p); + size_mapped += p.blob_size_; } +} } // namespace hermes::adapter diff --git a/adapter/mapper/mapper_factory.h b/adapter/mapper/mapper_factory.h index 12a3f4754..a007a55fe 100644 --- a/adapter/mapper/mapper_factory.h +++ b/adapter/mapper/mapper_factory.h @@ -33,7 +33,7 @@ class MapperFactory { AbstractMapper* Get(const MapperType& type) { switch (type) { case MapperType::kBalancedMapper: { - return hermes::Singleton::GetInstance(); + return hermes::EasyGlobalSingleton::GetInstance(); } default: { // TODO(llogan): @error_handling Mapper not implemented diff --git a/adapter/stdio/fs_api.h b/adapter/stdio/fs_api.h index a689b8e51..01b7d15b9 100644 --- a/adapter/stdio/fs_api.h +++ b/adapter/stdio/fs_api.h @@ -19,7 +19,7 @@ #include "filesystem/filesystem.h" #include "filesystem/metadata_manager.cc" #include "filesystem/metadata_manager.h" -#include "posix/real_api.h" +#include "posix/posix_api.h" #include "real_api.h" using hermes::Singleton; diff --git a/adapter/test/CMakeLists.txt b/adapter/test/CMakeLists.txt index 2ee65699f..b86dab7ea 100644 --- a/adapter/test/CMakeLists.txt +++ b/adapter/test/CMakeLists.txt @@ -3,10 +3,6 @@ set(ADAPTER_COMMON ${CMAKE_CURRENT_SOURCE_DIR}/catch_config.h) set(HERMES_ADAPTER_TEST_DIR ${HERMES_ADAPTER_DIR}/test) find_package(Catch2 REQUIRED) -add_executable(hermes_daemon hermes_daemon.cc) -target_link_libraries(hermes_daemon -ldl -lc MPI::MPI_CXX glog::glog) -target_link_libraries(hermes_daemon hermes) -add_dependencies(hermes_daemon hermes) function(gcc exec args) add_test(NAME Test${exec} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${args}) @@ -17,13 +13,13 @@ function(gcc exec args) endfunction() function(mpi exec mpi_proc args) - add_test(NAME Test${exec}_${mpi_proc} - COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${mpi_proc} - "${CMAKE_BINARY_DIR}/bin/${exec}" ${args} -d yes) - set_property(TEST Test${exec}_${mpi_proc} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) - set_property(TEST Test${exec}_${mpi_proc} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) +# add_test(NAME Test${exec}_${mpi_proc} +# COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${mpi_proc} +# "${CMAKE_BINARY_DIR}/bin/${exec}" ${args} -d yes) +# set_property(TEST Test${exec}_${mpi_proc} +# PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) +# set_property(TEST Test${exec}_${mpi_proc} APPEND +# PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) endfunction() find_program(BASH_PROGRAM bash) @@ -45,7 +41,7 @@ endfunction() enable_testing() if(HERMES_ENABLE_STDIO_ADAPTER) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/stdio) + # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/stdio) endif() if(HERMES_ENABLE_POSIX_ADAPTER) @@ -53,23 +49,13 @@ if(HERMES_ENABLE_POSIX_ADAPTER) endif() if(HERMES_ENABLE_MPIIO_ADAPTER) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/mpiio) + # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/mpiio) endif() if(HERMES_ENABLE_PUBSUB_ADAPTER) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/pubsub) + # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/pubsub) endif() if(HERMES_ENABLE_VFD) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vfd) + # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vfd) endif() - -install( - TARGETS - hermes_daemon - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) diff --git a/adapter/test/mpiio/mpiio_adapter_test.cpp b/adapter/test/mpiio/mpiio_adapter_test.cpp index 70dc5c018..6d87631e1 100644 --- a/adapter/test/mpiio/mpiio_adapter_test.cpp +++ b/adapter/test/mpiio/mpiio_adapter_test.cpp @@ -151,10 +151,10 @@ int pretest() { MPI_Barrier(MPI_COMM_WORLD); REQUIRE(info.total_size > 0); #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.shared_new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert( + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.shared_new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert( info.shared_existing_file_cmp); #endif return 0; @@ -162,8 +162,8 @@ int pretest() { int posttest(bool compare_data = true) { #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { @@ -231,10 +231,10 @@ int posttest(bool compare_data = true) { stdfs::remove(info.existing_file_cmp); #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); #endif return 0; } diff --git a/adapter/test/posix/posix_adapter_mpi_test.cpp b/adapter/test/posix/posix_adapter_mpi_test.cpp index cee4db946..76d29e882 100644 --- a/adapter/test/posix/posix_adapter_mpi_test.cpp +++ b/adapter/test/posix/posix_adapter_mpi_test.cpp @@ -26,7 +26,7 @@ #include "adapter_test_utils.h" #if HERMES_INTERCEPT == 1 -#include "posix/real_api.h" +#include "posix/posix_api.h" #endif namespace stdfs = std::experimental::filesystem; @@ -190,20 +190,21 @@ int pretest() { if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); REQUIRE(info.total_size > 0); MPI_Barrier(MPI_COMM_WORLD); + // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert( - info.existing_shared_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_shared_file_cmp); #endif return 0; } int posttest(bool compare_data = true) { + // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_shared_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_shared_file); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { @@ -306,14 +307,15 @@ int posttest(bool compare_data = true) { stdfs::remove(info.existing_shared_file_cmp); } -#if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file_cmp); -#endif + // NOTE(llogan): Are flush exclusions really necessary? + #if HERMES_INTERCEPT == 1 + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file_cmp); + #endif return 0; } diff --git a/adapter/test/posix/posix_adapter_test.cpp b/adapter/test/posix/posix_adapter_test.cpp index c3db44787..4dc8dc356 100644 --- a/adapter/test/posix/posix_adapter_test.cpp +++ b/adapter/test/posix/posix_adapter_test.cpp @@ -19,7 +19,7 @@ #include "catch_config.h" #if HERMES_INTERCEPT == 1 -#include "posix/real_api.h" +#include "posix/posix_api.h" #endif #ifndef O_TMPFILE @@ -118,17 +118,19 @@ int pretest() { args.request_size * info.num_iterations); } REQUIRE(info.total_size > 0); + // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); #endif return 0; } int posttest(bool compare_data = true) { + // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { @@ -198,11 +200,12 @@ int posttest(bool compare_data = true) { if (stdfs::exists(info.existing_file_cmp)) stdfs::remove(info.existing_file_cmp); + // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); #endif return 0; } diff --git a/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp b/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp index 3f8903321..b15cb54e7 100644 --- a/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp +++ b/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp @@ -99,16 +99,16 @@ int pretest() { } REQUIRE(info.total_size > 0); #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); #endif return 0; } int posttest(bool compare_data = true) { #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { @@ -179,10 +179,10 @@ int posttest(bool compare_data = true) { stdfs::remove(info.existing_file_cmp); #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); #endif return 0; } diff --git a/adapter/test/stdio/stdio_adapter_mode_test.cpp b/adapter/test/stdio/stdio_adapter_mode_test.cpp index d315c56e5..d37cdef1c 100644 --- a/adapter/test/stdio/stdio_adapter_mode_test.cpp +++ b/adapter/test/stdio/stdio_adapter_mode_test.cpp @@ -104,16 +104,16 @@ int pretest() { } REQUIRE(info.total_size > 0); #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); #endif return 0; } int posttest(bool compare_data = true) { #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { @@ -181,10 +181,10 @@ int posttest(bool compare_data = true) { stdfs::remove(info.existing_file_cmp); #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); #endif return 0; } diff --git a/adapter/test/stdio/stdio_adapter_mpi_test.cpp b/adapter/test/stdio/stdio_adapter_mpi_test.cpp index c279dd786..b126187f3 100644 --- a/adapter/test/stdio/stdio_adapter_mpi_test.cpp +++ b/adapter/test/stdio/stdio_adapter_mpi_test.cpp @@ -207,9 +207,9 @@ int pretest() { REQUIRE(info.total_size > 0); MPI_Barrier(MPI_COMM_WORLD); #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert( + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert( info.existing_shared_file_cmp); #endif return 0; @@ -217,9 +217,9 @@ int pretest() { int posttest(bool compare_data = true) { #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_shared_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_shared_file); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { @@ -323,12 +323,12 @@ int posttest(bool compare_data = true) { } #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_shared_file_cmp); #endif return 0; } diff --git a/adapter/test/stdio/stdio_adapter_test.cpp b/adapter/test/stdio/stdio_adapter_test.cpp index a88853f45..615dd084d 100644 --- a/adapter/test/stdio/stdio_adapter_test.cpp +++ b/adapter/test/stdio/stdio_adapter_test.cpp @@ -102,17 +102,19 @@ int pretest() { args.request_size * info.num_iterations); } REQUIRE(info.total_size > 0); + // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); #endif return 0; } int posttest(bool compare_data = true) { + // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { @@ -182,10 +184,10 @@ int posttest(bool compare_data = true) { stdfs::remove(info.existing_file_cmp); #if HERMES_INTERCEPT == 1 - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); - INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file_cmp); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.new_file); + // INTERCEPTOR_LIST->hermes_flush_exclusion.erase(info.existing_file); #endif return 0; } From c5abe0b051198bac48010d98b6e82d160facd3c9 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 3 Feb 2023 00:26:34 -0600 Subject: [PATCH 106/511] Add GetSize() to filesystem base class --- adapter/filesystem/filesystem.cc | 25 ++++++++++++++++++++++--- adapter/filesystem/filesystem.h | 4 ++++ adapter/posix/posix.cc | 2 +- adapter/test/posix/simple_posix.cc | 13 ------------- 4 files changed, 27 insertions(+), 17 deletions(-) delete mode 100644 adapter/test/posix/simple_posix.cc diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index ac400dd86..e19ba5c6e 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -199,6 +199,14 @@ void Filesystem::Wait(std::vector &req_ids, } } +size_t Filesystem::GetSize(File &f, AdapterStat &stat) { + (void) stat; + IoOptions opts; + opts.type_ = type_; + return stat.bkt_id_->GetSize(opts); + +} + off_t Filesystem::Seek(File &f, AdapterStat &stat, SeekMode whence, off_t offset) { if (stat.is_append_) { @@ -218,9 +226,9 @@ off_t Filesystem::Seek(File &f, AdapterStat &stat, break; } case SeekMode::kEnd: { - // TODO(llogan): Fix seek end - // stat.st_ptr_ = stat.bkt_id_-> + offset; - stat.st_ptr_ = 0 + offset; + IoOptions opts; + opts.type_ = type_; + stat.st_ptr_ = stat.bkt_id_->GetSize(opts) + offset; break; } default: { @@ -402,6 +410,17 @@ off_t Filesystem::Seek(File &f, bool &stat_exists, return Seek(f, *stat, whence, offset); } +size_t Filesystem::GetSize(File &f, bool &stat_exists) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto [stat, exists] = mdm->Find(f); + if (!exists) { + stat_exists = false; + return -1; + } + stat_exists = true; + return GetSize(f, *stat); +} + off_t Filesystem::Tell(File &f, bool &stat_exists) { auto mdm = HERMES_FS_METADATA_MANAGER; auto [stat, exists] = mdm->Find(f); diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index f951e0efb..ac8db0d3d 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -128,6 +128,8 @@ class Filesystem { void Wait(std::vector &req_id, std::vector &ret); /** seek */ off_t Seek(File &f, AdapterStat &stat, SeekMode whence, off_t offset); + /** file size */ + size_t GetSize(File &f, AdapterStat &stat); /** tell */ off_t Tell(File &f, AdapterStat &stat); /** sync */ @@ -192,6 +194,8 @@ class Filesystem { IoOptions opts); /** seek */ off_t Seek(File &f, bool &stat_exists, SeekMode whence, off_t offset); + /** file sizes */ + size_t GetSize(File &f, bool &stat_exists); /** tell */ off_t Tell(File &f, bool &stat_exists); /** sync */ diff --git a/adapter/posix/posix.cc b/adapter/posix/posix.cc index 1dfe5ab22..b3d9b9581 100644 --- a/adapter/posix/posix.cc +++ b/adapter/posix/posix.cc @@ -261,7 +261,7 @@ int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { buf->st_uid = astat.st_uid_; buf->st_gid = astat.st_gid_; buf->st_rdev = 0; - // buf->st_size = astat.st_size_; + buf->st_size = fs_api->GetSize(f, astat); // buf->st_blksize = astat.st_blksize_; buf->st_blocks = 0; buf->st_atime = astat.st_atim_.tv_sec; diff --git a/adapter/test/posix/simple_posix.cc b/adapter/test/posix/simple_posix.cc deleted file mode 100644 index 9d87bd5e7..000000000 --- a/adapter/test/posix/simple_posix.cc +++ /dev/null @@ -1,13 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - From bf677034c223f6b4cd3306c767be369d32077a0d Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 3 Feb 2023 00:38:18 -0600 Subject: [PATCH 107/511] Use EasySingleton for POSIX initialization for now. --- adapter/posix/posix_api_singleton.cc | 6 ++++-- adapter/posix/posix_api_singleton_macros.h | 2 +- src/singleton.h | 10 +++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/adapter/posix/posix_api_singleton.cc b/adapter/posix/posix_api_singleton.cc index 3217e0567..810f192e7 100644 --- a/adapter/posix/posix_api_singleton.cc +++ b/adapter/posix/posix_api_singleton.cc @@ -13,5 +13,7 @@ #include "singleton.h" #include "posix_api.h" -template<> hermes::adapter::fs::PosixApi hermes::GlobalSingleton< - hermes::adapter::fs::PosixApi>::obj_ = hermes::adapter::fs::PosixApi(); +/*template<> hermes::adapter::fs::PosixApi hermes::GlobalSingleton< + hermes::adapter::fs::PosixApi>::obj_ = hermes::adapter::fs::PosixApi();*/ +template<> std::unique_ptr + hermes::Singleton::obj_ = nullptr; \ No newline at end of file diff --git a/adapter/posix/posix_api_singleton_macros.h b/adapter/posix/posix_api_singleton_macros.h index e0ddb1500..80f916ad9 100644 --- a/adapter/posix/posix_api_singleton_macros.h +++ b/adapter/posix/posix_api_singleton_macros.h @@ -16,7 +16,7 @@ #include "singleton.h" #define HERMES_POSIX_API \ - hermes::GlobalSingleton::GetInstance() + hermes::Singleton::GetInstance() #define HERMES_POSIX_API_T hermes::adapter::fs::PosixApi* #endif // HERMES_POSIX_SINGLETON_ADAPTER_MACROS_H diff --git a/src/singleton.h b/src/singleton.h index 755bf6e81..a7bdba9b5 100644 --- a/src/singleton.h +++ b/src/singleton.h @@ -62,7 +62,7 @@ template class EasySingleton { protected: /** static instance. */ - static std::unique_ptr instance; + static std::unique_ptr obj_; public: /** @@ -71,14 +71,14 @@ class EasySingleton { * @return instance of T */ static T* GetInstance() { - if (instance == nullptr) { - instance = std::make_unique(); + if (obj_ == nullptr) { + obj_ = std::make_unique(); } - return instance.get(); + return obj_.get(); } }; template -std::unique_ptr EasySingleton::instance = nullptr; +std::unique_ptr EasySingleton::obj_ = nullptr; /** * Makes a singleton. Constructs during initialization of program. From ad720fbbf0a354be2bec3f8555de73fee54767ed Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 3 Feb 2023 03:41:50 -0600 Subject: [PATCH 108/511] Rename some I/O client variables --- adapter/CMakeLists.txt | 33 ------------- adapter/adapter_init.cc | 32 ------------- adapter/filesystem/file.h | 2 +- adapter/filesystem/filesystem.cc | 14 ++++-- adapter/filesystem/filesystem.h | 30 ++++++------ adapter/filesystem/filesystem_io_client.h | 34 ++++++++------ adapter/interceptor.h | 2 +- adapter/io_client/io_client.h | 30 ++++++------ adapter/mpiio/fs_api.h | 2 +- adapter/mpiio/mpiio.cc | 2 +- adapter/posix/CMakeLists.txt | 9 ++-- adapter/posix/posix.cc | 21 ++++++++- adapter/posix/posix_io_client.cc | 45 +++++++++++------- adapter/posix/posix_io_client.h | 46 +++++++++++-------- adapter/stdio/stdio.cc | 4 +- adapter/test/mpiio/mpiio_adapter_test.cpp | 4 +- adapter/test/mpiio/parallel.cc | 4 +- adapter/test/posix/posix_adapter_mpi_test.cpp | 4 +- adapter/test/posix/posix_adapter_test.cpp | 4 +- adapter/test/stdio/adapter_utils_test.cc | 2 +- .../stdio_adapter_low_buffer_space_test.cpp | 4 +- .../test/stdio/stdio_adapter_mapper_test.cpp | 4 +- .../test/stdio/stdio_adapter_mode_test.cpp | 4 +- adapter/test/stdio/stdio_adapter_mpi_test.cpp | 4 +- adapter/test/stdio/stdio_adapter_test.cpp | 4 +- adapter/test/vfd/hermes_vfd_test.cc | 4 +- config/hermes_client_default.yaml | 4 +- data_stager/stagers/posix_stager.cc | 2 +- src/api/bucket.cc | 21 ++++----- src/api/bucket.h | 16 +++---- src/api/hermes.cc | 6 ++- src/api/hermes.h | 22 +++++++-- src/api/hermes_singleton.cc | 2 +- src/api/vbucket.cc | 2 +- src/api/vbucket.h | 2 +- src/borg_io_clients/borg_posix_client.h | 4 +- src/config_client.cc | 6 +++ src/config_client_default.h | 18 ++------ src/config_server_default.h | 14 +----- src/hermes_types.h | 1 - src/metadata_manager.cc | 8 ++-- src/metadata_manager.h | 13 ++---- src/metadata_types.h | 4 +- src/singleton.h | 1 + 44 files changed, 237 insertions(+), 257 deletions(-) delete mode 100644 adapter/adapter_init.cc diff --git a/adapter/CMakeLists.txt b/adapter/CMakeLists.txt index 475f3528c..880f65a21 100644 --- a/adapter/CMakeLists.txt +++ b/adapter/CMakeLists.txt @@ -10,37 +10,4 @@ if(HERMES_ENABLE_POSIX_ADAPTER) add_subdirectory(filesystem) add_subdirectory(posix) add_subdirectory(test) -endif() - -# Transparently Start Hermes in Client Mode -add_library(adapter_init ${CMAKE_CURRENT_SOURCE_DIR}/adapter_init.cc) -add_dependencies(adapter_init hermes) -target_link_libraries(adapter_init hermes) - -#----------------------------------------------------------------------------- -# Add Target(s) to CMake Install -#----------------------------------------------------------------------------- -install( - TARGETS - adapter_init - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) - -#----------------------------------------------------------------------------- -# Export all exported targets to the build tree for use by parent project -#----------------------------------------------------------------------------- -set(HERMES_EXPORTED_LIBS - adapter_init - ${HERMES_EXPORTED_LIBS}) -if(NOT HERMES_EXTERNALLY_CONFIGURED) - EXPORT ( - TARGETS - ${HERMES_EXPORTED_LIBS} - FILE - ${HERMES_EXPORTED_TARGETS}.cmake - ) endif() \ No newline at end of file diff --git a/adapter/adapter_init.cc b/adapter/adapter_init.cc deleted file mode 100644 index 1283177af..000000000 --- a/adapter/adapter_init.cc +++ /dev/null @@ -1,32 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_GLOBAL_INIT_HERMES_H_ -#define HERMES_ADAPTER_GLOBAL_INIT_HERMES_H_ - -#include "hermes.h" - -/** Use C++ runtime to ensure Hermes starts and finalizes */ -struct TransparentInitHermes { - TransparentInitHermes() { - HERMES->Create(hermes::HermesType::kClient); - } - - ~TransparentInitHermes() { - HERMES->Finalize(); - } -}; - -/** Initialize Hermes transparently */ -TransparentInitHermes x; - -#endif // HERMES_ADAPTER_GLOBAL_INIT_HERMES_H_ diff --git a/adapter/filesystem/file.h b/adapter/filesystem/file.h index b47120e01..6398cf3d9 100644 --- a/adapter/filesystem/file.h +++ b/adapter/filesystem/file.h @@ -18,7 +18,7 @@ namespace hermes::adapter::fs { /** A structure to represent file */ -struct File : public IoClientContext { +struct File : public IoClientObject { /** default constructor */ File() = default; diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index e19ba5c6e..133ed838d 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -19,9 +19,9 @@ #include "mapper/mapper_factory.h" #include -#include +#include -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes::adapter::fs { @@ -46,7 +46,7 @@ void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { stat.bkt_id_ = HERMES->GetBucket(path, ctx, opts); // Allocate internal hermes data auto stat_ptr = std::make_unique(stat); - FilesystemIoClientContext fs_ctx(&mdm->fs_mdm_, (void*)stat_ptr.get()); + FilesystemIoClientObject fs_ctx(&mdm->fs_mdm_, (void*)stat_ptr.get()); io_client_->HermesOpen(f, stat, fs_ctx); mdm->Create(f, stat_ptr); } else { @@ -75,9 +75,11 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, const Blob blob_wrap((const char*)ptr + data_offset, off); lipc::charbuf blob_name(p.CreateBlobName()); BlobId blob_id; - IoClientContext io_ctx; + IoClientObject io_ctx; Context ctx; + io_ctx.type_ = type_; io_ctx.filename_ = filename; + opts.type_ = type_; opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; bkt->PartialPutOrCreate(blob_name.str(), @@ -116,11 +118,13 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, Blob blob_wrap((const char*)ptr + data_offset, off); lipc::charbuf blob_name(p.CreateBlobName()); BlobId blob_id; - IoClientContext io_ctx; + IoClientObject io_ctx; Context ctx; + io_ctx.type_ = type_; io_ctx.filename_ = filename; opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; + opts.type_ = type_; bkt->PartialGetOrCreate(blob_name.str(), blob_wrap, p.blob_off_, diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index ac8db0d3d..5877f75b3 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -28,6 +28,8 @@ #include "filesystem_io_client.h" #include "file.h" +#include + namespace hapi = hermes::api; namespace hermes::adapter::fs { @@ -44,7 +46,7 @@ enum class SeekMode { }; /** A structure to represent adapter statistics */ -struct AdapterStat : public IoClientStat { +struct AdapterStat : public IoClientStats { std::shared_ptr bkt_id_; /**< bucket associated with the file */ /** VBucket for persisting data asynchronously. */ std::shared_ptr vbkt_id_; @@ -65,11 +67,11 @@ struct AdapterStat : public IoClientStat { /** * A structure to represent IO options for FS adapter. - * For now, nothing additional than the typical IoClientOptions. + * For now, nothing additional than the typical IoClientContext. * */ -struct IoOptions : public IoClientOptions { +struct IoOptions : public IoClientContext { /** Default constructor */ - IoOptions() : IoClientOptions() { + IoOptions() : IoClientContext() { flags_.SetBits(HERMES_FS_SEEK); } @@ -205,8 +207,8 @@ class Filesystem { public: /** real open */ - void RealOpen(IoClientContext &f, - IoClientStat &stat, + void RealOpen(IoClientObject &f, + IoClientStats &stat, const std::string &path) { io_client_->RealOpen(f, stat, path); } @@ -217,19 +219,19 @@ class Filesystem { * and hermes file handler. These are not the same as POSIX file * descriptor and STDIO file handler. * */ - virtual void HermesOpen(IoClientContext &f, - IoClientStat &stat, - FilesystemIoClientContext &fs_mdm) { + virtual void HermesOpen(IoClientObject &f, + IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) { io_client_->HermesOpen(f, stat, fs_mdm); } /** real sync */ - int RealSync(const IoClientContext &f, const AdapterStat &stat) { + int RealSync(const IoClientObject &f, const AdapterStat &stat) { return io_client_->RealSync(f, stat); } /** real close */ - int RealClose(const IoClientContext &f, const AdapterStat &stat) { + int RealClose(const IoClientObject &f, const AdapterStat &stat) { return io_client_->RealClose(f, stat); } @@ -239,9 +241,7 @@ class Filesystem { if (!HERMES->IsInitialized()) { return false; } - stdfs::path stdfs_path(path); - // TODO(llogan): use weak_canonical for performance reasons - std::string abs_path = stdfs::canonical(stdfs_path); + std::string abs_path = stdfs::weakly_canonical(path).string(); auto &path_inclusions = HERMES->client_config_.path_inclusions_; auto &path_exclusions = HERMES->client_config_.path_exclusions_; // Check if path is included @@ -256,7 +256,7 @@ class Filesystem { return false; } } - return true; + return false; } }; diff --git a/adapter/filesystem/filesystem_io_client.h b/adapter/filesystem/filesystem_io_client.h index 81f88e141..61b121755 100644 --- a/adapter/filesystem/filesystem_io_client.h +++ b/adapter/filesystem/filesystem_io_client.h @@ -14,10 +14,10 @@ #define HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_IO_CLIENT_H_ #include "adapter/io_client/io_client.h" -#include +#include #include -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes::adapter::fs { @@ -50,7 +50,7 @@ struct FsIoClientMetadata { /** * State required by Filesystem I/O clients to perform a HermesOpen * */ -struct FilesystemIoClientContext { +struct FilesystemIoClientObject { /** * A pointer to the FsIoClientMetadata stored in the Filesystem * */ @@ -63,7 +63,7 @@ struct FilesystemIoClientContext { void *stat_; /** Default constructor */ - FilesystemIoClientContext(FsIoClientMetadata *mdm, void *stat) + FilesystemIoClientObject(FsIoClientMetadata *mdm, void *stat) : mdm_(mdm), stat_(stat) {} }; @@ -77,8 +77,8 @@ class FilesystemIoClient : public IoClient { virtual ~FilesystemIoClient() = default; /** real open */ - virtual void RealOpen(IoClientContext &f, - IoClientStat &stat, + virtual void RealOpen(IoClientObject &f, + IoClientStats &stat, const std::string &path) = 0; /** @@ -87,17 +87,25 @@ class FilesystemIoClient : public IoClient { * and hermes file handler. These are not the same as POSIX file * descriptor and STDIO file handler. * */ - virtual void HermesOpen(IoClientContext &f, - const IoClientStat &stat, - FilesystemIoClientContext &fs_mdm) = 0; + virtual void HermesOpen(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) = 0; /** real sync */ - virtual int RealSync(const IoClientContext &f, - const IoClientStat &stat) = 0; + virtual int RealSync(const IoClientObject &f, + const IoClientStats &stat) = 0; /** real close */ - virtual int RealClose(const IoClientContext &f, - const IoClientStat &stat) = 0; + virtual int RealClose(const IoClientObject &f, + const IoClientStats &stat) = 0; + + /** + * Called before RealClose. Releases information provisioned during + * the allocation phase. + * */ + virtual void HermesClose(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) = 0; }; } // namespace hermes::adapter::fs diff --git a/adapter/interceptor.h b/adapter/interceptor.h index fa58be973..2a3827b8e 100644 --- a/adapter/interceptor.h +++ b/adapter/interceptor.h @@ -17,7 +17,7 @@ #include "adapter/filesystem/filesystem_mdm.h" #include "adapter/filesystem/filesystem_mdm_singleton_macros.h" -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes::adapter { diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index bc7790b6f..24f270060 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -32,7 +32,7 @@ enum class AdapterType { }; /** Represents an object in the I/O client (e.g., a file) */ -struct IoClientContext { +struct IoClientObject { AdapterType type_; /**< Client to forward I/O request to */ std::string filename_; /**< Filename to read from */ @@ -44,7 +44,7 @@ struct IoClientContext { int mpi_status_; /**< MPI status */ /** Default constructor */ - IoClientContext() + IoClientObject() : type_(AdapterType::kNone), filename_(), hermes_fd_(-1), @@ -62,7 +62,7 @@ struct IoClientContext { #define HERMES_IO_CLIENT_FLAGS_COUNT 2 /** Represents any relevant settings for an I/O client operation */ -struct IoClientOptions { +struct IoClientContext { // TODO(llogan): We should use an std::variant or union instead of large set AdapterType type_; /**< Client to forward I/O request to */ hapi::PlacementPolicy dpe_; /**< data placement policy */ @@ -73,7 +73,7 @@ struct IoClientOptions { size_t backend_size_; /**< Size of I/O to perform at backend */ /** Default constructor */ - IoClientOptions() : type_(AdapterType::kNone), + IoClientContext() : type_(AdapterType::kNone), dpe_(hapi::PlacementPolicy::kNone), flags_(), mpi_type_(MPI_CHAR), @@ -83,7 +83,7 @@ struct IoClientOptions { }; /** Any relevant statistics from the I/O client */ -struct IoClientStat { +struct IoClientStats { int flags_; /**< open() flags for POSIX */ mode_t st_mode_; /**< protection */ size_t backend_size_; /**< size of the object in the backend */ @@ -107,7 +107,7 @@ struct IoClientStat { bool atomicity_; /**< Consistency semantics for data-access */ /** Default constructor */ - IoClientStat() + IoClientStats() : flags_(0), st_mode_(), st_ptr_(0), @@ -129,7 +129,7 @@ struct IoClientStat { }; /** Any statistics which need to be globally maintained across ranks */ -struct GlobalIoClientState { +struct GlobalIoClientStatse { size_t true_size_; }; @@ -166,26 +166,26 @@ class IoClient { /** Get initial statistics from the backend */ virtual void InitBucketState(const lipc::charbuf &bkt_name, - const IoClientOptions &opts, - GlobalIoClientState &stat) = 0; + const IoClientContext &opts, + GlobalIoClientStatse &stat) = 0; /** * What the statistics would be if all blobs were flushed from Hermes * to the backing storage system. * */ - virtual void UpdateBucketState(const IoClientOptions &opts, - GlobalIoClientState &stat) = 0; + virtual void UpdateBucketState(const IoClientContext &opts, + GlobalIoClientStatse &stat) = 0; /** Write blob to backend */ virtual void WriteBlob(const Blob &full_blob, - const IoClientContext &io_ctx, - const IoClientOptions &opts, + const IoClientObject &io_ctx, + const IoClientContext &opts, IoStatus &status) = 0; /** Read blob from the backend */ virtual void ReadBlob(Blob &full_blob, - const IoClientContext &io_ctx, - const IoClientOptions &opts, + const IoClientObject &io_ctx, + const IoClientContext &opts, IoStatus &status) = 0; }; diff --git a/adapter/mpiio/fs_api.h b/adapter/mpiio/fs_api.h index bdf3245a0..2a90ac7ff 100644 --- a/adapter/mpiio/fs_api.h +++ b/adapter/mpiio/fs_api.h @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include "real_api.h" diff --git a/adapter/mpiio/mpiio.cc b/adapter/mpiio/mpiio.cc index 675c11dc4..714aef8c4 100644 --- a/adapter/mpiio/mpiio.cc +++ b/adapter/mpiio/mpiio.cc @@ -38,7 +38,7 @@ using hermes::adapter::mpiio::MpiioSeekModeConv; using hermes::Singleton; namespace hapi = hermes::api; -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; using hermes::adapter::WeaklyCanonical; /** diff --git a/adapter/posix/CMakeLists.txt b/adapter/posix/CMakeLists.txt index 3d6ee71d3..9b3ab0468 100644 --- a/adapter/posix/CMakeLists.txt +++ b/adapter/posix/CMakeLists.txt @@ -13,17 +13,16 @@ target_link_libraries(hermes_posix_io_client MPI::MPI_CXX glog::glog stdc++fs dl) # Create the POSIX interceptor -add_library(hermes_posix SHARED ${CMAKE_CURRENT_SOURCE_DIR}/posix.cc) +add_library(hermes_posix SHARED + ${CMAKE_CURRENT_SOURCE_DIR}/posix.cc) add_dependencies(hermes_posix hermes hermes_posix_io_client - hermes_fs_base - adapter_init) + hermes_fs_base) target_link_libraries(hermes_posix hermes hermes_posix_io_client - hermes_fs_base - adapter_init) + hermes_fs_base) target_compile_options(hermes_posix PUBLIC -fPIC) #----------------------------------------------------------------------------- diff --git a/adapter/posix/posix.cc b/adapter/posix/posix.cc index b3d9b9581..a878b0e6b 100644 --- a/adapter/posix/posix.cc +++ b/adapter/posix/posix.cc @@ -17,7 +17,7 @@ bool posix_intercepted = true; #include #include #include -#include +#include #include "hermes_types.h" #include "singleton.h" @@ -34,7 +34,7 @@ using hermes::adapter::fs::File; using hermes::adapter::fs::SeekMode; namespace hapi = hermes::api; -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; extern "C" { @@ -42,6 +42,7 @@ extern "C" { * POSIX */ int HERMES_DECL(open)(const char *path, int flags, ...) { + TRANSPARENT_HERMES int mode = 0; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -52,6 +53,7 @@ int HERMES_DECL(open)(const char *path, int flags, ...) { va_end(arg); } if (fs_api->IsPathTracked(path)) { + TRANSPARENT_HERMES; LOG(INFO) << "Intercept open for filename: " << path << " and mode: " << flags << " is tracked." << std::endl; AdapterStat stat; @@ -66,6 +68,7 @@ int HERMES_DECL(open)(const char *path, int flags, ...) { } int HERMES_DECL(open64)(const char *path, int flags, ...) { + TRANSPARENT_HERMES int mode = 0; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -90,6 +93,7 @@ int HERMES_DECL(open64)(const char *path, int flags, ...) { } int HERMES_DECL(__open_2)(const char *path, int oflag) { + TRANSPARENT_HERMES auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; if (fs_api->IsPathTracked(path)) { @@ -104,6 +108,7 @@ int HERMES_DECL(__open_2)(const char *path, int oflag) { } int HERMES_DECL(creat)(const char *path, mode_t mode) { + TRANSPARENT_HERMES std::string path_str(path); auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -119,6 +124,7 @@ int HERMES_DECL(creat)(const char *path, mode_t mode) { } int HERMES_DECL(creat64)(const char *path, mode_t mode) { + TRANSPARENT_HERMES std::string path_str(path); auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -134,6 +140,7 @@ int HERMES_DECL(creat64)(const char *path, mode_t mode) { } ssize_t HERMES_DECL(read)(int fd, void *buf, size_t count) { + TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -147,6 +154,7 @@ ssize_t HERMES_DECL(read)(int fd, void *buf, size_t count) { } ssize_t HERMES_DECL(write)(int fd, const void *buf, size_t count) { + TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -160,6 +168,7 @@ ssize_t HERMES_DECL(write)(int fd, const void *buf, size_t count) { } ssize_t HERMES_DECL(pread)(int fd, void *buf, size_t count, off_t offset) { + TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -174,6 +183,7 @@ ssize_t HERMES_DECL(pread)(int fd, void *buf, size_t count, off_t offset) { ssize_t HERMES_DECL(pwrite)(int fd, const void *buf, size_t count, off_t offset) { + TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -187,6 +197,7 @@ ssize_t HERMES_DECL(pwrite)(int fd, const void *buf, size_t count, } ssize_t HERMES_DECL(pread64)(int fd, void *buf, size_t count, off64_t offset) { + TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -201,6 +212,7 @@ ssize_t HERMES_DECL(pread64)(int fd, void *buf, size_t count, off64_t offset) { ssize_t HERMES_DECL(pwrite64)(int fd, const void *buf, size_t count, off64_t offset) { + TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -214,6 +226,7 @@ ssize_t HERMES_DECL(pwrite64)(int fd, const void *buf, size_t count, } off_t HERMES_DECL(lseek)(int fd, off_t offset, int whence) { + TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -228,6 +241,7 @@ off_t HERMES_DECL(lseek)(int fd, off_t offset, int whence) { } off64_t HERMES_DECL(lseek64)(int fd, off64_t offset, int whence) { + TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -242,6 +256,7 @@ off64_t HERMES_DECL(lseek64)(int fd, off64_t offset, int whence) { } int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { + TRANSPARENT_HERMES int result = 0; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -280,6 +295,7 @@ int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { } int HERMES_DECL(fsync)(int fd) { + TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -292,6 +308,7 @@ int HERMES_DECL(fsync)(int fd) { } int HERMES_DECL(close)(int fd) { + TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index b5fcedfea..86d27d7db 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -15,8 +15,8 @@ namespace hermes::adapter::fs { /** Allocate an fd for the file f */ -void PosixIoClient::RealOpen(IoClientContext &f, - IoClientStat &stat, +void PosixIoClient::RealOpen(IoClientObject &f, + IoClientStats &stat, const std::string &path) { if (stat.flags_ & O_CREAT || stat.flags_ & O_TMPFILE) { stat.fd_ = real_api->open(path.c_str(), stat.flags_, stat.st_mode_); @@ -37,43 +37,54 @@ void PosixIoClient::RealOpen(IoClientContext &f, * and hermes file handler. These are not the same as POSIX file * descriptor and STDIO file handler. * */ -void PosixIoClient::HermesOpen(IoClientContext &f, - const IoClientStat &stat, - FilesystemIoClientContext &fs_mdm) { +void PosixIoClient::HermesOpen(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) { + f.hermes_fd_ = fs_mdm.mdm_->AllocateFd(); } /** Synchronize \a file FILE f */ -int PosixIoClient::RealSync(const IoClientContext &f, - const IoClientStat &stat) { +int PosixIoClient::RealSync(const IoClientObject &f, + const IoClientStats &stat) { (void) f; return real_api->fsync(stat.fd_); } /** Close \a file FILE f */ -int PosixIoClient::RealClose(const IoClientContext &f, - const IoClientStat &stat) { +int PosixIoClient::RealClose(const IoClientObject &f, + const IoClientStats &stat) { (void) f; return real_api->close(stat.fd_); } +/** + * Called before RealClose. Releases information provisioned during + * the allocation phase. + * */ +void PosixIoClient::HermesClose(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) { + fs_mdm.mdm_->ReleaseFd(f.hermes_fd_); +} + /** Get initial statistics from the backend */ void PosixIoClient::InitBucketState(const lipc::charbuf &bkt_name, - const IoClientOptions &opts, - GlobalIoClientState &stat) { + const IoClientContext &opts, + GlobalIoClientStatse &stat) { // real_api->__fxstat(); stat.true_size_ = 0; } /** Update backend statistics */ -void PosixIoClient::UpdateBucketState(const IoClientOptions &opts, - GlobalIoClientState &stat) { +void PosixIoClient::UpdateBucketState(const IoClientContext &opts, + GlobalIoClientStatse &stat) { stat.true_size_; } /** Write blob to backend */ void PosixIoClient::WriteBlob(const Blob &full_blob, - const IoClientContext &io_ctx, - const IoClientOptions &opts, + const IoClientObject &io_ctx, + const IoClientContext &opts, IoStatus &status) { (void) opts; LOG(INFO) << "Writing to file: " << io_ctx.filename_ @@ -95,8 +106,8 @@ void PosixIoClient::WriteBlob(const Blob &full_blob, /** Read blob from the backend */ void PosixIoClient::ReadBlob(Blob &full_blob, - const IoClientContext &io_ctx, - const IoClientOptions &opts, + const IoClientObject &io_ctx, + const IoClientContext &opts, IoStatus &status) { (void) opts; LOG(INFO) << "Writing to file: " << io_ctx.filename_ diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h index 67bc99c07..1a19b42d7 100644 --- a/adapter/posix/posix_io_client.h +++ b/adapter/posix/posix_io_client.h @@ -20,8 +20,8 @@ #include "posix_api.h" using hermes::Singleton; -using hermes::adapter::IoClientStat; -using hermes::adapter::IoClientOptions; +using hermes::adapter::IoClientStats; +using hermes::adapter::IoClientContext; using hermes::adapter::IoStatus; using hermes::adapter::fs::PosixApi; @@ -41,8 +41,8 @@ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { public: /** Allocate an fd for the file f */ - void RealOpen(IoClientContext &f, - IoClientStat &stat, + void RealOpen(IoClientObject &f, + IoClientStats &stat, const std::string &path) override; /** @@ -51,37 +51,45 @@ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { * and hermes file handler. These are not the same as POSIX file * descriptor and STDIO file handler. * */ - void HermesOpen(IoClientContext &f, - const IoClientStat &stat, - FilesystemIoClientContext &fs_mdm) override; + void HermesOpen(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) override; /** Synchronize \a file FILE f */ - int RealSync(const IoClientContext &f, - const IoClientStat &stat) override; + int RealSync(const IoClientObject &f, + const IoClientStats &stat) override; /** Close \a file FILE f */ - int RealClose(const IoClientContext &f, - const IoClientStat &stat) override; + int RealClose(const IoClientObject &f, + const IoClientStats &stat) override; + + /** + * Called before RealClose. Releases information provisioned during + * the allocation phase. + * */ + void HermesClose(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) override; /** Get initial statistics from the backend */ void InitBucketState(const lipc::charbuf &bkt_name, - const IoClientOptions &opts, - GlobalIoClientState &stat) override; + const IoClientContext &opts, + GlobalIoClientStatse &stat) override; /** Update backend statistics */ - void UpdateBucketState(const IoClientOptions &opts, - GlobalIoClientState &stat) override; + void UpdateBucketState(const IoClientContext &opts, + GlobalIoClientStatse &stat) override; /** Write blob to backend */ void WriteBlob(const Blob &full_blob, - const IoClientContext &io_ctx, - const IoClientOptions &opts, + const IoClientObject &io_ctx, + const IoClientContext &opts, IoStatus &status) override; /** Read blob from the backend */ void ReadBlob(Blob &full_blob, - const IoClientContext &io_ctx, - const IoClientOptions &opts, + const IoClientObject &io_ctx, + const IoClientContext &opts, IoStatus &status) override; }; diff --git a/adapter/stdio/stdio.cc b/adapter/stdio/stdio.cc index a8e5d8305..93dd0b7ec 100644 --- a/adapter/stdio/stdio.cc +++ b/adapter/stdio/stdio.cc @@ -28,12 +28,12 @@ using hermes::adapter::fs::MetadataManager; using hermes::adapter::fs::SeekMode; namespace hapi = hermes::api; -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; using hermes::u8; using hermes::u64; namespace hapi = hermes::api; -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; extern "C" { diff --git a/adapter/test/mpiio/mpiio_adapter_test.cpp b/adapter/test/mpiio/mpiio_adapter_test.cpp index 6d87631e1..b5e07f6be 100644 --- a/adapter/test/mpiio/mpiio_adapter_test.cpp +++ b/adapter/test/mpiio/mpiio_adapter_test.cpp @@ -12,7 +12,7 @@ #include -#include +#include #include #include "adapter_test_utils.h" @@ -23,7 +23,7 @@ #include "adapter_test_utils.h" -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes::adapter::mpiio::test { struct Arguments { diff --git a/adapter/test/mpiio/parallel.cc b/adapter/test/mpiio/parallel.cc index 6187ddb92..993707a1a 100644 --- a/adapter/test/mpiio/parallel.cc +++ b/adapter/test/mpiio/parallel.cc @@ -13,10 +13,10 @@ #include "mpi.h" #include #include -#include +#include #include -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; int main(int argc, char **argv) { MPI_File f; diff --git a/adapter/test/posix/posix_adapter_mpi_test.cpp b/adapter/test/posix/posix_adapter_mpi_test.cpp index 76d29e882..769189b65 100644 --- a/adapter/test/posix/posix_adapter_mpi_test.cpp +++ b/adapter/test/posix/posix_adapter_mpi_test.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include "catch_config.h" @@ -29,7 +29,7 @@ #include "posix/posix_api.h" #endif -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes::adapter::fs::test { struct Arguments { diff --git a/adapter/test/posix/posix_adapter_test.cpp b/adapter/test/posix/posix_adapter_test.cpp index 4dc8dc356..0f705a53f 100644 --- a/adapter/test/posix/posix_adapter_test.cpp +++ b/adapter/test/posix/posix_adapter_test.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include "catch_config.h" @@ -28,7 +28,7 @@ #include "adapter_test_utils.h" -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes::adapter::fs::test { struct Arguments { diff --git a/adapter/test/stdio/adapter_utils_test.cc b/adapter/test/stdio/adapter_utils_test.cc index c9bd32ef4..b1eea426d 100644 --- a/adapter/test/stdio/adapter_utils_test.cc +++ b/adapter/test/stdio/adapter_utils_test.cc @@ -13,7 +13,7 @@ #include "catch_config.h" #include "adapter_utils.h" -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; int init(int* argc, char*** argv) { (void)argc; diff --git a/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp b/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp index b15cb54e7..4e0ce4cc4 100644 --- a/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp +++ b/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include "adapter_test_utils.h" @@ -23,7 +23,7 @@ #include "stdio/real_api.h" #endif -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes::adapter::stdio::test { struct Arguments { diff --git a/adapter/test/stdio/stdio_adapter_mapper_test.cpp b/adapter/test/stdio/stdio_adapter_mapper_test.cpp index 1d5eb7ede..7d9b1ef67 100644 --- a/adapter/test/stdio/stdio_adapter_mapper_test.cpp +++ b/adapter/test/stdio/stdio_adapter_mapper_test.cpp @@ -10,7 +10,7 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include +#include #include "catch_config.h" #include "constants.h" @@ -22,7 +22,7 @@ using hermes::adapter::MapperFactory; using hermes::adapter::fs::kMapperType; using hermes::adapter::fs::MetadataManager; -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes::adapter::stdio::test { struct Arguments { diff --git a/adapter/test/stdio/stdio_adapter_mode_test.cpp b/adapter/test/stdio/stdio_adapter_mode_test.cpp index d37cdef1c..4ff439bcf 100644 --- a/adapter/test/stdio/stdio_adapter_mode_test.cpp +++ b/adapter/test/stdio/stdio_adapter_mode_test.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #if HERMES_INTERCEPT == 1 @@ -24,7 +24,7 @@ #include "adapter_test_utils.h" -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes::adapter::stdio::test { struct Arguments { diff --git a/adapter/test/stdio/stdio_adapter_mpi_test.cpp b/adapter/test/stdio/stdio_adapter_mpi_test.cpp index b126187f3..67d19731c 100644 --- a/adapter/test/stdio/stdio_adapter_mpi_test.cpp +++ b/adapter/test/stdio/stdio_adapter_mpi_test.cpp @@ -16,13 +16,13 @@ #include #include -#include +#include #include #if HERMES_INTERCEPT == 1 #include "stdio/real_api.h" #endif -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes::adapter::stdio::test { struct Arguments { diff --git a/adapter/test/stdio/stdio_adapter_test.cpp b/adapter/test/stdio/stdio_adapter_test.cpp index 615dd084d..0861da7bb 100644 --- a/adapter/test/stdio/stdio_adapter_test.cpp +++ b/adapter/test/stdio/stdio_adapter_test.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include "adapter_test_utils.h" @@ -25,7 +25,7 @@ #include "adapter_test_utils.h" -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes::adapter::stdio::test { struct Arguments { diff --git a/adapter/test/vfd/hermes_vfd_test.cc b/adapter/test/vfd/hermes_vfd_test.cc index e3458950e..9d743353d 100644 --- a/adapter/test/vfd/hermes_vfd_test.cc +++ b/adapter/test/vfd/hermes_vfd_test.cc @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include @@ -26,7 +26,7 @@ #include "adapter_test_utils.h" #include "catch_config.h" -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; using hermes::f32; using hermes::u32; diff --git a/config/hermes_client_default.yaml b/config/hermes_client_default.yaml index b8b208194..5b9456e42 100644 --- a/config/hermes_client_default.yaml +++ b/config/hermes_client_default.yaml @@ -1,2 +1,4 @@ stop_daemon: true -file_page_size: 1024KB \ No newline at end of file +file_page_size: 1024KB +path_inclusions: ["/home"] +path_exclusions: [] \ No newline at end of file diff --git a/data_stager/stagers/posix_stager.cc b/data_stager/stagers/posix_stager.cc index eee0695bf..1dea825e7 100644 --- a/data_stager/stagers/posix_stager.cc +++ b/data_stager/stagers/posix_stager.cc @@ -16,7 +16,7 @@ using hermes::adapter::fs::PosixFS; using hermes::api::PlacementPolicyConv; using hermes::api::PlacementPolicy; using hermes::adapter::fs::IoOptions; -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes { diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 9a98fe528..df36dd506 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -24,7 +24,7 @@ namespace hermes::api { * */ Bucket::Bucket(const std::string &bkt_name, Context &ctx, - const IoClientOptions &opts) + const IoClientContext &opts) : mdm_(&HERMES->mdm_), bpm_(&HERMES->bpm_) { lipc::string lname(bkt_name); id_ = mdm_->LocalGetOrCreateBucket(lname, opts); @@ -33,7 +33,7 @@ Bucket::Bucket(const std::string &bkt_name, /** * Get the current size of the bucket * */ -size_t Bucket::GetSize(IoClientOptions opts) { +size_t Bucket::GetSize(IoClientContext opts) { return mdm_->LocalGetBucketSize(id_, opts); } @@ -73,7 +73,7 @@ Status Bucket::Put(std::string blob_name, const Blob blob, BlobId &blob_id, Context &ctx, - IoClientOptions opts) { + IoClientContext opts) { // Calculate placement auto dpe = DPEFactory::Get(ctx.policy); std::vector blob_sizes(1, blob.size()); @@ -115,8 +115,8 @@ Status Bucket::PartialPutOrCreate(const std::string &blob_name, const Blob &blob, size_t blob_off, BlobId &blob_id, - const IoClientContext &io_ctx, - const IoClientOptions &opts, + const IoClientObject &io_ctx, + const IoClientContext &opts, Context &ctx) { Blob full_blob; // Put the blob @@ -135,10 +135,9 @@ Status Bucket::PartialPutOrCreate(const std::string &blob_name, IoStatus status; auto io_client = IoClientFactory::Get(io_ctx.type_); full_blob.resize(opts.backend_size_); - io_client->ReadBlob(full_blob, - io_ctx, - opts, - status); + if (io_client) { + io_client->ReadBlob(full_blob, io_ctx, opts, status); + } } // Ensure the blob can hold the update full_blob.resize(std::max(full_blob.size(), blob_off + blob.size())); @@ -175,8 +174,8 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, size_t blob_off, size_t blob_size, BlobId &blob_id, - const IoClientContext &io_ctx, - const IoClientOptions &opts, + const IoClientObject &io_ctx, + const IoClientContext &opts, Context &ctx) { Blob full_blob; if (ContainsBlob(blob_name, blob_id)) { diff --git a/src/api/bucket.h b/src/api/bucket.h index ba04a0d2b..0374ae4a6 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -20,7 +20,7 @@ namespace hermes::api { -using hermes::adapter::IoClientContext; +using hermes::adapter::IoClientObject; class Bucket { private: @@ -42,7 +42,7 @@ class Bucket { * */ Bucket(const std::string &bkt_name, Context &ctx, - const IoClientOptions &opts); + const IoClientContext &opts); public: /** @@ -63,7 +63,7 @@ class Bucket { /** * Get the current size of the bucket * */ - size_t GetSize(IoClientOptions opts = IoClientOptions()); + size_t GetSize(IoClientContext opts = IoClientContext()); /** * Rename this bucket @@ -103,7 +103,7 @@ class Bucket { const Blob blob, BlobId &blob_id, Context &ctx, - IoClientOptions opts = IoClientOptions()); + IoClientContext opts = IoClientContext()); /** * Put \a blob_name Blob into the bucket. Load the blob from the @@ -121,8 +121,8 @@ class Bucket { const Blob &blob, size_t blob_off, BlobId &blob_id, - const IoClientContext &io_ctx, - const IoClientOptions &opts, + const IoClientObject &io_ctx, + const IoClientContext &opts, Context &ctx); /** @@ -149,8 +149,8 @@ class Bucket { size_t blob_off, size_t blob_size, BlobId &blob_id, - const IoClientContext &io_ctx, - const IoClientOptions &opts, + const IoClientObject &io_ctx, + const IoClientContext &opts, Context &ctx); /** diff --git a/src/api/hermes.cc b/src/api/hermes.cc index ba6815869..55e50966a 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -20,6 +20,7 @@ void Hermes::Init(HermesType mode, std::string server_config_path, std::string client_config_path) { mode_ = mode; + is_being_initialized_ = true; switch (mode_) { case HermesType::kServer: { InitServer(std::move(server_config_path)); @@ -37,6 +38,7 @@ void Hermes::Init(HermesType mode, } } is_initialized_ = true; + is_being_initialized_ = false; } void Hermes::Finalize() { @@ -152,13 +154,13 @@ void Hermes::FinalizeColocated() { std::shared_ptr Hermes::GetBucket(std::string name, Context ctx, - IoClientOptions opts) { + IoClientContext opts) { return std::make_shared(name, ctx, opts); } std::shared_ptr Hermes::GetVBucket(std::string name, Context ctx, - IoClientOptions opts) { + IoClientContext opts) { return std::make_shared(name, ctx, opts); } diff --git a/src/api/hermes.h b/src/api/hermes.h index 4fa365a51..da61dda1c 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -23,6 +23,7 @@ #include "metadata_manager.h" #include "buffer_pool.h" #include "buffer_organizer.h" +#include "hermes_singleton_macros.h" namespace hermes::api { @@ -54,14 +55,21 @@ class Hermes { COMM_TYPE comm_; RPC_TYPE rpc_; lipc::Allocator *main_alloc_; + bool is_being_initialized_; bool is_initialized_; + bool is_transparent_; public: /** Default constructor */ - Hermes() : is_initialized_(false) {} + Hermes() : is_being_initialized_(false), + is_initialized_(false), + is_transparent_(false) {} /** Destructor */ - ~Hermes() = default; + ~Hermes() {} + + /** Whether or not Hermes is currently being initialized */ + bool IsBeingInitialized() { return is_being_initialized_; } /** Whether or not Hermes is initialized */ bool IsInitialized() { return is_initialized_; } @@ -89,12 +97,12 @@ class Hermes { /** Create a Bucket in Hermes */ std::shared_ptr GetBucket(std::string name, Context ctx = Context(), - IoClientOptions = IoClientOptions()); + IoClientContext = IoClientContext()); /** Create a VBucket in Hermes */ std::shared_ptr GetVBucket(std::string name, Context ctx = Context(), - IoClientOptions = IoClientOptions()); + IoClientContext = IoClientContext()); private: /** Internal initialization of Hermes */ @@ -145,6 +153,12 @@ class Hermes { } }; +#define TRANSPARENT_HERMES\ + if (!HERMES->IsInitialized() && !HERMES->IsBeingInitialized()) {\ + HERMES->Create(hermes::HermesType::kClient);\ + HERMES->is_transparent_ = true;\ + } + } // namespace hermes::api #endif // HERMES_SRC_API_HERMES_H_ diff --git a/src/api/hermes_singleton.cc b/src/api/hermes_singleton.cc index 56460506d..a607bd2db 100644 --- a/src/api/hermes_singleton.cc +++ b/src/api/hermes_singleton.cc @@ -14,4 +14,4 @@ #include "hermes.h" template<> hermes::api::Hermes hermes::GlobalSingleton< - hermes::api::Hermes>::obj_ = hermes::api::Hermes(); + hermes::api::Hermes>::obj_ = hermes::api::Hermes(); \ No newline at end of file diff --git a/src/api/vbucket.cc b/src/api/vbucket.cc index 39e3f0758..61c673252 100644 --- a/src/api/vbucket.cc +++ b/src/api/vbucket.cc @@ -23,7 +23,7 @@ namespace hermes::api { * */ VBucket::VBucket(const std::string &name, Context &ctx, - const IoClientOptions &opts) + const IoClientContext &opts) : mdm_(&HERMES->mdm_), ctx_(ctx) { lipc::string lname(name); // TODO(llogan): rpcify diff --git a/src/api/vbucket.h b/src/api/vbucket.h index 800ab3bb0..688e9d39c 100644 --- a/src/api/vbucket.h +++ b/src/api/vbucket.h @@ -34,7 +34,7 @@ class VBucket { * */ VBucket(const std::string &name, Context &ctx, - const IoClientOptions &opts); + const IoClientContext &opts); /** * Rename a VBucket. diff --git a/src/borg_io_clients/borg_posix_client.h b/src/borg_io_clients/borg_posix_client.h index 6edcb5edd..5ec777259 100644 --- a/src/borg_io_clients/borg_posix_client.h +++ b/src/borg_io_clients/borg_posix_client.h @@ -17,9 +17,9 @@ #include "adapter/posix/posix_api.h" #include "adapter/posix/posix_api_singleton_macros.h" -#include +#include -namespace stdfs = std::experimental::filesystem; +namespace stdfs = std::filesystem; namespace hermes::borg { diff --git a/src/config_client.cc b/src/config_client.cc index 9e57ed2b4..7d13694ec 100644 --- a/src/config_client.cc +++ b/src/config_client.cc @@ -24,6 +24,12 @@ void ClientConfig::ParseYAML(YAML::Node &yaml_conf) { file_page_size_ = ParseSize( yaml_conf["file_page_size"].as()); } + if (yaml_conf["path_inclusions"]) { + ParseVector(yaml_conf["path_inclusions"], path_inclusions_); + } + if (yaml_conf["path_exclusions"]) { + ParseVector(yaml_conf["path_inclusions"], path_exclusions_); + } } /** Load the default configuration */ diff --git a/src/config_client_default.h b/src/config_client_default.h index f4c6e6dc8..803d86396 100644 --- a/src/config_client_default.h +++ b/src/config_client_default.h @@ -1,18 +1,8 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - #ifndef HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ #define HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ const char* kClientDefaultConfigStr = "stop_daemon: true\n" -"file_page_size: 1024KB\n"; -#endif // HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ +"file_page_size: 1024KB\n" +"path_inclusions: [\"/home\"]\n" +"path_exclusions: []\n"; +#endif // HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ \ No newline at end of file diff --git a/src/config_server_default.h b/src/config_server_default.h index f29883f42..837f7265f 100644 --- a/src/config_server_default.h +++ b/src/config_server_default.h @@ -1,15 +1,3 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - #ifndef HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ #define HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ const char* kServerDefaultConfigStr = @@ -157,4 +145,4 @@ const char* kServerDefaultConfigStr = "#Paths which are never ignored when buffering data\n" "path_inclusions: [\"/var/opt/cray/dws/mounts/\"]\n" "\n"; -#endif // HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ +#endif // HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ \ No newline at end of file diff --git a/src/hermes_types.h b/src/hermes_types.h index dba485f59..4bb64cf90 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -23,7 +23,6 @@ #include "data_structures.h" #include "constants.h" -#include "api/hermes_singleton_macros.h" #include "statuses.h" /** diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 288504bec..709a7ac33 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -116,7 +116,7 @@ void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { * */ BucketId MetadataManager::LocalGetOrCreateBucket( lipc::charbuf &bkt_name, - const IoClientOptions &opts) { + const IoClientContext &opts) { // Create unique ID for the Bucket BucketId bkt_id; bkt_id.unique_ = header_->id_alloc_.fetch_add(1); @@ -170,7 +170,7 @@ BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { * @RPC_CLASS_INSTANCE mdm * */ size_t MetadataManager::LocalGetBucketSize(BucketId bkt_id, - const IoClientOptions &opts) { + const IoClientContext &opts) { auto iter = bkt_map_->find(bkt_id); if (iter == bkt_map_->end()) { return 0; @@ -241,7 +241,7 @@ Status MetadataManager::LocalBucketRegisterBlobId( size_t orig_blob_size, size_t new_blob_size, bool did_create, - const IoClientOptions &opts) { + const IoClientContext &opts) { auto iter = bkt_map_->find(bkt_id); if (iter == bkt_map_->end()) { return Status(); @@ -416,7 +416,7 @@ bool MetadataManager::LocalDestroyBlob(BucketId bkt_id, * */ VBucketId MetadataManager::LocalGetOrCreateVBucket( lipc::charbuf &vbkt_name, - const IoClientOptions &opts) { + const IoClientContext &opts) { (void) opts; // Create unique ID for the Bucket VBucketId vbkt_id; diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 20e4a1528..713ddca29 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -26,11 +26,8 @@ namespace hermes { /** Namespace simplification for AdapterFactory */ using hermes::adapter::IoClientFactory; -/** Namespace simplification for IoClientContext */ -using hermes::adapter::IoClientContext; - /** Namespace simplification for AbstractAdapter */ -using hermes::adapter::IoClientOptions; +using hermes::adapter::IoClientContext; /** Forward declaration of borg */ class BufferOrganizer; @@ -140,7 +137,7 @@ class MetadataManager { * @RPC_CLASS_INSTANCE mdm * */ RPC BucketId LocalGetOrCreateBucket(lipc::charbuf &bkt_name, - const IoClientOptions &opts); + const IoClientContext &opts); /** * Get the BucketId with \a bkt_name bucket name @@ -157,7 +154,7 @@ class MetadataManager { * @RPC_CLASS_INSTANCE mdm * */ RPC size_t LocalGetBucketSize(BucketId bkt_id, - const IoClientOptions &opts); + const IoClientContext &opts); /** * Check whether or not \a bkt_id bucket contains @@ -211,7 +208,7 @@ class MetadataManager { size_t orig_blob_size, size_t new_blob_size, bool did_create, - const IoClientOptions &opts); + const IoClientContext &opts); /** * Registers the existence of a Blob with the Bucket. Required for @@ -273,7 +270,7 @@ class MetadataManager { * @RPC_CLASS_INSTANCE mdm * */ RPC VBucketId LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name, - const IoClientOptions &opts); + const IoClientContext &opts); /** * Get the VBucketId of \a vbkt_name VBucket diff --git a/src/metadata_types.h b/src/metadata_types.h index 527d34d2f..f545d5b59 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -19,7 +19,7 @@ namespace hermes { -using adapter::GlobalIoClientState; +using adapter::GlobalIoClientStatse; using api::Blob; struct BucketInfo; /** Forward declaration of BucketInfo */ struct BlobInfo; /** Forward declaration of BlobInfo */ @@ -229,7 +229,7 @@ struct ShmHeader : public lipc::ShmBaseHeader { lipc::TypedPointer name_ar_; lipc::TypedPointer> blobs_ar_; size_t internal_size_; - GlobalIoClientState client_state_; + GlobalIoClientStatse client_state_; }; /** Metadata for a Bucket */ diff --git a/src/singleton.h b/src/singleton.h index a7bdba9b5..a71d8a00b 100644 --- a/src/singleton.h +++ b/src/singleton.h @@ -28,6 +28,7 @@ template class Singleton { private: static std::unique_ptr obj_; + public: Singleton() = default; From b7d4b3d21cbf0b357122df3a43dbef2e6b7f895b Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 3 Feb 2023 04:03:52 -0600 Subject: [PATCH 109/511] Track file size --- adapter/filesystem/filesystem.cc | 8 ------ adapter/filesystem/filesystem_io_client.h | 1 + adapter/io_client/io_client.h | 8 +++--- adapter/posix/posix_io_client.cc | 31 ++++++++++++++--------- adapter/posix/posix_io_client.h | 8 +++--- src/api/bucket.cc | 18 ++++++------- src/api/bucket.h | 2 -- 7 files changed, 36 insertions(+), 40 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 133ed838d..68075ec21 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -75,10 +75,7 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, const Blob blob_wrap((const char*)ptr + data_offset, off); lipc::charbuf blob_name(p.CreateBlobName()); BlobId blob_id; - IoClientObject io_ctx; Context ctx; - io_ctx.type_ = type_; - io_ctx.filename_ = filename; opts.type_ = type_; opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; @@ -86,7 +83,6 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, blob_wrap, p.blob_off_, blob_id, - io_ctx, opts, ctx); data_offset += p.blob_size_; @@ -118,10 +114,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, Blob blob_wrap((const char*)ptr + data_offset, off); lipc::charbuf blob_name(p.CreateBlobName()); BlobId blob_id; - IoClientObject io_ctx; Context ctx; - io_ctx.type_ = type_; - io_ctx.filename_ = filename; opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; opts.type_ = type_; @@ -130,7 +123,6 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, p.blob_off_, p.blob_size_, blob_id, - io_ctx, opts, ctx); data_offset += p.blob_size_; diff --git a/adapter/filesystem/filesystem_io_client.h b/adapter/filesystem/filesystem_io_client.h index 61b121755..575ca8e09 100644 --- a/adapter/filesystem/filesystem_io_client.h +++ b/adapter/filesystem/filesystem_io_client.h @@ -31,6 +31,7 @@ struct FsIoClientMetadata { /** Default constructor */ FsIoClientMetadata() { hermes_fd_min_ = 8192; // TODO(llogan): don't assume 8192 + hermes_fd_cur_ = hermes_fd_min_; hermes_fd_max_ = std::numeric_limits::max(); } diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index 24f270060..ae610bd56 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -177,14 +177,14 @@ class IoClient { GlobalIoClientStatse &stat) = 0; /** Write blob to backend */ - virtual void WriteBlob(const Blob &full_blob, - const IoClientObject &io_ctx, + virtual void WriteBlob(const lipc::charbuf &bkt_name, + const Blob &full_blob, const IoClientContext &opts, IoStatus &status) = 0; /** Read blob from the backend */ - virtual void ReadBlob(Blob &full_blob, - const IoClientObject &io_ctx, + virtual void ReadBlob(const lipc::charbuf &bkt_name, + Blob &full_blob, const IoClientContext &opts, IoStatus &status) = 0; }; diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 86d27d7db..34f4ddfde 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -71,28 +71,35 @@ void PosixIoClient::HermesClose(IoClientObject &f, void PosixIoClient::InitBucketState(const lipc::charbuf &bkt_name, const IoClientContext &opts, GlobalIoClientStatse &stat) { - // real_api->__fxstat(); stat.true_size_ = 0; + std::string filename = bkt_name.str(); + int fd = real_api->open(filename.c_str(), O_RDONLY); + if (fd < 0) { return; } + struct stat buf; + real_api->__fxstat(_STAT_VER, fd, &buf); + stat.true_size_ = buf.st_size; + real_api->close(fd); } /** Update backend statistics */ void PosixIoClient::UpdateBucketState(const IoClientContext &opts, GlobalIoClientStatse &stat) { - stat.true_size_; + stat.true_size_ = std::max(stat.true_size_, + opts.backend_off_ + opts.backend_size_); } /** Write blob to backend */ -void PosixIoClient::WriteBlob(const Blob &full_blob, - const IoClientObject &io_ctx, +void PosixIoClient::WriteBlob(const lipc::charbuf &bkt_name, + const Blob &full_blob, const IoClientContext &opts, IoStatus &status) { (void) opts; - LOG(INFO) << "Writing to file: " << io_ctx.filename_ + LOG(INFO) << "Writing to file: " << bkt_name.str() << " offset: " << opts.backend_off_ << " size:" << full_blob.size() << "." - << " file_size:" << stdfs::file_size(io_ctx.filename_) + << " file_size:" << stdfs::file_size(bkt_name.str()) << std::endl; - int fd = real_api->open(io_ctx.filename_.c_str(), O_RDWR | O_CREAT); + int fd = real_api->open(bkt_name.str().c_str(), O_RDWR | O_CREAT); if (fd < 0) { status.posix_ret_ = 0; return; @@ -105,17 +112,17 @@ void PosixIoClient::WriteBlob(const Blob &full_blob, } /** Read blob from the backend */ -void PosixIoClient::ReadBlob(Blob &full_blob, - const IoClientObject &io_ctx, +void PosixIoClient::ReadBlob(const lipc::charbuf &bkt_name, + Blob &full_blob, const IoClientContext &opts, IoStatus &status) { (void) opts; - LOG(INFO) << "Writing to file: " << io_ctx.filename_ + LOG(INFO) << "Writing to file: " << bkt_name.str() << " offset: " << opts.backend_off_ << " size:" << full_blob.size() << "." - << " file_size:" << stdfs::file_size(io_ctx.filename_) + << " file_size:" << stdfs::file_size(bkt_name.str()) << std::endl; - int fd = real_api->open(io_ctx.filename_.c_str(), O_RDONLY); + int fd = real_api->open(bkt_name.str().c_str(), O_RDONLY); if (fd < 0) { status.posix_ret_ = 0; return; diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h index 1a19b42d7..19703f0f8 100644 --- a/adapter/posix/posix_io_client.h +++ b/adapter/posix/posix_io_client.h @@ -81,14 +81,14 @@ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { GlobalIoClientStatse &stat) override; /** Write blob to backend */ - void WriteBlob(const Blob &full_blob, - const IoClientObject &io_ctx, + void WriteBlob(const lipc::charbuf &bkt_name, + const Blob &full_blob, const IoClientContext &opts, IoStatus &status) override; /** Read blob from the backend */ - void ReadBlob(Blob &full_blob, - const IoClientObject &io_ctx, + void ReadBlob(const lipc::charbuf &bkt_name, + Blob &full_blob, const IoClientContext &opts, IoStatus &status) override; }; diff --git a/src/api/bucket.cc b/src/api/bucket.cc index df36dd506..d8f7e85ee 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -25,7 +25,7 @@ namespace hermes::api { Bucket::Bucket(const std::string &bkt_name, Context &ctx, const IoClientContext &opts) -: mdm_(&HERMES->mdm_), bpm_(&HERMES->bpm_) { +: mdm_(&HERMES->mdm_), bpm_(&HERMES->bpm_), name_(bkt_name) { lipc::string lname(bkt_name); id_ = mdm_->LocalGetOrCreateBucket(lname, opts); } @@ -115,7 +115,6 @@ Status Bucket::PartialPutOrCreate(const std::string &blob_name, const Blob &blob, size_t blob_off, BlobId &blob_id, - const IoClientObject &io_ctx, const IoClientContext &opts, Context &ctx) { Blob full_blob; @@ -133,10 +132,11 @@ Status Bucket::PartialPutOrCreate(const std::string &blob_name, // Case 3: The blob did not exist (need to read from backend) // Read blob using adapter IoStatus status; - auto io_client = IoClientFactory::Get(io_ctx.type_); + auto io_client = IoClientFactory::Get(opts.type_); full_blob.resize(opts.backend_size_); if (io_client) { - io_client->ReadBlob(full_blob, io_ctx, opts, status); + io_client->ReadBlob(lipc::charbuf(name_), + full_blob, opts, status); } } // Ensure the blob can hold the update @@ -174,7 +174,6 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, size_t blob_off, size_t blob_size, BlobId &blob_id, - const IoClientObject &io_ctx, const IoClientContext &opts, Context &ctx) { Blob full_blob; @@ -186,12 +185,11 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, // Case 2: The blob did not exist (need to read from backend) // Read blob using adapter IoStatus status; - auto io_client = IoClientFactory::Get(io_ctx.type_); + auto io_client = IoClientFactory::Get(opts.type_); full_blob.resize(opts.backend_size_); - io_client->ReadBlob(full_blob, - io_ctx, - opts, - status); + if (io_client) { + io_client->ReadBlob(lipc::charbuf(name_), full_blob, opts, status); + } } // Ensure the blob can hold the update if (full_blob.size() < blob_off + blob_size) { diff --git a/src/api/bucket.h b/src/api/bucket.h index 0374ae4a6..1683ab037 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -121,7 +121,6 @@ class Bucket { const Blob &blob, size_t blob_off, BlobId &blob_id, - const IoClientObject &io_ctx, const IoClientContext &opts, Context &ctx); @@ -149,7 +148,6 @@ class Bucket { size_t blob_off, size_t blob_size, BlobId &blob_id, - const IoClientObject &io_ctx, const IoClientContext &opts, Context &ctx); From 9231700cd7cd3a14c0efedd8e276d6351a52df1c Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 3 Feb 2023 04:51:49 -0600 Subject: [PATCH 110/511] Destroy shm when re-creating backend --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 1017d715a..6071cf4d7 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,7 @@ GTAGS .gdb_history -/cmake-build-debug/ -/cmake-build-release/ +/cmake-build-* /.idea/ /.clang-format __pycache__/ From 85e2e52a346793ad2810e61dff4dd69781430c39 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 3 Feb 2023 05:18:21 -0600 Subject: [PATCH 111/511] Interceptor finalizes gracefully without MPI_Finalize --- .gitignore | 3 +-- adapter/filesystem/filesystem.cc | 5 ++--- adapter/posix/posix.cc | 1 - adapter/posix/posix_api_singleton.cc | 2 +- adapter/test/posix/simple_io.cc | 8 ++++---- src/api/bucket.cc | 2 +- src/api/bucket.h | 2 +- src/api/hermes.cc | 3 +++ src/api/hermes.h | 11 +++++++++-- src/api/hermes_singleton.cc | 9 ++++++++- 10 files changed, 30 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 1017d715a..6071cf4d7 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,7 @@ GTAGS .gdb_history -/cmake-build-debug/ -/cmake-build-release/ +/cmake-build-* /.idea/ /.clang-format __pycache__/ diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 68075ec21..b0367c09b 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -72,7 +72,7 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, size_t kPageSize = HERMES->client_config_.file_page_size_; for (const auto &p : mapping) { - const Blob blob_wrap((const char*)ptr + data_offset, off); + const Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); lipc::charbuf blob_name(p.CreateBlobName()); BlobId blob_id; Context ctx; @@ -111,7 +111,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, size_t kPageSize = HERMES->client_config_.file_page_size_; for (const auto &p : mapping) { - Blob blob_wrap((const char*)ptr + data_offset, off); + Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); lipc::charbuf blob_name(p.CreateBlobName()); BlobId blob_id; Context ctx; @@ -200,7 +200,6 @@ size_t Filesystem::GetSize(File &f, AdapterStat &stat) { IoOptions opts; opts.type_ = type_; return stat.bkt_id_->GetSize(opts); - } off_t Filesystem::Seek(File &f, AdapterStat &stat, diff --git a/adapter/posix/posix.cc b/adapter/posix/posix.cc index a878b0e6b..5e1a3af5c 100644 --- a/adapter/posix/posix.cc +++ b/adapter/posix/posix.cc @@ -53,7 +53,6 @@ int HERMES_DECL(open)(const char *path, int flags, ...) { va_end(arg); } if (fs_api->IsPathTracked(path)) { - TRANSPARENT_HERMES; LOG(INFO) << "Intercept open for filename: " << path << " and mode: " << flags << " is tracked." << std::endl; AdapterStat stat; diff --git a/adapter/posix/posix_api_singleton.cc b/adapter/posix/posix_api_singleton.cc index 810f192e7..c14bc95b0 100644 --- a/adapter/posix/posix_api_singleton.cc +++ b/adapter/posix/posix_api_singleton.cc @@ -16,4 +16,4 @@ /*template<> hermes::adapter::fs::PosixApi hermes::GlobalSingleton< hermes::adapter::fs::PosixApi>::obj_ = hermes::adapter::fs::PosixApi();*/ template<> std::unique_ptr - hermes::Singleton::obj_ = nullptr; \ No newline at end of file + hermes::Singleton::obj_ = nullptr; diff --git a/adapter/test/posix/simple_io.cc b/adapter/test/posix/simple_io.cc index 662da85e2..6f3afc838 100644 --- a/adapter/test/posix/simple_io.cc +++ b/adapter/test/posix/simple_io.cc @@ -33,10 +33,10 @@ static bool VerifyBuffer(char *ptr, size_t size, char nonce) { } int main(int argc, char **argv) { - int rank, nprocs; - MPI_Init(&argc, &argv); + int rank = 0, nprocs = 1; + /*MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nprocs); + MPI_Comm_size(MPI_COMM_WORLD, &nprocs);*/ if (argc != 7) { std::cout << "USAGE: ./posix_simple_io" << " [path] [read] [block_size (kb)] [count]" @@ -102,5 +102,5 @@ int main(int argc, char **argv) { } close(fd); - MPI_Finalize(); + // MPI_Finalize(); } diff --git a/src/api/bucket.cc b/src/api/bucket.cc index d8f7e85ee..789144f14 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -70,7 +70,7 @@ Status Bucket::GetBlobId(std::string blob_name, * Put \a blob_id Blob into the bucket * */ Status Bucket::Put(std::string blob_name, - const Blob blob, + const Blob &blob, BlobId &blob_id, Context &ctx, IoClientContext opts) { diff --git a/src/api/bucket.h b/src/api/bucket.h index 1683ab037..eb332492b 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -100,7 +100,7 @@ class Bucket { * Put \a blob_name Blob into the bucket * */ Status Put(std::string blob_name, - const Blob blob, + const Blob &blob, BlobId &blob_id, Context &ctx, IoClientContext opts = IoClientContext()); diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 55e50966a..e4c72f04f 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -56,6 +56,9 @@ void Hermes::Finalize() { break; } } + // TODO(llogan): make re-initialization possible. + is_initialized_ = false; + is_terminated_ = true; } void Hermes::RunDaemon() { diff --git a/src/api/hermes.h b/src/api/hermes.h index da61dda1c..4478dc3a5 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -57,13 +57,15 @@ class Hermes { lipc::Allocator *main_alloc_; bool is_being_initialized_; bool is_initialized_; + bool is_terminated_; bool is_transparent_; public: /** Default constructor */ Hermes() : is_being_initialized_(false), is_initialized_(false), - is_transparent_(false) {} + is_transparent_(false), + is_terminated_(false) {} /** Destructor */ ~Hermes() {} @@ -74,6 +76,9 @@ class Hermes { /** Whether or not Hermes is initialized */ bool IsInitialized() { return is_initialized_; } + /** Whether or not Hermes is finalized */ + bool IsTerminated() { return is_terminated_; } + /** Initialize Hermes explicitly */ static Hermes* Create(HermesType mode = HermesType::kClient, std::string server_config_path = "", @@ -154,7 +159,9 @@ class Hermes { }; #define TRANSPARENT_HERMES\ - if (!HERMES->IsInitialized() && !HERMES->IsBeingInitialized()) {\ + if (!HERMES->IsInitialized() && \ + !HERMES->IsBeingInitialized() && \ + !HERMES->IsTerminated()) {\ HERMES->Create(hermes::HermesType::kClient);\ HERMES->is_transparent_ = true;\ } diff --git a/src/api/hermes_singleton.cc b/src/api/hermes_singleton.cc index a607bd2db..0a74b3b6f 100644 --- a/src/api/hermes_singleton.cc +++ b/src/api/hermes_singleton.cc @@ -11,7 +11,14 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "singleton.h" +#include "hermes_singleton_macros.h" #include "hermes.h" template<> hermes::api::Hermes hermes::GlobalSingleton< - hermes::api::Hermes>::obj_ = hermes::api::Hermes(); \ No newline at end of file + hermes::api::Hermes>::obj_ = hermes::api::Hermes(); + +void Finalize() { + HERMES->Finalize(); +} + +void __attribute__((destructor)) Finalize(); \ No newline at end of file From 1bdb8b7ff69ad204a3b377a6f1e9d88ee1424cc0 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 3 Feb 2023 05:34:54 -0600 Subject: [PATCH 112/511] MPI_Finalize no longer fails --- adapter/filesystem/filesystem.cc | 13 ++++++------- adapter/filesystem/filesystem.h | 1 + adapter/test/posix/simple_io.cc | 6 +++--- src/api/bucket.cc | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index b0367c09b..b3ecc8d39 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -35,15 +35,16 @@ File Filesystem::Open(AdapterStat &stat, const std::string &path) { void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { auto mdm = HERMES_FS_METADATA_MANAGER; - stat.bkt_id_ = HERMES->GetBucket(path); + IoOptions opts; + opts.type_ = type_; + stat.bkt_id_ = HERMES->GetBucket(path, ctx_, opts); std::pair exists = mdm->Find(f); if (!exists.second) { LOG(INFO) << "File not opened before by adapter" << std::endl; // Create the new bucket - Context ctx; IoOptions opts; opts.type_ = type_; - stat.bkt_id_ = HERMES->GetBucket(path, ctx, opts); + stat.bkt_id_ = HERMES->GetBucket(path, ctx_, opts); // Allocate internal hermes data auto stat_ptr = std::make_unique(stat); FilesystemIoClientObject fs_ctx(&mdm->fs_mdm_, (void*)stat_ptr.get()); @@ -75,7 +76,6 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, const Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); lipc::charbuf blob_name(p.CreateBlobName()); BlobId blob_id; - Context ctx; opts.type_ = type_; opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; @@ -84,7 +84,7 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, p.blob_off_, blob_id, opts, - ctx); + ctx_); data_offset += p.blob_size_; } if (opts.DoSeek()) { stat.st_ptr_ = off + data_offset; } @@ -114,7 +114,6 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); lipc::charbuf blob_name(p.CreateBlobName()); BlobId blob_id; - Context ctx; opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; opts.type_ = type_; @@ -124,7 +123,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, p.blob_size_, blob_id, opts, - ctx); + ctx_); data_offset += p.blob_size_; } if (opts.DoSeek()) { stat.st_ptr_ = off + data_offset; } diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index 5877f75b3..ff35ca927 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -96,6 +96,7 @@ class Filesystem { public: FilesystemIoClient *io_client_; AdapterType type_; + Context ctx_; public: /** Constructor */ diff --git a/adapter/test/posix/simple_io.cc b/adapter/test/posix/simple_io.cc index 6f3afc838..652d12c1e 100644 --- a/adapter/test/posix/simple_io.cc +++ b/adapter/test/posix/simple_io.cc @@ -34,9 +34,9 @@ static bool VerifyBuffer(char *ptr, size_t size, char nonce) { int main(int argc, char **argv) { int rank = 0, nprocs = 1; - /*MPI_Init(&argc, &argv); + MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nprocs);*/ + MPI_Comm_size(MPI_COMM_WORLD, &nprocs);/**/ if (argc != 7) { std::cout << "USAGE: ./posix_simple_io" << " [path] [read] [block_size (kb)] [count]" @@ -102,5 +102,5 @@ int main(int argc, char **argv) { } close(fd); - // MPI_Finalize(); + MPI_Finalize(); } diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 789144f14..003577b09 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -208,7 +208,7 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, bool Bucket::ContainsBlob(const std::string &blob_name, BlobId &blob_id) { GetBlobId(blob_name, blob_id); - return blob_id.IsNull(); + return !blob_id.IsNull(); } /** From e4e21cc4b794e0e035d0dc941f1601539527e868 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 3 Feb 2023 07:26:51 -0600 Subject: [PATCH 113/511] Begin stdio compiling --- adapter/CMakeLists.txt | 1 + adapter/interceptor.h | 12 -- adapter/posix/CMakeLists.txt | 12 +- adapter/stdio/CMakeLists.txt | 42 +++--- adapter/stdio/fs_api.cc | 102 -------------- adapter/stdio/fs_api.h | 64 --------- adapter/stdio/stdio.cc | 14 +- adapter/stdio/{real_api.h => stdio_api.h} | 11 +- adapter/stdio/stdio_api_singleton.cc | 17 +++ adapter/stdio/stdio_api_singleton_macros.h | 22 +++ adapter/stdio/stdio_fs_api.h | 63 +++++++++ adapter/stdio/stdio_io_client.cc | 126 ++++++++++++++++++ adapter/stdio/stdio_io_client.h | 102 ++++++++++++++ .../test/stdio/stdio_adapter_mapper_test.cpp | 2 +- 14 files changed, 367 insertions(+), 223 deletions(-) delete mode 100644 adapter/stdio/fs_api.cc delete mode 100644 adapter/stdio/fs_api.h rename adapter/stdio/{real_api.h => stdio_api.h} (97%) create mode 100644 adapter/stdio/stdio_api_singleton.cc create mode 100644 adapter/stdio/stdio_api_singleton_macros.h create mode 100644 adapter/stdio/stdio_fs_api.h create mode 100644 adapter/stdio/stdio_io_client.cc create mode 100644 adapter/stdio/stdio_io_client.h diff --git a/adapter/CMakeLists.txt b/adapter/CMakeLists.txt index 880f65a21..7bfa3c82b 100644 --- a/adapter/CMakeLists.txt +++ b/adapter/CMakeLists.txt @@ -9,5 +9,6 @@ if(HERMES_ENABLE_POSIX_ADAPTER) add_subdirectory(io_client) add_subdirectory(filesystem) add_subdirectory(posix) + add_subdirectory(stdio) add_subdirectory(test) endif() \ No newline at end of file diff --git a/adapter/interceptor.h b/adapter/interceptor.h index 2a3827b8e..0b23c0e40 100644 --- a/adapter/interceptor.h +++ b/adapter/interceptor.h @@ -26,18 +26,6 @@ namespace hermes::adapter { /** The maximum length of a POSIX path */ static inline const int kMaxPathLen = 4096; - -/** get the file name from \a fp file pointer */ -inline std::string GetFilenameFromFP(FILE* fp) { - char proclnk[kMaxPathLen]; - char filename[kMaxPathLen]; - int fno = fileno(fp); - snprintf(proclnk, kMaxPathLen, "/proc/self/fd/%d", fno); - size_t r = readlink(proclnk, filename, kMaxPathLen); - filename[r] = '\0'; - return filename; -} - } // namespace hermes::adapter #endif // HERMES_ADAPTER_UTILS_H_ diff --git a/adapter/posix/CMakeLists.txt b/adapter/posix/CMakeLists.txt index 9b3ab0468..101078edd 100644 --- a/adapter/posix/CMakeLists.txt +++ b/adapter/posix/CMakeLists.txt @@ -13,16 +13,14 @@ target_link_libraries(hermes_posix_io_client MPI::MPI_CXX glog::glog stdc++fs dl) # Create the POSIX interceptor -add_library(hermes_posix SHARED - ${CMAKE_CURRENT_SOURCE_DIR}/posix.cc) -add_dependencies(hermes_posix - hermes - hermes_posix_io_client - hermes_fs_base) -target_link_libraries(hermes_posix +set(INTERCEPTOR_DEPS hermes hermes_posix_io_client hermes_fs_base) +add_library(hermes_posix SHARED + ${CMAKE_CURRENT_SOURCE_DIR}/posix.cc) +add_dependencies(hermes_posix ${INTERCEPTOR_DEPS}) +target_link_libraries(hermes_posix ${INTERCEPTOR_DEPS}) target_compile_options(hermes_posix PUBLIC -fPIC) #----------------------------------------------------------------------------- diff --git a/adapter/stdio/CMakeLists.txt b/adapter/stdio/CMakeLists.txt index fb34ba472..7eb1c7f6b 100644 --- a/adapter/stdio/CMakeLists.txt +++ b/adapter/stdio/CMakeLists.txt @@ -1,31 +1,35 @@ project(StdioAdapter VERSION ${HERMES_PACKAGE_VERSION}) -include_directories(${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) +include_directories( + ${CMAKE_SOURCE_DIR} + ${HERMES_SRC_DIR} + ${HERMES_ADAPTER_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}) -# STDIO src code. We only include stdio.cc as it includes other cc to reduce compilation time. -set(STDIO_ADAPTER_SRC stdio.cc) +# Creates the STDIO I/O client and singleton +add_library(hermes_stdio_io_client + ${CMAKE_CURRENT_SOURCE_DIR}/stdio_api_singleton.cc + ${CMAKE_CURRENT_SOURCE_DIR}/stdio_io_client.cc) +target_compile_options(hermes_stdio_io_client PUBLIC -fPIC) +target_link_libraries(hermes_stdio_io_client + MPI::MPI_CXX glog::glog stdc++fs dl) -set(HERMES_STDIO_ADAPTER_DIR ${HERMES_ADAPTER_DIR}/stdio) - -# Only stdio.h is the public adapter. -set(STDIO_ADAPTER_PUBLIC_HEADER - ${HERMES_STDIO_ADAPTER_DIR}/real_api.h - ${HERMES_STDIO_ADAPTER_DIR}/fs_api.h) - -# Add library hermes_stdio -add_library(hermes_stdio_backend ${CMAKE_CURRENT_SOURCE_DIR}/fs_api.cc) -add_dependencies(hermes_stdio_backend hermes) -target_link_libraries(hermes_stdio_backend hermes MPI::MPI_CXX glog::glog stdc++fs dl) - -add_library(hermes_stdio SHARED ${STDIO_ADAPTER_PUBLIC_HEADER} ${STDIO_ADAPTER_SRC}) -add_dependencies(hermes_stdio hermes_stdio_backend) -target_link_libraries(hermes_stdio hermes_stdio_backend) +# Create the STDIO interceptor +set(INTERCEPTOR_DEPS + hermes + hermes_stdio_io_client + hermes_fs_base) +add_library(hermes_stdio SHARED + ${CMAKE_CURRENT_SOURCE_DIR}/stdio.cc) +add_dependencies(hermes_stdio ${INTERCEPTOR_DEPS}) +target_link_libraries(hermes_stdio ${INTERCEPTOR_DEPS}) +target_compile_options(hermes_stdio PUBLIC -fPIC) #----------------------------------------------------------------------------- # Add Target(s) to CMake Install #----------------------------------------------------------------------------- install( TARGETS - hermes_stdio_backend + hermes_stdio_io_client EXPORT ${HERMES_EXPORTED_TARGETS} LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} diff --git a/adapter/stdio/fs_api.cc b/adapter/stdio/fs_api.cc deleted file mode 100644 index ed8a92881..000000000 --- a/adapter/stdio/fs_api.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "real_api.h" -#include "fs_api.h" -#include - -namespace hermes::adapter::stdio { - -File StdioFS::RealOpen(AdapterStat &stat, const std::string &path) { - File f; - f.fh_ = real_api->fopen(path.c_str(), stat.mode_str.c_str()); - if (f.fh_ == nullptr) { - f.status_ = false; - } - InitFile(f); - return f; -} - -void StdioFS::InitFile(File &f) { - struct stat st; - if (f.fh_ == nullptr) { - f.fd_ = -1; - return; - } - f.fd_ = fileno(f.fh_); - posix_api->__fxstat(_STAT_VER, f.fd_, &st); - f.st_dev = st.st_dev; - f.st_ino = st.st_ino; -} - -void StdioFS::OpenInitStat(File &f, AdapterStat &stat) { - struct stat st; - posix_api->__fxstat(_STAT_VER, f.fd_, &st); - stat.st_mode = st.st_mode; - stat.st_uid = st.st_uid; - stat.st_gid = st.st_gid; - stat.st_size = st.st_size; - stat.st_blksize = st.st_blksize; - stat.st_atim = st.st_atim; - stat.st_mtim = st.st_mtim; - stat.st_ctim = st.st_ctim; - if (stat.mode_str.find('a') != std::string::npos) { - stat.is_append = true; - } -} - -size_t StdioFS::_RealWrite(const std::string &filename, off_t offset, - size_t size, const u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) { - (void) opts; (void) io_status; - LOG(INFO) << "Writing to file: " << filename - << " offset: " << offset - << " size:" << size << "." - << " file_size:" << stdfs::file_size(filename) << std::endl; - FILE *fh = real_api->fopen(filename.c_str(), "r+"); - if (fh == nullptr) { return 0; } - real_api->fseek(fh, offset, SEEK_SET); - flock(fileno(fh), LOCK_EX); - size_t write_size = real_api->fwrite(data_ptr, sizeof(char), size, fh); - flock(fileno(fh), LOCK_UN); - real_api->fclose(fh); - return write_size; -} - -size_t StdioFS::_RealRead(const std::string &filename, off_t offset, - size_t size, u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) { - (void) opts; (void) io_status; - LOG(INFO) << "Read called for filename from destination: " << filename - << " on offset: " << offset - << " and size: " << size << "." - << " file_size:" << stdfs::file_size(filename) << std::endl; - FILE *fh = real_api->fopen(filename.c_str(), "r"); - if (fh == nullptr) { return 0; } - real_api->fseek(fh, offset, SEEK_SET); - flock(fileno(fh), LOCK_SH); - size_t read_size = real_api->fread(data_ptr, sizeof(char), size, fh); - flock(fileno(fh), LOCK_UN); - real_api->fclose(fh); - return read_size; -} - -int StdioFS::RealSync(File &f) { - return real_api->fflush(f.fh_); -} - -int StdioFS::RealClose(File &f) { - return real_api->fclose(f.fh_); -} - -} // namespace hermes::adapter::stdio diff --git a/adapter/stdio/fs_api.h b/adapter/stdio/fs_api.h deleted file mode 100644 index 01b7d15b9..000000000 --- a/adapter/stdio/fs_api.h +++ /dev/null @@ -1,64 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_STDIO_NATIVE_H_ -#define HERMES_ADAPTER_STDIO_NATIVE_H_ - -#include - -#include "filesystem/filesystem.cc" -#include "filesystem/filesystem.h" -#include "filesystem/metadata_manager.cc" -#include "filesystem/metadata_manager.h" -#include "posix/posix_api.h" -#include "real_api.h" - -using hermes::Singleton; -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::File; -using hermes::adapter::fs::IoOptions; -using hermes::adapter::fs::IoStatus; -using hermes::adapter::stdio::API; - -namespace hermes::adapter::stdio { -/** - A class to represent standard IO file system -*/ -class StdioFS : public hermes::adapter::fs::Filesystem { - private: - API *real_api; /**< pointer to real APIs */ - hermes::adapter::fs::API *posix_api; /**< pointer to POSIX APIs */ - - public: - StdioFS() { - real_api = Singleton::GetInstance(); - posix_api = Singleton::GetInstance(); - } - ~StdioFS() = default; - - void InitFile(File &f) override; - - private: - void OpenInitStat(File &f, AdapterStat &stat) override; - File RealOpen(AdapterStat &stat, const std::string &path) override; - size_t _RealWrite(const std::string &filename, off_t offset, size_t size, - const u8 *data_ptr, IoStatus &io_status, - IoOptions &opts) override; - size_t _RealRead(const std::string &filename, off_t offset, size_t size, - u8 *data_ptr, IoStatus &io_status, IoOptions &opts) override; - int RealSync(File &f) override; - int RealClose(File &f) override; -}; - -} // namespace hermes::adapter::stdio - -#endif // HERMES_ADAPTER_STDIO_NATIVE_H_ diff --git a/adapter/stdio/stdio.cc b/adapter/stdio/stdio.cc index 93dd0b7ec..8190da83a 100644 --- a/adapter/stdio/stdio.cc +++ b/adapter/stdio/stdio.cc @@ -14,16 +14,11 @@ bool stdio_intercepted = true; #include #include - -#include "interceptor.cc" #include -#include "stdio/real_api.h" -#include "stdio/fs_api.h" +#include "stdio/stdio_api.h" +#include "stdio/stdio_fs_api.h" +#include "interceptor.h" -using hermes::adapter::WeaklyCanonical; -using hermes::adapter::stdio::API; -using hermes::adapter::stdio::StdioFS; -using hermes::Singleton; using hermes::adapter::fs::MetadataManager; using hermes::adapter::fs::SeekMode; @@ -32,9 +27,6 @@ namespace stdfs = std::filesystem; using hermes::u8; using hermes::u64; -namespace hapi = hermes::api; -namespace stdfs = std::filesystem; - extern "C" { /** diff --git a/adapter/stdio/real_api.h b/adapter/stdio/stdio_api.h similarity index 97% rename from adapter/stdio/real_api.h rename to adapter/stdio/stdio_api.h index 7fceff47e..de5f7b5e0 100644 --- a/adapter/stdio/real_api.h +++ b/adapter/stdio/stdio_api.h @@ -17,9 +17,6 @@ #include #include #include -#include "interceptor.h" -#include "filesystem/filesystem.h" -#include "filesystem/metadata_manager.h" #define REQUIRE_API(api_name) \ if (api_name == nullptr) { \ @@ -59,10 +56,10 @@ typedef int (*fsetpos64_t)(FILE * stream, const fpos64_t * pos); typedef long int (*ftell_t)(FILE * fp); } -namespace hermes::adapter::stdio { +namespace hermes::adapter::fs { /** Pointers to the real stdio API */ -class API { +class StdioApi { public: /** MPI_Init */ MPI_Init_t MPI_Init = nullptr; @@ -121,7 +118,7 @@ class API { /** ftell */ ftell_t ftell = nullptr; - API() { + StdioApi() { void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, "stdio_intercepted"); if (is_intercepted) { MPI_Init = (MPI_Init_t)dlsym(RTLD_NEXT, "MPI_Init"); @@ -293,7 +290,7 @@ class API { REQUIRE_API(ftell) } }; -} // namespace hermes::adapter::stdio +} // namespace hermes::adapter::fs #undef REQUIRE_API diff --git a/adapter/stdio/stdio_api_singleton.cc b/adapter/stdio/stdio_api_singleton.cc new file mode 100644 index 000000000..d02405a48 --- /dev/null +++ b/adapter/stdio/stdio_api_singleton.cc @@ -0,0 +1,17 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "singleton.h" + +#include "stdio_api.h" +template<> std::unique_ptr + hermes::Singleton::obj_ = nullptr; diff --git a/adapter/stdio/stdio_api_singleton_macros.h b/adapter/stdio/stdio_api_singleton_macros.h new file mode 100644 index 000000000..b00212705 --- /dev/null +++ b/adapter/stdio/stdio_api_singleton_macros.h @@ -0,0 +1,22 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_STDIO_SINGLETON_ADAPTER_MACROS_H +#define HERMES_STDIO_SINGLETON_ADAPTER_MACROS_H + +#include "singleton.h" + +#define HERMES_STDIO_API \ + hermes::Singleton::GetInstance() +#define HERMES_STDIO_API_T hermes::adapter::fs::StdioApi* + +#endif // HERMES_STDIO_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/stdio/stdio_fs_api.h b/adapter/stdio/stdio_fs_api.h new file mode 100644 index 000000000..3c1f04890 --- /dev/null +++ b/adapter/stdio/stdio_fs_api.h @@ -0,0 +1,63 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_ADAPTER_STDIO_NATIVE_H_ +#define HERMES_ADAPTER_STDIO_NATIVE_H_ + +#include + +#include "adapter/filesystem/filesystem.h" +#include "adapter/filesystem/filesystem_mdm.h" +#include "stdio_api_singleton_macros.h" +#include "stdio_api.h" +#include "stdio_io_client.h" + +namespace hermes::adpater::fs { + +/** A class to represent POSIX IO file system */ +class StdioFs : public hermes::adapter::fs::Filesystem { + public: + StdioFs() : hermes::adapter::fs::Filesystem(HERMES_STDIO_IO_CLIENT, + AdapterType::kStdio) {} + + /** Whether or not \a fd FILE DESCRIPTOR was generated by Hermes */ + static bool IsFpTracked(FILE* fp) { + if (!HERMES->IsInitialized()) { + return false; + } + hermes::adapter::fs::File f; + f.hermes_fh_ = fp; + std::pair stat_pair = + HERMES_FS_METADATA_MANAGER->Find(f); + return stat_pair.second; + } + + /** get the file name from \a fp file pointer */ + inline std::string GetFilenameFromFP(FILE* fp) { + char proclnk[kMaxPathLen]; + char filename[kMaxPathLen]; + int fno = fileno(fp); + snprintf(proclnk, kMaxPathLen, "/proc/self/fd/%d", fno); + size_t r = readlink(proclnk, filename, kMaxPathLen); + filename[r] = '\0'; + return filename; + } +}; + +/** Simplify access to the stateless StdioFs Singleton */ +#define HERMES_STDIO_FS \ + hermes::EasyGlobalSingleton::GetInstance() +#define HERMES_STDIO_FS_T hermes::adapter::fs::StdioFs* + +} // namespace hermes::adapter::fs + +#endif // HERMES_ADAPTER_STDIO_NATIVE_H_ diff --git a/adapter/stdio/stdio_io_client.cc b/adapter/stdio/stdio_io_client.cc new file mode 100644 index 000000000..4627f65b9 --- /dev/null +++ b/adapter/stdio/stdio_io_client.cc @@ -0,0 +1,126 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "stdio_io_client.h" + +namespace hermes::adapter::fs { + +/** Allocate an fd for the file f */ +void StdioIoClient::RealOpen(IoClientObject &f, + IoClientStats &stat, + const std::string &path) { + stat.fh_ = real_api->fopen(path.c_str(), stat.mode_str_.c_str()); + if (stat.fh_ == nullptr) { + f.status_ = false; + return; + } + if (stat.mode_str_.find('a') != std::string::npos) { + stat.is_append_ = true; + } +} + +/** + * Called after real open. Allocates the Hermes representation of + * identifying file information, such as a hermes file descriptor + * and hermes file handler. These are not the same as POSIX file + * descriptor and STDIO file handler. + * */ +void StdioIoClient::HermesOpen(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) { + f.hermes_fh_ = (FILE*)fs_mdm.stat_; +} + +/** Synchronize \a file FILE f */ +int StdioIoClient::RealSync(const IoClientObject &f, + const IoClientStats &stat) { + (void) f; + return real_api->fflush(stat.fh_); +} + +/** Close \a file FILE f */ +int StdioIoClient::RealClose(const IoClientObject &f, + const IoClientStats &stat) { + return real_api->fclose(stat.fh_); +} + +/** + * Called before RealClose. Releases information provisioned during + * the allocation phase. + * */ +void StdioIoClient::HermesClose(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) { + (void) f; (void) stat; (void) fs_mdm; +} + +/** Get initial statistics from the backend */ +void StdioIoClient::InitBucketState(const lipc::charbuf &bkt_name, + const IoClientContext &opts, + GlobalIoClientStatse &stat) { + // TODO(llogan) +} + +/** Update backend statistics */ +void StdioIoClient::UpdateBucketState(const IoClientContext &opts, + GlobalIoClientStatse &stat) { + stat.true_size_ = std::max(stat.true_size_, + opts.backend_off_ + opts.backend_size_); +} + +/** Write blob to backend */ +void StdioIoClient::WriteBlob(const lipc::charbuf &bkt_name, + const Blob &full_blob, + const IoClientContext &opts, + IoStatus &status) { + std::string filename = bkt_name.str(); + LOG(INFO) << "Writing to file: " << filename + << " offset: " << opts.backend_off_ + << " size:" << opts.backend_size_ << "." + << " file_size:" << stdfs::file_size(filename) << std::endl; + FILE *fh = real_api->fopen(filename.c_str(), "r+"); + if (fh == nullptr) { + status.posix_ret_ = 0; + return; + } + real_api->fseek(fh, opts.backend_off_, SEEK_SET); + status.posix_ret_ = real_api->fwrite(full_blob.data(), + sizeof(char), + full_blob.size(), + fh); + real_api->fclose(fh); +} + +/** Read blob from the backend */ +void StdioIoClient::ReadBlob(const lipc::charbuf &bkt_name, + Blob &full_blob, + const IoClientContext &opts, + IoStatus &status) { + std::string filename = bkt_name.str(); + LOG(INFO) << "Read called for filename from destination: " << filename + << " on offset: " << opts.backend_off_ + << " and size: " << opts.backend_size_ << "." + << " file_size:" << stdfs::file_size(filename) << std::endl; + FILE *fh = real_api->fopen(filename.c_str(), "r"); + if (fh == nullptr) { + status.posix_ret_ = 0; + return; + } + real_api->fseek(fh, opts.backend_off_, SEEK_SET); + status.posix_ret_ = real_api->fread(full_blob.data(), + sizeof(char), + full_blob.size(), + fh); + real_api->fclose(fh); +} + +} // namespace hermes::adapter::fs diff --git a/adapter/stdio/stdio_io_client.h b/adapter/stdio/stdio_io_client.h new file mode 100644 index 000000000..9e7c4c392 --- /dev/null +++ b/adapter/stdio/stdio_io_client.h @@ -0,0 +1,102 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_ADAPTER_STDIO_STDIO_IO_CLIENT_H_ +#define HERMES_ADAPTER_STDIO_STDIO_IO_CLIENT_H_ + +#include + +#include "adapter/filesystem/filesystem_io_client.h" +#include "stdio_api_singleton_macros.h" +#include "stdio_api.h" + +using hermes::adapter::IoClientStats; +using hermes::adapter::IoClientContext; +using hermes::adapter::IoStatus; +using hermes::adapter::fs::StdioApi; + +namespace hermes::adapter::fs { + +/** A class to represent STDIO IO file system */ +class StdioIoClient : public hermes::adapter::fs::FilesystemIoClient { + private: + HERMES_STDIO_API_T real_api; /**< pointer to real APIs */ + + public: + /** Default constructor */ + StdioIoClient() { real_api = HERMES_STDIO_API; } + + /** Virtual destructor */ + virtual ~StdioIoClient() = default; + + public: + /** Allocate an fd for the file f */ + void RealOpen(IoClientObject &f, + IoClientStats &stat, + const std::string &path) override; + + /** + * Called after real open. Allocates the Hermes representation of + * identifying file information, such as a hermes file descriptor + * and hermes file handler. These are not the same as STDIO file + * descriptor and STDIO file handler. + * */ + void HermesOpen(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) override; + + /** Synchronize \a file FILE f */ + int RealSync(const IoClientObject &f, + const IoClientStats &stat) override; + + /** Close \a file FILE f */ + int RealClose(const IoClientObject &f, + const IoClientStats &stat) override; + + /** + * Called before RealClose. Releases information provisioned during + * the allocation phase. + * */ + void HermesClose(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) override; + + /** Get initial statistics from the backend */ + void InitBucketState(const lipc::charbuf &bkt_name, + const IoClientContext &opts, + GlobalIoClientStatse &stat) override; + + /** Update backend statistics */ + void UpdateBucketState(const IoClientContext &opts, + GlobalIoClientStatse &stat) override; + + /** Write blob to backend */ + void WriteBlob(const lipc::charbuf &bkt_name, + const Blob &full_blob, + const IoClientContext &opts, + IoStatus &status) override; + + /** Read blob from the backend */ + void ReadBlob(const lipc::charbuf &bkt_name, + Blob &full_blob, + const IoClientContext &opts, + IoStatus &status) override; +}; + +} // namespace hermes::adapter::fs + +/** Simplify access to the stateless StdioIoClient Singleton */ +#define HERMES_STDIO_IO_CLIENT \ + hermes::EasyGlobalSingleton::GetInstance() +#define HERMES_STDIO_IO_CLIENT_T hermes::adapter::fs::StdioIoClient* + +#endif // HERMES_ADAPTER_STDIO_STDIO_IO_CLIENT_H_ diff --git a/adapter/test/stdio/stdio_adapter_mapper_test.cpp b/adapter/test/stdio/stdio_adapter_mapper_test.cpp index 7d9b1ef67..22a2ba5cd 100644 --- a/adapter/test/stdio/stdio_adapter_mapper_test.cpp +++ b/adapter/test/stdio/stdio_adapter_mapper_test.cpp @@ -15,7 +15,7 @@ #include "catch_config.h" #include "constants.h" #include "mapper/mapper_factory.h" -#include "stdio/fs_api.h" +#include "stdio/stdio_fs_api.h" using hermes::adapter::BlobPlacements; using hermes::adapter::MapperFactory; From 1271f18206690216bd283146c0992f728b7386a2 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Fri, 3 Feb 2023 08:01:43 -0600 Subject: [PATCH 114/511] Remove singleton_macros --- adapter/filesystem/filesystem.cc | 1 - adapter/filesystem/filesystem_mdm.h | 7 + .../filesystem_mdm_singleton_macros.h | 22 --- adapter/interceptor.h | 1 - adapter/posix/posix.cc | 1 - adapter/posix/posix_api.h | 7 + adapter/posix/posix_api_singleton_macros.h | 22 --- adapter/posix/posix_fs_api.h | 1 - adapter/posix/posix_io_client.h | 1 - adapter/stdio/stdio.cc | 129 +++++++----------- adapter/stdio/stdio_api.h | 7 + adapter/stdio/stdio_api_singleton_macros.h | 22 --- adapter/stdio/stdio_fs_api.h | 3 +- adapter/stdio/stdio_io_client.h | 1 - src/api/hermes.h | 6 +- src/api/hermes_singleton.cc | 1 - src/api/hermes_singleton_macros.h | 21 --- src/borg_io_clients/borg_posix_client.h | 1 - src/borg_io_clients/borg_ram_client.h | 1 - 19 files changed, 80 insertions(+), 175 deletions(-) delete mode 100644 adapter/filesystem/filesystem_mdm_singleton_macros.h delete mode 100644 adapter/posix/posix_api_singleton_macros.h delete mode 100644 adapter/stdio/stdio_api_singleton_macros.h delete mode 100644 src/api/hermes_singleton_macros.h diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index b3ecc8d39..802fb353b 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -10,7 +10,6 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "filesystem_mdm_singleton_macros.h" #include "filesystem.h" #include "constants.h" #include "singleton.h" diff --git a/adapter/filesystem/filesystem_mdm.h b/adapter/filesystem/filesystem_mdm.h index 1e496fd41..0a6efae37 100644 --- a/adapter/filesystem/filesystem_mdm.h +++ b/adapter/filesystem/filesystem_mdm.h @@ -75,4 +75,11 @@ class MetadataManager { }; } // namespace hermes::adapter::fs +// Singleton macros +#include "singleton.h" + +#define HERMES_FS_METADATA_MANAGER \ + hermes::GlobalSingleton::GetInstance() +#define HERMES_FS_METADATA_MANAGER_T hermes::adapter::fs::MetadataManager* + #endif // HERMES_ADAPTER_METADATA_MANAGER_H diff --git a/adapter/filesystem/filesystem_mdm_singleton_macros.h b/adapter/filesystem/filesystem_mdm_singleton_macros.h deleted file mode 100644 index 25bb028af..000000000 --- a/adapter/filesystem/filesystem_mdm_singleton_macros.h +++ /dev/null @@ -1,22 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SINGLETON_ADAPTER_MACROS_H -#define HERMES_SINGLETON_ADAPTER_MACROS_H - -#include "singleton.h" - -#define HERMES_FS_METADATA_MANAGER \ - hermes::GlobalSingleton::GetInstance() -#define HERMES_FS_METADATA_MANAGER_T hermes::adapter::fs::MetadataManager* - -#endif // HERMES_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/interceptor.h b/adapter/interceptor.h index 0b23c0e40..d291c4cd6 100644 --- a/adapter/interceptor.h +++ b/adapter/interceptor.h @@ -15,7 +15,6 @@ #include "hermes.h" #include "adapter/filesystem/filesystem_mdm.h" -#include "adapter/filesystem/filesystem_mdm_singleton_macros.h" namespace stdfs = std::filesystem; diff --git a/adapter/posix/posix.cc b/adapter/posix/posix.cc index 5e1a3af5c..96aff5e66 100644 --- a/adapter/posix/posix.cc +++ b/adapter/posix/posix.cc @@ -25,7 +25,6 @@ bool posix_intercepted = true; #include "posix_api.h" #include "posix_fs_api.h" -#include "posix_api_singleton_macros.h" #include "filesystem/filesystem.h" using hermes::adapter::fs::AdapterStat; diff --git a/adapter/posix/posix_api.h b/adapter/posix/posix_api.h index 6206d962c..070e15eff 100644 --- a/adapter/posix/posix_api.h +++ b/adapter/posix/posix_api.h @@ -187,6 +187,13 @@ class PosixApi { }; } // namespace hermes::adapter::fs +// Singleton macros +#include "singleton.h" + +#define HERMES_POSIX_API \ + hermes::Singleton::GetInstance() +#define HERMES_POSIX_API_T hermes::adapter::fs::PosixApi* + #undef REQUIRE_API #endif // HERMES_ADAPTER_POSIX_H diff --git a/adapter/posix/posix_api_singleton_macros.h b/adapter/posix/posix_api_singleton_macros.h deleted file mode 100644 index 80f916ad9..000000000 --- a/adapter/posix/posix_api_singleton_macros.h +++ /dev/null @@ -1,22 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_POSIX_SINGLETON_ADAPTER_MACROS_H -#define HERMES_POSIX_SINGLETON_ADAPTER_MACROS_H - -#include "singleton.h" - -#define HERMES_POSIX_API \ - hermes::Singleton::GetInstance() -#define HERMES_POSIX_API_T hermes::adapter::fs::PosixApi* - -#endif // HERMES_POSIX_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/posix/posix_fs_api.h b/adapter/posix/posix_fs_api.h index 361ae908b..949bbd55c 100644 --- a/adapter/posix/posix_fs_api.h +++ b/adapter/posix/posix_fs_api.h @@ -17,7 +17,6 @@ #include "adapter/filesystem/filesystem.h" #include "adapter/filesystem/filesystem_mdm.h" -#include "posix_api_singleton_macros.h" #include "posix_api.h" #include "posix_io_client.h" diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h index 19703f0f8..dcc3cb161 100644 --- a/adapter/posix/posix_io_client.h +++ b/adapter/posix/posix_io_client.h @@ -16,7 +16,6 @@ #include #include "adapter/filesystem/filesystem_io_client.h" -#include "posix_api_singleton_macros.h" #include "posix_api.h" using hermes::Singleton; diff --git a/adapter/stdio/stdio.cc b/adapter/stdio/stdio.cc index 8190da83a..dd992dd6f 100644 --- a/adapter/stdio/stdio.cc +++ b/adapter/stdio/stdio.cc @@ -29,38 +29,15 @@ using hermes::u64; extern "C" { -/** - * MPI - */ -int HERMES_DECL(MPI_Init)(int *argc, char ***argv) { - auto real_api = Singleton::GetInstance(); - int status = real_api->MPI_Init(argc, argv); - if (status == 0) { - auto mdm = Singleton::GetInstance(); - mdm->InitializeHermes(true); - LOG(INFO) << "MPI Init intercepted." << std::endl; - } - return status; -} - -int HERMES_DECL(MPI_Finalize)(void) { - LOG(INFO) << "MPI Finalize intercepted." << std::endl; - auto real_api = Singleton::GetInstance(); - auto mdm = Singleton::GetInstance(); - mdm->FinalizeHermes(); - int status = real_api->MPI_Finalize(); - return status; -} - /** * STDIO */ FILE *reopen_internal(const std::string &user_path, const char *mode, FILE *stream) { - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - auto mdm = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; + auto mdm = HERMES_FS_METADATA_MANAGER; FILE *ret; ret = real_api->freopen(user_path.c_str(), mode, stream); if (!ret) { @@ -89,8 +66,8 @@ FILE *reopen_internal(const std::string &user_path, const char *mode, } FILE *HERMES_DECL(fopen)(const char *path, const char *mode) { - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(path)) { LOG(INFO) << "Intercepting fopen(" << path << ", " << mode << ")\n"; AdapterStat stat; @@ -102,8 +79,8 @@ FILE *HERMES_DECL(fopen)(const char *path, const char *mode) { } FILE *HERMES_DECL(fopen64)(const char *path, const char *mode) { - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(path)) { LOG(INFO) << "Intercepting fopen64(" << path << ", " << mode << ")\n"; AdapterStat stat; @@ -115,8 +92,8 @@ FILE *HERMES_DECL(fopen64)(const char *path, const char *mode) { } FILE *HERMES_DECL(fdopen)(int fd, const char *mode) { - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; FILE *ret = real_api->fdopen(fd, mode); if (ret && hermes::adapter::IsTracked(ret)) { LOG(INFO) << "Intercepting fdopen(" << fd << ", " << mode << ")\n"; @@ -132,7 +109,7 @@ FILE *HERMES_DECL(fdopen)(int fd, const char *mode) { } FILE *HERMES_DECL(freopen)(const char *path, const char *mode, FILE *stream) { - auto real_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; if (hermes::adapter::IsTracked(path)) { LOG(INFO) << "Intercepting freopen(" << path << ", " << mode << ", " << stream << ")\n"; @@ -142,7 +119,7 @@ FILE *HERMES_DECL(freopen)(const char *path, const char *mode, FILE *stream) { } FILE *HERMES_DECL(freopen64)(const char *path, const char *mode, FILE *stream) { - auto real_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; if (hermes::adapter::IsTracked(path)) { LOG(INFO) << "Intercepting freopen64(" << path << ", " << mode << ", " << stream << ")\n"; @@ -153,8 +130,8 @@ FILE *HERMES_DECL(freopen64)(const char *path, const char *mode, FILE *stream) { int HERMES_DECL(fflush)(FILE *fp) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (fp && hermes::adapter::IsTracked(fp)) { File f; f.fh_ = fp; @@ -166,8 +143,8 @@ int HERMES_DECL(fflush)(FILE *fp) { int HERMES_DECL(fclose)(FILE *fp) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(fp)) { LOG(INFO) << "Intercepting fclose(" << fp << ")\n"; File f; @@ -182,8 +159,8 @@ int HERMES_DECL(fclose)(FILE *fp) { size_t HERMES_DECL(fwrite)(const void *ptr, size_t size, size_t nmemb, FILE *fp) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(fp)) { LOG(INFO) << "Intercepting fwrite(" << ptr << ", " << size << ", " << nmemb << ", " << fp << ")\n"; @@ -201,8 +178,8 @@ size_t HERMES_DECL(fwrite)(const void *ptr, size_t size, size_t nmemb, int HERMES_DECL(fputc)(int c, FILE *fp) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(fp)) { LOG(INFO) << "Intercepting fputc(" << c << ", " << fp << ")\n"; File f; @@ -219,8 +196,8 @@ int HERMES_DECL(fputc)(int c, FILE *fp) { int HERMES_DECL(fgetpos)(FILE *fp, fpos_t *pos) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(fp) && pos) { File f; f.fh_ = fp; @@ -241,8 +218,8 @@ int HERMES_DECL(fgetpos)(FILE *fp, fpos_t *pos) { int HERMES_DECL(fgetpos64)(FILE *fp, fpos64_t *pos) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(fp) && pos) { File f; f.fh_ = fp; @@ -263,8 +240,8 @@ int HERMES_DECL(fgetpos64)(FILE *fp, fpos64_t *pos) { int HERMES_DECL(putc)(int c, FILE *fp) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(fp)) { File f; f.fh_ = fp; @@ -281,8 +258,8 @@ int HERMES_DECL(putc)(int c, FILE *fp) { int HERMES_DECL(putw)(int w, FILE *fp) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(fp)) { LOG(INFO) << "Intercept putw." << std::endl; File f; @@ -301,8 +278,8 @@ int HERMES_DECL(putw)(int w, FILE *fp) { int HERMES_DECL(fputs)(const char *s, FILE *stream) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(stream)) { LOG(INFO) << "Intercept fputs." << std::endl; File f; @@ -319,8 +296,8 @@ int HERMES_DECL(fputs)(const char *s, FILE *stream) { size_t HERMES_DECL(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(stream)) { LOG(INFO) << "Intercept fread with size: " << size << "." << std::endl; File f; @@ -337,8 +314,8 @@ size_t HERMES_DECL(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream) { int HERMES_DECL(fgetc)(FILE *stream) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(stream)) { LOG(INFO) << "Intercept fgetc." << std::endl; File f; @@ -356,8 +333,8 @@ int HERMES_DECL(fgetc)(FILE *stream) { int HERMES_DECL(getc)(FILE *stream) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(stream)) { LOG(INFO) << "Intercept getc." << std::endl; File f; @@ -375,8 +352,8 @@ int HERMES_DECL(getc)(FILE *stream) { int HERMES_DECL(getw)(FILE *stream) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(stream)) { LOG(INFO) << "Intercept getw." << std::endl; File f; @@ -394,8 +371,8 @@ int HERMES_DECL(getw)(FILE *stream) { char *HERMES_DECL(fgets)(char *s, int size, FILE *stream) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(stream)) { LOG(INFO) << "Intercept fgets." << std::endl; File f; @@ -429,8 +406,8 @@ char *HERMES_DECL(fgets)(char *s, int size, FILE *stream) { void HERMES_DECL(rewind)(FILE *stream) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(stream)) { LOG(INFO) << "Intercept rewind." << std::endl; File f; @@ -446,8 +423,8 @@ void HERMES_DECL(rewind)(FILE *stream) { int HERMES_DECL(fseek)(FILE *stream, long offset, int whence) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(stream)) { LOG(INFO) << "Intercept fseek offset:" << offset << " whence:" << whence << "." << std::endl; @@ -465,8 +442,8 @@ int HERMES_DECL(fseek)(FILE *stream, long offset, int whence) { int HERMES_DECL(fseeko)(FILE *stream, off_t offset, int whence) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(stream)) { LOG(INFO) << "Intercept fseeko offset:" << offset << " whence:" << whence << "." << std::endl; @@ -484,8 +461,8 @@ int HERMES_DECL(fseeko)(FILE *stream, off_t offset, int whence) { int HERMES_DECL(fseeko64)(FILE *stream, off64_t offset, int whence) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(stream)) { LOG(INFO) << "Intercept fseeko offset:" << offset << " whence:" << whence << "." << std::endl; @@ -503,8 +480,8 @@ int HERMES_DECL(fseeko64)(FILE *stream, off64_t offset, int whence) { int HERMES_DECL(fsetpos)(FILE *stream, const fpos_t *pos) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; off_t offset = pos->__pos; if (hermes::adapter::IsTracked(stream)) { LOG(INFO) << "Intercept fsetpos offset:" << offset << "." << std::endl; @@ -521,8 +498,8 @@ int HERMES_DECL(fsetpos)(FILE *stream, const fpos_t *pos) { int HERMES_DECL(fsetpos64)(FILE *stream, const fpos64_t *pos) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; off_t offset = pos->__pos; if (hermes::adapter::IsTracked(stream)) { LOG(INFO) << "Intercept fsetpos64 offset:" << offset << "." << std::endl; @@ -539,8 +516,8 @@ int HERMES_DECL(fsetpos64)(FILE *stream, const fpos64_t *pos) { long int HERMES_DECL(ftell)(FILE *fp) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_STDIO_API; + auto fs_api = HERMES_STDIO_FS; if (hermes::adapter::IsTracked(fp)) { LOG(INFO) << "Intercept ftell." << std::endl; File f; diff --git a/adapter/stdio/stdio_api.h b/adapter/stdio/stdio_api.h index de5f7b5e0..371c086d3 100644 --- a/adapter/stdio/stdio_api.h +++ b/adapter/stdio/stdio_api.h @@ -294,4 +294,11 @@ class StdioApi { #undef REQUIRE_API +#include "singleton.h" + +// Singleton macros +#define HERMES_STDIO_API \ + hermes::Singleton::GetInstance() +#define HERMES_STDIO_API_T hermes::adapter::fs::StdioApi* + #endif // HERMES_ADAPTER_STDIO_H diff --git a/adapter/stdio/stdio_api_singleton_macros.h b/adapter/stdio/stdio_api_singleton_macros.h deleted file mode 100644 index b00212705..000000000 --- a/adapter/stdio/stdio_api_singleton_macros.h +++ /dev/null @@ -1,22 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_STDIO_SINGLETON_ADAPTER_MACROS_H -#define HERMES_STDIO_SINGLETON_ADAPTER_MACROS_H - -#include "singleton.h" - -#define HERMES_STDIO_API \ - hermes::Singleton::GetInstance() -#define HERMES_STDIO_API_T hermes::adapter::fs::StdioApi* - -#endif // HERMES_STDIO_SINGLETON_ADAPTER_MACROS_H diff --git a/adapter/stdio/stdio_fs_api.h b/adapter/stdio/stdio_fs_api.h index 3c1f04890..6fe221de6 100644 --- a/adapter/stdio/stdio_fs_api.h +++ b/adapter/stdio/stdio_fs_api.h @@ -17,11 +17,10 @@ #include "adapter/filesystem/filesystem.h" #include "adapter/filesystem/filesystem_mdm.h" -#include "stdio_api_singleton_macros.h" #include "stdio_api.h" #include "stdio_io_client.h" -namespace hermes::adpater::fs { +namespace hermes::adapter::fs { /** A class to represent POSIX IO file system */ class StdioFs : public hermes::adapter::fs::Filesystem { diff --git a/adapter/stdio/stdio_io_client.h b/adapter/stdio/stdio_io_client.h index 9e7c4c392..5bfa57679 100644 --- a/adapter/stdio/stdio_io_client.h +++ b/adapter/stdio/stdio_io_client.h @@ -16,7 +16,6 @@ #include #include "adapter/filesystem/filesystem_io_client.h" -#include "stdio_api_singleton_macros.h" #include "stdio_api.h" using hermes::adapter::IoClientStats; diff --git a/src/api/hermes.h b/src/api/hermes.h index 4478dc3a5..e54f11a0e 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -23,7 +23,11 @@ #include "metadata_manager.h" #include "buffer_pool.h" #include "buffer_organizer.h" -#include "hermes_singleton_macros.h" +#include "singleton.h" + +// Singleton macros +#define HERMES hermes::GlobalSingleton::GetInstance() +#define HERMES_T hermes::api::Hermes* namespace hermes::api { diff --git a/src/api/hermes_singleton.cc b/src/api/hermes_singleton.cc index 0a74b3b6f..481517830 100644 --- a/src/api/hermes_singleton.cc +++ b/src/api/hermes_singleton.cc @@ -11,7 +11,6 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "singleton.h" -#include "hermes_singleton_macros.h" #include "hermes.h" template<> hermes::api::Hermes hermes::GlobalSingleton< diff --git a/src/api/hermes_singleton_macros.h b/src/api/hermes_singleton_macros.h deleted file mode 100644 index 51da6d3a2..000000000 --- a/src/api/hermes_singleton_macros.h +++ /dev/null @@ -1,21 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SINGLETON_SRC_MACROS_H -#define HERMES_SINGLETON_SRC_MACROS_H - -#include "singleton.h" - -#define HERMES hermes::GlobalSingleton::GetInstance() -#define HERMES_T hermes::api::Hermes* - -#endif // HERMES_SINGLETON_SRC_MACROS_H diff --git a/src/borg_io_clients/borg_posix_client.h b/src/borg_io_clients/borg_posix_client.h index 5ec777259..365810fea 100644 --- a/src/borg_io_clients/borg_posix_client.h +++ b/src/borg_io_clients/borg_posix_client.h @@ -15,7 +15,6 @@ #include "borg_io_client.h" #include "adapter/posix/posix_api.h" -#include "adapter/posix/posix_api_singleton_macros.h" #include diff --git a/src/borg_io_clients/borg_ram_client.h b/src/borg_io_clients/borg_ram_client.h index 6716c660c..392e41bb3 100644 --- a/src/borg_io_clients/borg_ram_client.h +++ b/src/borg_io_clients/borg_ram_client.h @@ -15,7 +15,6 @@ #include "borg_io_client.h" #include "adapter/posix/posix_api.h" -#include "adapter/posix/posix_api_singleton_macros.h" #include "hermes.h" namespace hermes::borg { From 7689baf1c2af3d2d5f6f56bc0013e08d07058afa Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sat, 4 Feb 2023 06:58:48 -0600 Subject: [PATCH 115/511] STDIO compiles --- adapter/filesystem/filesystem.cc | 60 +++--- adapter/filesystem/filesystem_mdm.cc | 9 +- adapter/filesystem/filesystem_mdm.h | 6 +- adapter/posix/posix.cc | 4 +- adapter/posix/posix_fs_api.h | 13 +- adapter/stdio/stdio.cc | 275 ++++++++------------------- adapter/stdio/stdio_fs_api.h | 58 +++++- 7 files changed, 181 insertions(+), 244 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 802fb353b..d44d1b054 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -37,21 +37,21 @@ void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { IoOptions opts; opts.type_ = type_; stat.bkt_id_ = HERMES->GetBucket(path, ctx_, opts); - std::pair exists = mdm->Find(f); - if (!exists.second) { + std::shared_ptr exists = mdm->Find(f); + if (!exists) { LOG(INFO) << "File not opened before by adapter" << std::endl; // Create the new bucket IoOptions opts; opts.type_ = type_; stat.bkt_id_ = HERMES->GetBucket(path, ctx_, opts); // Allocate internal hermes data - auto stat_ptr = std::make_unique(stat); + auto stat_ptr = std::make_shared(stat); FilesystemIoClientObject fs_ctx(&mdm->fs_mdm_, (void*)stat_ptr.get()); io_client_->HermesOpen(f, stat, fs_ctx); mdm->Create(f, stat_ptr); } else { LOG(INFO) << "File opened by adapter" << std::endl; - exists.first->UpdateTime(); + exists->UpdateTime(); } } @@ -287,8 +287,8 @@ size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, size_t total_size, IoStatus &io_status, IoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return 0; } @@ -300,8 +300,8 @@ size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, size_t total_size, IoStatus &io_status, IoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return 0; } @@ -313,8 +313,8 @@ size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return 0; } @@ -327,8 +327,8 @@ size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return 0; } @@ -341,8 +341,8 @@ HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, size_t total_size, size_t req_id, IoStatus &io_status, IoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return 0; } @@ -354,8 +354,8 @@ HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, size_t total_size, size_t req_id, IoStatus &io_status, IoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return 0; } @@ -367,8 +367,8 @@ HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, IoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return 0; } @@ -381,8 +381,8 @@ HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, IoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return 0; } @@ -394,8 +394,8 @@ HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, off_t Filesystem::Seek(File &f, bool &stat_exists, SeekMode whence, off_t offset) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return -1; } @@ -405,8 +405,8 @@ off_t Filesystem::Seek(File &f, bool &stat_exists, size_t Filesystem::GetSize(File &f, bool &stat_exists) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return -1; } @@ -416,8 +416,8 @@ size_t Filesystem::GetSize(File &f, bool &stat_exists) { off_t Filesystem::Tell(File &f, bool &stat_exists) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return -1; } @@ -427,8 +427,8 @@ off_t Filesystem::Tell(File &f, bool &stat_exists) { int Filesystem::Sync(File &f, bool &stat_exists) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return -1; } @@ -438,8 +438,8 @@ int Filesystem::Sync(File &f, bool &stat_exists) { int Filesystem::Close(File &f, bool &stat_exists, bool destroy) { auto mdm = HERMES_FS_METADATA_MANAGER; - auto [stat, exists] = mdm->Find(f); - if (!exists) { + auto stat = mdm->Find(f); + if (!stat) { stat_exists = false; return -1; } diff --git a/adapter/filesystem/filesystem_mdm.cc b/adapter/filesystem/filesystem_mdm.cc index fe0538d0c..769b4439d 100644 --- a/adapter/filesystem/filesystem_mdm.cc +++ b/adapter/filesystem/filesystem_mdm.cc @@ -20,7 +20,7 @@ using hermes::adapter::fs::AdapterStat; using hermes::adapter::fs::MetadataManager; bool MetadataManager::Create(const File &f, - std::unique_ptr &stat) { + std::shared_ptr &stat) { VLOG(1) << "Create metadata for file handler." << std::endl; auto ret = metadata.emplace(f, std::move(stat)); return ret.second; @@ -37,13 +37,12 @@ bool MetadataManager::Update(const File &f, const AdapterStat &stat) { } } -std::pair MetadataManager::Find(const File &f) { - typedef std::pair MetadataReturn; +std::shared_ptr MetadataManager::Find(const File &f) { auto iter = metadata.find(f); if (iter == metadata.end()) - return std::pair(nullptr, false); + return nullptr; else - return std::pair(iter->second.get(), true); + return iter->second; } bool MetadataManager::Delete(const File &f) { diff --git a/adapter/filesystem/filesystem_mdm.h b/adapter/filesystem/filesystem_mdm.h index 0a6efae37..be88ae228 100644 --- a/adapter/filesystem/filesystem_mdm.h +++ b/adapter/filesystem/filesystem_mdm.h @@ -26,7 +26,7 @@ namespace hermes::adapter::fs { */ class MetadataManager { private: - std::unordered_map> + std::unordered_map> metadata; /**< Map for metadata*/ public: @@ -46,7 +46,7 @@ class MetadataManager { * @return true, if operation was successful. * false, if operation was unsuccessful. */ - bool Create(const File& f, std::unique_ptr &stat); + bool Create(const File& f, std::shared_ptr &stat); /** * Update existing metadata entry for filesystem adapters. @@ -71,7 +71,7 @@ class MetadataManager { * @return The metadata entry if exist. * The bool in pair indicated whether metadata entry exists. */ - std::pair Find(const File& f); + std::shared_ptr Find(const File& f); }; } // namespace hermes::adapter::fs diff --git a/adapter/posix/posix.cc b/adapter/posix/posix.cc index 96aff5e66..4ea91f9f1 100644 --- a/adapter/posix/posix.cc +++ b/adapter/posix/posix.cc @@ -263,8 +263,8 @@ int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { LOG(INFO) << "Intercepted fstat." << std::endl; auto mdm = HERMES_FS_METADATA_MANAGER; auto existing = mdm->Find(f); - if (existing.second) { - AdapterStat &astat = *existing.first; + if (existing) { + AdapterStat &astat = *existing; // TODO(chogan): st_dev and st_ino need to be assigned by us, but // currently we get them by calling the real fstat on open. buf->st_dev = 0; diff --git a/adapter/posix/posix_fs_api.h b/adapter/posix/posix_fs_api.h index 949bbd55c..4ba9a94bd 100644 --- a/adapter/posix/posix_fs_api.h +++ b/adapter/posix/posix_fs_api.h @@ -29,15 +29,20 @@ class PosixFs : public hermes::adapter::fs::Filesystem { AdapterType::kPosix) {} /** Whether or not \a fd FILE DESCRIPTOR was generated by Hermes */ - static bool IsFdTracked(int fd) { + static bool IsFdTracked(int fd, std::shared_ptr &stat) { if (!HERMES->IsInitialized()) { return false; } hermes::adapter::fs::File f; f.hermes_fd_ = fd; - std::pair stat_pair = - HERMES_FS_METADATA_MANAGER->Find(f); - return stat_pair.second; + stat = HERMES_FS_METADATA_MANAGER->Find(f); + return stat != nullptr; + } + + /** Whether or not \a fd FILE DESCRIPTOR was generated by Hermes */ + static bool IsFdTracked(int fd) { + std::shared_ptr stat; + return IsFdTracked(fd, stat); } /** get the file name from \a fd file descriptor */ diff --git a/adapter/stdio/stdio.cc b/adapter/stdio/stdio.cc index dd992dd6f..b561423e9 100644 --- a/adapter/stdio/stdio.cc +++ b/adapter/stdio/stdio.cc @@ -21,6 +21,8 @@ bool stdio_intercepted = true; using hermes::adapter::fs::MetadataManager; using hermes::adapter::fs::SeekMode; +using hermes::adapter::fs::AdapterStat; +using hermes::adapter::fs::File; namespace hapi = hermes::api; namespace stdfs = std::filesystem; @@ -33,46 +35,14 @@ extern "C" { * STDIO */ -FILE *reopen_internal(const std::string &user_path, const char *mode, - FILE *stream) { - auto real_api = HERMES_STDIO_API; - auto fs_api = HERMES_STDIO_FS; - auto mdm = HERMES_FS_METADATA_MANAGER; - FILE *ret; - ret = real_api->freopen(user_path.c_str(), mode, stream); - if (!ret) { - return ret; - } - - File f; - f.fh_ = ret; - fs_api->InitFile(f); - std::string path_str = WeaklyCanonical(user_path).string(); - LOG(INFO) << "Reopen file for filename " << path_str << " in mode " << mode - << std::endl; - auto existing = mdm->Find(f); - if (!existing.second) { - LOG(INFO) << "File not opened before by adapter" << std::endl; - return nullptr; - } else { - LOG(INFO) << "File opened before by adapter" << std::endl; - struct timespec ts; - timespec_get(&ts, TIME_UTC); - existing.first.st_atim = ts; - existing.first.st_ctim = ts; - mdm->Update(f, existing.first); - } - return ret; -} - FILE *HERMES_DECL(fopen)(const char *path, const char *mode) { auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(path)) { + if (fs_api->IsPathTracked(path)) { LOG(INFO) << "Intercepting fopen(" << path << ", " << mode << ")\n"; AdapterStat stat; - stat.mode_str = mode; - return fs_api->Open(stat, path).fh_; + stat.mode_str_ = mode; + return fs_api->Open(stat, path).hermes_fh_; } else { return real_api->fopen(path, mode); } @@ -81,11 +51,11 @@ FILE *HERMES_DECL(fopen)(const char *path, const char *mode) { FILE *HERMES_DECL(fopen64)(const char *path, const char *mode) { auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(path)) { + if (fs_api->IsPathTracked(path)) { LOG(INFO) << "Intercepting fopen64(" << path << ", " << mode << ")\n"; AdapterStat stat; - stat.mode_str = mode; - return fs_api->Open(stat, path).fh_; + stat.mode_str_ = mode; + return fs_api->Open(stat, path).hermes_fh_; } else { return real_api->fopen64(path, mode); } @@ -94,36 +64,33 @@ FILE *HERMES_DECL(fopen64)(const char *path, const char *mode) { FILE *HERMES_DECL(fdopen)(int fd, const char *mode) { auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - FILE *ret = real_api->fdopen(fd, mode); - if (ret && hermes::adapter::IsTracked(ret)) { + std::shared_ptr stat; + if (fs_api->IsFdTracked(fd, stat)) { LOG(INFO) << "Intercepting fdopen(" << fd << ", " << mode << ")\n"; - std::string path_str = hermes::adapter::GetFilenameFromFD(fd); - File f; - f.fh_ = ret; - fs_api->InitFile(f); - AdapterStat stat; - stat.mode_str = mode; - fs_api->Open(stat, f, path_str); + fs_api->FdOpen(mode, stat); + } else { + return real_api->fdopen(fd, mode); } - return ret; } FILE *HERMES_DECL(freopen)(const char *path, const char *mode, FILE *stream) { auto real_api = HERMES_STDIO_API; - if (hermes::adapter::IsTracked(path)) { + auto fs_api = HERMES_STDIO_FS; + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercepting freopen(" << path << ", " << mode << ", " << stream << ")\n"; - return reopen_internal(path, mode, stream); + return fs_api->Reopen(path, mode, *(AdapterStat*)stream); } return real_api->freopen(path, mode, stream); } FILE *HERMES_DECL(freopen64)(const char *path, const char *mode, FILE *stream) { auto real_api = HERMES_STDIO_API; - if (hermes::adapter::IsTracked(path)) { + auto fs_api = HERMES_STDIO_FS; + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercepting freopen64(" << path << ", " << mode << ", " << stream << ")\n"; - return reopen_internal(path, mode, stream); + return fs_api->Reopen(path, mode, *(AdapterStat*)stream); } return real_api->freopen64(path, mode, stream); } @@ -132,10 +99,9 @@ int HERMES_DECL(fflush)(FILE *fp) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (fp && hermes::adapter::IsTracked(fp)) { + if (fs_api->IsFpTracked(fp)) { File f; - f.fh_ = fp; - fs_api->InitFile(f); + f.hermes_fh_ = fp; return fs_api->Sync(f, stat_exists); } return real_api->fflush(fp); @@ -145,13 +111,10 @@ int HERMES_DECL(fclose)(FILE *fp) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(fp)) { + if (fs_api->IsFpTracked(fp)) { LOG(INFO) << "Intercepting fclose(" << fp << ")\n"; - File f; - f.fh_ = fp; - fs_api->InitFile(f); - int ret = fs_api->Close(f, stat_exists); - if (stat_exists) return ret; + File f; f.hermes_fh_ = fp; + return fs_api->Close(f, stat_exists); } return real_api->fclose(fp); } @@ -161,17 +124,12 @@ size_t HERMES_DECL(fwrite)(const void *ptr, size_t size, size_t nmemb, bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(fp)) { + if (fs_api->IsFpTracked(fp)) { LOG(INFO) << "Intercepting fwrite(" << ptr << ", " << size << ", " << nmemb << ", " << fp << ")\n"; - File f; - f.fh_ = fp; - fs_api->InitFile(f); + File f; f.hermes_fh_ = fp; IoStatus io_status; - size_t ret = fs_api->Write(f, stat_exists, ptr, size * nmemb, io_status); - if (stat_exists) { - return ret; - } + return fs_api->Write(f, stat_exists, ptr, size * nmemb, io_status); } return real_api->fwrite(ptr, size, nmemb, fp); } @@ -180,11 +138,9 @@ int HERMES_DECL(fputc)(int c, FILE *fp) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(fp)) { + if (fs_api->IsFpTracked(fp)) { LOG(INFO) << "Intercepting fputc(" << c << ", " << fp << ")\n"; - File f; - f.fh_ = fp; - fs_api->InitFile(f); + File f; f.hermes_fh_ = fp; IoStatus io_status; fs_api->Write(f, stat_exists, &c, 1, io_status); if (stat_exists) { @@ -198,10 +154,8 @@ int HERMES_DECL(fgetpos)(FILE *fp, fpos_t *pos) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(fp) && pos) { - File f; - f.fh_ = fp; - fs_api->InitFile(f); + if (fs_api->IsFpTracked(fp) && pos) { + File f; f.hermes_fh_ = fp; LOG(INFO) << "Intercept fgetpos." << std::endl; // TODO(chogan): @portability In the GNU C Library, fpos_t is an opaque // data structure that contains internal data to represent file offset and @@ -220,10 +174,8 @@ int HERMES_DECL(fgetpos64)(FILE *fp, fpos64_t *pos) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(fp) && pos) { - File f; - f.fh_ = fp; - fs_api->InitFile(f); + if (fs_api->IsFpTracked(fp) && pos) { + File f; f.hermes_fh_ = fp; LOG(INFO) << "Intercept fgetpos64." << std::endl; // TODO(chogan): @portability In the GNU C Library, fpos_t is an opaque // data structure that contains internal data to represent file offset and @@ -231,9 +183,7 @@ int HERMES_DECL(fgetpos64)(FILE *fp, fpos64_t *pos) { // different internal representation. This will need to change to support // other compilers. pos->__pos = fs_api->Tell(f, stat_exists); - if (stat_exists) { - return 0; - } + return 0; } return real_api->fgetpos64(fp, pos); } @@ -242,16 +192,12 @@ int HERMES_DECL(putc)(int c, FILE *fp) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(fp)) { - File f; - f.fh_ = fp; - fs_api->InitFile(f); + if (fs_api->IsFpTracked(fp)) { + File f; f.hermes_fh_ = fp; IoStatus io_status; LOG(INFO) << "Intercept putc." << std::endl; fs_api->Write(f, stat_exists, &c, 1, io_status); - if (stat_exists) { - return c; - } + return c; } return real_api->fputc(c, fp); } @@ -260,11 +206,9 @@ int HERMES_DECL(putw)(int w, FILE *fp) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(fp)) { + if (fs_api->IsFpTracked(fp)) { LOG(INFO) << "Intercept putw." << std::endl; - File f; - f.fh_ = fp; - fs_api->InitFile(f); + File f; f.hermes_fh_ = fp; IoStatus io_status; int ret = fs_api->Write(f, stat_exists, &w, sizeof(w), io_status); if (ret == sizeof(w)) { @@ -280,16 +224,11 @@ int HERMES_DECL(fputs)(const char *s, FILE *stream) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(stream)) { + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercept fputs." << std::endl; - File f; - f.fh_ = stream; - fs_api->InitFile(f); + File f; f.hermes_fh_ = stream; IoStatus io_status; - int ret = fs_api->Write(f, stat_exists, s, strlen(s), io_status); - if (stat_exists) { - return ret; - } + return fs_api->Write(f, stat_exists, s, strlen(s), io_status); } return real_api->fputs(s, stream); } @@ -298,16 +237,11 @@ size_t HERMES_DECL(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(stream)) { + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercept fread with size: " << size << "." << std::endl; - File f; - f.fh_ = stream; - fs_api->InitFile(f); + File f; f.hermes_fh_ = stream; IoStatus io_status; - size_t ret = fs_api->Read(f, stat_exists, ptr, size * nmemb, io_status); - if (stat_exists) { - return ret; - } + return fs_api->Read(f, stat_exists, ptr, size * nmemb, io_status); } return real_api->fread(ptr, size, nmemb, stream); } @@ -316,17 +250,13 @@ int HERMES_DECL(fgetc)(FILE *stream) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(stream)) { + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercept fgetc." << std::endl; - File f; - f.fh_ = stream; - fs_api->InitFile(f); + File f; f.hermes_fh_ = stream; IoStatus io_status; u8 value; fs_api->Read(f, stat_exists, &value, sizeof(u8), io_status); - if (stat_exists) { - return value; - } + return value; } return real_api->fgetc(stream); } @@ -335,17 +265,13 @@ int HERMES_DECL(getc)(FILE *stream) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(stream)) { + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercept getc." << std::endl; - File f; - f.fh_ = stream; - fs_api->InitFile(f); + File f; f.hermes_fh_ = stream; IoStatus io_status; u8 value; fs_api->Read(f, stat_exists, &value, sizeof(u8), io_status); - if (stat_exists) { - return value; - } + return value; } return real_api->getc(stream); } @@ -354,17 +280,13 @@ int HERMES_DECL(getw)(FILE *stream) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(stream)) { + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercept getw." << std::endl; - File f; - f.fh_ = stream; - fs_api->InitFile(f); + File f; f.hermes_fh_ = stream; IoStatus io_status; int value; fs_api->Read(f, stat_exists, &value, sizeof(int), io_status); - if (stat_exists) { - return value; - } + return value; } return real_api->getc(stream); } @@ -373,11 +295,9 @@ char *HERMES_DECL(fgets)(char *s, int size, FILE *stream) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(stream)) { + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercept fgets." << std::endl; - File f; - f.fh_ = stream; - fs_api->InitFile(f); + File f; f.hermes_fh_ = stream; IoStatus io_status; size_t read_size = size - 1; size_t ret_size = fs_api->Read(f, stat_exists, s, read_size, io_status); @@ -399,7 +319,7 @@ char *HERMES_DECL(fgets)(char *s, int size, FILE *stream) { } else { s[read_size] = '\0'; } - if (stat_exists) return s; + return s; } return real_api->fgets(s, size, stream); } @@ -408,15 +328,11 @@ void HERMES_DECL(rewind)(FILE *stream) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(stream)) { + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercept rewind." << std::endl; - File f; - f.fh_ = stream; - fs_api->InitFile(f); + File f; f.hermes_fh_ = stream; fs_api->Seek(f, stat_exists, SeekMode::kSet, 0); - if (stat_exists) { - return; - } + return; } real_api->rewind(stream); } @@ -425,17 +341,12 @@ int HERMES_DECL(fseek)(FILE *stream, long offset, int whence) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(stream)) { + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercept fseek offset:" << offset << " whence:" << whence << "." << std::endl; - File f; - f.fh_ = stream; - fs_api->InitFile(f); - off_t ret = - fs_api->Seek(f, stat_exists, static_cast(whence), offset); - if (stat_exists && ret > 0) { - return 0; - } + File f; f.hermes_fh_ = stream; + fs_api->Seek(f, stat_exists, static_cast(whence), offset); + return 0; } return real_api->fseek(stream, offset, whence); } @@ -444,17 +355,12 @@ int HERMES_DECL(fseeko)(FILE *stream, off_t offset, int whence) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(stream)) { + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercept fseeko offset:" << offset << " whence:" << whence << "." << std::endl; - File f; - f.fh_ = stream; - fs_api->InitFile(f); - off_t ret = - fs_api->Seek(f, stat_exists, static_cast(whence), offset); - if (stat_exists && ret > 0) { - return 0; - } + File f; f.hermes_fh_ = stream; + fs_api->Seek(f, stat_exists, static_cast(whence), offset); + return 0; } return real_api->fseeko(stream, offset, whence); } @@ -463,17 +369,12 @@ int HERMES_DECL(fseeko64)(FILE *stream, off64_t offset, int whence) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(stream)) { + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercept fseeko offset:" << offset << " whence:" << whence << "." << std::endl; - File f; - f.fh_ = stream; - fs_api->InitFile(f); - off_t ret = - fs_api->Seek(f, stat_exists, static_cast(whence), offset); - if (stat_exists && ret > 0) { - return 0; - } + File f; f.hermes_fh_ = stream; + fs_api->Seek(f, stat_exists, static_cast(whence), offset); + return 0; } return real_api->fseeko64(stream, offset, whence); } @@ -483,15 +384,11 @@ int HERMES_DECL(fsetpos)(FILE *stream, const fpos_t *pos) { auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; off_t offset = pos->__pos; - if (hermes::adapter::IsTracked(stream)) { + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercept fsetpos offset:" << offset << "." << std::endl; - File f; - f.fh_ = stream; - fs_api->InitFile(f); - off_t ret = fs_api->Seek(f, stat_exists, SeekMode::kSet, offset); - if (stat_exists && ret > 0) { - return 0; - } + File f; f.hermes_fh_ = stream; + fs_api->Seek(f, stat_exists, SeekMode::kSet, offset); + return 0; } return real_api->fsetpos(stream, pos); } @@ -501,15 +398,11 @@ int HERMES_DECL(fsetpos64)(FILE *stream, const fpos64_t *pos) { auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; off_t offset = pos->__pos; - if (hermes::adapter::IsTracked(stream)) { + if (fs_api->IsFpTracked(stream)) { LOG(INFO) << "Intercept fsetpos64 offset:" << offset << "." << std::endl; - File f; - f.fh_ = stream; - fs_api->InitFile(f); + File f; f.hermes_fh_ = stream; off_t ret = fs_api->Seek(f, stat_exists, SeekMode::kSet, offset); - if (stat_exists && ret > 0) { - return 0; - } + return 0; } return real_api->fsetpos64(stream, pos); } @@ -518,15 +411,11 @@ long int HERMES_DECL(ftell)(FILE *fp) { bool stat_exists; auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; - if (hermes::adapter::IsTracked(fp)) { + if (fs_api->IsFpTracked(fp)) { LOG(INFO) << "Intercept ftell." << std::endl; - File f; - f.fh_ = fp; - fs_api->InitFile(f); + File f; f.hermes_fh_ = fp; off_t ret = fs_api->Tell(f, stat_exists); - if (stat_exists) { - return ret; - } + return ret; } return real_api->ftell(fp); } diff --git a/adapter/stdio/stdio_fs_api.h b/adapter/stdio/stdio_fs_api.h index 6fe221de6..62f1053d2 100644 --- a/adapter/stdio/stdio_fs_api.h +++ b/adapter/stdio/stdio_fs_api.h @@ -17,6 +17,7 @@ #include "adapter/filesystem/filesystem.h" #include "adapter/filesystem/filesystem_mdm.h" +#include "adapter/posix/posix_fs_api.h" #include "stdio_api.h" #include "stdio_io_client.h" @@ -27,17 +28,60 @@ class StdioFs : public hermes::adapter::fs::Filesystem { public: StdioFs() : hermes::adapter::fs::Filesystem(HERMES_STDIO_IO_CLIENT, AdapterType::kStdio) {} - - /** Whether or not \a fd FILE DESCRIPTOR was generated by Hermes */ - static bool IsFpTracked(FILE* fp) { - if (!HERMES->IsInitialized()) { + + /** Close an existing stream and then open with new path */ + FILE* Reopen(const std::string &user_path, const char *mode, + AdapterStat &stat) { + auto real_api = HERMES_STDIO_API; + FILE *ret; + ret = real_api->freopen(user_path.c_str(), mode, stat.fh_); + if (!ret) { + return ret; + } + stat.fh_ = ret; + LOG(INFO) << "Reopen file for filename " << user_path << " in mode " << mode + << std::endl; + stat.UpdateTime(); + return (FILE*)&stat; + } + + /** */ + FILE* FdOpen(const std::string &mode, + std::shared_ptr &stat) { + auto real_api = HERMES_STDIO_API; + auto mdm = HERMES_FS_METADATA_MANAGER; + stat->fh_ = real_api->fdopen(stat->fd_, mode.c_str()); + stat->mode_str_ = mode; + File f; f.hermes_fh_ = (FILE*)stat.get(); + mdm->Create(f, stat); + return f.hermes_fh_; + } + + /** Whether or not \a fd FILE DESCRIPTOR is tracked */ + static bool IsFdTracked(int fd, std::shared_ptr &stat) { + return PosixFs::IsFdTracked(fd, stat); + } + + /** Whether or not \a fd FILE DESCRIPTOR is tracked */ + static bool IsFdTracked(int fd) { + return PosixFs::IsFdTracked(fd); + } + + /** Whether or not \a fp FILE was generated by Hermes */ + static bool IsFpTracked(FILE* fp, std::shared_ptr &stat) { + if (!fp || !HERMES->IsInitialized()) { return false; } hermes::adapter::fs::File f; f.hermes_fh_ = fp; - std::pair stat_pair = - HERMES_FS_METADATA_MANAGER->Find(f); - return stat_pair.second; + stat = HERMES_FS_METADATA_MANAGER->Find(f); + return stat != nullptr; + } + + /** Whether or not \a fp FILE was generated by Hermes */ + static bool IsFpTracked(FILE* fp) { + std::shared_ptr stat; + return IsFpTracked(fp, stat); } /** get the file name from \a fp file pointer */ From 024b572f7aff80e07f29a1504aa8d7e83cf1f888 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sat, 4 Feb 2023 08:30:15 -0600 Subject: [PATCH 116/511] MPI structure --- adapter/CMakeLists.txt | 1 + adapter/filesystem/filesystem.cc | 44 +- adapter/filesystem/filesystem.h | 44 +- adapter/io_client/io_client.h | 10 +- adapter/mpiio/CMakeLists.txt | 44 +- adapter/mpiio/fs_api.cc | 622 ---------------------- adapter/mpiio/fs_api.h | 241 --------- adapter/mpiio/{mpiio.cc => mpiio_api.cc} | 2 +- adapter/mpiio/{real_api.h => mpiio_api.h} | 16 +- adapter/mpiio/mpiio_api_singleton.cc | 17 + adapter/mpiio/mpiio_fs_api.h | 461 ++++++++++++++++ adapter/mpiio/mpiio_io_client.cc | 174 ++++++ adapter/mpiio/mpiio_io_client.h | 101 ++++ adapter/posix/posix_io_client.cc | 12 +- adapter/posix/posix_io_client.h | 4 +- adapter/stdio/CMakeLists.txt | 2 +- adapter/stdio/{stdio.cc => stdio_api.cc} | 0 adapter/stdio/stdio_io_client.cc | 12 +- adapter/stdio/stdio_io_client.h | 4 +- data_stager/stagers/posix_stager.cc | 4 +- src/metadata_types.h | 4 +- 21 files changed, 863 insertions(+), 956 deletions(-) delete mode 100644 adapter/mpiio/fs_api.cc delete mode 100644 adapter/mpiio/fs_api.h rename adapter/mpiio/{mpiio.cc => mpiio_api.cc} (99%) rename adapter/mpiio/{real_api.h => mpiio_api.h} (97%) create mode 100644 adapter/mpiio/mpiio_api_singleton.cc create mode 100644 adapter/mpiio/mpiio_fs_api.h create mode 100644 adapter/mpiio/mpiio_io_client.cc create mode 100644 adapter/mpiio/mpiio_io_client.h rename adapter/stdio/{stdio.cc => stdio_api.cc} (100%) diff --git a/adapter/CMakeLists.txt b/adapter/CMakeLists.txt index 7bfa3c82b..2b811dd77 100644 --- a/adapter/CMakeLists.txt +++ b/adapter/CMakeLists.txt @@ -10,5 +10,6 @@ if(HERMES_ENABLE_POSIX_ADAPTER) add_subdirectory(filesystem) add_subdirectory(posix) add_subdirectory(stdio) + add_subdirectory(mpiio) add_subdirectory(test) endif() \ No newline at end of file diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index d44d1b054..7170603a6 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -34,14 +34,14 @@ File Filesystem::Open(AdapterStat &stat, const std::string &path) { void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { auto mdm = HERMES_FS_METADATA_MANAGER; - IoOptions opts; + FsIoOptions opts; opts.type_ = type_; stat.bkt_id_ = HERMES->GetBucket(path, ctx_, opts); std::shared_ptr exists = mdm->Find(f); if (!exists) { LOG(INFO) << "File not opened before by adapter" << std::endl; // Create the new bucket - IoOptions opts; + FsIoOptions opts; opts.type_ = type_; stat.bkt_id_ = HERMES->GetBucket(path, ctx_, opts); // Allocate internal hermes data @@ -57,7 +57,7 @@ void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { (void) f; std::shared_ptr &bkt = stat.bkt_id_; std::string filename = bkt->GetName(); @@ -95,7 +95,7 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, size_t off, size_t total_size, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { (void) f; std::shared_ptr &bkt = stat.bkt_id_; std::string filename = bkt->GetName(); @@ -134,7 +134,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { /*(void) io_status; LOG(INFO) << "Starting an asynchronous write" << std::endl; auto pool = @@ -142,7 +142,7 @@ HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, HermesRequest *hreq = new HermesRequest(); auto lambda = [](Filesystem *fs, File &f, AdapterStat &stat, const void *ptr, - size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { + size_t off, size_t total_size, IoStatus &io_status, FsIoOptions opts) { return fs->Write(f, stat, ptr, off, total_size, io_status, opts); }; auto func = std::bind(lambda, this, f, stat, ptr, off, @@ -155,14 +155,14 @@ HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { /*(void) io_status; auto pool = Singleton::GetInstance(kNumThreads); HermesRequest *hreq = new HermesRequest(); auto lambda = [](Filesystem *fs, File &f, AdapterStat &stat, void *ptr, - size_t off, size_t total_size, IoStatus &io_status, IoOptions opts) { + size_t off, size_t total_size, IoStatus &io_status, FsIoOptions opts) { return fs->Read(f, stat, ptr, off, total_size, io_status, opts); }; auto func = std::bind(lambda, this, f, stat, @@ -195,7 +195,7 @@ void Filesystem::Wait(std::vector &req_ids, size_t Filesystem::GetSize(File &f, AdapterStat &stat) { (void) stat; - IoOptions opts; + FsIoOptions opts; opts.type_ = type_; return stat.bkt_id_->GetSize(opts); } @@ -219,7 +219,7 @@ off_t Filesystem::Seek(File &f, AdapterStat &stat, break; } case SeekMode::kEnd: { - IoOptions opts; + FsIoOptions opts; opts.type_ = type_; stat.st_ptr_ = stat.bkt_id_->GetSize(opts) + offset; break; @@ -251,28 +251,28 @@ int Filesystem::Close(File &f, AdapterStat &stat, bool destroy) { size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, size_t total_size, IoStatus &io_status, - IoOptions opts) { + FsIoOptions opts) { off_t off = Tell(f, stat); return Write(f, stat, ptr, off, total_size, io_status, opts); } size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, size_t total_size, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { off_t off = Tell(f, stat); return Read(f, stat, ptr, off, total_size, io_status, opts); } HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { off_t off = Tell(f, stat); return AWrite(f, stat, ptr, off, total_size, req_id, io_status, opts); } HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { off_t off = Tell(f, stat); return ARead(f, stat, ptr, off, total_size, req_id, io_status, opts); } @@ -285,7 +285,7 @@ HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, size_t total_size, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; auto stat = mdm->Find(f); if (!stat) { @@ -298,7 +298,7 @@ size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, size_t total_size, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; auto stat = mdm->Find(f); if (!stat) { @@ -311,7 +311,7 @@ size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, size_t off, size_t total_size, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; auto stat = mdm->Find(f); if (!stat) { @@ -325,7 +325,7 @@ size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, size_t off, size_t total_size, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; auto stat = mdm->Find(f); if (!stat) { @@ -339,7 +339,7 @@ size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; auto stat = mdm->Find(f); if (!stat) { @@ -352,7 +352,7 @@ HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; auto stat = mdm->Find(f); if (!stat) { @@ -365,7 +365,7 @@ HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; auto stat = mdm->Find(f); if (!stat) { @@ -379,7 +379,7 @@ HermesRequest* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, HermesRequest* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, IoOptions opts) { + IoStatus &io_status, FsIoOptions opts) { auto mdm = HERMES_FS_METADATA_MANAGER; auto stat = mdm->Find(f); if (!stat) { diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index ff35ca927..3fbda4d0e 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -69,9 +69,9 @@ struct AdapterStat : public IoClientStats { * A structure to represent IO options for FS adapter. * For now, nothing additional than the typical IoClientContext. * */ -struct IoOptions : public IoClientContext { +struct FsIoOptions : public IoClientContext { /** Default constructor */ - IoOptions() : IoClientContext() { + FsIoOptions() : IoClientContext() { flags_.SetBits(HERMES_FS_SEEK); } @@ -89,6 +89,14 @@ struct IoOptions : public IoClientContext { bool DoSeek() { return flags_.OrBits(HERMES_FS_SEEK); } + + /** return IO options with \a mpi_type MPI data type */ + static FsIoOptions DataType(MPI_Datatype mpi_type, bool seek = true) { + FsIoOptions opts; + opts.mpi_type_ = mpi_type; + if (!seek) { opts.UnsetSeek(); } + return opts; + } }; /** A class to represent file system */ @@ -111,20 +119,20 @@ class Filesystem { /** write */ size_t Write(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, IoStatus &io_status, - IoOptions opts = IoOptions()); + FsIoOptions opts = FsIoOptions()); /** read */ size_t Read(File &f, AdapterStat &stat, void *ptr, size_t off, size_t total_size, - IoStatus &io_status, IoOptions opts = IoOptions()); + IoStatus &io_status, FsIoOptions opts = FsIoOptions()); /** write asynchronously */ HermesRequest *AWrite(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, - IoOptions opts = IoOptions()); + FsIoOptions opts = FsIoOptions()); /** read asynchronously */ HermesRequest *ARead(File &f, AdapterStat &stat, void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, - IoOptions opts = IoOptions()); + FsIoOptions opts = FsIoOptions()); /** wait for \a req_id request ID */ size_t Wait(uint64_t req_id); /** wait for request IDs in \a req_id vector */ @@ -148,17 +156,17 @@ class Filesystem { public: /** write */ size_t Write(File &f, AdapterStat &stat, const void *ptr, size_t total_size, - IoStatus &io_status, IoOptions opts); + IoStatus &io_status, FsIoOptions opts); /** read */ size_t Read(File &f, AdapterStat &stat, void *ptr, size_t total_size, - IoStatus &io_status, IoOptions opts); + IoStatus &io_status, FsIoOptions opts); /** write asynchronously */ HermesRequest *AWrite(File &f, AdapterStat &stat, const void *ptr, size_t total_size, size_t req_id, IoStatus &io_status, - IoOptions opts); + FsIoOptions opts); /** read asynchronously */ HermesRequest *ARead(File &f, AdapterStat &stat, void *ptr, size_t total_size, - size_t req_id, IoStatus &io_status, IoOptions opts); + size_t req_id, IoStatus &io_status, FsIoOptions opts); /* * Locates the AdapterStat data structure internally, and @@ -168,33 +176,33 @@ class Filesystem { public: /** write */ size_t Write(File &f, bool &stat_exists, const void *ptr, size_t total_size, - IoStatus &io_status, IoOptions opts = IoOptions()); + IoStatus &io_status, FsIoOptions opts = FsIoOptions()); /** read */ size_t Read(File &f, bool &stat_exists, void *ptr, size_t total_size, - IoStatus &io_status, IoOptions opts = IoOptions()); + IoStatus &io_status, FsIoOptions opts = FsIoOptions()); /** write \a off offset */ size_t Write(File &f, bool &stat_exists, const void *ptr, size_t off, size_t total_size, IoStatus &io_status, - IoOptions opts = IoOptions()); + FsIoOptions opts = FsIoOptions()); /** read \a off offset */ size_t Read(File &f, bool &stat_exists, void *ptr, size_t off, size_t total_size, IoStatus &io_status, - IoOptions opts = IoOptions()); + FsIoOptions opts = FsIoOptions()); /** write asynchronously */ HermesRequest *AWrite(File &f, bool &stat_exists, const void *ptr, size_t total_size, size_t req_id, IoStatus &io_status, - IoOptions opts); + FsIoOptions opts); /** read asynchronously */ HermesRequest *ARead(File &f, bool &stat_exists, void *ptr, size_t total_size, - size_t req_id, IoStatus &io_status, IoOptions opts); + size_t req_id, IoStatus &io_status, FsIoOptions opts); /** write \a off offset asynchronously */ HermesRequest *AWrite(File &f, bool &stat_exists, const void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, - IoOptions opts); + FsIoOptions opts); /** read \a off offset asynchronously */ HermesRequest *ARead(File &f, bool &stat_exists, void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, - IoOptions opts); + FsIoOptions opts); /** seek */ off_t Seek(File &f, bool &stat_exists, SeekMode whence, off_t offset); /** file sizes */ diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index ae610bd56..6145e2beb 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -129,19 +129,19 @@ struct IoClientStats { }; /** Any statistics which need to be globally maintained across ranks */ -struct GlobalIoClientStatse { +struct GlobalIoClientState { size_t true_size_; }; /** A structure to represent IO status */ struct IoStatus { - size_t posix_ret_; /**< POSIX/STDIO return value */ + size_t size_; /**< POSIX/STDIO return value */ int mpi_ret_; /**< MPI return value */ MPI_Status mpi_status_; /**< MPI status */ MPI_Status *mpi_status_ptr_; /**< MPI status pointer */ /** Default constructor */ - IoStatus() : posix_ret_(0), + IoStatus() : size_(0), mpi_ret_(MPI_SUCCESS), mpi_status_ptr_(&mpi_status_) {} }; @@ -167,14 +167,14 @@ class IoClient { /** Get initial statistics from the backend */ virtual void InitBucketState(const lipc::charbuf &bkt_name, const IoClientContext &opts, - GlobalIoClientStatse &stat) = 0; + GlobalIoClientState &stat) = 0; /** * What the statistics would be if all blobs were flushed from Hermes * to the backing storage system. * */ virtual void UpdateBucketState(const IoClientContext &opts, - GlobalIoClientStatse &stat) = 0; + GlobalIoClientState &stat) = 0; /** Write blob to backend */ virtual void WriteBlob(const lipc::charbuf &bkt_name, diff --git a/adapter/mpiio/CMakeLists.txt b/adapter/mpiio/CMakeLists.txt index 556d95567..425680dbe 100644 --- a/adapter/mpiio/CMakeLists.txt +++ b/adapter/mpiio/CMakeLists.txt @@ -1,31 +1,35 @@ project(MPIIOAdapter VERSION ${HERMES_PACKAGE_VERSION}) -include_directories(${HERMES_ADAPTER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) +include_directories( + ${CMAKE_SOURCE_DIR} + ${HERMES_SRC_DIR} + ${HERMES_ADAPTER_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}) -# MPIIO src code. We only include mpiio.cc as it includes other cc to reduce compilation time. -set(MPIIO_ADAPTER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/mpiio.cc) +# Creates the MPIIO I/O client and singleton +add_library(hermes_mpiio_io_client + ${CMAKE_CURRENT_SOURCE_DIR}/mpiio_api_singleton.cc + ${CMAKE_CURRENT_SOURCE_DIR}/mpiio_io_client.cc) +target_compile_options(hermes_mpiio_io_client PUBLIC -fPIC) +target_link_libraries(hermes_mpiio_io_client + MPI::MPI_CXX glog::glog stdc++fs dl) -set(HERMES_MPIIO_ADAPTER_DIR ${HERMES_ADAPTER_DIR}/mpiio) - -# Public headers -set(MPIIO_ADAPTER_PUBLIC_HEADER - ${HERMES_MPIIO_ADAPTER_DIR}/real_api.h - ${HERMES_MPIIO_ADAPTER_DIR}/fs_api.h) - -# Add library hermes_mpiio -add_library(hermes_mpiio_backend ${CMAKE_CURRENT_SOURCE_DIR}/fs_api.cc) -add_dependencies(hermes_mpiio_backend hermes) -target_link_libraries(hermes_mpiio_backend hermes MPI::MPI_CXX glog::glog stdc++fs) - -add_library(hermes_mpiio SHARED ${MPIIO_ADAPTER_PUBLIC_HEADER} ${MPIIO_ADAPTER_SRC}) -add_dependencies(hermes_mpiio hermes_mpiio_backend) -target_link_libraries(hermes_mpiio hermes_mpiio_backend) +# Create the MPIIO interceptor +set(INTERCEPTOR_DEPS + hermes + hermes_mpiio_io_client + hermes_fs_base) +add_library(hermes_mpiio SHARED + ${CMAKE_CURRENT_SOURCE_DIR}/mpiio_api.cc) +add_dependencies(hermes_mpiio ${INTERCEPTOR_DEPS}) +target_link_libraries(hermes_mpiio ${INTERCEPTOR_DEPS}) +target_compile_options(hermes_mpiio PUBLIC -fPIC) #----------------------------------------------------------------------------- # Add Target(s) to CMake Install #----------------------------------------------------------------------------- install( TARGETS - hermes_mpiio_backend + hermes_mpiio_io_client EXPORT ${HERMES_EXPORTED_TARGETS} LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} @@ -46,4 +50,4 @@ install( #----------------------------------------------------------------------------- if(HERMES_ENABLE_COVERAGE) set_coverage_flags(hermes_mpiio) -endif() +endif() \ No newline at end of file diff --git a/adapter/mpiio/fs_api.cc b/adapter/mpiio/fs_api.cc deleted file mode 100644 index 8429e8294..000000000 --- a/adapter/mpiio/fs_api.cc +++ /dev/null @@ -1,622 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "fs_api.h" - -namespace hermes::adapter::mpiio { - -size_t IoSizeFromCount(int count, MPI_Datatype datatype, IoOptions &opts) { - int datatype_size; - opts.mpi_type_ = datatype; - opts.count_ = count; - MPI_Type_size(datatype, &datatype_size); - return static_cast(count * datatype_size); -} - -int MpiioFS::Read(File &f, AdapterStat &stat, - void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status, IoOptions opts) { - opts.mpi_type_ = datatype; - if (offset + count >= static_cast(stat.st_size)) { - status->count_hi_and_cancelled = 0; - status->count_lo = 0; - return 0; - } - IoStatus io_status; - io_status.mpi_status_ptr_ = status; - size_t total_size = IoSizeFromCount(count, datatype, opts); - Filesystem::Read(f, stat, ptr, offset, - total_size, io_status, opts); - return io_status.mpi_ret_; -} - -int MpiioFS::ARead(File &f, AdapterStat &stat, - void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Request *request, IoOptions opts) { - opts.mpi_type_ = datatype; - IoStatus io_status; - size_t total_size = IoSizeFromCount(count, datatype, opts); - Filesystem::ARead(f, stat, ptr, offset, total_size, - reinterpret_cast(request), - io_status, opts); - return io_status.mpi_ret_; -} - -int MpiioFS::ReadAll(File &f, AdapterStat &stat, - void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status, IoOptions opts) { - opts.mpi_type_ = datatype; - MPI_Barrier(stat.comm); - size_t ret = Read(f, stat, ptr, offset, count, datatype, status, opts); - MPI_Barrier(stat.comm); - return ret; -} - -int MpiioFS::ReadOrdered(File &f, AdapterStat &stat, - void *ptr, int count, - MPI_Datatype datatype, - MPI_Status *status, IoOptions opts) { - opts.mpi_type_ = datatype; - - int total; - MPI_Scan(&count, &total, 1, MPI_INT, MPI_SUM, stat.comm); - MPI_Offset my_offset = total - count; - size_t ret = ReadAll(f, stat, ptr, my_offset, count, datatype, status, opts); - return ret; -} - -int MpiioFS::Write(File &f, AdapterStat &stat, - const void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status, IoOptions opts) { - opts.mpi_type_ = datatype; - IoStatus io_status; - io_status.mpi_status_ptr_ = status; - size_t total_size = IoSizeFromCount(count, datatype, opts); - Filesystem::Write(f, stat, ptr, offset, total_size, - io_status, opts); - return io_status.mpi_ret_; -} - -int MpiioFS::AWrite(File &f, AdapterStat &stat, - const void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Request *request, IoOptions opts) { - opts.mpi_type_ = datatype; - IoStatus io_status; - size_t total_size = IoSizeFromCount(count, datatype, opts); - Filesystem::AWrite(f, stat, ptr, offset, total_size, - reinterpret_cast(request), - io_status, opts); - return io_status.mpi_ret_; -} - -int MpiioFS::WriteAll(File &f, AdapterStat &stat, - const void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status, IoOptions opts) { - opts.mpi_type_ = datatype; - MPI_Barrier(stat.comm); - int ret = Write(f, stat, ptr, offset, count, datatype, status, opts); - MPI_Barrier(stat.comm); - return ret; -} - -int MpiioFS::WriteOrdered(File &f, AdapterStat &stat, - const void *ptr, int count, - MPI_Datatype datatype, - MPI_Status *status, IoOptions opts) { - opts.mpi_type_ = datatype; - int total; - MPI_Scan(&count, &total, 1, MPI_INT, MPI_SUM, stat.comm); - MPI_Offset my_offset = total - count; - size_t ret = WriteAll(f, stat, ptr, my_offset, count, datatype, status, opts); - return ret; -} - -int MpiioFS::AWriteOrdered(File &f, AdapterStat &stat, - const void *ptr, int count, - MPI_Datatype datatype, - MPI_Request *request, IoOptions opts) { - LOG(INFO) << "Starting an asynchronous write" << std::endl; - auto pool = - Singleton::GetInstance(); - HermesRequest *hreq = new HermesRequest(); - auto lambda = - [](MpiioFS *fs, File &f, AdapterStat &stat, - const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status, - IoOptions opts) { - int ret = fs->WriteOrdered(f, stat, ptr, - count, datatype, status, opts); - return static_cast(ret); - }; - auto func = std::bind(lambda, this, f, stat, ptr, - count, datatype, &hreq->io_status.mpi_status_, - opts); - hreq->return_future = pool->run(func); - auto mdm = Singleton::GetInstance(); - mdm->request_map.emplace(reinterpret_cast(request), hreq); - return MPI_SUCCESS; -} - -int MpiioFS::Wait(MPI_Request *req, MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto iter = mdm->request_map.find(reinterpret_cast(req)); - if (iter != mdm->request_map.end()) { - hermes::adapter::fs::HermesRequest *hreq = iter->second; - hreq->return_future.get(); - memcpy(status, - hreq->io_status.mpi_status_ptr_, - sizeof(MPI_Status)); - mdm->request_map.erase(iter); - delete (hreq); - return MPI_SUCCESS; - } - return real_api->MPI_Wait(req, status); -} - -int MpiioFS::WaitAll(int count, MPI_Request *req, MPI_Status *status) { - int ret = 0; - for (int i = 0; i < count; i++) { - auto sub_ret = Wait(&req[i], &status[i]); - if (sub_ret != MPI_SUCCESS) { - ret = sub_ret; - } - } - return ret; -} - -int MpiioFS::Seek(File &f, AdapterStat &stat, - MPI_Offset offset, int whence) { - Filesystem::Seek(f, stat, - MpiioSeekModeConv::Normalize(whence), - offset); - return MPI_SUCCESS; -} - -int MpiioFS::SeekShared(File &f, AdapterStat &stat, - MPI_Offset offset, int whence) { - MPI_Offset sum_offset; - int sum_whence; - int comm_participators; - MPI_Comm_size(stat.comm, &comm_participators); - MPI_Allreduce(&offset, &sum_offset, 1, MPI_LONG_LONG_INT, MPI_SUM, - stat.comm); - MPI_Allreduce(&whence, &sum_whence, 1, MPI_INT, MPI_SUM, - stat.comm); - if (sum_offset / comm_participators != offset) { - LOG(ERROR) - << "Same offset should be passed across the opened file communicator." - << std::endl; - } - if (sum_whence / comm_participators != whence) { - LOG(ERROR) - << "Same whence should be passed across the opened file communicator." - << std::endl; - } - Seek(f, stat, offset, whence); - return 0; -} - -/** - * Variants which internally find the correct offset -* */ - -int MpiioFS::Read(File &f, AdapterStat &stat, - void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - IoOptions opts = IoOptions::DataType(datatype, true); - return Read(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); -} - -int MpiioFS::ARead(File &f, AdapterStat &stat, - void *ptr, int count, MPI_Datatype datatype, MPI_Request *request) { - IoOptions opts = IoOptions::DataType(datatype, true); - return ARead(f, stat, ptr, Tell(f, stat), count, datatype, request, opts); -} - -int MpiioFS::ReadAll(File &f, AdapterStat &stat, - void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - IoOptions opts = IoOptions::DataType(datatype, true); - return ReadAll(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); -} - -int MpiioFS::Write(File &f, AdapterStat &stat, - const void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - IoOptions opts = IoOptions::DataType(datatype, true); - return Write(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); -} - -int MpiioFS::AWrite(File &f, AdapterStat &stat, - const void *ptr, int count, MPI_Datatype datatype, - MPI_Request *request) { - IoOptions opts = IoOptions::DataType(datatype, true); - return AWrite(f, stat, ptr, Tell(f, stat), count, datatype, request, opts); -} - -int MpiioFS::WriteAll(File &f, AdapterStat &stat, - const void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - IoOptions opts = IoOptions::DataType(datatype, true); - return WriteAll(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); -} - - -/** - * Variants which retrieve the stat data structure internally - * */ - -int MpiioFS::Read(File &f, bool &stat_exists, - void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return Read(f, stat, ptr, offset, count, datatype, status, opts); -} - -int MpiioFS::ARead(File &f, bool &stat_exists, - void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Request *request) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return ARead(f, stat, ptr, offset, count, datatype, request, opts); -} - -int MpiioFS::ReadAll(File &f, bool &stat_exists, - void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return ReadAll(f, stat, ptr, offset, count, datatype, status, opts); -} - -int MpiioFS::ReadOrdered(File &f, bool &stat_exists, - void *ptr, int count, - MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return ReadOrdered(f, stat, ptr, count, datatype, status, opts); -} - -int MpiioFS::Write(File &f, bool &stat_exists, - const void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return Write(f, stat, ptr, offset, count, datatype, status, opts); -} - -int MpiioFS::AWrite(File &f, bool &stat_exists, - const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Request *request) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return AWrite(f, stat, ptr, offset, count, datatype, request, opts); -} - -int MpiioFS::WriteAll(File &f, bool &stat_exists, - const void *ptr, size_t offset, - int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return WriteAll(f, stat, ptr, offset, count, datatype, status, opts); -} - -int MpiioFS::WriteOrdered(File &f, bool &stat_exists, - const void *ptr, int count, - MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return WriteOrdered(f, stat, ptr, count, datatype, status, opts); -} - -int MpiioFS::AWriteOrdered(File &f, bool &stat_exists, - const void *ptr, int count, - MPI_Datatype datatype, - MPI_Request *request) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - IoOptions opts = IoOptions::DataType(datatype, false); - return AWriteOrdered(f, stat, ptr, count, datatype, request, opts); -} - -int MpiioFS::Read(File &f, bool &stat_exists, - void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Read(f, stat, ptr, count, datatype, status); -} - -int MpiioFS::ARead(File &f, bool &stat_exists, - void *ptr, int count, MPI_Datatype datatype, - MPI_Request *request) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return ARead(f, stat, ptr, count, datatype, request); -} - -int MpiioFS::ReadAll(File &f, bool &stat_exists, - void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return ReadAll(f, stat, ptr, count, datatype, status); -} - -int MpiioFS::Write(File &f, bool &stat_exists, - const void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Write(f, stat, ptr, count, datatype, status); -} - -int MpiioFS::AWrite(File &f, bool &stat_exists, - const void *ptr, int count, MPI_Datatype datatype, - MPI_Request *request) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return AWrite(f, stat, ptr, count, datatype, request); -} - -int MpiioFS::WriteAll(File &f, bool &stat_exists, - const void *ptr, int count, MPI_Datatype datatype, - MPI_Status *status) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return WriteAll(f, stat, ptr, count, datatype, status); -} - -int MpiioFS::Seek(File &f, bool &stat_exists, - MPI_Offset offset, int whence) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Seek(f, stat, offset, whence); -} - -int MpiioFS::SeekShared(File &f, bool &stat_exists, - MPI_Offset offset, int whence) { - auto mdm = Singleton::GetInstance(); - auto [stat, exists] = mdm->Find(f); - if (!exists) { - stat_exists = false; - return -1; - } - stat_exists = true; - return SeekShared(f, stat, offset, whence); -} - -/** - * Internal overrides - * */ - -File MpiioFS::RealOpen(AdapterStat &stat, const std::string &path) { - File f; - f.mpi_status_ = real_api->MPI_File_open(stat.comm, path.c_str(), stat.amode, - stat.info, &f.mpi_fh_); - if (f.mpi_status_ != MPI_SUCCESS) { - f.status_ = false; - } - // NOTE(llogan): MPI_Info_get does not behave well, so removing - /* - MPI_Info info; - MPI_File_get_info(f.mpi_fh_, &info); - MPI_Info_set(info, "path", path.c_str()); - MPI_File_set_info(f.mpi_fh_, info);*/ - return f; -} - -void MpiioFS::InitFile(File &f) { - // NOTE(llogan): MPI_Info_get does not behave well, so removing - (void) f; - /*struct stat st; - std::string filename = GetFilenameFromFP(&f.mpi_fh_); - int fd = posix_api->open(filename.c_str(), O_RDONLY); - posix_api->__fxstat(_STAT_VER, fd, &st); - f.st_dev = st.st_dev; - f.st_ino = st.st_ino; - posix_api->close(fd);*/ -} - -void MpiioFS::OpenInitStat(File &f, AdapterStat &stat) { - MPI_Offset size = static_cast(stat.st_size); - MPI_File_get_size(f.mpi_fh_, &size); - stat.st_size = size; - if (stat.amode & MPI_MODE_APPEND) { - stat.is_append = true; - } -} - -size_t MpiioFS::_RealWrite(const std::string &filename, off_t offset, - size_t size, const u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) { - LOG(INFO) << "Writing to file: " << filename << " offset: " << offset - << " size:" << size << "." - << " offset:" << offset << "." - << " file_size:" << stdfs::file_size(filename) - << " pid: " << getpid() << std::endl; - MPI_File fh; - int write_count = 0; - io_status.mpi_ret_ = real_api->MPI_File_open(MPI_COMM_SELF, filename.c_str(), - MPI_MODE_RDWR, MPI_INFO_NULL, &fh); - if (io_status.mpi_ret_ != MPI_SUCCESS) { - return 0; - } - - io_status.mpi_ret_ = real_api->MPI_File_seek(fh, offset, MPI_SEEK_SET); - if (io_status.mpi_ret_ != MPI_SUCCESS) { - goto ERROR; - } - io_status.mpi_ret_ = real_api->MPI_File_write(fh, data_ptr, - opts.count_, opts.mpi_type_, - io_status.mpi_status_ptr_); - MPI_Get_count(io_status.mpi_status_ptr_, opts.mpi_type_, &write_count); - if (opts.count_ != write_count) { - LOG(ERROR) << "writing failed: write " << write_count << " of " - << opts.count_ << "." << std::endl; - } - -ERROR: - real_api->MPI_File_close(&fh); - return size; -} - -size_t MpiioFS::_RealRead(const std::string &filename, off_t offset, - size_t size, u8 *data_ptr, - IoStatus &io_status, IoOptions &opts) { - LOG(INFO) << "Read called for filename from destination: " << filename - << " on offset: " << offset << " and size: " << size << "." - << " file_size:" << stdfs::file_size(filename) - << " pid: " << getpid() << std::endl; - MPI_File fh; - int read_count = 0; - io_status.mpi_ret_ = real_api->MPI_File_open(MPI_COMM_SELF, filename.c_str(), - MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); - if (io_status.mpi_ret_ != MPI_SUCCESS) { - return 0; - } - - io_status.mpi_ret_ = real_api->MPI_File_seek(fh, offset, MPI_SEEK_SET); - if (io_status.mpi_ret_ != MPI_SUCCESS) { - goto ERROR; - } - io_status.mpi_ret_ = real_api->MPI_File_read(fh, data_ptr, - opts.count_, opts.mpi_type_, - io_status.mpi_status_ptr_); - MPI_Get_count(io_status.mpi_status_ptr_, - opts.mpi_type_, &read_count); - if (read_count != opts.count_) { - LOG(ERROR) << "reading failed: read " << read_count << " of " << opts.count_ - << "." << std::endl; - } - -ERROR: - real_api->MPI_File_close(&fh); - return size; -} - -void MpiioFS::_IoStats(size_t count, IoStatus &io_status, IoOptions &opts) { - (void) opts; - io_status.mpi_status_ptr_->count_hi_and_cancelled = 0; - io_status.mpi_status_ptr_->count_lo = count; -} - -int MpiioFS::RealSync(File &f) { - return real_api->MPI_File_sync(f.mpi_fh_); -} - -int MpiioFS::RealClose(File &f) { - return real_api->MPI_File_close(&f.mpi_fh_); -} - -} // namespace hermes::adapter::mpiio diff --git a/adapter/mpiio/fs_api.h b/adapter/mpiio/fs_api.h deleted file mode 100644 index 2a90ac7ff..000000000 --- a/adapter/mpiio/fs_api.h +++ /dev/null @@ -1,241 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_MPIIO_FS_API_H_ -#define HERMES_ADAPTER_MPIIO_FS_API_H_ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "real_api.h" - -namespace hermes::adapter::mpiio { - -using hermes::Singleton; -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::File; -using hermes::adapter::fs::HermesRequest; -using hermes::adapter::fs::IoOptions; -using hermes::adapter::fs::IoStatus; -using hermes::adapter::fs::MetadataManager; -using hermes::adapter::fs::SeekMode; -using hermes::adapter::mpiio::API; - -/** - A class to represent MPI IO seek mode conversion -*/ -class MpiioSeekModeConv { - public: - /** normalize \a mpi_seek MPI seek mode */ - static SeekMode Normalize(int mpi_seek) { - switch (mpi_seek) { - case MPI_SEEK_SET: - return SeekMode::kSet; - case MPI_SEEK_CUR: - return SeekMode::kCurrent; - case MPI_SEEK_END: - return SeekMode::kEnd; - default: - return SeekMode::kNone; - } - } -}; - -/** - A class to represent MPI IO file system -*/ -class MpiioFS : public hermes::adapter::fs::Filesystem { - private: - API *real_api; /**< pointer to real APIs */ - hermes::adapter::fs::API *posix_api; /**< pointer to POSIX APIs */ - - public: - MpiioFS() { - real_api = Singleton::GetInstance(); - posix_api = Singleton::GetInstance(); - } - ~MpiioFS() = default; - - void InitFile(File &f) override; - - public: - /** get file name from \a fh MPI file pointer */ - static inline std::string GetFilenameFromFP(MPI_File *fh) { - MPI_Info info; - int status = MPI_File_get_info(*fh, &info); - if (status != MPI_SUCCESS) { - LOG(ERROR) << "MPI_File_get_info on file handler failed." << std::endl; - } - const int kMaxSize = 0xFFF; - int flag; - char filename[kMaxSize] = {0}; - MPI_Info_get(info, "filename", kMaxSize, filename, &flag); - return filename; - } - /** Read */ - int Read(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, - MPI_Datatype datatype, MPI_Status *status, - IoOptions opts = IoOptions()); - /** ARead */ - int ARead(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, - MPI_Datatype datatype, MPI_Request *request, - IoOptions opts = IoOptions()); - /** ReadAll */ - int ReadAll(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, - MPI_Datatype datatype, MPI_Status *status, - IoOptions opts = IoOptions()); - /** ReadOrdered */ - int ReadOrdered(File &f, AdapterStat &stat, void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status, - IoOptions opts = IoOptions()); - /** Write */ - int Write(File &f, AdapterStat &stat, const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Status *status, - IoOptions opts = IoOptions()); - /** AWrite */ - int AWrite(File &f, AdapterStat &stat, const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Request *request, - IoOptions opts = IoOptions()); - /** WriteAll */ - int WriteAll(File &f, AdapterStat &stat, const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Status *status, - IoOptions opts = IoOptions()); - /** WriteOrdered */ - int WriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status, - IoOptions opts = IoOptions()); - /** AWriteOrdered */ - int AWriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, - MPI_Datatype datatype, MPI_Request *request, - IoOptions opts = IoOptions()); - /** Wait */ - int Wait(MPI_Request *req, MPI_Status *status); - /** WaitAll */ - int WaitAll(int count, MPI_Request *req, MPI_Status *status); - /** Seek */ - int Seek(File &f, AdapterStat &stat, MPI_Offset offset, int whence); - /** SeekShared */ - int SeekShared(File &f, AdapterStat &stat, MPI_Offset offset, int whence); - - /** - * Variants which internally find the correct offset - */ - - public: - /** Read */ - int Read(File &f, AdapterStat &stat, void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** ARead */ - int ARead(File &f, AdapterStat &stat, void *ptr, int count, - MPI_Datatype datatype, MPI_Request *request); - /** ReadAll */ - int ReadAll(File &f, AdapterStat &stat, void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** Write */ - int Write(File &f, AdapterStat &stat, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** AWrite */ - int AWrite(File &f, AdapterStat &stat, const void *ptr, int count, - MPI_Datatype datatype, MPI_Request *request); - /** WriteAll */ - int WriteAll(File &f, AdapterStat &stat, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - - /** - * Variants which retrieve the stat data structure internally - */ - - public: - /** Read */ - int Read(File &f, bool &stat_exists, void *ptr, size_t offset, int count, - MPI_Datatype datatype, MPI_Status *status); - /** ARead */ - int ARead(File &f, bool &stat_exists, void *ptr, size_t offset, int count, - MPI_Datatype datatype, MPI_Request *request); - /** ReadAll */ - int ReadAll(File &f, bool &stat_exists, void *ptr, size_t offset, int count, - MPI_Datatype datatype, MPI_Status *status); - /** ReadOrdered */ - int ReadOrdered(File &f, bool &stat_exists, void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** Write */ - int Write(File &f, bool &stat_exists, const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Status *status); - /** AWrite */ - int AWrite(File &f, bool &stat_exists, const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Request *request); - /** WriteAll */ - int WriteAll(File &f, bool &stat_exists, const void *ptr, size_t offset, - int count, MPI_Datatype datatype, MPI_Status *status); - /** WriteOrdered */ - int WriteOrdered(File &f, bool &stat_exists, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** AWriteOrdered */ - int AWriteOrdered(File &f, bool &stat_exists, const void *ptr, int count, - MPI_Datatype datatype, MPI_Request *request); - /** Read */ - int Read(File &f, bool &stat_exists, void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** ARead */ - int ARead(File &f, bool &stat_exists, void *ptr, int count, - MPI_Datatype datatype, MPI_Request *request); - /** ReadAll */ - int ReadAll(File &f, bool &stat_exists, void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** Write */ - int Write(File &f, bool &stat_exists, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** AWrite */ - int AWrite(File &f, bool &stat_exists, const void *ptr, int count, - MPI_Datatype datatype, MPI_Request *request); - /** WriteAll */ - int WriteAll(File &f, bool &stat_exists, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status); - /** Seek */ - int Seek(File &f, bool &stat_exists, MPI_Offset offset, int whence); - /** SeekShared */ - int SeekShared(File &f, bool &stat_exists, MPI_Offset offset, int whence); - - /** - * Internal overrides - */ - - private: - /** OpenInitStat */ - void OpenInitStat(File &f, AdapterStat &stat) override; - /** RealOpen */ - File RealOpen(AdapterStat &stat, const std::string &path) override; - /** RealWrite */ - size_t _RealWrite(const std::string &filename, off_t offset, size_t size, - const u8 *data_ptr, IoStatus &io_status, - IoOptions &opts) override; - /** RealRead */ - size_t _RealRead(const std::string &filename, off_t offset, size_t size, - u8 *data_ptr, IoStatus &io_status, IoOptions &opts) override; - /** IoStats */ - void _IoStats(size_t count, IoStatus &io_status, IoOptions &opts) override; - /** RealSync */ - int RealSync(File &f) override; - /** RealClose */ - int RealClose(File &f) override; -}; - -} // namespace hermes::adapter::mpiio - -#endif // HERMES_ADAPTER_MPIIO_FS_API_H_ diff --git a/adapter/mpiio/mpiio.cc b/adapter/mpiio/mpiio_api.cc similarity index 99% rename from adapter/mpiio/mpiio.cc rename to adapter/mpiio/mpiio_api.cc index 714aef8c4..a12f752b6 100644 --- a/adapter/mpiio/mpiio.cc +++ b/adapter/mpiio/mpiio_api.cc @@ -16,7 +16,7 @@ bool mpiio_intercepted = true; #include #include -#include "real_api.h" +#include "mpiio_api.h" #include "fs_api.h" #include "constants.h" diff --git a/adapter/mpiio/real_api.h b/adapter/mpiio/mpiio_api.h similarity index 97% rename from adapter/mpiio/real_api.h rename to adapter/mpiio/mpiio_api.h index 93a601367..c34e2cd7e 100644 --- a/adapter/mpiio/real_api.h +++ b/adapter/mpiio/mpiio_api.h @@ -18,9 +18,6 @@ #include #include #include -#include "interceptor.h" -#include "filesystem/filesystem.h" -#include "filesystem/metadata_manager.h" #define REQUIRE_API(api_name) \ if (api_name == nullptr) { \ @@ -60,10 +57,10 @@ typedef int (*MPI_File_iwrite_shared_t)(MPI_File fh, const void * buf, int count typedef int (*MPI_File_sync_t)(MPI_File fh); } -namespace hermes::adapter::mpiio { +namespace hermes::adapter::fs { /** Pointers to the real mpiio API */ -class API { +class MpiioApi { public: /** MPI_Init */ MPI_Init_t MPI_Init = nullptr; @@ -122,7 +119,7 @@ class API { /** MPI_File_sync */ MPI_File_sync_t MPI_File_sync = nullptr; - API() { + MpiioApi() { void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, "mpiio_intercepted"); if (is_intercepted) { MPI_Init = (MPI_Init_t)dlsym(RTLD_NEXT, "MPI_Init"); @@ -298,4 +295,11 @@ class API { #undef REQUIRE_API +#include "singleton.h" + +/** Simplify access to the stateless MpiioFs Singleton */ +#define HERMES_MPIIO_API \ + hermes::EasyGlobalSingleton::GetInstance() +#define HERMES_MPIIO_API_T hermes::adapter::fs::MpiioApi* + #endif // HERMES_ADAPTER_MPIIO_H diff --git a/adapter/mpiio/mpiio_api_singleton.cc b/adapter/mpiio/mpiio_api_singleton.cc new file mode 100644 index 000000000..df46931f8 --- /dev/null +++ b/adapter/mpiio/mpiio_api_singleton.cc @@ -0,0 +1,17 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "singleton.h" + +#include "mpiio_api.h" +template<> std::unique_ptr + hermes::Singleton::obj_ = nullptr; diff --git a/adapter/mpiio/mpiio_fs_api.h b/adapter/mpiio/mpiio_fs_api.h new file mode 100644 index 000000000..0a714cfd7 --- /dev/null +++ b/adapter/mpiio/mpiio_fs_api.h @@ -0,0 +1,461 @@ +// +// Created by lukemartinlogan on 2/4/23. +// + +#ifndef HERMES_ADAPTER_MPIIO_MPIIO_FS_API_H_ +#define HERMES_ADAPTER_MPIIO_MPIIO_FS_API_H_ + +#include + +#include "adapter/filesystem/filesystem.h" +#include "adapter/filesystem/filesystem_mdm.h" +#include "mpiio_api.h" +#include "mpiio_io_client.h" + +namespace hermes::adapter::fs { + +/** A class to represent MPI IO seek mode conversion */ +class MpiioSeekModeConv { + public: + /** normalize \a mpi_seek MPI seek mode */ + static SeekMode Normalize(int mpi_seek) { + switch (mpi_seek) { + case MPI_SEEK_SET: + return SeekMode::kSet; + case MPI_SEEK_CUR: + return SeekMode::kCurrent; + case MPI_SEEK_END: + return SeekMode::kEnd; + default: + return SeekMode::kNone; + } + } +}; + +/** A class to represent POSIX IO file system */ +class MpiioFs : public Filesystem { + public: + MpiioFs() + : Filesystem(HERMES_MPIIO_IO_CLIENT, + AdapterType::kMpiio) {} + + int Read(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, + MPI_Datatype datatype, MPI_Status *status, FsIoOptions opts) { + opts.mpi_type_ = datatype; + IoStatus io_status; + io_status.mpi_status_ptr_ = status; + size_t total_size = MpiioIoClient::IoSizeFromCount(count, datatype, opts); + Filesystem::Read(f, stat, ptr, offset, total_size, io_status, opts); + return io_status.mpi_ret_; + } + + int ARead(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, + MPI_Datatype datatype, MPI_Request *request, FsIoOptions opts) { + opts.mpi_type_ = datatype; + IoStatus io_status; + size_t total_size = MpiioIoClient::IoSizeFromCount(count, datatype, opts); + Filesystem::ARead(f, stat, ptr, offset, total_size, + reinterpret_cast(request), io_status, opts); + return io_status.mpi_ret_; + } + + int ReadAll(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, + MPI_Datatype datatype, MPI_Status *status, FsIoOptions opts) { + opts.mpi_type_ = datatype; + MPI_Barrier(stat.comm_); + size_t ret = Read(f, stat, ptr, offset, count, datatype, status, opts); + MPI_Barrier(stat.comm_); + return ret; + } + + int ReadOrdered(File &f, AdapterStat &stat, void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status, FsIoOptions opts) { + opts.mpi_type_ = datatype; + + int total; + MPI_Scan(&count, &total, 1, MPI_INT, MPI_SUM, stat.comm_); + MPI_Offset my_offset = total - count; + size_t ret = + ReadAll(f, stat, ptr, my_offset, count, datatype, status, opts); + return ret; + } + + int Write(File &f, AdapterStat &stat, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Status *status, + FsIoOptions opts) { + opts.mpi_type_ = datatype; + IoStatus io_status; + io_status.mpi_status_ptr_ = status; + size_t total_size = MpiioIoClient::IoSizeFromCount(count, datatype, opts); + Filesystem::Write(f, stat, ptr, offset, total_size, io_status, opts); + return io_status.mpi_ret_; + } + + int AWrite(File &f, AdapterStat &stat, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Request *request, + FsIoOptions opts) { + opts.mpi_type_ = datatype; + IoStatus io_status; + size_t total_size = MpiioIoClient::IoSizeFromCount(count, datatype, opts); + Filesystem::AWrite(f, stat, ptr, offset, total_size, + reinterpret_cast(request), io_status, opts); + return io_status.mpi_ret_; + } + + int WriteAll(File &f, AdapterStat &stat, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Status *status, + FsIoOptions opts) { + opts.mpi_type_ = datatype; + MPI_Barrier(stat.comm_); + int ret = Write(f, stat, ptr, offset, count, datatype, status, opts); + MPI_Barrier(stat.comm_); + return ret; + } + + int WriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status, FsIoOptions opts) { + opts.mpi_type_ = datatype; + int total; + MPI_Scan(&count, &total, 1, MPI_INT, MPI_SUM, stat.comm_); + MPI_Offset my_offset = total - count; + size_t ret = + WriteAll(f, stat, ptr, my_offset, count, datatype, status, opts); + return ret; + } + + int AWriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, + MPI_Datatype datatype, MPI_Request *request, + FsIoOptions opts) { + LOG(INFO) << "Starting an asynchronous write" << std::endl; + auto pool = Singleton::GetInstance(); + HermesRequest *hreq = new HermesRequest(); + auto lambda = [](MpiioFs *fs, File &f, AdapterStat &stat, const void *ptr, + int count, MPI_Datatype datatype, MPI_Status *status, + FsIoOptions opts) { + int ret = fs->WriteOrdered(f, stat, ptr, count, datatype, status, opts); + return static_cast(ret); + }; + auto func = std::bind(lambda, this, f, stat, ptr, count, datatype, + &hreq->io_status.mpi_status_, opts); + hreq->return_future = pool->run(func); + auto mdm = HERMES_FS_METADATA_MANAGER; + mdm->request_map.emplace(reinterpret_cast(request), hreq); + return MPI_SUCCESS; + } + + int Wait(MPI_Request *req, MPI_Status *status) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto iter = mdm->request_map.find(reinterpret_cast(req)); + if (iter != mdm->request_map.end()) { + HermesRequest *hreq = iter->second; + hreq->return_future.get(); + memcpy(status, hreq->io_status.mpi_status_ptr_, sizeof(MPI_Status)); + mdm->request_map.erase(iter); + delete (hreq); + return MPI_SUCCESS; + } + return real_api->MPI_Wait(req, status); + } + + int WaitAll(int count, MPI_Request *req, MPI_Status *status) { + int ret = 0; + for (int i = 0; i < count; i++) { + auto sub_ret = Wait(&req[i], &status[i]); + if (sub_ret != MPI_SUCCESS) { + ret = sub_ret; + } + } + return ret; + } + + int Seek(File &f, AdapterStat &stat, MPI_Offset offset, int whence) { + Filesystem::Seek(f, stat, MpiioSeekModeConv::Normalize(whence), offset); + return MPI_SUCCESS; + } + + int SeekShared(File &f, AdapterStat &stat, MPI_Offset offset, int whence) { + MPI_Offset sum_offset; + int sum_whence; + int comm_participators; + MPI_Comm_size(stat.comm_, &comm_participators); + MPI_Allreduce(&offset, &sum_offset, 1, MPI_LONG_LONG_INT, MPI_SUM, + stat.comm_); + MPI_Allreduce(&whence, &sum_whence, 1, MPI_INT, MPI_SUM, stat.comm_); + if (sum_offset / comm_participators != offset) { + LOG(ERROR) + << "Same offset should be passed across the opened file communicator." + << std::endl; + } + if (sum_whence / comm_participators != whence) { + LOG(ERROR) + << "Same whence should be passed across the opened file communicator." + << std::endl; + } + Seek(f, stat, offset, whence); + return 0; + } + + ////////////////////////// + /// NO OFFSET PARAM + ////////////////////////// + + int Read(File &f, AdapterStat &stat, void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status) { + FsIoOptions opts = FsIoOptions::DataType(datatype, true); + return Read(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); + } + + int ARead(File &f, AdapterStat &stat, void *ptr, int count, + MPI_Datatype datatype, MPI_Request *request) { + FsIoOptions opts = FsIoOptions::DataType(datatype, true); + return ARead(f, stat, ptr, Tell(f, stat), count, datatype, request, opts); + } + + int ReadAll(File &f, AdapterStat &stat, void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status) { + FsIoOptions opts = FsIoOptions::DataType(datatype, true); + return ReadAll(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); + } + + int Write(File &f, AdapterStat &stat, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status) { + FsIoOptions opts = FsIoOptions::DataType(datatype, true); + return Write(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); + } + + int AWrite(File &f, AdapterStat &stat, const void *ptr, int count, + MPI_Datatype datatype, MPI_Request *request) { + FsIoOptions opts = FsIoOptions::DataType(datatype, true); + return AWrite(f, stat, ptr, Tell(f, stat), count, datatype, request, opts); + } + + int WriteAll(File &f, AdapterStat &stat, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status) { + FsIoOptions opts = FsIoOptions::DataType(datatype, true); + return WriteAll(f, stat, ptr, Tell(f, stat), count, datatype, status, opts); + } + + ////////////////////////// + /// NO STAT PARAM + ////////////////////////// + + int Read(File &f, bool &stat_exists, void *ptr, size_t offset, int count, + MPI_Datatype datatype, MPI_Status *status) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + FsIoOptions opts = FsIoOptions::DataType(datatype, false); + return Read(f, *stat, ptr, offset, count, datatype, status, opts); + } + + int ARead(File &f, bool &stat_exists, void *ptr, size_t offset, int count, + MPI_Datatype datatype, MPI_Request *request) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + FsIoOptions opts = FsIoOptions::DataType(datatype, false); + return ARead(f, *stat, ptr, offset, count, datatype, request, opts); + } + + int ReadAll(File &f, bool &stat_exists, void *ptr, size_t offset, int count, + MPI_Datatype datatype, MPI_Status *status) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + FsIoOptions opts = FsIoOptions::DataType(datatype, false); + return ReadAll(f, *stat, ptr, offset, count, datatype, status, opts); + } + + int ReadOrdered(File &f, bool &stat_exists, void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + FsIoOptions opts = FsIoOptions::DataType(datatype, false); + return ReadOrdered(f, *stat, ptr, count, datatype, status, opts); + } + + int Write(File &f, bool &stat_exists, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Status *status) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + FsIoOptions opts = FsIoOptions::DataType(datatype, false); + return Write(f, *stat, ptr, offset, count, datatype, status, opts); + } + + int AWrite(File &f, bool &stat_exists, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Request *request) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + FsIoOptions opts = FsIoOptions::DataType(datatype, false); + return AWrite(f, *stat, ptr, offset, count, datatype, request, opts); + } + + int WriteAll(File &f, bool &stat_exists, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Status *status) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + FsIoOptions opts = FsIoOptions::DataType(datatype, false); + return WriteAll(f, *stat, ptr, offset, count, datatype, status, opts); + } + + int WriteOrdered(File &f, bool &stat_exists, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + FsIoOptions opts = FsIoOptions::DataType(datatype, false); + return WriteOrdered(f, *stat, ptr, count, datatype, status, opts); + } + + int AWriteOrdered(File &f, bool &stat_exists, const void *ptr, int count, + MPI_Datatype datatype, MPI_Request *request) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + FsIoOptions opts = FsIoOptions::DataType(datatype, false); + return AWriteOrdered(f, *stat, ptr, count, datatype, request, opts); + } + + int Read(File &f, bool &stat_exists, void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Read(f, *stat, ptr, count, datatype, status); + } + + int ARead(File &f, bool &stat_exists, void *ptr, int count, + MPI_Datatype datatype, MPI_Request *request) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return ARead(f, *stat, ptr, count, datatype, request); + } + + int ReadAll(File &f, bool &stat_exists, void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return ReadAll(f, *stat, ptr, count, datatype, status); + } + + int Write(File &f, bool &stat_exists, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Write(f, *stat, ptr, count, datatype, status); + } + + int AWrite(File &f, bool &stat_exists, const void *ptr, int count, + MPI_Datatype datatype, MPI_Request *request) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return AWrite(f, *stat, ptr, count, datatype, request); + } + + int WriteAll(File &f, bool &stat_exists, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return WriteAll(f, *stat, ptr, count, datatype, status); + } + + int Seek(File &f, bool &stat_exists, MPI_Offset offset, int whence) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Seek(f, *stat, offset, whence); + } + + int SeekShared(File &f, bool &stat_exists, MPI_Offset offset, int whence) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return SeekShared(f, *stat, offset, whence); + } +}; + +} // namespace hermes::adapter::fs + +/** Simplify access to the stateless StdioFs Singleton */ +#define HERMES_MPIIO_FS \ + hermes::EasyGlobalSingleton::GetInstance() +#define HERMES_STDIO_FS_T hermes::adapter::fs::MpiioFs* + +#endif // HERMES_ADAPTER_MPIIO_MPIIO_FS_API_H_ diff --git a/adapter/mpiio/mpiio_io_client.cc b/adapter/mpiio/mpiio_io_client.cc new file mode 100644 index 000000000..0178f720a --- /dev/null +++ b/adapter/mpiio/mpiio_io_client.cc @@ -0,0 +1,174 @@ +// +// Created by lukemartinlogan on 2/4/23. +// + +#include "mpiio_io_client.h" + +namespace hermes::adapter::fs { + +/** Allocate an fd for the file f */ +void MpiioIoClient::RealOpen(IoClientObject &f, + IoClientStats &stat, + const std::string &path) { + f.mpi_status_ = real_api->MPI_File_open(stat.comm_, + path.c_str(), + stat.amode_, + stat.info_, + &stat.mpi_fh_); + if (f.mpi_status_ != MPI_SUCCESS) { + f.status_ = false; + } + if (stat.amode_ & MPI_MODE_APPEND) { + stat.is_append_ = true; + } +} + +/** + * Called after real open. Allocates the Hermes representation of + * identifying file information, such as a hermes file descriptor + * and hermes file handler. These are not the same as POSIX file + * descriptor and STDIO file handler. + * */ +void MpiioIoClient::HermesOpen(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) { + f.hermes_mpi_fh_ = (MPI_File)fs_mdm.stat_; +} + +/** Synchronize \a file FILE f */ +int MpiioIoClient::RealSync(const IoClientObject &f, + const IoClientStats &stat) { + return real_api->MPI_File_sync(stat.mpi_fh_); +} + +/** Close \a file FILE f */ +int MpiioIoClient::RealClose(const IoClientObject &f, + const IoClientStats &stat) { + return real_api->MPI_File_close(&stat.mpi_fh_); +} + +/** + * Called before RealClose. Releases information provisioned during + * the allocation phase. + * */ +void MpiioIoClient::HermesClose(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) { + (void) f; (void) stat; (void) fs_mdm; +} + +/** Get initial statistics from the backend */ +void MpiioIoClient::InitBucketState(const lipc::charbuf &bkt_name, + const IoClientContext &opts, + GlobalIoClientState &stat) { +} + +/** Update backend statistics */ +void MpiioIoClient::UpdateBucketState(const IoClientContext &opts, + GlobalIoClientState &stat) { +} + +/** Initialize I/O context using count + datatype */ +size_t MpiioIoClient::IoSizeFromCount(int count, + MPI_Datatype datatype, + IoClientContext &opts) { + int datatype_size; + opts.mpi_type_ = datatype; + opts.mpi_count_ = count; + MPI_Type_size(datatype, &datatype_size); + return static_cast(count * datatype_size); +} + +/** Write blob to backend */ +void MpiioIoClient::WriteBlob(const lipc::charbuf &bkt_name, + const Blob &full_blob, + const IoClientContext &opts, + IoStatus &status) { + std::string filename = bkt_name.str(); + LOG(INFO) << "Write called for filename to destination: " << filename + << " on offset: " << opts.backend_off_ + << " and size: " << full_blob.size() << "." + << " file_size:" << stdfs::file_size(filename) + << " pid: " << getpid() << std::endl; + MPI_File fh; + int write_count = 0; + status.mpi_ret_ = real_api->MPI_File_open(MPI_COMM_SELF, filename.c_str(), + MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); + if (status.mpi_ret_ != MPI_SUCCESS) { + return; + } + + status.mpi_ret_ = real_api->MPI_File_seek(fh, opts.backend_off_, + MPI_SEEK_SET); + if (status.mpi_ret_ != MPI_SUCCESS) { + goto ERROR; + } + status.mpi_ret_ = real_api->MPI_File_write(fh, + full_blob.data(), + opts.mpi_count_, + opts.mpi_type_, + status.mpi_status_ptr_); + MPI_Get_count(status.mpi_status_ptr_, + opts.mpi_type_, &write_count); + if (write_count != opts.mpi_count_) { + LOG(ERROR) << "writing failed: wrote " << write_count + << " / " << opts.mpi_count_ + << "." << std::endl; + } + +ERROR: + real_api->MPI_File_close(&fh); + status.size_ = full_blob.size(); + UpdateIoStatus(opts.mpi_count_, status); +} + +/** Read blob from the backend */ +void MpiioIoClient::ReadBlob(const lipc::charbuf &bkt_name, + Blob &full_blob, + const IoClientContext &opts, + IoStatus &status) { + std::string filename = bkt_name.str(); + LOG(INFO) << "Read called for filename from destination: " << filename + << " on offset: " << opts.backend_off_ + << " and size: " << full_blob.size() << "." + << " file_size:" << stdfs::file_size(filename) + << " pid: " << getpid() << std::endl; + MPI_File fh; + int read_count = 0; + status.mpi_ret_ = real_api->MPI_File_open(MPI_COMM_SELF, filename.c_str(), + MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); + if (status.mpi_ret_ != MPI_SUCCESS) { + return; + } + + status.mpi_ret_ = real_api->MPI_File_seek(fh, opts.backend_off_, + MPI_SEEK_SET); + if (status.mpi_ret_ != MPI_SUCCESS) { + goto ERROR; + } + status.mpi_ret_ = real_api->MPI_File_read(fh, + full_blob.data(), + opts.mpi_count_, + opts.mpi_type_, + status.mpi_status_ptr_); + MPI_Get_count(status.mpi_status_ptr_, + opts.mpi_type_, &read_count); + if (read_count != opts.mpi_count_) { + LOG(ERROR) << "reading failed: read " << read_count + << " / " << opts.mpi_count_ + << "." << std::endl; + } + +ERROR: + real_api->MPI_File_close(&fh); + status.size_ = full_blob.size(); + UpdateIoStatus(opts.mpi_count_, status); +} + +/** Update the I/O status after a ReadBlob or WriteBlob */ +void MpiioIoClient::UpdateIoStatus(size_t count, IoStatus &status) { + status.mpi_status_ptr_->count_hi_and_cancelled = 0; + status.mpi_status_ptr_->count_lo = count; +} + +} // namespace hermes::adapter::fs \ No newline at end of file diff --git a/adapter/mpiio/mpiio_io_client.h b/adapter/mpiio/mpiio_io_client.h new file mode 100644 index 000000000..4832a73c4 --- /dev/null +++ b/adapter/mpiio/mpiio_io_client.h @@ -0,0 +1,101 @@ +// +// Created by lukemartinlogan on 2/4/23. +// + +#ifndef HERMES_ADAPTER_MPIIO_MPIIO_IO_CLIENT_H_ +#define HERMES_ADAPTER_MPIIO_MPIIO_IO_CLIENT_H_ + +#include + +#include "adapter/filesystem/filesystem_io_client.h" +#include "mpiio_api.h" + +using hermes::adapter::IoClientStats; +using hermes::adapter::IoClientContext; +using hermes::adapter::IoStatus; +using hermes::adapter::fs::MpiioApi; + +namespace hermes::adapter::fs { + +/** A class to represent STDIO IO file system */ +class MpiioIoClient : public hermes::adapter::fs::FilesystemIoClient { + private: + HERMES_MPIIO_API_T real_api; /**< pointer to real APIs */ + + public: + /** Default constructor */ + MpiioIoClient() { real_api = HERMES_MPIIO_API; } + + /** Virtual destructor */ + virtual ~MpiioIoClient() = default; + + public: + /** Allocate an fd for the file f */ + void RealOpen(IoClientObject &f, + IoClientStats &stat, + const std::string &path) override; + + /** + * Called after real open. Allocates the Hermes representation of + * identifying file information, such as a hermes file descriptor + * and hermes file handler. These are not the same as STDIO file + * descriptor and STDIO file handler. + * */ + void HermesOpen(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) override; + + /** Synchronize \a file FILE f */ + int RealSync(const IoClientObject &f, + const IoClientStats &stat) override; + + /** Close \a file FILE f */ + int RealClose(const IoClientObject &f, + const IoClientStats &stat) override; + + /** + * Called before RealClose. Releases information provisioned during + * the allocation phase. + * */ + void HermesClose(IoClientObject &f, + const IoClientStats &stat, + FilesystemIoClientObject &fs_mdm) override; + + /** Get initial statistics from the backend */ + void InitBucketState(const lipc::charbuf &bkt_name, + const IoClientContext &opts, + GlobalIoClientState &stat) override; + + /** Update backend statistics */ + void UpdateBucketState(const IoClientContext &opts, + GlobalIoClientState &stat) override; + + /** Initialize I/O context using count + datatype */ + static size_t IoSizeFromCount(int count, + MPI_Datatype datatype, + IoClientContext &opts); + + /** Write blob to backend */ + void WriteBlob(const lipc::charbuf &bkt_name, + const Blob &full_blob, + const IoClientContext &opts, + IoStatus &status) override; + + /** Read blob from the backend */ + void ReadBlob(const lipc::charbuf &bkt_name, + Blob &full_blob, + const IoClientContext &opts, + IoStatus &status) override; + + /** Update the I/O status after a ReadBlob or WriteBlob */ + void UpdateIoStatus(size_t count, IoStatus &status); +}; + +} // namespace hermes::adapter::fs + +/** Simplify access to the stateless StdioIoClient Singleton */ +#define HERMES_MPIIO_IO_CLIENT \ + hermes::EasyGlobalSingleton::GetInstance() +#define HERMES_MPIIO_IO_CLIENT_T hermes::adapter::fs::MpiioIoClient* + +#endif // HERMES_ADAPTER_MPIIO_MPIIO_IO_CLIENT_H_ diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 34f4ddfde..60df9616e 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -70,7 +70,7 @@ void PosixIoClient::HermesClose(IoClientObject &f, /** Get initial statistics from the backend */ void PosixIoClient::InitBucketState(const lipc::charbuf &bkt_name, const IoClientContext &opts, - GlobalIoClientStatse &stat) { + GlobalIoClientState &stat) { stat.true_size_ = 0; std::string filename = bkt_name.str(); int fd = real_api->open(filename.c_str(), O_RDONLY); @@ -83,7 +83,7 @@ void PosixIoClient::InitBucketState(const lipc::charbuf &bkt_name, /** Update backend statistics */ void PosixIoClient::UpdateBucketState(const IoClientContext &opts, - GlobalIoClientStatse &stat) { + GlobalIoClientState &stat) { stat.true_size_ = std::max(stat.true_size_, opts.backend_off_ + opts.backend_size_); } @@ -101,10 +101,10 @@ void PosixIoClient::WriteBlob(const lipc::charbuf &bkt_name, << std::endl; int fd = real_api->open(bkt_name.str().c_str(), O_RDWR | O_CREAT); if (fd < 0) { - status.posix_ret_ = 0; + status.size_ = 0; return; } - status.posix_ret_ = real_api->pwrite(fd, + status.size_ = real_api->pwrite(fd, full_blob.data(), full_blob.size(), opts.backend_off_); @@ -124,10 +124,10 @@ void PosixIoClient::ReadBlob(const lipc::charbuf &bkt_name, << std::endl; int fd = real_api->open(bkt_name.str().c_str(), O_RDONLY); if (fd < 0) { - status.posix_ret_ = 0; + status.size_ = 0; return; } - status.posix_ret_ = real_api->pread(fd, + status.size_ = real_api->pread(fd, full_blob.data(), full_blob.size(), opts.backend_off_); diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h index dcc3cb161..f10118dce 100644 --- a/adapter/posix/posix_io_client.h +++ b/adapter/posix/posix_io_client.h @@ -73,11 +73,11 @@ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { /** Get initial statistics from the backend */ void InitBucketState(const lipc::charbuf &bkt_name, const IoClientContext &opts, - GlobalIoClientStatse &stat) override; + GlobalIoClientState &stat) override; /** Update backend statistics */ void UpdateBucketState(const IoClientContext &opts, - GlobalIoClientStatse &stat) override; + GlobalIoClientState &stat) override; /** Write blob to backend */ void WriteBlob(const lipc::charbuf &bkt_name, diff --git a/adapter/stdio/CMakeLists.txt b/adapter/stdio/CMakeLists.txt index 7eb1c7f6b..f006048e5 100644 --- a/adapter/stdio/CMakeLists.txt +++ b/adapter/stdio/CMakeLists.txt @@ -19,7 +19,7 @@ set(INTERCEPTOR_DEPS hermes_stdio_io_client hermes_fs_base) add_library(hermes_stdio SHARED - ${CMAKE_CURRENT_SOURCE_DIR}/stdio.cc) + ${CMAKE_CURRENT_SOURCE_DIR}/stdio_api.cc) add_dependencies(hermes_stdio ${INTERCEPTOR_DEPS}) target_link_libraries(hermes_stdio ${INTERCEPTOR_DEPS}) target_compile_options(hermes_stdio PUBLIC -fPIC) diff --git a/adapter/stdio/stdio.cc b/adapter/stdio/stdio_api.cc similarity index 100% rename from adapter/stdio/stdio.cc rename to adapter/stdio/stdio_api.cc diff --git a/adapter/stdio/stdio_io_client.cc b/adapter/stdio/stdio_io_client.cc index 4627f65b9..a42d268a9 100644 --- a/adapter/stdio/stdio_io_client.cc +++ b/adapter/stdio/stdio_io_client.cc @@ -66,13 +66,13 @@ void StdioIoClient::HermesClose(IoClientObject &f, /** Get initial statistics from the backend */ void StdioIoClient::InitBucketState(const lipc::charbuf &bkt_name, const IoClientContext &opts, - GlobalIoClientStatse &stat) { + GlobalIoClientState &stat) { // TODO(llogan) } /** Update backend statistics */ void StdioIoClient::UpdateBucketState(const IoClientContext &opts, - GlobalIoClientStatse &stat) { + GlobalIoClientState &stat) { stat.true_size_ = std::max(stat.true_size_, opts.backend_off_ + opts.backend_size_); } @@ -89,11 +89,11 @@ void StdioIoClient::WriteBlob(const lipc::charbuf &bkt_name, << " file_size:" << stdfs::file_size(filename) << std::endl; FILE *fh = real_api->fopen(filename.c_str(), "r+"); if (fh == nullptr) { - status.posix_ret_ = 0; + status.size_ = 0; return; } real_api->fseek(fh, opts.backend_off_, SEEK_SET); - status.posix_ret_ = real_api->fwrite(full_blob.data(), + status.size_ = real_api->fwrite(full_blob.data(), sizeof(char), full_blob.size(), fh); @@ -112,11 +112,11 @@ void StdioIoClient::ReadBlob(const lipc::charbuf &bkt_name, << " file_size:" << stdfs::file_size(filename) << std::endl; FILE *fh = real_api->fopen(filename.c_str(), "r"); if (fh == nullptr) { - status.posix_ret_ = 0; + status.size_ = 0; return; } real_api->fseek(fh, opts.backend_off_, SEEK_SET); - status.posix_ret_ = real_api->fread(full_blob.data(), + status.size_ = real_api->fread(full_blob.data(), sizeof(char), full_blob.size(), fh); diff --git a/adapter/stdio/stdio_io_client.h b/adapter/stdio/stdio_io_client.h index 5bfa57679..883073edb 100644 --- a/adapter/stdio/stdio_io_client.h +++ b/adapter/stdio/stdio_io_client.h @@ -72,11 +72,11 @@ class StdioIoClient : public hermes::adapter::fs::FilesystemIoClient { /** Get initial statistics from the backend */ void InitBucketState(const lipc::charbuf &bkt_name, const IoClientContext &opts, - GlobalIoClientStatse &stat) override; + GlobalIoClientState &stat) override; /** Update backend statistics */ void UpdateBucketState(const IoClientContext &opts, - GlobalIoClientStatse &stat) override; + GlobalIoClientState &stat) override; /** Write blob to backend */ void WriteBlob(const lipc::charbuf &bkt_name, diff --git a/data_stager/stagers/posix_stager.cc b/data_stager/stagers/posix_stager.cc index 1dea825e7..ac71d92e3 100644 --- a/data_stager/stagers/posix_stager.cc +++ b/data_stager/stagers/posix_stager.cc @@ -15,7 +15,7 @@ using hermes::adapter::fs::PosixFS; using hermes::api::PlacementPolicyConv; using hermes::api::PlacementPolicy; -using hermes::adapter::fs::IoOptions; +using hermes::adapter::fs::FsIoOptions; namespace stdfs = std::filesystem; namespace hermes { @@ -64,7 +64,7 @@ void PosixStager::FileStageIn(std::string path, IoStatus io_status; File f = fs_api.Open(stat, path); fs_api.Read(f, stat_exists, buf.data(), off, size, - io_status, IoOptions::WithParallelDpe(dpe)); + io_status, FsIoOptions::WithParallelDpe(dpe)); fs_api.Close(f, stat_exists, false); } diff --git a/src/metadata_types.h b/src/metadata_types.h index f545d5b59..527d34d2f 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -19,7 +19,7 @@ namespace hermes { -using adapter::GlobalIoClientStatse; +using adapter::GlobalIoClientState; using api::Blob; struct BucketInfo; /** Forward declaration of BucketInfo */ struct BlobInfo; /** Forward declaration of BlobInfo */ @@ -229,7 +229,7 @@ struct ShmHeader : public lipc::ShmBaseHeader { lipc::TypedPointer name_ar_; lipc::TypedPointer> blobs_ar_; size_t internal_size_; - GlobalIoClientStatse client_state_; + GlobalIoClientState client_state_; }; /** Metadata for a Bucket */ From 4b67fbdd63eece6e794c0a2e77bd191dbd77bbe4 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 5 Feb 2023 02:33:51 -0600 Subject: [PATCH 117/511] Add dynamic path inclusion and exclusion. Add per-file page size. Adapter tests compile --- adapter/adapter_constants.h | 16 + adapter/adapter_types.h | 74 +++++ adapter/filesystem/filesystem.cc | 36 ++- adapter/filesystem/filesystem.h | 26 +- adapter/filesystem/filesystem_io_client.h | 2 +- adapter/filesystem/filesystem_mdm.h | 19 ++ adapter/io_client/io_client.h | 11 +- adapter/mapper/abstract_mapper.h | 4 +- adapter/mapper/balanced_mapper.cc | 6 +- adapter/mapper/balanced_mapper.h | 3 +- adapter/mpiio/mpiio_api.cc | 306 +++++++----------- adapter/mpiio/mpiio_fs_api.h | 18 +- adapter/mpiio/mpiio_io_client.cc | 2 +- adapter/mpiio/mpiio_io_client.h | 2 +- adapter/posix/CMakeLists.txt | 2 +- adapter/posix/{posix.cc => posix_api.cc} | 0 adapter/posix/posix_io_client.cc | 2 +- adapter/posix/posix_io_client.h | 2 +- adapter/stdio/stdio_io_client.cc | 2 +- adapter/stdio/stdio_io_client.h | 2 +- adapter/test/CMakeLists.txt | 16 +- adapter/test/stdio/CMakeLists.txt | 10 +- adapter/test/stdio/adapter_utils_test.cc | 104 ------ .../stdio_adapter_low_buffer_space_test.cpp | 2 +- .../test/stdio/stdio_adapter_mapper_test.cpp | 15 +- .../test/stdio/stdio_adapter_mode_test.cpp | 24 +- adapter/test/stdio/stdio_adapter_mpi_test.cpp | 4 +- adapter/test/stdio/stdio_adapter_test.cpp | 2 +- src/config_client.cc | 42 ++- src/config_client.h | 52 ++- src/thread_pool.h | 18 +- 31 files changed, 420 insertions(+), 404 deletions(-) create mode 100644 adapter/adapter_constants.h create mode 100644 adapter/adapter_types.h rename adapter/posix/{posix.cc => posix_api.cc} (100%) delete mode 100644 adapter/test/stdio/adapter_utils_test.cc diff --git a/adapter/adapter_constants.h b/adapter/adapter_constants.h new file mode 100644 index 000000000..c6a78a033 --- /dev/null +++ b/adapter/adapter_constants.h @@ -0,0 +1,16 @@ +// +// Created by lukemartinlogan on 2/4/23. +// + +#ifndef HERMES_ADAPTER_ADAPTER_CONSTANTS_H_ +#define HERMES_ADAPTER_ADAPTER_CONSTANTS_H_ + +#include "mapper/abstract_mapper.h" + +namespace hermes::adapter { + +static inline const MapperType kMapperType = MapperType::kBalancedMapper; + +} + +#endif // HERMES_ADAPTER_ADAPTER_CONSTANTS_H_ diff --git a/adapter/adapter_types.h b/adapter/adapter_types.h new file mode 100644 index 000000000..ae3f6eb4a --- /dev/null +++ b/adapter/adapter_types.h @@ -0,0 +1,74 @@ +// +// Created by lukemartinlogan on 2/4/23. +// + +#ifndef HERMES_ADAPTER_ADAPTER_TYPES_H_ +#define HERMES_ADAPTER_ADAPTER_TYPES_H_ + +namespace hermes::adapter { + +/** Adapter types */ +enum class AdapterType { + kNone, + kPosix, + kStdio, + kMpiio, + kPubsub, + kVfd +}; + +/** Adapter modes */ +enum class AdapterMode { + kDefault, + kBypass, + kScratch, + kWorkflow +}; + +/** + * Per-Object Adapter Settings. + * An object may be a file, for example. + * */ +struct AdapterObjectConfig { + AdapterMode mode_; + size_t page_size_; +}; + +/** Adapter Mode converter */ +class AdapterModeConv { + public: + static std::string str(AdapterMode mode) { + switch(mode) { + case AdapterMode::kDefault: { + return "AdapterMode::kDefault"; + } + case AdapterMode::kBypass: { + return "AdapterMode::kBypass"; + } + case AdapterMode::kScratch: { + return "AdapterMode::kScratch"; + } + case AdapterMode::kWorkflow: { + return "AdapterMode::kWorkflow"; + } + } + } + + static AdapterMode to_enum(const std::string &mode) { + if (mode.find("kDefault") != std::string::npos) { + return AdapterMode::kDefault; + } else if (mode.find("kBypass") != std::string::npos) { + return AdapterMode::kBypass; + } else if (mode.find("kScratch") != std::string::npos) { + return AdapterMode::kScratch; + } else if (mode.find("kWorkflow") != std::string::npos) { + return AdapterMode::kWorkflow; + } + return AdapterMode::kDefault; + } +}; + + +} // namespace hermes + +#endif // HERMES_ADAPTER_ADAPTER_TYPES_H_ diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 7170603a6..8f2b03b73 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -37,6 +37,9 @@ void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { FsIoOptions opts; opts.type_ = type_; stat.bkt_id_ = HERMES->GetBucket(path, ctx_, opts); + // TODO(llogan): can avoid two unordered_map queries here + stat.adapter_mode_ = mdm->GetAdapterMode(path); + stat.page_size_ = mdm->GetAdapterPageSize(path); std::shared_ptr exists = mdm->Find(f); if (!exists) { LOG(INFO) << "File not opened before by adapter" << std::endl; @@ -66,10 +69,10 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, size_t ret; BlobPlacements mapping; - auto mapper = MapperFactory().Get(MapperType::kBalancedMapper); - mapper->map(off, total_size, mapping); + size_t kPageSize = stat.page_size_; size_t data_offset = 0; - size_t kPageSize = HERMES->client_config_.file_page_size_; + auto mapper = MapperFactory().Get(MapperType::kBalancedMapper); + mapper->map(off, total_size, kPageSize, mapping); for (const auto &p : mapping) { const Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); @@ -78,6 +81,7 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, opts.type_ = type_; opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; + opts.mode_ = stat.adapter_mode_; bkt->PartialPutOrCreate(blob_name.str(), blob_wrap, p.blob_off_, @@ -104,10 +108,10 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, size_t ret; BlobPlacements mapping; - auto mapper = MapperFactory().Get(MapperType::kBalancedMapper); - mapper->map(off, total_size, mapping); + size_t kPageSize = stat.page_size_; size_t data_offset = 0; - size_t kPageSize = HERMES->client_config_.file_page_size_; + auto mapper = MapperFactory().Get(MapperType::kBalancedMapper); + mapper->map(off, total_size, kPageSize, mapping); for (const auto &p : mapping) { Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); @@ -116,6 +120,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; opts.type_ = type_; + opts.mode_ = stat.adapter_mode_; bkt->PartialGetOrCreate(blob_name.str(), blob_wrap, p.blob_off_, @@ -135,10 +140,9 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, FsIoOptions opts) { - /*(void) io_status; + (void) io_status; LOG(INFO) << "Starting an asynchronous write" << std::endl; - auto pool = - Singleton::GetInstance(kNumThreads); + auto pool = HERMES_FS_THREAD_POOL; HermesRequest *hreq = new HermesRequest(); auto lambda = [](Filesystem *fs, File &f, AdapterStat &stat, const void *ptr, @@ -150,15 +154,14 @@ HermesRequest* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, hreq->return_future = pool->run(func); auto mdm = HERMES_FS_METADATA_MANAGER; mdm->request_map.emplace(req_id, hreq); - return hreq;*/ + return hreq;/**/ } HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, size_t off, size_t total_size, size_t req_id, IoStatus &io_status, FsIoOptions opts) { - /*(void) io_status; - auto pool = - Singleton::GetInstance(kNumThreads); + (void) io_status; + auto pool = HERMES_FS_THREAD_POOL; HermesRequest *hreq = new HermesRequest(); auto lambda = [](Filesystem *fs, File &f, AdapterStat &stat, void *ptr, @@ -170,11 +173,11 @@ HermesRequest* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, hreq->return_future = pool->run(func); auto mdm = HERMES_FS_METADATA_MANAGER; mdm->request_map.emplace(req_id, hreq); - return hreq;*/ + return hreq; } size_t Filesystem::Wait(uint64_t req_id) { - /*auto mdm = HERMES_FS_METADATA_MANAGER; + auto mdm = HERMES_FS_METADATA_MANAGER; auto req_iter = mdm->request_map.find(req_id); if (req_iter == mdm->request_map.end()) { return 0; @@ -182,8 +185,7 @@ size_t Filesystem::Wait(uint64_t req_id) { HermesRequest *req = (*req_iter).second; size_t ret = req->return_future.get(); delete req; - return ret;*/ - return 0; + return ret; } void Filesystem::Wait(std::vector &req_ids, diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index 3fbda4d0e..ca8fb562e 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -50,6 +50,10 @@ struct AdapterStat : public IoClientStats { std::shared_ptr bkt_id_; /**< bucket associated with the file */ /** VBucket for persisting data asynchronously. */ std::shared_ptr vbkt_id_; + /** Page size used for file */ + size_t page_size_; + /** Mode used for adapter */ + AdapterMode adapter_mode_; /** Default constructor. */ AdapterStat() @@ -70,6 +74,8 @@ struct AdapterStat : public IoClientStats { * For now, nothing additional than the typical IoClientContext. * */ struct FsIoOptions : public IoClientContext { + AdapterMode mode_; /**< Mode used for the adapter */ + /** Default constructor */ FsIoOptions() : IoClientContext() { flags_.SetBits(HERMES_FS_SEEK); @@ -240,7 +246,7 @@ class Filesystem { } /** real close */ - int RealClose(const IoClientObject &f, const AdapterStat &stat) { + int RealClose(const IoClientObject &f, AdapterStat &stat) { return io_client_->RealClose(f, stat); } @@ -251,20 +257,14 @@ class Filesystem { return false; } std::string abs_path = stdfs::weakly_canonical(path).string(); - auto &path_inclusions = HERMES->client_config_.path_inclusions_; - auto &path_exclusions = HERMES->client_config_.path_exclusions_; - // Check if path is included - for (const std::string &pth : path_inclusions) { - if (abs_path.rfind(pth) != std::string::npos) { - return true; - } - } - // Check if path is excluded - for (const std::string &pth : path_exclusions) { - if (abs_path.rfind(pth) != std::string::npos) { - return false; + auto &paths = HERMES->client_config_.path_list_; + // Check if path is included or excluded + for (std::pair &pth : paths) { + if (abs_path.rfind(pth.first) != std::string::npos) { + return pth.second; } } + // Assume it is excluded return false; } }; diff --git a/adapter/filesystem/filesystem_io_client.h b/adapter/filesystem/filesystem_io_client.h index 575ca8e09..2eeb0e496 100644 --- a/adapter/filesystem/filesystem_io_client.h +++ b/adapter/filesystem/filesystem_io_client.h @@ -98,7 +98,7 @@ class FilesystemIoClient : public IoClient { /** real close */ virtual int RealClose(const IoClientObject &f, - const IoClientStats &stat) = 0; + IoClientStats &stat) = 0; /** * Called before RealClose. Releases information provisioned during diff --git a/adapter/filesystem/filesystem_mdm.h b/adapter/filesystem/filesystem_mdm.h index be88ae228..62ab950e4 100644 --- a/adapter/filesystem/filesystem_mdm.h +++ b/adapter/filesystem/filesystem_mdm.h @@ -18,6 +18,7 @@ #include "file.h" #include "filesystem_io_client.h" #include "filesystem.h" +#include "thread_pool.h" namespace hermes::adapter::fs { @@ -38,6 +39,21 @@ class MetadataManager { /** Constructor */ MetadataManager() = default; + /** Get the current adapter mode */ + AdapterMode GetBaseAdapterMode() { + return HERMES->client_config_.GetBaseAdapterMode(); + } + + /** Get the adapter mode for a particular file */ + AdapterMode GetAdapterMode(const std::string &path) { + return HERMES->client_config_.GetAdapterConfig(path).mode_; + } + + /** Get the adapter page size for a particular file */ + size_t GetAdapterPageSize(const std::string &path) { + return HERMES->client_config_.GetAdapterConfig(path).page_size_; + } + /** * Create a metadata entry for filesystem adapters given File handler. * @param f original file handler of the file on the destination @@ -82,4 +98,7 @@ class MetadataManager { hermes::GlobalSingleton::GetInstance() #define HERMES_FS_METADATA_MANAGER_T hermes::adapter::fs::MetadataManager* +#define HERMES_FS_THREAD_POOL \ + hermes::EasySingleton::GetInstance() + #endif // HERMES_ADAPTER_METADATA_MANAGER_H diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index 6145e2beb..04a94720e 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -15,22 +15,13 @@ #include #include "hermes_types.h" +#include "adapter/adapter_types.h" #include namespace hapi = hermes::api; namespace hermes::adapter { -/** Adapter types */ -enum class AdapterType { - kNone, - kPosix, - kStdio, - kMpiio, - kPubsub, - kVfd -}; - /** Represents an object in the I/O client (e.g., a file) */ struct IoClientObject { AdapterType type_; /**< Client to forward I/O request to */ diff --git a/adapter/mapper/abstract_mapper.h b/adapter/mapper/abstract_mapper.h index dd352b225..843643d8f 100644 --- a/adapter/mapper/abstract_mapper.h +++ b/adapter/mapper/abstract_mapper.h @@ -60,10 +60,12 @@ class AbstractMapper { * * @param off offset * @param size size + * @param page_size the page division factor * @param ps BLOB placement * */ - virtual void map(size_t off, size_t size, BlobPlacements &ps) = 0; + virtual void map(size_t off, size_t size, size_t page_size, + BlobPlacements &ps) = 0; }; } // namespace hermes::adapter diff --git a/adapter/mapper/balanced_mapper.cc b/adapter/mapper/balanced_mapper.cc index b1e335287..028844955 100644 --- a/adapter/mapper/balanced_mapper.cc +++ b/adapter/mapper/balanced_mapper.cc @@ -20,11 +20,13 @@ namespace hermes::adapter { * Convert a range defined by \a off and \a size into specific * blob placements. */ -void BalancedMapper::map(size_t off, size_t size, BlobPlacements &ps) { +void BalancedMapper::map(size_t off, size_t size, + size_t page_size, + BlobPlacements &ps) { VLOG(1) << "Mapping File with offset:" << off << " and size:" << size << "." << std::endl; - size_t kPageSize = HERMES->client_config_.file_page_size_; + size_t kPageSize = page_size; size_t size_mapped = 0; while (size > size_mapped) { BlobPlacement p; diff --git a/adapter/mapper/balanced_mapper.h b/adapter/mapper/balanced_mapper.h index 343efc50c..6cfc03fd7 100644 --- a/adapter/mapper/balanced_mapper.h +++ b/adapter/mapper/balanced_mapper.h @@ -27,7 +27,8 @@ class BalancedMapper : public AbstractMapper { * This method maps the current Operation to Hermes data structures. * */ - void map(size_t off, size_t size, BlobPlacements &ps) override; + void map(size_t off, size_t size, size_t page_size, + BlobPlacements &ps) override; }; } // namespace hermes::adapter diff --git a/adapter/mpiio/mpiio_api.cc b/adapter/mpiio/mpiio_api.cc index a12f752b6..e1eb6c305 100644 --- a/adapter/mpiio/mpiio_api.cc +++ b/adapter/mpiio/mpiio_api.cc @@ -17,14 +17,11 @@ bool mpiio_intercepted = true; #include #include "mpiio_api.h" -#include "fs_api.h" +#include "mpiio_fs_api.h" #include "constants.h" #include "singleton.h" #include "interceptor.h" -#include "interceptor.cc" - -#include "thread_pool.h" /** * Namespace declarations @@ -32,28 +29,13 @@ bool mpiio_intercepted = true; using hermes::ThreadPool; using hermes::adapter::fs::MetadataManager; using hermes::adapter::fs::File; -using hermes::adapter::mpiio::API; -using hermes::adapter::mpiio::MpiioFS; -using hermes::adapter::mpiio::MpiioSeekModeConv; +using hermes::adapter::fs::AdapterStat; +using hermes::adapter::fs::MpiioApi; +using hermes::adapter::fs::MpiioFs; +using hermes::adapter::fs::MpiioSeekModeConv; using hermes::Singleton; namespace hapi = hermes::api; -namespace stdfs = std::filesystem; -using hermes::adapter::WeaklyCanonical; - -/** - * Internal Functions. - */ - - -inline bool IsTracked(MPI_File *fh) { - if (hermes::adapter::exit) return false; - auto mdm = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - File f; f.mpi_fh_ = (*fh); fs_api->InitFile(f); - auto [stat, exists] = mdm->Find(f); - return exists; -} extern "C" { @@ -61,33 +43,24 @@ extern "C" { * MPI */ int HERMES_DECL(MPI_Init)(int *argc, char ***argv) { - auto real_api = Singleton::GetInstance(); - int status = real_api->MPI_Init(argc, argv); - if (status == 0) { - LOG(INFO) << "MPI Init intercepted." << std::endl; - auto mdm = Singleton::GetInstance(); - mdm->InitializeHermes(true); - Singleton::GetInstance(hermes::adapter::fs::kNumThreads); - } - return status; + LOG(INFO) << "MPI Init intercepted." << std::endl; + auto real_api = HERMES_MPIIO_API; + return real_api->MPI_Init(argc, argv); } int HERMES_DECL(MPI_Finalize)(void) { LOG(INFO) << "MPI Finalize intercepted." << std::endl; - auto real_api = Singleton::GetInstance(); - auto mdm = Singleton::GetInstance(); - mdm->FinalizeHermes(); - int status = real_api->MPI_Finalize(); - return status; + auto real_api = HERMES_MPIIO_API; + return real_api->MPI_Finalize(); } int HERMES_DECL(MPI_Wait)(MPI_Request *req, MPI_Status *status) { - auto fs_api = Singleton::GetInstance(); + auto fs_api = HERMES_MPIIO_FS; return fs_api->Wait(req, status); } int HERMES_DECL(MPI_Waitall)(int count, MPI_Request *req, MPI_Status *status) { - auto fs_api = Singleton::GetInstance(); + auto fs_api = HERMES_MPIIO_FS; return fs_api->WaitAll(count, req, status); } @@ -96,17 +69,17 @@ int HERMES_DECL(MPI_Waitall)(int count, MPI_Request *req, MPI_Status *status) { */ int HERMES_DECL(MPI_File_open)(MPI_Comm comm, const char *filename, int amode, MPI_Info info, MPI_File *fh) { - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (hermes::adapter::IsTracked(filename)) { + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsPathTracked(filename)) { LOG(INFO) << "Intercept MPI_File_open for filename: " << filename << " and mode: " << amode << " is tracked." << std::endl; AdapterStat stat; - stat.comm = comm; - stat.amode = amode; - stat.info = info; + stat.comm_ = comm; + stat.amode_ = amode; + stat.info_ = info; File f = fs_api->Open(stat, filename); - (*fh) = f.mpi_fh_; + (*fh) = stat.mpi_fh_; return f.mpi_status_; } return real_api->MPI_File_open(comm, filename, amode, info, fh); @@ -114,12 +87,10 @@ int HERMES_DECL(MPI_File_open)(MPI_Comm comm, const char *filename, int amode, int HERMES_DECL(MPI_File_close)(MPI_File *fh) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(fh)) { - File f; - f.mpi_fh_ = *fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(fh)) { + File f; f.hermes_mpi_fh_ = *fh; return fs_api->Close(f, stat_exists); } return real_api->MPI_File_close(fh); @@ -127,12 +98,10 @@ int HERMES_DECL(MPI_File_close)(MPI_File *fh) { int HERMES_DECL(MPI_File_seek)(MPI_File fh, MPI_Offset offset, int whence) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; return fs_api->Seek(f, stat_exists, offset, whence); } return real_api->MPI_File_seek(fh, offset, whence); @@ -141,14 +110,12 @@ int HERMES_DECL(MPI_File_seek)(MPI_File fh, MPI_Offset offset, int whence) { int HERMES_DECL(MPI_File_seek_shared)(MPI_File fh, MPI_Offset offset, int whence) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { LOG(INFO) << "Intercept MPI_File_seek_shared offset:" << offset << " whence:" << whence << "." << std::endl; - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + File f; f.hermes_mpi_fh_ = fh; return fs_api->SeekShared(f, stat_exists, offset, whence); } return real_api->MPI_File_seek_shared(fh, offset, whence); @@ -156,12 +123,10 @@ int HERMES_DECL(MPI_File_seek_shared)(MPI_File fh, MPI_Offset offset, int HERMES_DECL(MPI_File_get_position)(MPI_File fh, MPI_Offset *offset) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; (*offset) = static_cast(fs_api->Tell(f, stat_exists)); return MPI_SUCCESS; } @@ -171,13 +136,11 @@ int HERMES_DECL(MPI_File_get_position)(MPI_File fh, MPI_Offset *offset) { int HERMES_DECL(MPI_File_read_all)(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { LOG(INFO) << "Intercept MPI_File_read_all." << std::endl; - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + File f; f.hermes_mpi_fh_ = fh; return fs_api->ReadAll(f, stat_exists, buf, count, datatype, status); } return real_api->MPI_File_read_all(fh, buf, count, datatype, status); @@ -186,12 +149,10 @@ int HERMES_DECL(MPI_File_read_at_all)(MPI_File fh, MPI_Offset offset, void *buf, int count, MPI_Datatype datatype, MPI_Status *status) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; return fs_api->ReadAll(f, stat_exists, buf, offset, count, datatype, status); } @@ -202,12 +163,10 @@ int HERMES_DECL(MPI_File_read_at)(MPI_File fh, MPI_Offset offset, void *buf, int count, MPI_Datatype datatype, MPI_Status *status) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; return fs_api->Read(f, stat_exists, buf, offset, count, datatype, status); } return real_api->MPI_File_read_at(fh, offset, buf, count, datatype, status); @@ -215,12 +174,10 @@ int HERMES_DECL(MPI_File_read_at)(MPI_File fh, MPI_Offset offset, void *buf, int HERMES_DECL(MPI_File_read)(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; int ret = fs_api->Read(f, stat_exists, buf, count, datatype, status); if (stat_exists) return ret; } @@ -230,12 +187,10 @@ int HERMES_DECL(MPI_File_read_ordered)(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; return fs_api->ReadOrdered(f, stat_exists, buf, count, datatype, status); } return real_api->MPI_File_read_ordered(fh, buf, count, datatype, status); @@ -244,13 +199,11 @@ int HERMES_DECL(MPI_File_read_shared)(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { LOG(INFO) << "Intercept MPI_File_read_shared." << std::endl; - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + File f; f.hermes_mpi_fh_ = fh; return fs_api->Read(f, stat_exists, buf, count, datatype, status); } return real_api->MPI_File_read_shared(fh, buf, count, datatype, status); @@ -258,15 +211,12 @@ int HERMES_DECL(MPI_File_read_shared)(MPI_File fh, void *buf, int count, int HERMES_DECL(MPI_File_write_all)(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Status *status) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { LOG(INFO) << "Intercept MPI_File_write_all." << std::endl; - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); - int ret = fs_api->WriteAll(f, stat_exists, buf, count, datatype, status); - if (stat_exists) return ret; + File f; f.hermes_mpi_fh_ = fh; + return fs_api->WriteAll(f, stat_exists, buf, count, datatype, status); } return real_api->MPI_File_write_all(fh, buf, count, datatype, status); } @@ -275,15 +225,12 @@ int HERMES_DECL(MPI_File_write_at_all)(MPI_File fh, MPI_Offset offset, MPI_Datatype datatype, MPI_Status *status) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); - int ret = - fs_api->WriteAll(f, stat_exists, buf, offset, count, datatype, status); - if (stat_exists) return ret; + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; + return fs_api->WriteAll(f, stat_exists, buf, + offset, count, datatype, status); } return real_api->MPI_File_write_at_all(fh, offset, buf, count, datatype, status); @@ -292,13 +239,11 @@ int HERMES_DECL(MPI_File_write_at)(MPI_File fh, MPI_Offset offset, const void *buf, int count, MPI_Datatype datatype, MPI_Status *status) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; LOG(INFO) << "In MPI_File_write_at" << std::endl; - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; return fs_api->Write(f, stat_exists, buf, offset, count, datatype, status); } return real_api->MPI_File_write_at(fh, offset, buf, count, datatype, status); @@ -306,15 +251,12 @@ int HERMES_DECL(MPI_File_write_at)(MPI_File fh, MPI_Offset offset, int HERMES_DECL(MPI_File_write)(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Status *status) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; LOG(INFO) << "In MPI_File_write" << std::endl; - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); - int ret = fs_api->Write(f, stat_exists, buf, count, datatype, status); - if (stat_exists) return ret; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; + return fs_api->Write(f, stat_exists, buf, count, datatype, status); } return real_api->MPI_File_write(fh, buf, count, datatype, status); } @@ -322,12 +264,10 @@ int HERMES_DECL(MPI_File_write_ordered)(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Status *status) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; return fs_api->WriteOrdered(f, stat_exists, buf, count, datatype, status); } return real_api->MPI_File_write_ordered(fh, buf, count, datatype, status); @@ -336,13 +276,11 @@ int HERMES_DECL(MPI_File_write_shared)(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Status *status) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { // NOTE(llogan): originally WriteOrdered - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + File f; f.hermes_mpi_fh_ = fh; return fs_api->WriteOrdered(f, stat_exists, buf, count, datatype, status); } return real_api->MPI_File_write_shared(fh, buf, count, datatype, status); @@ -355,12 +293,10 @@ int HERMES_DECL(MPI_File_iread_at)(MPI_File fh, MPI_Offset offset, void *buf, int count, MPI_Datatype datatype, MPI_Request *request) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; fs_api->ARead(f, stat_exists, buf, offset, count, datatype, request); return MPI_SUCCESS; } @@ -369,12 +305,10 @@ int HERMES_DECL(MPI_File_iread_at)(MPI_File fh, MPI_Offset offset, void *buf, int HERMES_DECL(MPI_File_iread)(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Request *request) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; fs_api->ARead(f, stat_exists, buf, count, datatype, request); } return real_api->MPI_File_iread(fh, buf, count, datatype, request); @@ -383,12 +317,10 @@ int HERMES_DECL(MPI_File_iread_shared)(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Request *request) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; fs_api->ARead(f, stat_exists, buf, count, datatype, request); return MPI_SUCCESS; } @@ -399,12 +331,10 @@ int HERMES_DECL(MPI_File_iwrite_at)(MPI_File fh, MPI_Offset offset, MPI_Datatype datatype, MPI_Request *request) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; fs_api->AWrite(f, stat_exists, buf, offset, count, datatype, request); return MPI_SUCCESS; } @@ -415,12 +345,10 @@ int HERMES_DECL(MPI_File_iwrite_at)(MPI_File fh, MPI_Offset offset, int HERMES_DECL(MPI_File_iwrite)(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Request *request) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; fs_api->AWrite(f, stat_exists, buf, count, datatype, request); return MPI_SUCCESS; } @@ -430,12 +358,10 @@ int HERMES_DECL(MPI_File_iwrite_shared)(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Request *request) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; fs_api->AWriteOrdered(f, stat_exists, buf, count, datatype, request); return MPI_SUCCESS; } @@ -447,12 +373,10 @@ int HERMES_DECL(MPI_File_iwrite_shared)(MPI_File fh, const void *buf, int count, */ int HERMES_DECL(MPI_File_sync)(MPI_File fh) { bool stat_exists; - auto real_api = Singleton::GetInstance(); - auto fs_api = Singleton::GetInstance(); - if (IsTracked(&fh)) { - File f; - f.mpi_fh_ = fh; - fs_api->InitFile(f); + auto real_api = HERMES_MPIIO_API; + auto fs_api = HERMES_MPIIO_FS; + if (fs_api->IsMpiFpTracked(&fh)) { + File f; f.hermes_mpi_fh_ = fh; fs_api->Sync(f, stat_exists); return 0; } diff --git a/adapter/mpiio/mpiio_fs_api.h b/adapter/mpiio/mpiio_fs_api.h index 0a714cfd7..bc9c39335 100644 --- a/adapter/mpiio/mpiio_fs_api.h +++ b/adapter/mpiio/mpiio_fs_api.h @@ -39,6 +39,19 @@ class MpiioFs : public Filesystem { : Filesystem(HERMES_MPIIO_IO_CLIENT, AdapterType::kMpiio) {} + inline bool IsMpiFpTracked(MPI_File *fh, std::shared_ptr &stat) { + auto mdm = HERMES_FS_METADATA_MANAGER; + if (fh == nullptr) { return false; } + File f; f.hermes_mpi_fh_ = (*fh); + stat = mdm->Find(f); + return stat != nullptr; + } + + inline bool IsMpiFpTracked(MPI_File *fh) { + std::shared_ptr stat; + return IsMpiFpTracked(fh, stat); + } + int Read(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, MPI_Datatype datatype, MPI_Status *status, FsIoOptions opts) { opts.mpi_type_ = datatype; @@ -127,7 +140,8 @@ class MpiioFs : public Filesystem { MPI_Datatype datatype, MPI_Request *request, FsIoOptions opts) { LOG(INFO) << "Starting an asynchronous write" << std::endl; - auto pool = Singleton::GetInstance(); + auto mdm = HERMES_FS_METADATA_MANAGER; + auto pool = HERMES_FS_THREAD_POOL; HermesRequest *hreq = new HermesRequest(); auto lambda = [](MpiioFs *fs, File &f, AdapterStat &stat, const void *ptr, int count, MPI_Datatype datatype, MPI_Status *status, @@ -138,13 +152,13 @@ class MpiioFs : public Filesystem { auto func = std::bind(lambda, this, f, stat, ptr, count, datatype, &hreq->io_status.mpi_status_, opts); hreq->return_future = pool->run(func); - auto mdm = HERMES_FS_METADATA_MANAGER; mdm->request_map.emplace(reinterpret_cast(request), hreq); return MPI_SUCCESS; } int Wait(MPI_Request *req, MPI_Status *status) { auto mdm = HERMES_FS_METADATA_MANAGER; + auto real_api = HERMES_MPIIO_API; auto iter = mdm->request_map.find(reinterpret_cast(req)); if (iter != mdm->request_map.end()) { HermesRequest *hreq = iter->second; diff --git a/adapter/mpiio/mpiio_io_client.cc b/adapter/mpiio/mpiio_io_client.cc index 0178f720a..5664f705a 100644 --- a/adapter/mpiio/mpiio_io_client.cc +++ b/adapter/mpiio/mpiio_io_client.cc @@ -43,7 +43,7 @@ int MpiioIoClient::RealSync(const IoClientObject &f, /** Close \a file FILE f */ int MpiioIoClient::RealClose(const IoClientObject &f, - const IoClientStats &stat) { + IoClientStats &stat) { return real_api->MPI_File_close(&stat.mpi_fh_); } diff --git a/adapter/mpiio/mpiio_io_client.h b/adapter/mpiio/mpiio_io_client.h index 4832a73c4..5d539ced9 100644 --- a/adapter/mpiio/mpiio_io_client.h +++ b/adapter/mpiio/mpiio_io_client.h @@ -51,7 +51,7 @@ class MpiioIoClient : public hermes::adapter::fs::FilesystemIoClient { /** Close \a file FILE f */ int RealClose(const IoClientObject &f, - const IoClientStats &stat) override; + IoClientStats &stat) override; /** * Called before RealClose. Releases information provisioned during diff --git a/adapter/posix/CMakeLists.txt b/adapter/posix/CMakeLists.txt index 101078edd..38bcfefea 100644 --- a/adapter/posix/CMakeLists.txt +++ b/adapter/posix/CMakeLists.txt @@ -18,7 +18,7 @@ set(INTERCEPTOR_DEPS hermes_posix_io_client hermes_fs_base) add_library(hermes_posix SHARED - ${CMAKE_CURRENT_SOURCE_DIR}/posix.cc) + ${CMAKE_CURRENT_SOURCE_DIR}/posix_api.cc) add_dependencies(hermes_posix ${INTERCEPTOR_DEPS}) target_link_libraries(hermes_posix ${INTERCEPTOR_DEPS}) target_compile_options(hermes_posix PUBLIC -fPIC) diff --git a/adapter/posix/posix.cc b/adapter/posix/posix_api.cc similarity index 100% rename from adapter/posix/posix.cc rename to adapter/posix/posix_api.cc diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 60df9616e..0d4eafda8 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -52,7 +52,7 @@ int PosixIoClient::RealSync(const IoClientObject &f, /** Close \a file FILE f */ int PosixIoClient::RealClose(const IoClientObject &f, - const IoClientStats &stat) { + IoClientStats &stat) { (void) f; return real_api->close(stat.fd_); } diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h index f10118dce..0d2ef74cc 100644 --- a/adapter/posix/posix_io_client.h +++ b/adapter/posix/posix_io_client.h @@ -60,7 +60,7 @@ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { /** Close \a file FILE f */ int RealClose(const IoClientObject &f, - const IoClientStats &stat) override; + IoClientStats &stat) override; /** * Called before RealClose. Releases information provisioned during diff --git a/adapter/stdio/stdio_io_client.cc b/adapter/stdio/stdio_io_client.cc index a42d268a9..71be07eb7 100644 --- a/adapter/stdio/stdio_io_client.cc +++ b/adapter/stdio/stdio_io_client.cc @@ -49,7 +49,7 @@ int StdioIoClient::RealSync(const IoClientObject &f, /** Close \a file FILE f */ int StdioIoClient::RealClose(const IoClientObject &f, - const IoClientStats &stat) { + IoClientStats &stat) { return real_api->fclose(stat.fh_); } diff --git a/adapter/stdio/stdio_io_client.h b/adapter/stdio/stdio_io_client.h index 883073edb..6c2b1881c 100644 --- a/adapter/stdio/stdio_io_client.h +++ b/adapter/stdio/stdio_io_client.h @@ -59,7 +59,7 @@ class StdioIoClient : public hermes::adapter::fs::FilesystemIoClient { /** Close \a file FILE f */ int RealClose(const IoClientObject &f, - const IoClientStats &stat) override; + IoClientStats &stat) override; /** * Called before RealClose. Releases information provisioned during diff --git a/adapter/test/CMakeLists.txt b/adapter/test/CMakeLists.txt index b86dab7ea..f17bb010f 100644 --- a/adapter/test/CMakeLists.txt +++ b/adapter/test/CMakeLists.txt @@ -13,13 +13,13 @@ function(gcc exec args) endfunction() function(mpi exec mpi_proc args) -# add_test(NAME Test${exec}_${mpi_proc} -# COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${mpi_proc} -# "${CMAKE_BINARY_DIR}/bin/${exec}" ${args} -d yes) -# set_property(TEST Test${exec}_${mpi_proc} -# PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) -# set_property(TEST Test${exec}_${mpi_proc} APPEND -# PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) + add_test(NAME Test${exec}_${mpi_proc} + COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${mpi_proc} + "${CMAKE_BINARY_DIR}/bin/${exec}" ${args} -d yes) + set_property(TEST Test${exec}_${mpi_proc} + PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) + set_property(TEST Test${exec}_${mpi_proc} APPEND + PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) endfunction() find_program(BASH_PROGRAM bash) @@ -41,7 +41,7 @@ endfunction() enable_testing() if(HERMES_ENABLE_STDIO_ADAPTER) - # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/stdio) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/stdio) endif() if(HERMES_ENABLE_POSIX_ADAPTER) diff --git a/adapter/test/stdio/CMakeLists.txt b/adapter/test/stdio/CMakeLists.txt index c1d2fb4f8..485d2c7fd 100644 --- a/adapter/test/stdio/CMakeLists.txt +++ b/adapter/test/stdio/CMakeLists.txt @@ -25,6 +25,10 @@ function(gcc_hermes_mode exec tag_name tags mode path) PROPERTY ENVIRONMENT SET_PATH=${path}) endfunction() +include_directories( + ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src) + #------------------------------------------------------------------------------ # STDIO Adapter Internal tests #------------------------------------------------------------------------------ @@ -76,11 +80,6 @@ set_target_properties(hermes_stdio_adapter_mpi_test PROPERTIES COMPILE_FLAGS "-D mpi_daemon(hermes_stdio_adapter_mpi_test 2 "~[request_size=range-large]" "" 1) mpi_daemon(hermes_stdio_adapter_mpi_test 2 "[request_size=range-large]" "large" 1) -add_executable(adapter_utils_test adapter_utils_test.cc ${ADAPTER_COMMON}) -target_link_libraries(adapter_utils_test hermes_stdio) -add_dependencies(adapter_utils_test hermes_stdio) -gcc(adapter_utils_test "") - set(STDIO_TESTS stdio_adapter_mapper_test stdio_adapter_test @@ -89,7 +88,6 @@ set(STDIO_TESTS hermes_stdio_adapter_mode_test stdio_adapter_mpi_test hermes_stdio_adapter_mpi_test - adapter_utils_test ) foreach(program ${STDIO_TESTS}) diff --git a/adapter/test/stdio/adapter_utils_test.cc b/adapter/test/stdio/adapter_utils_test.cc deleted file mode 100644 index b1eea426d..000000000 --- a/adapter/test/stdio/adapter_utils_test.cc +++ /dev/null @@ -1,104 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "catch_config.h" -#include "adapter_utils.h" - -namespace stdfs = std::filesystem; - -int init(int* argc, char*** argv) { - (void)argc; - (void)argv; - return 0; -} - -int finalize() { - return 0; -} - -cl::Parser define_options() { - return cl::Parser(); -} - -// NOTE(chogan) GCC's test for weakly_canonical -TEST_CASE("WeaklyCanonical") { - namespace had = hermes::adapter; - - const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); - std::error_code ec; - - auto dir = stdfs::path("tmp"); - if (stdfs::exists(dir)) { - stdfs::remove_all(dir, ec); - } - - stdfs::create_directory(dir); - const auto dirc = stdfs::canonical(dir); - stdfs::path foo = dir/"foo", bar = dir/"bar"; - stdfs::create_directory(foo); - stdfs::create_directory(bar); - stdfs::create_directory(bar/"baz"); - stdfs::path p; - - stdfs::create_symlink("../bar", foo/"bar"); - - p = had::WeaklyCanonical(dir/"foo//./bar///../biz/."); - REQUIRE(p == dirc/"biz"); - p = had::WeaklyCanonical(dir/"foo/.//bar/././baz/."); - REQUIRE(p == dirc/"bar/baz"); - p = had::WeaklyCanonical(stdfs::current_path()/dir/"bar//../foo/bar/baz"); - REQUIRE(p == dirc/"bar/baz"); - - ec = bad_ec; - p = had::WeaklyCanonical(dir/"foo//./bar///../biz/.", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"biz"); - ec = bad_ec; - p = had::WeaklyCanonical(dir/"foo/.//bar/././baz/.", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"bar/baz"); - ec = bad_ec; - p = had::WeaklyCanonical(stdfs::current_path()/dir/"bar//../foo/bar/baz", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"bar/baz"); - - ec = bad_ec; - p = had::WeaklyCanonical(dir/"bar/", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"bar"); - - // As above, but using "foo/.." instead of "foo", - // because there is no "foo/bar" symlink - - p = had::WeaklyCanonical(dir/"./bar///../biz/."); - REQUIRE(p == dirc/"biz"); - p = had::WeaklyCanonical(dir/"foo/.././/bar/././baz/."); - REQUIRE(p == dirc/"bar/baz"); - p = had::WeaklyCanonical(stdfs::current_path()/dir/"bar//../foo/../bar/baz"); - REQUIRE(p == dirc/"bar/baz"); - - ec = bad_ec; - p = had::WeaklyCanonical(dir/"foo/..//./bar///../biz/.", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"biz"); - ec = bad_ec; - p = had::WeaklyCanonical(dir/"foo/.././/bar/././baz/.", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"bar/baz"); - ec = bad_ec; - p = had::WeaklyCanonical( - stdfs::current_path()/dir/"bar//../foo/../bar/baz", ec); - REQUIRE(!ec); - REQUIRE(p == dirc/"bar/baz"); - - stdfs::remove_all(dir, ec); -} diff --git a/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp b/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp index 4e0ce4cc4..fa6100d1a 100644 --- a/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp +++ b/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp @@ -20,7 +20,7 @@ #include "adapter_test_utils.h" #include "catch_config.h" #if HERMES_INTERCEPT == 1 -#include "stdio/real_api.h" +#include "stdio/stdio_api.h" #endif namespace stdfs = std::filesystem; diff --git a/adapter/test/stdio/stdio_adapter_mapper_test.cpp b/adapter/test/stdio/stdio_adapter_mapper_test.cpp index 22a2ba5cd..139d45045 100644 --- a/adapter/test/stdio/stdio_adapter_mapper_test.cpp +++ b/adapter/test/stdio/stdio_adapter_mapper_test.cpp @@ -13,13 +13,15 @@ #include #include "catch_config.h" -#include "constants.h" +#include "adapter_constants.h" +#include "src/hermes_types.h" #include "mapper/mapper_factory.h" #include "stdio/stdio_fs_api.h" using hermes::adapter::BlobPlacements; using hermes::adapter::MapperFactory; -using hermes::adapter::fs::kMapperType; +using hermes::adapter::MapperType; +using hermes::adapter::kMapperType; using hermes::adapter::fs::MetadataManager; namespace stdfs = std::filesystem; @@ -104,6 +106,7 @@ TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + "[request_size=type-fixed][repetition=1]" "[pattern=sequential][file=1]") { pretest(); + const size_t kPageSize = MEGABYTES(1); SECTION("Map a one request") { auto mapper = MapperFactory().Get(kMapperType); size_t total_size = args.request_size; @@ -112,7 +115,7 @@ TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + size_t offset = 0; REQUIRE(kPageSize > total_size + offset); BlobPlacements mapping; - mapper->map(offset, total_size, mapping); + mapper->map(offset, total_size, kPageSize, mapping); REQUIRE(mapping.size() == 1); REQUIRE(mapping[0].bucket_off_ == offset); REQUIRE(mapping[0].blob_size_ == total_size); @@ -127,7 +130,7 @@ TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + REQUIRE(fp != nullptr); size_t offset = 0; BlobPlacements mapping; - mapper->map(offset, total_size, mapping); + mapper->map(offset, total_size, kPageSize, mapping); REQUIRE(mapping.size() == ceil((double)total_size / kPageSize)); for (const auto& item : mapping) { size_t mapped_size = @@ -147,7 +150,7 @@ TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + REQUIRE(fp != nullptr); size_t offset = 1; BlobPlacements mapping; - mapper->map(offset, total_size, mapping); + mapper->map(offset, total_size, kPageSize, mapping); bool has_rem = (total_size + offset) % kPageSize != 0; if (has_rem) { REQUIRE(mapping.size() == ceil((double)total_size / kPageSize) + 1); @@ -183,7 +186,7 @@ TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + size_t offset = 1; REQUIRE(kPageSize > total_size + offset); BlobPlacements mapping; - mapper->map(offset, total_size, mapping); + mapper->map(offset, total_size, kPageSize, mapping); REQUIRE(mapping.size() == 1); REQUIRE(mapping[0].bucket_off_ == offset); REQUIRE(mapping[0].blob_size_ == total_size); diff --git a/adapter/test/stdio/stdio_adapter_mode_test.cpp b/adapter/test/stdio/stdio_adapter_mode_test.cpp index 4ff439bcf..607e2f335 100644 --- a/adapter/test/stdio/stdio_adapter_mode_test.cpp +++ b/adapter/test/stdio/stdio_adapter_mode_test.cpp @@ -19,12 +19,15 @@ #include #if HERMES_INTERCEPT == 1 -#include "stdio/real_api.h" +#include "stdio/stdio_api.h" #endif #include "adapter_test_utils.h" +#include "adapter_types.h" +#include "hermes.h" namespace stdfs = std::filesystem; +using hermes::adapter::AdapterMode; namespace hermes::adapter::stdio::test { struct Arguments { @@ -66,8 +69,8 @@ int init(int* argc, char*** argv) { fullpath.string() + "_ext_cmp" + std::to_string(getpid()); char* set_path = getenv("SET_PATH"); if (set_path && strcmp(set_path, "1") == 0) { - auto paths = info.new_file + "," + info.existing_file; - setenv(kAdapterModeInfo, paths.c_str(), 1); + HERMES->client_config_.SetAdapterPathTracking(info.new_file, false); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file, false); } MPI_Init(argc, argv); info.write_data = GenRandom(args.request_size); @@ -259,10 +262,7 @@ TEST_CASE("BatchedWriteSequentialPersistent", std::to_string(info.num_iterations) + "]" "[pattern=sequential][file=1]") { - char* adapter_mode = getenv(kAdapterMode); - REQUIRE(adapter_mode != nullptr); - bool is_same = strcmp(kAdapterDefaultMode, adapter_mode) == 0; - REQUIRE(is_same); + REQUIRE(HERMES->client_config_.GetBaseAdapterMode() == AdapterMode::kDefault); pretest(); SECTION("write to new file always at end") { test::test_fopen(info.new_file.c_str(), "w+"); @@ -289,10 +289,7 @@ TEST_CASE("BatchedWriteSequentialBypass", std::to_string(info.num_iterations) + "]" "[pattern=sequential][file=1]") { - char* adapter_mode = getenv(kAdapterMode); - REQUIRE(adapter_mode != nullptr); - bool is_same = strcmp(kAdapterBypassMode, adapter_mode) == 0; - REQUIRE(is_same); + REQUIRE(HERMES->client_config_.GetBaseAdapterMode() == AdapterMode::kBypass); pretest(); SECTION("write to new file always at end") { test::test_fopen(info.new_file.c_str(), "w+"); @@ -319,10 +316,7 @@ TEST_CASE("BatchedWriteSequentialScratch", std::to_string(info.num_iterations) + "]" "[pattern=sequential][file=1]") { - char* adapter_mode = getenv(kAdapterMode); - REQUIRE(adapter_mode != nullptr); - bool is_same = strcmp(kAdapterScratchMode, adapter_mode) == 0; - REQUIRE(is_same); + REQUIRE(HERMES->client_config_.GetBaseAdapterMode() == AdapterMode::kScratch); pretest(); SECTION("write to new file always at end") { test::test_fopen(info.new_file.c_str(), "w+"); diff --git a/adapter/test/stdio/stdio_adapter_mpi_test.cpp b/adapter/test/stdio/stdio_adapter_mpi_test.cpp index 67d19731c..e0b5336ef 100644 --- a/adapter/test/stdio/stdio_adapter_mpi_test.cpp +++ b/adapter/test/stdio/stdio_adapter_mpi_test.cpp @@ -19,7 +19,7 @@ #include #include #if HERMES_INTERCEPT == 1 -#include "stdio/real_api.h" +#include "stdio/stdio_api.h" #endif namespace stdfs = std::filesystem; @@ -210,7 +210,7 @@ int pretest() { // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); // INTERCEPTOR_LIST->hermes_flush_exclusion.insert( - info.existing_shared_file_cmp); + // info.existing_shared_file_cmp); #endif return 0; } diff --git a/adapter/test/stdio/stdio_adapter_test.cpp b/adapter/test/stdio/stdio_adapter_test.cpp index 0861da7bb..a2d8ba45e 100644 --- a/adapter/test/stdio/stdio_adapter_test.cpp +++ b/adapter/test/stdio/stdio_adapter_test.cpp @@ -20,7 +20,7 @@ #include "adapter_test_utils.h" #include "catch_config.h" #if HERMES_INTERCEPT == 1 -#include "stdio/real_api.h" +#include "stdio/stdio_api.h" #endif #include "adapter_test_utils.h" diff --git a/src/config_client.cc b/src/config_client.cc index 7d13694ec..4b5dd03e5 100644 --- a/src/config_client.cc +++ b/src/config_client.cc @@ -12,23 +12,59 @@ #include "config_client.h" #include "config_client_default.h" +#include + +namespace stdfs = std::filesystem; namespace hermes::config { +/** parse the AdapterConfig YAML node */ +void ClientConfig::ParseAdapterConfig(YAML::Node &yaml_conf, + AdapterObjectConfig &conf) { + std::string path = yaml_conf["path"].as(); + path = stdfs::weakly_canonical(path).string(); + if (yaml_conf["mode"]) { + conf.mode_ = AdapterModeConv::to_enum(yaml_conf["mode"].as()); + } + if (yaml_conf["page_size"]) { + conf.page_size_ = ParseSize( + yaml_conf["page_size"].as()); + } + SetAdapterConfig(path, conf); +} + /** parse the YAML node */ void ClientConfig::ParseYAML(YAML::Node &yaml_conf) { if (yaml_conf["stop_daemon"]) { stop_daemon_ = yaml_conf["stop_daemon"].as(); } + if (yaml_conf["base_adapter_mode"]) { + base_adapter_config_.mode_ = AdapterModeConv::to_enum( + yaml_conf["base_adapter_mode"].as()); + } if (yaml_conf["file_page_size"]) { - file_page_size_ = ParseSize( + base_adapter_config_.page_size_ = ParseSize( yaml_conf["file_page_size"].as()); } if (yaml_conf["path_inclusions"]) { - ParseVector(yaml_conf["path_inclusions"], path_inclusions_); + std::vector inclusions; + ParseVector(yaml_conf["path_inclusions"], inclusions); + for (auto &entry : inclusions) { + SetAdapterPathTracking(std::move(entry), true); + } } if (yaml_conf["path_exclusions"]) { - ParseVector(yaml_conf["path_inclusions"], path_exclusions_); + std::vector exclusions; + ParseVector(yaml_conf["path_inclusions"], exclusions); + for (auto &entry : exclusions) { + SetAdapterPathTracking(std::move(entry), false); + } + } + if (yaml_conf["file_adapter_configs"]) { + for (auto node : yaml_conf["file_adapter_modes"]) { + AdapterObjectConfig conf(base_adapter_config_); + ParseAdapterConfig(node.second, conf); + } } } diff --git a/src/config_client.h b/src/config_client.h index a4be3c6f6..396454104 100644 --- a/src/config_client.h +++ b/src/config_client.h @@ -14,25 +14,69 @@ #define HERMES_SRC_CONFIG_CLIENT_H_ #include "config.h" +#include "constants.h" +#include "adapter/adapter_types.h" namespace hermes::config { +using hermes::adapter::AdapterType; +using hermes::adapter::AdapterMode; +using hermes::adapter::AdapterModeConv; +using hermes::adapter::AdapterObjectConfig; + +/**< A path is included */ +static inline const bool do_include = true; +/**< A path is excluded */ +static inline const bool do_exclude = false; + /** * Configuration used to intialize client * */ class ClientConfig : public BaseConfig { public: - bool stop_daemon_; - size_t file_page_size_; - std::vector path_inclusions_; - std::vector path_exclusions_; + bool stop_daemon_; /**< Whether or not to stop daemon at exit */ + /** The set of paths to monitor or exclude, ordered by length */ + std::vector> path_list_; + /** The default adapter config */ + AdapterObjectConfig base_adapter_config_; + /** Per-object (e.g., file) adapter configuration */ + std::unordered_map adapter_config_; public: ClientConfig() = default; void LoadDefault() override; + AdapterMode GetBaseAdapterMode() { + return base_adapter_config_.mode_; + } + + AdapterObjectConfig& GetAdapterConfig(const std::string &path) { + auto iter = adapter_config_.find(path); + if (iter == adapter_config_.end()) { + return base_adapter_config_; + } + return iter->second; + } + + void SetAdapterConfig(const std::string &path, AdapterObjectConfig &conf) { + adapter_config_.emplace(path, conf); + } + + void SetAdapterPathTracking(const std::string &path, bool include) { + path_list_.emplace_back(path, include); + std::sort(path_list_.begin(), + path_list_.end(), + [](const std::pair &a, + const std::pair &b) { + return a.first.size() > b.first.size(); + }); + } + private: void ParseYAML(YAML::Node &yaml_conf) override; + + void ParseAdapterConfig(YAML::Node &yaml_conf, + AdapterObjectConfig &conf); }; } // namespace hermes::config diff --git a/src/thread_pool.h b/src/thread_pool.h index 8e99b4017..3e1f2a366 100644 --- a/src/thread_pool.h +++ b/src/thread_pool.h @@ -24,6 +24,15 @@ namespace hermes { A class to represent thread pool */ class ThreadPool { + private: + std::vector threads; /**< a vector of threads */ + /** high-priority queue */ + mutable std::queue> queue_low; + /** low-priority queue */ + mutable std::queue> queue_high; + mutable std::mutex mutex; /**< mutex lock */ + mutable std::condition_variable condvar; /**< conditional variable */ + public: /** construct thread pool with \a num_threads number of threads */ explicit ThreadPool( @@ -90,15 +99,6 @@ class ThreadPool { thread.join(); } } - - private: - std::vector threads; /**< a vector of threads */ - /** high-priority queue */ - mutable std::queue> queue_low; - /** low-priority queue */ - mutable std::queue> queue_high; - mutable std::mutex mutex; /**< mutex lock */ - mutable std::condition_variable condvar; /**< conditional variable */ }; } // namespace hermes #endif // HERMES_THREAD_POOL_H_ From 91afe6ff22617c4f358da17448b2f511fae43d44 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 5 Feb 2023 02:57:23 -0600 Subject: [PATCH 118/511] Adapters are working --- adapter/filesystem/filesystem_mdm.h | 2 +- adapter/filesystem/filesystem_mdm_singleton.cc | 5 ++--- adapter/posix/posix_api.cc | 11 ----------- adapter/test/posix/simple_io.cc | 2 +- config/hermes_client_default.yaml | 9 +++++++-- src/config_client.cc | 4 ++-- src/config_client_default.h | 9 +++++++-- 7 files changed, 20 insertions(+), 22 deletions(-) diff --git a/adapter/filesystem/filesystem_mdm.h b/adapter/filesystem/filesystem_mdm.h index 62ab950e4..12123e94b 100644 --- a/adapter/filesystem/filesystem_mdm.h +++ b/adapter/filesystem/filesystem_mdm.h @@ -95,7 +95,7 @@ class MetadataManager { #include "singleton.h" #define HERMES_FS_METADATA_MANAGER \ - hermes::GlobalSingleton::GetInstance() + hermes::Singleton::GetInstance() #define HERMES_FS_METADATA_MANAGER_T hermes::adapter::fs::MetadataManager* #define HERMES_FS_THREAD_POOL \ diff --git a/adapter/filesystem/filesystem_mdm_singleton.cc b/adapter/filesystem/filesystem_mdm_singleton.cc index b2b004681..69256151d 100644 --- a/adapter/filesystem/filesystem_mdm_singleton.cc +++ b/adapter/filesystem/filesystem_mdm_singleton.cc @@ -13,6 +13,5 @@ #include "singleton.h" #include "filesystem_mdm.h" -template<> hermes::adapter::fs::MetadataManager -hermes::GlobalSingleton::obj_ = - hermes::adapter::fs::MetadataManager(); +template<> std::unique_ptr +hermes::Singleton::obj_ = nullptr; diff --git a/adapter/posix/posix_api.cc b/adapter/posix/posix_api.cc index 4ea91f9f1..3944919be 100644 --- a/adapter/posix/posix_api.cc +++ b/adapter/posix/posix_api.cc @@ -138,7 +138,6 @@ int HERMES_DECL(creat64)(const char *path, mode_t mode) { } ssize_t HERMES_DECL(read)(int fd, void *buf, size_t count) { - TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -152,7 +151,6 @@ ssize_t HERMES_DECL(read)(int fd, void *buf, size_t count) { } ssize_t HERMES_DECL(write)(int fd, const void *buf, size_t count) { - TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -166,7 +164,6 @@ ssize_t HERMES_DECL(write)(int fd, const void *buf, size_t count) { } ssize_t HERMES_DECL(pread)(int fd, void *buf, size_t count, off_t offset) { - TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -181,7 +178,6 @@ ssize_t HERMES_DECL(pread)(int fd, void *buf, size_t count, off_t offset) { ssize_t HERMES_DECL(pwrite)(int fd, const void *buf, size_t count, off_t offset) { - TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -195,7 +191,6 @@ ssize_t HERMES_DECL(pwrite)(int fd, const void *buf, size_t count, } ssize_t HERMES_DECL(pread64)(int fd, void *buf, size_t count, off64_t offset) { - TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -210,7 +205,6 @@ ssize_t HERMES_DECL(pread64)(int fd, void *buf, size_t count, off64_t offset) { ssize_t HERMES_DECL(pwrite64)(int fd, const void *buf, size_t count, off64_t offset) { - TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -224,7 +218,6 @@ ssize_t HERMES_DECL(pwrite64)(int fd, const void *buf, size_t count, } off_t HERMES_DECL(lseek)(int fd, off_t offset, int whence) { - TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -239,7 +232,6 @@ off_t HERMES_DECL(lseek)(int fd, off_t offset, int whence) { } off64_t HERMES_DECL(lseek64)(int fd, off64_t offset, int whence) { - TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -254,7 +246,6 @@ off64_t HERMES_DECL(lseek64)(int fd, off64_t offset, int whence) { } int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { - TRANSPARENT_HERMES int result = 0; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -293,7 +284,6 @@ int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { } int HERMES_DECL(fsync)(int fd) { - TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; @@ -306,7 +296,6 @@ int HERMES_DECL(fsync)(int fd) { } int HERMES_DECL(close)(int fd) { - TRANSPARENT_HERMES bool stat_exists; auto real_api = HERMES_POSIX_API; auto fs_api = HERMES_POSIX_FS; diff --git a/adapter/test/posix/simple_io.cc b/adapter/test/posix/simple_io.cc index 652d12c1e..ec652ac1a 100644 --- a/adapter/test/posix/simple_io.cc +++ b/adapter/test/posix/simple_io.cc @@ -36,7 +36,7 @@ int main(int argc, char **argv) { int rank = 0, nprocs = 1; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nprocs);/**/ + MPI_Comm_size(MPI_COMM_WORLD, &nprocs); if (argc != 7) { std::cout << "USAGE: ./posix_simple_io" << " [path] [read] [block_size (kb)] [count]" diff --git a/config/hermes_client_default.yaml b/config/hermes_client_default.yaml index 5b9456e42..e212f3113 100644 --- a/config/hermes_client_default.yaml +++ b/config/hermes_client_default.yaml @@ -1,4 +1,9 @@ stop_daemon: true -file_page_size: 1024KB path_inclusions: ["/home"] -path_exclusions: [] \ No newline at end of file +path_exclusions: ["/"] +file_page_size: 1024KB +base_adapter_mode: kDefault +file_adapter_configs: + - path: "/" + page_size: 1MB + mode: kDefault \ No newline at end of file diff --git a/src/config_client.cc b/src/config_client.cc index 4b5dd03e5..7a74a13bb 100644 --- a/src/config_client.cc +++ b/src/config_client.cc @@ -61,9 +61,9 @@ void ClientConfig::ParseYAML(YAML::Node &yaml_conf) { } } if (yaml_conf["file_adapter_configs"]) { - for (auto node : yaml_conf["file_adapter_modes"]) { + for (auto node : yaml_conf["file_adapter_configs"]) { AdapterObjectConfig conf(base_adapter_config_); - ParseAdapterConfig(node.second, conf); + ParseAdapterConfig(node, conf); } } } diff --git a/src/config_client_default.h b/src/config_client_default.h index 803d86396..b6099cfb6 100644 --- a/src/config_client_default.h +++ b/src/config_client_default.h @@ -2,7 +2,12 @@ #define HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ const char* kClientDefaultConfigStr = "stop_daemon: true\n" -"file_page_size: 1024KB\n" "path_inclusions: [\"/home\"]\n" -"path_exclusions: []\n"; +"path_exclusions: [\"/\"]\n" +"file_page_size: 1024KB\n" +"base_adapter_mode: kDefault\n" +"file_adapter_configs:\n" +" - path: \"/\"\n" +" page_size: 1MB\n" +" mode: kDefault\n"; #endif // HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ \ No newline at end of file From 50d341eb1c0ce8f7a0e9572bc78e397fb6f8ed51 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 5 Feb 2023 11:27:21 -0600 Subject: [PATCH 119/511] Locking --- src/api/bucket.cc | 27 ++++++++++ src/api/bucket.h | 20 +++++++ src/data_structures.h | 2 + src/metadata_manager.cc | 90 +++++++++++++++++++++++++++++-- src/metadata_manager.h | 83 +++++++++++++++++++++++++++- src/metadata_types.h | 116 ++++++++++++++++++++++++++++++++++------ 6 files changed, 317 insertions(+), 21 deletions(-) diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 003577b09..41a7e7e53 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -37,6 +37,20 @@ size_t Bucket::GetSize(IoClientContext opts) { return mdm_->LocalGetBucketSize(id_, opts); } +/** + * Lock the bucket + * */ +void Bucket::LockBucket(MdLockType lock_type) { + mdm_->LocalLockBucket(id_, lock_type); +} + +/** + * Unlock the bucket + * */ +void Bucket::UnlockBucket(MdLockType lock_type) { + mdm_->LocalUnlockBucket(id_, lock_type); +} + /** * Rename this bucket * */ @@ -65,6 +79,19 @@ Status Bucket::GetBlobId(std::string blob_name, return Status(); } +/** + * Lock the bucket + * */ +void Bucket::LockBlob(BlobId blob_id, MdLockType lock_type) { + mdm_->LocalLockBlob(blob_id, lock_type); +} + +/** + * Unlock the bucket + * */ +void Bucket::UnlockBlob(BlobId blob_id, MdLockType lock_type) { + mdm_->LocalUnlockBlob(blob_id, lock_type); +} /** * Put \a blob_id Blob into the bucket diff --git a/src/api/bucket.h b/src/api/bucket.h index eb332492b..51552541a 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -65,6 +65,16 @@ class Bucket { * */ size_t GetSize(IoClientContext opts = IoClientContext()); + /** + * Lock the bucket + * */ + void LockBucket(MdLockType lock_type); + + /** + * Unlock the bucket + * */ + void UnlockBucket(MdLockType lock_type); + /** * Rename this bucket * */ @@ -96,6 +106,16 @@ class Bucket { * */ Status GetBlobId(std::string blob_name, BlobId &blob_id); + /** + * Lock the blob + * */ + void LockBlob(BlobId blob_id, MdLockType lock_type); + + /** + * Unlock the blob + * */ + void UnlockBlob(BlobId blob_id, MdLockType lock_type); + /** * Put \a blob_name Blob into the bucket * */ diff --git a/src/data_structures.h b/src/data_structures.h index ee1972cae..fcbf55faf 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -26,6 +26,8 @@ namespace lipc = labstor::ipc; using labstor::RwLock; using labstor::Mutex; using labstor::bitfield32_t; +using labstor::ScopedRwReadLock; +using labstor::ScopedRwWriteLock; #include #include diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 709a7ac33..2f199aa18 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -117,6 +117,9 @@ void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { BucketId MetadataManager::LocalGetOrCreateBucket( lipc::charbuf &bkt_name, const IoClientContext &opts) { + // Acquire MD write lock (modifying bkt_map) + ScopedRwWriteLock md_lock(lock_); + // Create unique ID for the Bucket BucketId bkt_id; bkt_id.unique_ = header_->id_alloc_.fetch_add(1); @@ -153,6 +156,8 @@ BucketId MetadataManager::LocalGetOrCreateBucket( * @RPC_CLASS_INSTANCE mdm * */ BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { + // Acquire MD read lock (reading bkt_id_map) + ScopedRwReadLock md_lock(lock_); auto iter = bkt_id_map_->find(bkt_name); if (iter == bkt_id_map_->end()) { return BucketId::GetNull(); @@ -171,6 +176,8 @@ BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { * */ size_t MetadataManager::LocalGetBucketSize(BucketId bkt_id, const IoClientContext &opts) { + // Acquire MD read lock (reading bkt_map) + ScopedRwReadLock md_lock(lock_); auto iter = bkt_map_->find(bkt_id); if (iter == bkt_map_->end()) { return 0; @@ -185,6 +192,22 @@ size_t MetadataManager::LocalGetBucketSize(BucketId bkt_id, } } +/** + * Lock the bucket + * */ +RPC void MetadataManager::LocalLockBucket(BucketId bkt_id, + MdLockType lock_type) { + LockMdObject(*bkt_map_, bkt_id, lock_type); +} + +/** + * Unlock the bucket + * */ +RPC void MetadataManager::LocalUnlockBucket(BucketId blob_id, + MdLockType lock_type) { + UnlockMdObject(*bkt_map_, blob_id, lock_type); +} + /** * Check whether or not \a bkt_id bucket contains * \a blob_id blob @@ -194,6 +217,8 @@ size_t MetadataManager::LocalGetBucketSize(BucketId bkt_id, * */ bool MetadataManager::LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id) { + // Acquire MD read lock (reading blob_map_) + ScopedRwReadLock md_lock(lock_); auto iter = blob_map_->find(blob_id); if (iter == blob_map_->end()) { return false; @@ -212,6 +237,8 @@ bool MetadataManager::LocalBucketContainsBlob(BucketId bkt_id, * */ bool MetadataManager::LocalRenameBucket(BucketId bkt_id, lipc::charbuf &new_bkt_name) { + // Acquire MD write lock (modifying bkt_map_) + ScopedRwWriteLock md_lock(lock_); auto iter = bkt_map_->find(bkt_id); if (iter == bkt_map_->end()) { return true; @@ -230,6 +257,8 @@ bool MetadataManager::LocalRenameBucket(BucketId bkt_id, * @RPC_CLASS_INSTANCE mdm * */ bool MetadataManager::LocalDestroyBucket(BucketId bkt_id) { + // Acquire MD write lock (modifying bkt_map_) + ScopedRwWriteLock md_lock(lock_); bkt_map_->erase(bkt_id); return true; } @@ -242,12 +271,16 @@ Status MetadataManager::LocalBucketRegisterBlobId( size_t new_blob_size, bool did_create, const IoClientContext &opts) { + // Acquire MD read lock (read bkt_map_) + ScopedRwReadLock md_lock(lock_); auto iter = bkt_map_->find(bkt_id); if (iter == bkt_map_->end()) { return Status(); } lipc::ShmRef> info = (*iter); BucketInfo &bkt_info = *info->second_; + // Acquire BktInfo Write Lock (modifying) + ScopedRwWriteLock info_lock(bkt_info.header_->lock_[0]); // Update I/O client bucket stats auto io_client = IoClientFactory::Get(opts.type_); if (io_client) { @@ -285,10 +318,10 @@ std::tuple MetadataManager::LocalBucketPutBlob( size_t blob_size, lipc::vector &buffers) { size_t orig_blob_size = 0; - + // Acquire MD read lock (read blob_map_) + ScopedRwReadLock md_lock(lock_); // Get internal blob name lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); - // Create unique ID for the Blob BlobId blob_id; blob_id.unique_ = header_->id_alloc_.fetch_add(1); @@ -306,6 +339,8 @@ std::tuple MetadataManager::LocalBucketPutBlob( auto iter = blob_map_->find(blob_id); lipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; + // Acquire blob_info write lock before modifying buffers + ScopedRwWriteLock(blob_info.header_->lock_[0]); (*blob_info.buffers_) = std::move(buffers); } return std::tuple(blob_id, did_create, orig_blob_size); @@ -318,9 +353,13 @@ std::tuple MetadataManager::LocalBucketPutBlob( * @RPC_CLASS_INSTANCE mdm * */ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { + // Acquire MD read lock (read blob_map_) + ScopedRwReadLock md_lock(lock_); auto iter = blob_map_->find(blob_id); lipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; + // Acquire blob_info read lock (read buffers) + ScopedRwReadLock blob_info_lock(blob_info.header_->lock_[0]); lipc::vector &buffers = *blob_info.buffers_; return borg_->LocalReadBlobFromBuffers(buffers);; } @@ -333,6 +372,8 @@ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { * */ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, lipc::charbuf &blob_name) { + // Acquire MD read lock (read blob_id_map_) + ScopedRwReadLock md_lock(lock_); lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); auto iter = blob_id_map_->find(internal_blob_name); if (iter == blob_id_map_->end()) { @@ -342,6 +383,22 @@ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, return *info->second_; } +/** + * Lock the blob + * */ +void MetadataManager::LocalLockBlob(BlobId blob_id, + MdLockType lock_type) { + LockMdObject(*blob_map_, blob_id, lock_type); +} + +/** + * Unlock the blob + * */ +void MetadataManager::LocalUnlockBlob(BlobId blob_id, + MdLockType lock_type) { + UnlockMdObject(*blob_map_, blob_id, lock_type); +} + /** * Get \a blob_id blob's buffers * @@ -349,13 +406,16 @@ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, * @RPC_CLASS_INSTANCE mdm * */ std::vector MetadataManager::LocalGetBlobBuffers(BlobId blob_id) { + // Acquire MD read lock (read blob_map_) + ScopedRwReadLock md_lock(lock_); auto iter = blob_map_->find(blob_id); if (iter == blob_map_->end()) { return std::vector(); } lipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; - + // Acquire blob_info read lock + ScopedRwReadLock blob_info_lock(blob_info.header_->lock_[0]); // TODO(llogan): make this internal to the lipc::vec std::vector v; v.reserve(blob_info.buffers_->size()); @@ -374,6 +434,8 @@ std::vector MetadataManager::LocalGetBlobBuffers(BlobId blob_id) { * */ bool MetadataManager::LocalRenameBlob(BucketId bkt_id, BlobId blob_id, lipc::charbuf &new_blob_name) { + // Acquire MD write lock (modify blob_id_map_) + ScopedRwWriteLock md_lock(lock_); auto iter = (*blob_map_).find(blob_id); if (iter == blob_map_->end()) { return true; @@ -395,6 +457,8 @@ bool MetadataManager::LocalRenameBlob(BucketId bkt_id, BlobId blob_id, * */ bool MetadataManager::LocalDestroyBlob(BucketId bkt_id, BlobId blob_id) { + // Acquire MD write lock (modify blob_id_map & blob_map_) + ScopedRwWriteLock md_lock(lock_); (void)bkt_id; auto iter = (*blob_map_).find(blob_id); if (iter == blob_map_->end()) { @@ -418,6 +482,8 @@ VBucketId MetadataManager::LocalGetOrCreateVBucket( lipc::charbuf &vbkt_name, const IoClientContext &opts) { (void) opts; + // Acquire MD write lock (read vbkt_map_) + ScopedRwWriteLock md_lock(lock_); // Create unique ID for the Bucket VBucketId vbkt_id; vbkt_id.unique_ = header_->id_alloc_.fetch_add(1); @@ -446,6 +512,8 @@ VBucketId MetadataManager::LocalGetOrCreateVBucket( * @RPC_CLASS_INSTANCE mdm * */ VBucketId MetadataManager::LocalGetVBucketId(lipc::charbuf &vbkt_name) { + // Acquire MD read lock (read vbkt_id_map_) + ScopedRwReadLock md_lock(lock_); auto iter = vbkt_id_map_->find(vbkt_name); if (iter == vbkt_id_map_->end()) { return VBucketId::GetNull(); @@ -463,12 +531,16 @@ VBucketId MetadataManager::LocalGetVBucketId(lipc::charbuf &vbkt_name) { * */ bool MetadataManager::LocalVBucketLinkBlob(VBucketId vbkt_id, BlobId blob_id) { + // Acquire MD read lock (read vbkt_map_) + ScopedRwReadLock md_lock(lock_); auto iter = vbkt_map_->find(vbkt_id); if (iter == vbkt_map_->end()) { return true; } lipc::ShmRef> info = (*iter); VBucketInfo &vbkt_info = *info->second_; + // Acquire vbkt_info write lock (modify blobs) + ScopedRwWriteLock vbkt_info_lock(vbkt_info.header_->lock_); vbkt_info.blobs_->emplace(blob_id, blob_id); return true; } @@ -482,12 +554,16 @@ bool MetadataManager::LocalVBucketLinkBlob(VBucketId vbkt_id, * */ bool MetadataManager::LocalVBucketUnlinkBlob(VBucketId vbkt_id, BlobId blob_id) { + // Acquire MD read lock (read blob_id_map_) + ScopedRwReadLock md_lock(lock_); auto iter = vbkt_map_->find(vbkt_id); if (iter == vbkt_map_->end()) { return true; } lipc::ShmRef> info = (*iter); VBucketInfo &vbkt_info = *info->second_; + // Acquire vbkt_info write lock (modify blobs) + ScopedRwWriteLock vbkt_info_lock(vbkt_info.header_->lock_); vbkt_info.blobs_->erase(blob_id); return true; } @@ -508,12 +584,16 @@ std::list MetadataManager::LocalVBucketGetLinks(VBucketId vbkt_id) { * */ bool MetadataManager::LocalVBucketContainsBlob(VBucketId vbkt_id, BlobId blob_id) { + // Acquire MD read lock (read vbkt_map_) + ScopedRwReadLock md_lock(lock_); auto iter = vbkt_map_->find(vbkt_id); if (iter == vbkt_map_->end()) { return true; } lipc::ShmRef> info = (*iter); VBucketInfo &vbkt_info = *info->second_; + // Acquire vbkt_info read lock (read blobs) + ScopedRwReadLock vbkt_info_lock(vbkt_info.header_->lock_); auto link_iter = vbkt_info.blobs_->find(blob_id); return link_iter != vbkt_info.blobs_->end(); } @@ -526,6 +606,8 @@ bool MetadataManager::LocalVBucketContainsBlob(VBucketId vbkt_id, * */ bool MetadataManager::LocalRenameVBucket(VBucketId vbkt_id, lipc::charbuf &new_vbkt_name) { + // Acquire MD write lock (modify vbkt_id_map_) + ScopedRwWriteLock md_lock(lock_); auto iter = vbkt_map_->find(vbkt_id); if (iter == vbkt_map_->end()) { return true; @@ -545,6 +627,8 @@ bool MetadataManager::LocalRenameVBucket(VBucketId vbkt_id, * @RPC_CLASS_INSTANCE mdm * */ bool MetadataManager::LocalDestroyVBucket(VBucketId vbkt_id) { + // Acquire MD write lock (modify vbkt_map_) + ScopedRwWriteLock md_lock(lock_); vbkt_map_->erase(vbkt_id); return true; } diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 713ddca29..198427189 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -64,6 +64,8 @@ struct MetadataManagerShmHeader { lipc::TypedPointer>> targets_; /// Used to create unique ids. Starts at 1. std::atomic id_alloc_; + /// Synchronization + RwLock lock_; }; /** @@ -156,6 +158,18 @@ class MetadataManager { RPC size_t LocalGetBucketSize(BucketId bkt_id, const IoClientContext &opts); + /** + * Lock the bucket + * */ + RPC void LocalLockBucket(BucketId bkt_id, + MdLockType lock_type); + + /** + * Unlock the bucket + * */ + RPC void LocalUnlockBucket(BucketId bkt_id, + MdLockType lock_type); + /** * Check whether or not \a bkt_id bucket contains * \a blob_id blob @@ -163,7 +177,7 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - bool LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id); + RPC bool LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id); /** * Rename \a bkt_id bucket to \a new_bkt_name new name @@ -237,6 +251,18 @@ class MetadataManager { * */ RPC BlobId LocalGetBlobId(BucketId bkt_id, lipc::charbuf &blob_name); + /** + * Lock the blob + * */ + RPC void LocalLockBlob(BlobId blob_id, + MdLockType lock_type); + + /** + * Unlock the blob + * */ + RPC void LocalUnlockBlob(BlobId blob_id, + MdLockType lock_type); + /** * Get \a blob_id blob's buffers * @@ -355,6 +381,61 @@ class MetadataManager { lipc::vector GetGlobalTargetInfo() { return {}; } + + private: + /** Acquire the external lock to Bucket or Blob */ + template + void LockMdObject(lipc::unordered_map &map, + IdT id, + MdLockType lock_type) { + ScopedRwReadLock md_lock(lock_); + auto iter = map.find(id); + if (iter == map.end()) { + return; + } + lipc::ShmRef> info = *iter; + MapSecond &obj_info = *info->second_; + switch (lock_type) { + case MdLockType::kExternalRead: { + obj_info.header_->lock_[1].ReadLock(); + return; + } + case MdLockType::kExternalWrite: { + obj_info.header_->lock_[1].WriteLock(); + return; + } + default: { + return; + } + } + } + + /** Release the external lock to Bucket or Blob */ + template + void UnlockMdObject(lipc::unordered_map &map, + IdT id, + MdLockType lock_type) { + ScopedRwReadLock md_lock(lock_); + auto iter = map.find(id); + if (iter == map.end()) { + return; + } + lipc::ShmRef> info = *iter; + MapSecond &obj_info = *info->second_; + switch (lock_type) { + case MdLockType::kExternalRead: { + obj_info.header_->lock_[1].ReadLock(); + return; + } + case MdLockType::kExternalWrite: { + obj_info.header_->lock_[1].WriteLock(); + return; + } + default: { + return; + } + } + } }; } // namespace hermes diff --git a/src/metadata_types.h b/src/metadata_types.h index 527d34d2f..666b9a82c 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -20,15 +20,24 @@ namespace hermes { using adapter::GlobalIoClientState; -using api::Blob; -struct BucketInfo; /** Forward declaration of BucketInfo */ -struct BlobInfo; /** Forward declaration of BlobInfo */ -struct VBucketInfo; /** Forward declaration of VBucketInfo */ +using api::Blob; /**< Namespace simplification for blob */ +struct BucketInfo; /**< Forward declaration of BucketInfo */ +struct BlobInfo; /**< Forward declaration of BlobInfo */ +struct VBucketInfo; /**< Forward declaration of VBucketInfo */ -/** Device information required by other processes */ +/** Device information (e.g., path) */ using config::DeviceInfo; +/** I/O interface to use for BORG (e.g., POSIX) */ using config::IoInterface; +/** Lock type used for internal metadata */ +enum class MdLockType { + kInternalRead, /**< Internal read lock used by Hermes */ + kInternalWrite, /**< Internal write lock by Hermes */ + kExternalRead, /**< External is used by programs */ + kExternalWrite, /**< External is used by programs */ +}; + /** Represents the current status of a target */ struct TargetInfo { TargetId id_; /**< unique Target ID */ @@ -104,7 +113,7 @@ struct ShmHeader : public lipc::ShmBaseHeader { lipc::TypedPointer> buffers_ar_; /**< SHM pointer to BufferInfo vector */ size_t blob_size_; /**< The overall size of the blob */ - RwLock rwlock_; /**< Ensures BlobInfo access is synchronized */ + RwLock lock_[2]; /**< Ensures BlobInfo access is synchronized */ /** Default constructor */ ShmHeader() = default; @@ -113,15 +122,13 @@ struct ShmHeader : public lipc::ShmBaseHeader { ShmHeader(const ShmHeader &other) noexcept : bkt_id_(other.bkt_id_), name_ar_(other.name_ar_), buffers_ar_(other.buffers_ar_), - blob_size_(other.blob_size_), - rwlock_() {} + blob_size_(other.blob_size_) {} /** Move constructor */ ShmHeader(ShmHeader &&other) noexcept : bkt_id_(std::move(other.bkt_id_)), name_ar_(std::move(other.name_ar_)), buffers_ar_(std::move(other.buffers_ar_)), - blob_size_(other.blob_size_), - rwlock_() {} + blob_size_(other.blob_size_) {} /** Copy assignment */ ShmHeader& operator=(const ShmHeader &other) { @@ -226,10 +233,53 @@ struct BlobInfo : public lipc::ShmContainer { /** Represents BucketInfo in shared memory */ template<> struct ShmHeader : public lipc::ShmBaseHeader { + /** Name of the bucket */ lipc::TypedPointer name_ar_; + /** Archive of blob vector */ lipc::TypedPointer> blobs_ar_; - size_t internal_size_; + size_t internal_size_; /**< Current bucket size */ + /** State needed to be maintained for I/O clients */ GlobalIoClientState client_state_; + RwLock lock_[2]; /**< Ensures BucketInfo access is synchronized */ + + /** Default constructor */ + ShmHeader() = default; + + /** Copy constructor */ + ShmHeader(const ShmHeader &other) noexcept + : name_ar_(other.name_ar_), + blobs_ar_(other.blobs_ar_), + internal_size_(other.internal_size_), + client_state_(other.client_state_) {} + + /** Move constructor */ + ShmHeader(ShmHeader &&other) noexcept + : name_ar_(other.name_ar_), + blobs_ar_(other.blobs_ar_), + internal_size_(other.internal_size_), + client_state_(other.client_state_) {} + + /** Copy assignment */ + ShmHeader& operator=(const ShmHeader &other) { + if (this != &other) { + name_ar_ = other.name_ar_; + blobs_ar_ = other.blobs_ar_; + internal_size_ = other.internal_size_; + client_state_ = other.client_state_; + } + return *this; + } + + /** Move assignment */ + ShmHeader& operator=(ShmHeader &&other) { + if (this != &other) { + name_ar_ = other.name_ar_; + blobs_ar_ = other.blobs_ar_; + internal_size_ = other.internal_size_; + client_state_ = other.client_state_; + } + return *this; + } }; /** Metadata for a Bucket */ @@ -293,8 +343,40 @@ struct BucketInfo : public lipc::ShmContainer { /** Represents a VBucket in shared memory */ template<> struct ShmHeader : public lipc::ShmBaseHeader { - lipc::TypedPointer name_; - lipc::TypedPointer> blobs_; + lipc::TypedPointer name_ar_; + lipc::TypedPointer> blobs_ar_; + RwLock lock_; + + /** Default constructor */ + ShmHeader() = default; + + /** Copy constructor */ + ShmHeader(const ShmHeader &other) noexcept + : name_ar_(other.name_ar_), + blobs_ar_(other.blobs_ar_) {} + + /** Move constructor */ + ShmHeader(ShmHeader &&other) noexcept + : name_ar_(other.name_ar_), + blobs_ar_(other.blobs_ar_) {} + + /** Copy assignment */ + ShmHeader& operator=(const ShmHeader &other) { + if (this != &other) { + name_ar_ = other.name_ar_; + blobs_ar_ = other.blobs_ar_; + } + return *this; + } + + /** Move assignment */ + ShmHeader& operator=(ShmHeader &&other) { + if (this != &other) { + name_ar_ = other.name_ar_; + blobs_ar_ = other.blobs_ar_; + } + return *this; + } }; /** Metadata for a VBucket */ @@ -327,14 +409,14 @@ struct VBucketInfo : public lipc::ShmContainer { /** Serialize into SHM */ void shm_serialize_main() const { - name_ >> header_->name_; - blobs_ >> header_->blobs_; + name_ >> header_->name_ar_; + blobs_ >> header_->blobs_ar_; } /** Deserialize from SHM */ void shm_deserialize_main() { - name_ << header_->name_; - blobs_ << header_->blobs_; + name_ << header_->name_ar_; + blobs_ << header_->blobs_ar_; } /** Move other object into this one */ From 2bb39f2d54bd16c6ae71dfebcf6a70de51e279c8 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 5 Feb 2023 11:43:28 -0600 Subject: [PATCH 120/511] Multi-threaded I/O seems to pass --- adapter/filesystem/filesystem.cc | 5 +++-- adapter/posix/posix_io_client.cc | 12 ++++++------ adapter/test/posix/simple_io.cc | 29 ++++++++++++++++++++--------- config/hermes_client_default.yaml | 2 +- src/config_client_default.h | 2 +- 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 8f2b03b73..69da34468 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -64,8 +64,9 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, (void) f; std::shared_ptr &bkt = stat.bkt_id_; std::string filename = bkt->GetName(); - LOG(INFO) << "Write called for filename: " << filename << " on offset: " - << off << " and size: " << total_size << std::endl; + LOG(INFO) << "Write called for filename: " << filename + << " on offset: " << off + << " and size: " << total_size << std::endl; size_t ret; BlobPlacements mapping; diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 0d4eafda8..6f119c89d 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -105,9 +105,9 @@ void PosixIoClient::WriteBlob(const lipc::charbuf &bkt_name, return; } status.size_ = real_api->pwrite(fd, - full_blob.data(), - full_blob.size(), - opts.backend_off_); + full_blob.data(), + full_blob.size(), + opts.backend_off_); real_api->close(fd); } @@ -128,9 +128,9 @@ void PosixIoClient::ReadBlob(const lipc::charbuf &bkt_name, return; } status.size_ = real_api->pread(fd, - full_blob.data(), - full_blob.size(), - opts.backend_off_); + full_blob.data(), + full_blob.size(), + opts.backend_off_); real_api->close(fd); } diff --git a/adapter/test/posix/simple_io.cc b/adapter/test/posix/simple_io.cc index ec652ac1a..ad6564e0c 100644 --- a/adapter/test/posix/simple_io.cc +++ b/adapter/test/posix/simple_io.cc @@ -59,15 +59,19 @@ int main(int argc, char **argv) { size_t total_size = size * nprocs; int off = (rank * size) + block_off * block_size; - std::stringstream ss; - ss << "RANK: " << rank << std::endl - << " PATH: " << path << std::endl - << " READ or WRITE: " << (do_read ? "READ" : "WRITE") << std::endl - << " Block Off: " << block_off << std::endl - << " Block Size: " << block_size << std::endl - << " Count: " << count << std::endl - << " Proc Size (MB): " << size / (1<<20) << std::endl; - std::cout << ss.str() << std::endl; + { + std::stringstream ss; + ss << "RANK: " << rank << std::endl + << " PATH: " << path << std::endl + << " READ or WRITE: " << (do_read ? "READ" : "WRITE") << std::endl + << " Block Off: " << block_off << std::endl + << " Block Size: " << block_size << std::endl + << " Count: " << count << std::endl + << " Proc Size (MB): " << size / (1 << 20) << std::endl + << " Num Ranks: " << nprocs << std::endl; + std::cout << ss.str() << std::endl; + } + MPI_Barrier(MPI_COMM_WORLD); sleep(lag); @@ -102,5 +106,12 @@ int main(int argc, char **argv) { } close(fd); + + MPI_Barrier(MPI_COMM_WORLD); + { + std::stringstream ss; + ss << "SIMPLE I/O COMPLETED! (rank: " << rank << ")" << std::endl; + std::cout << ss.str(); + } MPI_Finalize(); } diff --git a/config/hermes_client_default.yaml b/config/hermes_client_default.yaml index e212f3113..ee3c489d9 100644 --- a/config/hermes_client_default.yaml +++ b/config/hermes_client_default.yaml @@ -1,4 +1,4 @@ -stop_daemon: true +stop_daemon: false path_inclusions: ["/home"] path_exclusions: ["/"] file_page_size: 1024KB diff --git a/src/config_client_default.h b/src/config_client_default.h index b6099cfb6..5ac8b8081 100644 --- a/src/config_client_default.h +++ b/src/config_client_default.h @@ -1,7 +1,7 @@ #ifndef HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ #define HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ const char* kClientDefaultConfigStr = -"stop_daemon: true\n" +"stop_daemon: false\n" "path_inclusions: [\"/home\"]\n" "path_exclusions: [\"/\"]\n" "file_page_size: 1024KB\n" From 7e6a6f19e22cbc0c19f8561cca316248d7d6d22e Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 5 Feb 2023 14:25:20 -0600 Subject: [PATCH 121/511] Improved concurrency control by enabling creation + then locking of blob --- adapter/filesystem/filesystem.cc | 4 +++ src/api/bucket.cc | 21 ++++++++++----- src/api/bucket.h | 14 ++++++++-- src/metadata_manager.cc | 45 ++++++++++++++++++++++++++------ src/metadata_manager.h | 32 ++++++++++++----------- 5 files changed, 84 insertions(+), 32 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 69da34468..33f9effbd 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -83,12 +83,14 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; opts.mode_ = stat.adapter_mode_; + bkt->LockBlob(blob_name.str(), MdLockType::kExternalWrite); bkt->PartialPutOrCreate(blob_name.str(), blob_wrap, p.blob_off_, blob_id, opts, ctx_); + bkt->UnlockBlob(blob_name.str(), MdLockType::kExternalWrite); data_offset += p.blob_size_; } if (opts.DoSeek()) { stat.st_ptr_ = off + data_offset; } @@ -122,6 +124,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, opts.backend_size_ = kPageSize; opts.type_ = type_; opts.mode_ = stat.adapter_mode_; + bkt->LockBlob(blob_name.str(), MdLockType::kExternalRead); bkt->PartialGetOrCreate(blob_name.str(), blob_wrap, p.blob_off_, @@ -129,6 +132,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, blob_id, opts, ctx_); + bkt->UnlockBlob(blob_name.str(), MdLockType::kExternalRead); data_offset += p.blob_size_; } if (opts.DoSeek()) { stat.st_ptr_ = off + data_offset; } diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 41a7e7e53..46c87c0ad 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -82,15 +82,15 @@ Status Bucket::GetBlobId(std::string blob_name, /** * Lock the bucket * */ -void Bucket::LockBlob(BlobId blob_id, MdLockType lock_type) { - mdm_->LocalLockBlob(blob_id, lock_type); +bool Bucket::LockBlob(const std::string &blob_name, MdLockType lock_type) { + return mdm_->LocalLockBlob(id_, blob_name, lock_type); } /** * Unlock the bucket * */ -void Bucket::UnlockBlob(BlobId blob_id, MdLockType lock_type) { - mdm_->LocalUnlockBlob(blob_id, lock_type); +bool Bucket::UnlockBlob(const std::string &blob_name, MdLockType lock_type) { + return mdm_->LocalUnlockBlob(id_, blob_name, lock_type); } /** @@ -149,15 +149,19 @@ Status Bucket::PartialPutOrCreate(const std::string &blob_name, if (blob_off == 0 && blob.size() == opts.backend_size_) { // Case 1: We're overriding the entire blob // Put the entire blob, no need to load from storage + LOG(INFO) << "Putting the entire blob." << std::endl; return Put(blob_name, blob, blob_id, ctx); } - if (ContainsBlob(blob_id)) { + if (ContainsBlob(blob_name, blob_id)) { // Case 2: The blob already exists (read from hermes) // Read blob from Hermes + LOG(INFO) << "Blob existed. Reading from Hermes." << std::endl; Get(blob_id, full_blob, ctx); - } else { + } + if (full_blob.size() != opts.backend_size_) { // Case 3: The blob did not exist (need to read from backend) // Read blob using adapter + LOG(INFO) << "Blob didn't fully exist. Reading from backend." << std::endl; IoStatus status; auto io_client = IoClientFactory::Get(opts.type_); full_blob.resize(opts.backend_size_); @@ -207,10 +211,13 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, if (ContainsBlob(blob_name, blob_id)) { // Case 1: The blob already exists (read from hermes) // Read blob from Hermes + LOG(INFO) << "Blob existed. Reading blob from Hermes." << std::endl; Get(blob_id, full_blob, ctx); - } else { + } + if (full_blob.size() != opts.backend_size_) { // Case 2: The blob did not exist (need to read from backend) // Read blob using adapter + LOG(INFO) << "Blob did not exist. Reading blob from backend." << std::endl; IoStatus status; auto io_client = IoClientFactory::Get(opts.type_); full_blob.resize(opts.backend_size_); diff --git a/src/api/bucket.h b/src/api/bucket.h index 51552541a..05e708762 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -109,12 +109,12 @@ class Bucket { /** * Lock the blob * */ - void LockBlob(BlobId blob_id, MdLockType lock_type); + bool LockBlob(const std::string &blob_name, MdLockType lock_type); /** * Unlock the blob * */ - void UnlockBlob(BlobId blob_id, MdLockType lock_type); + bool UnlockBlob(const std::string &blob_name, MdLockType lock_type); /** * Put \a blob_name Blob into the bucket @@ -171,6 +171,16 @@ class Bucket { const IoClientContext &opts, Context &ctx); + /** + * Flush a blob + * */ + void FlushBlob(BlobId blob_id); + + /** + * Flush the entire bucket + * */ + void FlushBucket(); + /** * Determine if the bucket contains \a blob_id BLOB * */ diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 2f199aa18..4b5f79a8d 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -318,8 +318,8 @@ std::tuple MetadataManager::LocalBucketPutBlob( size_t blob_size, lipc::vector &buffers) { size_t orig_blob_size = 0; - // Acquire MD read lock (read blob_map_) - ScopedRwReadLock md_lock(lock_); + // Acquire MD write lock (modify blob_map_) + ScopedRwWriteLock md_lock(lock_); // Get internal blob name lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); // Create unique ID for the Blob @@ -330,9 +330,10 @@ std::tuple MetadataManager::LocalBucketPutBlob( if (did_create) { BlobInfo blob_info(HERMES->main_alloc_); blob_info.bkt_id_ = bkt_id; - (*blob_info.name_) = std::move(internal_blob_name); + (*blob_info.name_) = internal_blob_name; (*blob_info.buffers_) = std::move(buffers); blob_info.header_->blob_size_ = blob_size; + blob_id_map_->emplace(internal_blob_name, blob_id); blob_map_->emplace(blob_id, std::move(blob_info)); } else { blob_id = *(*blob_id_map_)[internal_blob_name]; @@ -356,6 +357,9 @@ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { // Acquire MD read lock (read blob_map_) ScopedRwReadLock md_lock(lock_); auto iter = blob_map_->find(blob_id); + if (iter == blob_map_->end()) { + return Blob(); + } lipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; // Acquire blob_info read lock (read buffers) @@ -371,7 +375,7 @@ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { * @RPC_CLASS_INSTANCE mdm * */ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, - lipc::charbuf &blob_name) { + const lipc::charbuf &blob_name) { // Acquire MD read lock (read blob_id_map_) ScopedRwReadLock md_lock(lock_); lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); @@ -386,17 +390,42 @@ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, /** * Lock the blob * */ -void MetadataManager::LocalLockBlob(BlobId blob_id, +bool MetadataManager::LocalLockBlob(BucketId bkt_id, + const std::string &blob_name, MdLockType lock_type) { - LockMdObject(*blob_map_, blob_id, lock_type); + // Acquire MD write lock (might modify blob_map_) + BlobId blob_id = LocalGetBlobId(bkt_id, lipc::charbuf(blob_name)); + if (blob_id.IsNull()) { + // Create blob if it DNE + ScopedRwWriteLock md_lock(lock_); + lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, + lipc::charbuf(blob_name)); + auto iter = blob_id_map_->find(internal_blob_name); + if (iter == blob_id_map_->end()) { + blob_id.unique_ = header_->id_alloc_.fetch_add(1); + blob_id.node_id_ = rpc_->node_id_; + BlobInfo blob_info(HERMES->main_alloc_); + blob_info.bkt_id_ = bkt_id; + (*blob_info.name_) = internal_blob_name; + blob_info.header_->blob_size_ = 0; + blob_id_map_->emplace(internal_blob_name, blob_id); + blob_map_->emplace(blob_id, std::move(blob_info)); + } + } + return LockMdObject(*blob_map_, blob_id, lock_type); } /** * Unlock the blob * */ -void MetadataManager::LocalUnlockBlob(BlobId blob_id, +bool MetadataManager::LocalUnlockBlob(BucketId bkt_id, + const std::string &blob_name, MdLockType lock_type) { - UnlockMdObject(*blob_map_, blob_id, lock_type); + BlobId blob_id = LocalGetBlobId(bkt_id, lipc::charbuf(blob_name)); + if (blob_id.IsNull()) { + return false; + } + return UnlockMdObject(*blob_map_, blob_id, lock_type); } /** diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 198427189..248fec6b6 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -249,18 +249,20 @@ class MetadataManager { * @RPC_TARGET_NODE rpc_->node_id_ * @RPC_CLASS_INSTANCE mdm * */ - RPC BlobId LocalGetBlobId(BucketId bkt_id, lipc::charbuf &blob_name); + RPC BlobId LocalGetBlobId(BucketId bkt_id, const lipc::charbuf &blob_name); /** * Lock the blob * */ - RPC void LocalLockBlob(BlobId blob_id, + RPC bool LocalLockBlob(BucketId bkt_id, + const std::string &blob_name, MdLockType lock_type); /** * Unlock the blob * */ - RPC void LocalUnlockBlob(BlobId blob_id, + RPC bool LocalUnlockBlob(BucketId bkt_id, + const std::string &blob_name, MdLockType lock_type); /** @@ -385,54 +387,54 @@ class MetadataManager { private: /** Acquire the external lock to Bucket or Blob */ template - void LockMdObject(lipc::unordered_map &map, + bool LockMdObject(lipc::unordered_map &map, IdT id, MdLockType lock_type) { ScopedRwReadLock md_lock(lock_); auto iter = map.find(id); if (iter == map.end()) { - return; + return false; } lipc::ShmRef> info = *iter; MapSecond &obj_info = *info->second_; switch (lock_type) { case MdLockType::kExternalRead: { obj_info.header_->lock_[1].ReadLock(); - return; + return true; } case MdLockType::kExternalWrite: { obj_info.header_->lock_[1].WriteLock(); - return; + return true; } default: { - return; + return false; } } } /** Release the external lock to Bucket or Blob */ template - void UnlockMdObject(lipc::unordered_map &map, + bool UnlockMdObject(lipc::unordered_map &map, IdT id, MdLockType lock_type) { ScopedRwReadLock md_lock(lock_); auto iter = map.find(id); if (iter == map.end()) { - return; + return false; } lipc::ShmRef> info = *iter; MapSecond &obj_info = *info->second_; switch (lock_type) { case MdLockType::kExternalRead: { - obj_info.header_->lock_[1].ReadLock(); - return; + obj_info.header_->lock_[1].ReadUnlock(); + return true; } case MdLockType::kExternalWrite: { - obj_info.header_->lock_[1].WriteLock(); - return; + obj_info.header_->lock_[1].WriteUnlock(); + return true; } default: { - return; + return false; } } } From 5fa082ccd4c35f70bb055e0b4cd9eca1497b6bfa Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 5 Feb 2023 17:55:04 -0600 Subject: [PATCH 122/511] FlushBlob --- adapter/filesystem/filesystem_io_client.h | 24 ++++ adapter/io_client/io_client.h | 17 ++- adapter/mapper/abstract_mapper.h | 5 + adapter/mpiio/mpiio_io_client.cc | 5 - adapter/mpiio/mpiio_io_client.h | 4 - adapter/posix/posix_io_client.cc | 7 -- adapter/posix/posix_io_client.h | 4 - adapter/stdio/stdio_api.cc | 2 +- adapter/stdio/stdio_io_client.cc | 7 -- adapter/stdio/stdio_io_client.h | 4 - src/api/bucket.cc | 59 ++++++++- src/api/bucket.h | 25 +++- src/metadata_manager.cc | 147 +++++++++++----------- src/metadata_manager.h | 71 ++--------- src/metadata_types.h | 8 +- 15 files changed, 214 insertions(+), 175 deletions(-) diff --git a/adapter/filesystem/filesystem_io_client.h b/adapter/filesystem/filesystem_io_client.h index 2eeb0e496..290440a69 100644 --- a/adapter/filesystem/filesystem_io_client.h +++ b/adapter/filesystem/filesystem_io_client.h @@ -14,6 +14,7 @@ #define HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_IO_CLIENT_H_ #include "adapter/io_client/io_client.h" +#include "adapter/mapper/balanced_mapper.h" #include #include @@ -77,6 +78,29 @@ class FilesystemIoClient : public IoClient { /** virtual destructor */ virtual ~FilesystemIoClient() = default; + /** Update backend statistics when registering a blob */ + void RegisterBlob(const IoClientContext &opts, + GlobalIoClientState &stat) override { + stat.true_size_ = std::max(stat.true_size_, + opts.backend_off_ + opts.backend_size_); + } + + /** Update backend statistics when unregistering a blob */ + void UnregisterBlob(const IoClientContext &opts, + GlobalIoClientState &stat) override {} + + /** Decode I/O client context from the original blob name */ + IoClientContext DecodeBlobName(const IoClientContext &opts, + const std::string &blob_name) override { + IoClientContext decode_opts; + BlobPlacement p; + p.DecodeBlobName(blob_name); + decode_opts.type_ = opts.type_; + decode_opts.backend_off_ = p.bucket_off_; + decode_opts.backend_size_ = p.blob_size_; + return decode_opts; + } + /** real open */ virtual void RealOpen(IoClientObject &f, IoClientStats &stat, diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index 04a94720e..d696c5cb9 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -161,11 +161,16 @@ class IoClient { GlobalIoClientState &stat) = 0; /** - * What the statistics would be if all blobs were flushed from Hermes - * to the backing storage system. + * How to update the backend when registering a blob * */ - virtual void UpdateBucketState(const IoClientContext &opts, - GlobalIoClientState &stat) = 0; + virtual void RegisterBlob(const IoClientContext &opts, + GlobalIoClientState &stat) = 0; + + /** + * How to update the backend when unregistering a blob + * */ + virtual void UnregisterBlob(const IoClientContext &opts, + GlobalIoClientState &stat) = 0; /** Write blob to backend */ virtual void WriteBlob(const lipc::charbuf &bkt_name, @@ -178,6 +183,10 @@ class IoClient { Blob &full_blob, const IoClientContext &opts, IoStatus &status) = 0; + + /** Decode I/O client context from the blob name */ + virtual IoClientContext DecodeBlobName(const IoClientContext &opts, + const std::string &blob_name) = 0; }; } // namespace hermes::adapter diff --git a/adapter/mapper/abstract_mapper.h b/adapter/mapper/abstract_mapper.h index 843643d8f..b426091ec 100644 --- a/adapter/mapper/abstract_mapper.h +++ b/adapter/mapper/abstract_mapper.h @@ -46,6 +46,11 @@ struct BlobPlacement { void DecodeBlobName(const lipc::charbuf &blob_name) { memcpy(&page_, blob_name.data(), sizeof(page_)); } + + /** decode \a blob_name BLOB name to index. */ + void DecodeBlobName(const std::string &blob_name) { + memcpy(&page_, blob_name.data(), sizeof(page_)); + } }; typedef std::vector BlobPlacements; diff --git a/adapter/mpiio/mpiio_io_client.cc b/adapter/mpiio/mpiio_io_client.cc index 5664f705a..b8fa1da92 100644 --- a/adapter/mpiio/mpiio_io_client.cc +++ b/adapter/mpiio/mpiio_io_client.cc @@ -63,11 +63,6 @@ void MpiioIoClient::InitBucketState(const lipc::charbuf &bkt_name, GlobalIoClientState &stat) { } -/** Update backend statistics */ -void MpiioIoClient::UpdateBucketState(const IoClientContext &opts, - GlobalIoClientState &stat) { -} - /** Initialize I/O context using count + datatype */ size_t MpiioIoClient::IoSizeFromCount(int count, MPI_Datatype datatype, diff --git a/adapter/mpiio/mpiio_io_client.h b/adapter/mpiio/mpiio_io_client.h index 5d539ced9..0808869f6 100644 --- a/adapter/mpiio/mpiio_io_client.h +++ b/adapter/mpiio/mpiio_io_client.h @@ -66,10 +66,6 @@ class MpiioIoClient : public hermes::adapter::fs::FilesystemIoClient { const IoClientContext &opts, GlobalIoClientState &stat) override; - /** Update backend statistics */ - void UpdateBucketState(const IoClientContext &opts, - GlobalIoClientState &stat) override; - /** Initialize I/O context using count + datatype */ static size_t IoSizeFromCount(int count, MPI_Datatype datatype, diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 6f119c89d..65865dd8c 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -81,13 +81,6 @@ void PosixIoClient::InitBucketState(const lipc::charbuf &bkt_name, real_api->close(fd); } -/** Update backend statistics */ -void PosixIoClient::UpdateBucketState(const IoClientContext &opts, - GlobalIoClientState &stat) { - stat.true_size_ = std::max(stat.true_size_, - opts.backend_off_ + opts.backend_size_); -} - /** Write blob to backend */ void PosixIoClient::WriteBlob(const lipc::charbuf &bkt_name, const Blob &full_blob, diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h index 0d2ef74cc..40620d661 100644 --- a/adapter/posix/posix_io_client.h +++ b/adapter/posix/posix_io_client.h @@ -75,10 +75,6 @@ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { const IoClientContext &opts, GlobalIoClientState &stat) override; - /** Update backend statistics */ - void UpdateBucketState(const IoClientContext &opts, - GlobalIoClientState &stat) override; - /** Write blob to backend */ void WriteBlob(const lipc::charbuf &bkt_name, const Blob &full_blob, diff --git a/adapter/stdio/stdio_api.cc b/adapter/stdio/stdio_api.cc index b561423e9..7e18ff194 100644 --- a/adapter/stdio/stdio_api.cc +++ b/adapter/stdio/stdio_api.cc @@ -67,7 +67,7 @@ FILE *HERMES_DECL(fdopen)(int fd, const char *mode) { std::shared_ptr stat; if (fs_api->IsFdTracked(fd, stat)) { LOG(INFO) << "Intercepting fdopen(" << fd << ", " << mode << ")\n"; - fs_api->FdOpen(mode, stat); + return fs_api->FdOpen(mode, stat); } else { return real_api->fdopen(fd, mode); } diff --git a/adapter/stdio/stdio_io_client.cc b/adapter/stdio/stdio_io_client.cc index 71be07eb7..3a9f55772 100644 --- a/adapter/stdio/stdio_io_client.cc +++ b/adapter/stdio/stdio_io_client.cc @@ -70,13 +70,6 @@ void StdioIoClient::InitBucketState(const lipc::charbuf &bkt_name, // TODO(llogan) } -/** Update backend statistics */ -void StdioIoClient::UpdateBucketState(const IoClientContext &opts, - GlobalIoClientState &stat) { - stat.true_size_ = std::max(stat.true_size_, - opts.backend_off_ + opts.backend_size_); -} - /** Write blob to backend */ void StdioIoClient::WriteBlob(const lipc::charbuf &bkt_name, const Blob &full_blob, diff --git a/adapter/stdio/stdio_io_client.h b/adapter/stdio/stdio_io_client.h index 6c2b1881c..2ad97e602 100644 --- a/adapter/stdio/stdio_io_client.h +++ b/adapter/stdio/stdio_io_client.h @@ -74,10 +74,6 @@ class StdioIoClient : public hermes::adapter::fs::FilesystemIoClient { const IoClientContext &opts, GlobalIoClientState &stat) override; - /** Update backend statistics */ - void UpdateBucketState(const IoClientContext &opts, - GlobalIoClientState &stat) override; - /** Write blob to backend */ void WriteBlob(const lipc::charbuf &bkt_name, const Blob &full_blob, diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 46c87c0ad..4424eded9 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -72,13 +72,27 @@ void Bucket::Destroy() { /** * Get the id of a blob from the blob name * */ -Status Bucket::GetBlobId(std::string blob_name, +Status Bucket::GetBlobId(const std::string &blob_name, BlobId &blob_id) { lipc::string lblob_name(blob_name); blob_id = mdm_->LocalGetBlobId(GetId(), lblob_name); return Status(); } +/** + * Get the name of a blob from the blob id + * + * @param blob_id the blob_id + * @param blob_name the name of the blob + * @return The Status of the operation + * */ +Status Bucket::GetBlobName(const BlobId &blob_id, std::string &blob_name) { + lipc::string lblob_name(blob_name); + blob_name = mdm_->LocalGetBlobName(blob_id); + return Status(); +} + + /** * Lock the bucket * */ @@ -236,6 +250,38 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, return Status(); } +/** + * Flush a blob + * */ +void Bucket::FlushBlob(BlobId blob_id, + const IoClientContext &opts) { + Blob full_blob; + IoStatus status; + // Read blob from Hermes + Get(blob_id, full_blob, ctx_); + std::string blob_name; + GetBlobName(blob_id, blob_name); + // Write blob to backend + auto io_client = IoClientFactory::Get(opts.type_); + if (io_client) { + IoClientContext decode_opts = io_client->DecodeBlobName(opts, blob_name); + io_client->WriteBlob(lipc::charbuf(name_), + full_blob, + decode_opts, + status); + } +} + +/** + * Flush the entire bucket + * */ +void Bucket::Flush(const IoClientContext &opts) { + std::vector blob_ids = GetContainedBlobIds(); + for (BlobId &blob_id : blob_ids) { + FlushBlob(blob_id, opts); + } +} + /** * Determine if the bucket contains \a blob_id BLOB * */ @@ -265,8 +311,17 @@ void Bucket::RenameBlob(BlobId blob_id, /** * Delete \a blob_id blob * */ -void Bucket::DestroyBlob(BlobId blob_id, Context &ctx) { +void Bucket::DestroyBlob(BlobId blob_id, Context &ctx, + IoClientContext opts) { + mdm_->LocalBucketUnregisterBlobId(id_, blob_id, opts); mdm_->LocalDestroyBlob(id_, blob_id); } +/** + * Get the set of blob IDs contained in the bucket + * */ +std::vector Bucket::GetContainedBlobIds() { + return mdm_->LocalBucketGetContainedBlobIds(id_); +} + } // namespace hermes::api diff --git a/src/api/bucket.h b/src/api/bucket.h index 05e708762..7a97c004a 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -104,7 +104,16 @@ class Bucket { * @param blob_id (output) the returned blob_id * @return The Status of the operation * */ - Status GetBlobId(std::string blob_name, BlobId &blob_id); + Status GetBlobId(const std::string &blob_name, BlobId &blob_id); + + /** + * Get the name of a blob from the blob id + * + * @param blob_id the blob_id + * @param blob_name the name of the blob + * @return The Status of the operation + * */ + Status GetBlobName(const BlobId &blob_id, std::string &blob_name); /** * Lock the blob @@ -174,12 +183,13 @@ class Bucket { /** * Flush a blob * */ - void FlushBlob(BlobId blob_id); + void FlushBlob(BlobId blob_id, + const IoClientContext &opts); /** * Flush the entire bucket * */ - void FlushBucket(); + void Flush(const IoClientContext &opts); /** * Determine if the bucket contains \a blob_id BLOB @@ -200,7 +210,14 @@ class Bucket { /** * Delete \a blob_id blob * */ - void DestroyBlob(BlobId blob_id, Context &ctx); + void DestroyBlob(BlobId blob_id, Context &ctx, + IoClientContext opts = IoClientContext()); + + private: + /** + * Get the set of blob IDs contained in the bucket + * */ + std::vector GetContainedBlobIds(); }; } // namespace hermes::api diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 4b5f79a8d..6e09485ae 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -110,9 +110,6 @@ void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { /** * Get or create a bucket with \a bkt_name bucket name - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ BucketId MetadataManager::LocalGetOrCreateBucket( lipc::charbuf &bkt_name, @@ -151,9 +148,6 @@ BucketId MetadataManager::LocalGetOrCreateBucket( /** * Get the BucketId with \a bkt_name bucket name - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { // Acquire MD read lock (reading bkt_id_map) @@ -170,9 +164,6 @@ BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { /** * Get the size of the bucket. May consider the impact the bucket has * on the backing storage system's statistics using the io_ctx. - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ size_t MetadataManager::LocalGetBucketSize(BucketId bkt_id, const IoClientContext &opts) { @@ -211,9 +202,6 @@ RPC void MetadataManager::LocalUnlockBucket(BucketId blob_id, /** * Check whether or not \a bkt_id bucket contains * \a blob_id blob - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ bool MetadataManager::LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id) { @@ -229,11 +217,29 @@ bool MetadataManager::LocalBucketContainsBlob(BucketId bkt_id, return blob_info.bkt_id_ == bkt_id; } +/** + * Get the set of all blobs contained in \a bkt_id BUCKET + * */ +std::vector +MetadataManager::LocalBucketGetContainedBlobIds(BucketId bkt_id) { + // Acquire MD read lock (reading bkt_map_) + ScopedRwReadLock md_lock(lock_); + std::vector blob_ids; + auto iter = bkt_map_->find(bkt_id); + if (iter == bkt_map_->end()) { + return blob_ids; + } + lipc::ShmRef> info = *iter; + BucketInfo &bkt_info = *info->second_; + blob_ids.resize(bkt_info.blobs_->size()); + for (lipc::ShmRef blob_id : *bkt_info.blobs_) { + blob_ids.emplace_back(*blob_id); + } + return blob_ids; +} + /** * Rename \a bkt_id bucket to \a new_bkt_name new name - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ bool MetadataManager::LocalRenameBucket(BucketId bkt_id, lipc::charbuf &new_bkt_name) { @@ -252,9 +258,6 @@ bool MetadataManager::LocalRenameBucket(BucketId bkt_id, /** * Destroy \a bkt_id bucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ bool MetadataManager::LocalDestroyBucket(BucketId bkt_id) { // Acquire MD write lock (modifying bkt_map_) @@ -279,26 +282,54 @@ Status MetadataManager::LocalBucketRegisterBlobId( } lipc::ShmRef> info = (*iter); BucketInfo &bkt_info = *info->second_; - // Acquire BktInfo Write Lock (modifying) + // Acquire BktInfo Write Lock (modifying bkt_info) ScopedRwWriteLock info_lock(bkt_info.header_->lock_[0]); // Update I/O client bucket stats auto io_client = IoClientFactory::Get(opts.type_); if (io_client) { - io_client->UpdateBucketState(opts, bkt_info.header_->client_state_); + io_client->RegisterBlob(opts, bkt_info.header_->client_state_); } // Update internal bucket size bkt_info.header_->internal_size_ += new_blob_size - orig_blob_size; // Add blob to ID vector if it didn't already exist if (!did_create) { return Status(); } - // TODO(llogan): add blob id + bkt_info.blobs_->emplace_back(blob_id); return Status(); } /** Unregister a blob from a bucket */ Status MetadataManager::LocalBucketUnregisterBlobId( BucketId bkt_id, BlobId blob_id, - const IoClientContext &io_ctx) { - // TODO(llogan) + const IoClientContext &opts) { + // Acquire MD read lock (read bkt_map_) + ScopedRwReadLock md_lock(lock_); + auto iter = bkt_map_->find(bkt_id); + if (iter == bkt_map_->end()) { + return Status(); + } + // Get blob information + auto iter_blob = blob_map_->find(blob_id); + if (iter_blob == blob_map_->end()) { + return Status(); + } + // Acquire the blob read lock (read blob_size) + lipc::ShmRef> info_blob = (*iter_blob); + BlobInfo &blob_info = *info_blob->second_; + size_t blob_size = blob_info.header_->blob_size_; + // Acquire the bkt_info write lock (modifying bkt_info) + lipc::ShmRef> info = (*iter); + BucketInfo &bkt_info = *info->second_; + ScopedRwWriteLock(bkt_info.header_->lock_[0]); + // Update I/O client bucket stats + auto io_client = IoClientFactory::Get(opts.type_); + if (io_client) { + io_client->UnregisterBlob(opts, bkt_info.header_->client_state_); + } + // Update internal bucket size + bkt_info.header_->internal_size_ -= blob_size; + // Remove BlobId from bucket + bkt_info.blobs_->erase(blob_id); + return Status(); } /** @@ -308,9 +339,6 @@ Status MetadataManager::LocalBucketUnregisterBlobId( * @param blob_name semantic blob name * @param data the data being placed * @param buffers the buffers to place data in - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ std::tuple MetadataManager::LocalBucketPutBlob( BucketId bkt_id, @@ -330,7 +358,7 @@ std::tuple MetadataManager::LocalBucketPutBlob( if (did_create) { BlobInfo blob_info(HERMES->main_alloc_); blob_info.bkt_id_ = bkt_id; - (*blob_info.name_) = internal_blob_name; + (*blob_info.name_) = blob_name; (*blob_info.buffers_) = std::move(buffers); blob_info.header_->blob_size_ = blob_size; blob_id_map_->emplace(internal_blob_name, blob_id); @@ -349,9 +377,6 @@ std::tuple MetadataManager::LocalBucketPutBlob( /** * Get \a blob_name blob from \a bkt_id bucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { // Acquire MD read lock (read blob_map_) @@ -370,9 +395,6 @@ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { /** * Get \a blob_name blob from \a bkt_id bucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, const lipc::charbuf &blob_name) { @@ -387,6 +409,21 @@ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, return *info->second_; } +/** + * Get \a blob_name BLOB name from \a blob_id BLOB id + * */ +RPC std::string MetadataManager::LocalGetBlobName(BlobId blob_id) { + // Acquire MD read lock (read blob_id_map_) + ScopedRwReadLock md_lock(lock_); + auto iter = blob_map_->find(blob_id); + if (iter == blob_map_->end()) { + return ""; + } + lipc::ShmRef> info = *iter; + BlobInfo &blob_info = *info->second_; + return blob_info.name_->str(); +} + /** * Lock the blob * */ @@ -406,7 +443,7 @@ bool MetadataManager::LocalLockBlob(BucketId bkt_id, blob_id.node_id_ = rpc_->node_id_; BlobInfo blob_info(HERMES->main_alloc_); blob_info.bkt_id_ = bkt_id; - (*blob_info.name_) = internal_blob_name; + (*blob_info.name_) = lipc::charbuf(blob_name); blob_info.header_->blob_size_ = 0; blob_id_map_->emplace(internal_blob_name, blob_id); blob_map_->emplace(blob_id, std::move(blob_info)); @@ -430,9 +467,6 @@ bool MetadataManager::LocalUnlockBlob(BucketId bkt_id, /** * Get \a blob_id blob's buffers - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ std::vector MetadataManager::LocalGetBlobBuffers(BlobId blob_id) { // Acquire MD read lock (read blob_map_) @@ -445,21 +479,12 @@ std::vector MetadataManager::LocalGetBlobBuffers(BlobId blob_id) { BlobInfo &blob_info = *info->second_; // Acquire blob_info read lock ScopedRwReadLock blob_info_lock(blob_info.header_->lock_[0]); - // TODO(llogan): make this internal to the lipc::vec - std::vector v; - v.reserve(blob_info.buffers_->size()); - for (lipc::ShmRef buffer_info : *blob_info.buffers_) { - v.emplace_back(*buffer_info); - } - return v; + return blob_info.buffers_->vec(); } /** * Rename \a blob_id blob to \a new_blob_name new blob name * in \a bkt_id bucket. - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ bool MetadataManager::LocalRenameBlob(BucketId bkt_id, BlobId blob_id, lipc::charbuf &new_blob_name) { @@ -471,7 +496,7 @@ bool MetadataManager::LocalRenameBlob(BucketId bkt_id, BlobId blob_id, } lipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; - lipc::charbuf &old_blob_name = (*blob_info.name_); + lipc::charbuf old_blob_name = CreateBlobName(bkt_id, *blob_info.name_); lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, new_blob_name); blob_id_map_->erase(old_blob_name); blob_id_map_->emplace(internal_blob_name, blob_id); @@ -480,9 +505,6 @@ bool MetadataManager::LocalRenameBlob(BucketId bkt_id, BlobId blob_id, /** * Destroy \a blob_id blob in \a bkt_id bucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ bool MetadataManager::LocalDestroyBlob(BucketId bkt_id, BlobId blob_id) { @@ -495,7 +517,7 @@ bool MetadataManager::LocalDestroyBlob(BucketId bkt_id, } lipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; - lipc::charbuf &blob_name = (*blob_info.name_); + lipc::charbuf blob_name = CreateBlobName(bkt_id, *blob_info.name_); blob_id_map_->erase(blob_name); blob_map_->erase(blob_id); return true; @@ -503,9 +525,6 @@ bool MetadataManager::LocalDestroyBlob(BucketId bkt_id, /** * Get or create \a vbkt_name VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ VBucketId MetadataManager::LocalGetOrCreateVBucket( lipc::charbuf &vbkt_name, @@ -536,9 +555,6 @@ VBucketId MetadataManager::LocalGetOrCreateVBucket( /** * Get the VBucketId of \a vbkt_name VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ VBucketId MetadataManager::LocalGetVBucketId(lipc::charbuf &vbkt_name) { // Acquire MD read lock (read vbkt_id_map_) @@ -554,9 +570,6 @@ VBucketId MetadataManager::LocalGetVBucketId(lipc::charbuf &vbkt_name) { /** * Link \a vbkt_id VBucketId - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ bool MetadataManager::LocalVBucketLinkBlob(VBucketId vbkt_id, BlobId blob_id) { @@ -577,9 +590,6 @@ bool MetadataManager::LocalVBucketLinkBlob(VBucketId vbkt_id, /** * Unlink \a blob_name Blob of \a bkt_id Bucket * from \a vbkt_id VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ bool MetadataManager::LocalVBucketUnlinkBlob(VBucketId vbkt_id, BlobId blob_id) { @@ -599,9 +609,6 @@ bool MetadataManager::LocalVBucketUnlinkBlob(VBucketId vbkt_id, /** * Get the linked blobs from \a vbkt_id VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ std::list MetadataManager::LocalVBucketGetLinks(VBucketId vbkt_id) { // TODO(llogan) @@ -629,9 +636,6 @@ bool MetadataManager::LocalVBucketContainsBlob(VBucketId vbkt_id, /** * Rename \a vbkt_id VBucket to \a new_vbkt_name name - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ bool MetadataManager::LocalRenameVBucket(VBucketId vbkt_id, lipc::charbuf &new_vbkt_name) { @@ -651,9 +655,6 @@ bool MetadataManager::LocalRenameVBucket(VBucketId vbkt_id, /** * Destroy \a vbkt_id VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ bool MetadataManager::LocalDestroyVBucket(VBucketId vbkt_id) { // Acquire MD write lock (modify vbkt_map_) diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 248fec6b6..0635b6e89 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -134,26 +134,17 @@ class MetadataManager { /** * Get or create a bucket with \a bkt_name bucket name - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC BucketId LocalGetOrCreateBucket(lipc::charbuf &bkt_name, const IoClientContext &opts); /** * Get the BucketId with \a bkt_name bucket name - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC BucketId LocalGetBucketId(lipc::charbuf &bkt_name); /** * Get the size of a bucket (depends on the IoClient used). - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC size_t LocalGetBucketSize(BucketId bkt_id, const IoClientContext &opts); @@ -173,26 +164,22 @@ class MetadataManager { /** * Check whether or not \a bkt_id bucket contains * \a blob_id blob - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalBucketContainsBlob(BucketId bkt_id, BlobId blob_id); + /** + * Get the set of all blobs contained in \a bkt_id BUCKET + * */ + RPC std::vector LocalBucketGetContainedBlobIds(BucketId bkt_id); + /** * Rename \a bkt_id bucket to \a new_bkt_name new name - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalRenameBucket(BucketId bkt_id, lipc::charbuf &new_bkt_name); /** * Destroy \a bkt_id bucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalDestroyBucket(BucketId bkt_id); @@ -203,9 +190,6 @@ class MetadataManager { * @param blob_name semantic blob name * @param data the data being placed * @param buffers the buffers to place data in - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC std::tuple LocalBucketPutBlob( BucketId bkt_id, @@ -230,27 +214,26 @@ class MetadataManager { * */ Status LocalBucketUnregisterBlobId(BucketId bkt_id, BlobId blob_id, - const IoClientContext &io_ctx); + const IoClientContext &opts); /** * Get a blob from a bucket * * @param bkt_id id of the bucket * @param blob_id id of the blob to get - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC Blob LocalBucketGetBlob(BlobId blob_id); /** - * Get \a blob_name blob from \a bkt_id bucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm + * Get \a blob_name BLOB from \a bkt_id bucket * */ RPC BlobId LocalGetBlobId(BucketId bkt_id, const lipc::charbuf &blob_name); + /** + * Get \a blob_name BLOB name from \a blob_id BLOB id + * */ + RPC std::string LocalGetBlobName(BlobId blob_id); + /** * Lock the blob * */ @@ -267,69 +250,45 @@ class MetadataManager { /** * Get \a blob_id blob's buffers - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC std::vector LocalGetBlobBuffers(BlobId blob_id); /** * Rename \a blob_id blob to \a new_blob_name new blob name * in \a bkt_id bucket. - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalRenameBlob(BucketId bkt_id, BlobId blob_id, lipc::charbuf &new_blob_name); /** * Destroy \a blob_id blob in \a bkt_id bucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalDestroyBlob(BucketId bkt_id, BlobId blob_id); /** * Get or create \a vbkt_name VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC VBucketId LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name, const IoClientContext &opts); /** * Get the VBucketId of \a vbkt_name VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC VBucketId LocalGetVBucketId(lipc::charbuf &vbkt_name); /** * Link \a vbkt_id VBucketId - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalVBucketLinkBlob(VBucketId vbkt_id, BlobId blob_id); /** * Unlink \a blob_name Blob of \a bkt_id Bucket * from \a vbkt_id VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalVBucketUnlinkBlob(VBucketId vbkt_id, BlobId blob_id); /** * Get the linked blobs from \a vbkt_id VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC std::list LocalVBucketGetLinks(VBucketId vbkt_id); @@ -340,17 +299,11 @@ class MetadataManager { /** * Rename \a vbkt_id VBucket to \a new_vbkt_name name - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalRenameVBucket(VBucketId vbkt_id, lipc::charbuf &new_vbkt_name); /** * Destroy \a vbkt_id VBucket - * - * @RPC_TARGET_NODE rpc_->node_id_ - * @RPC_CLASS_INSTANCE mdm * */ RPC bool LocalDestroyVBucket(VBucketId vbkt_id); diff --git a/src/metadata_types.h b/src/metadata_types.h index 666b9a82c..234696ca5 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -236,7 +236,7 @@ struct ShmHeader : public lipc::ShmBaseHeader { /** Name of the bucket */ lipc::TypedPointer name_ar_; /** Archive of blob vector */ - lipc::TypedPointer> blobs_ar_; + lipc::TypedPointer> blobs_ar_; size_t internal_size_; /**< Current bucket size */ /** State needed to be maintained for I/O clients */ GlobalIoClientState client_state_; @@ -289,6 +289,7 @@ struct BucketInfo : public lipc::ShmContainer { public: lipc::mptr name_; /**< The name of the bucket */ + lipc::mptr> blobs_; /**< All blobs in this Bucket */ public: /** Default constructor */ @@ -300,6 +301,7 @@ struct BucketInfo : public lipc::ShmContainer { shm_init_allocator(alloc); shm_init_header(header); name_ = lipc::make_mptr(alloc); + blobs_ = lipc::make_mptr>(alloc); } /** Destroy all allocated data */ @@ -310,11 +312,13 @@ struct BucketInfo : public lipc::ShmContainer { /** Serialize pointers */ void shm_serialize_main() const { name_ >> header_->name_ar_; + blobs_ >> header_->blobs_ar_; } /** Deserialize pointers */ void shm_deserialize_main() { name_ << header_->name_ar_; + blobs_ << header_->blobs_ar_; } /** Move other object into this one */ @@ -325,6 +329,7 @@ struct BucketInfo : public lipc::ShmContainer { shm_init_header(header); (*header_) = (*other.header_); (*name_) = (*other.name_); + (*blobs_) = (*other.blobs_); shm_serialize_main(); } @@ -336,6 +341,7 @@ struct BucketInfo : public lipc::ShmContainer { shm_init_header(header); (*header_) = (*other.header_); (*name_) = (*other.name_); + (*blobs_) = (*other.blobs_); shm_serialize_main(); } }; From 3f8a956407c4782cb902e6c6efb30ec6948ce680 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 5 Feb 2023 19:03:37 -0600 Subject: [PATCH 123/511] Track blobs in bucket --- adapter/filesystem/filesystem.cc | 25 +++++++++++++---- adapter/filesystem/filesystem.h | 1 - src/api/bucket.cc | 21 +++++++++++++++ src/api/bucket.h | 12 +++++++-- src/metadata_manager.cc | 46 +++++++++++++++++++++----------- src/metadata_manager.h | 10 +++++++ 6 files changed, 92 insertions(+), 23 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 33f9effbd..c52b0e74f 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -35,8 +35,9 @@ File Filesystem::Open(AdapterStat &stat, const std::string &path) { void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { auto mdm = HERMES_FS_METADATA_MANAGER; FsIoOptions opts; + Context ctx; opts.type_ = type_; - stat.bkt_id_ = HERMES->GetBucket(path, ctx_, opts); + stat.bkt_id_ = HERMES->GetBucket(path, ctx, opts); // TODO(llogan): can avoid two unordered_map queries here stat.adapter_mode_ = mdm->GetAdapterMode(path); stat.page_size_ = mdm->GetAdapterPageSize(path); @@ -46,7 +47,7 @@ void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { // Create the new bucket FsIoOptions opts; opts.type_ = type_; - stat.bkt_id_ = HERMES->GetBucket(path, ctx_, opts); + stat.bkt_id_ = HERMES->GetBucket(path, ctx, opts); // Allocate internal hermes data auto stat_ptr = std::make_shared(stat); FilesystemIoClientObject fs_ctx(&mdm->fs_mdm_, (void*)stat_ptr.get()); @@ -69,6 +70,7 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, << " and size: " << total_size << std::endl; size_t ret; + Context ctx; BlobPlacements mapping; size_t kPageSize = stat.page_size_; size_t data_offset = 0; @@ -83,13 +85,14 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; opts.mode_ = stat.adapter_mode_; + bkt->TryCreateBlob(blob_name.str(), blob_id, ctx, opts); bkt->LockBlob(blob_name.str(), MdLockType::kExternalWrite); bkt->PartialPutOrCreate(blob_name.str(), blob_wrap, p.blob_off_, blob_id, opts, - ctx_); + ctx); bkt->UnlockBlob(blob_name.str(), MdLockType::kExternalWrite); data_offset += p.blob_size_; } @@ -110,6 +113,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, << off << " and size: " << total_size << std::endl; size_t ret; + Context ctx; BlobPlacements mapping; size_t kPageSize = stat.page_size_; size_t data_offset = 0; @@ -124,6 +128,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, opts.backend_size_ = kPageSize; opts.type_ = type_; opts.mode_ = stat.adapter_mode_; + bkt->TryCreateBlob(blob_name.str(), blob_id, ctx, opts); bkt->LockBlob(blob_name.str(), MdLockType::kExternalRead); bkt->PartialGetOrCreate(blob_name.str(), blob_wrap, @@ -131,7 +136,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, p.blob_size_, blob_id, opts, - ctx_); + ctx); bkt->UnlockBlob(blob_name.str(), MdLockType::kExternalRead); data_offset += p.blob_size_; } @@ -245,12 +250,22 @@ off_t Filesystem::Tell(File &f, AdapterStat &stat) { } int Filesystem::Sync(File &f, AdapterStat &stat) { + IoClientContext opts; + opts.type_ = type_; + stat.bkt_id_->Flush(opts); + return 0; } int Filesystem::Close(File &f, AdapterStat &stat, bool destroy) { + Sync(f, stat); + if (destroy) { + stat.bkt_id_->Destroy(); + } + auto mdm = HERMES_FS_METADATA_MANAGER; + mdm->Delete(f); + return 0; } - /** * Variants of Read and Write which do not take an offset as * input. diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index ca8fb562e..5d9a4c593 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -110,7 +110,6 @@ class Filesystem { public: FilesystemIoClient *io_client_; AdapterType type_; - Context ctx_; public: /** Constructor */ diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 4424eded9..771831342 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -107,6 +107,25 @@ bool Bucket::UnlockBlob(const std::string &blob_name, MdLockType lock_type) { return mdm_->LocalUnlockBlob(id_, blob_name, lock_type); } +/** + * Put \a blob_id Blob into the bucket + * */ +Status Bucket::TryCreateBlob(const std::string &blob_name, + BlobId &blob_id, + Context &ctx, + const IoClientContext &opts) { + std::pair ret = mdm_->LocalBucketTryCreateBlob( + id_, lipc::charbuf(blob_name)); + blob_id = ret.first; + if (ret.second) { + mdm_->LocalBucketRegisterBlobId(id_, + blob_id, + 0, 0, true, + opts); + } + return Status(); +} + /** * Put \a blob_id Blob into the bucket * */ @@ -255,6 +274,7 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, * */ void Bucket::FlushBlob(BlobId blob_id, const IoClientContext &opts) { + LOG(INFO) << "Flushing blob" << std::endl; Blob full_blob; IoStatus status; // Read blob from Hermes @@ -277,6 +297,7 @@ void Bucket::FlushBlob(BlobId blob_id, * */ void Bucket::Flush(const IoClientContext &opts) { std::vector blob_ids = GetContainedBlobIds(); + LOG(INFO) << "Flushing " << blob_ids.size() << " blobs" << std::endl; for (BlobId &blob_id : blob_ids) { FlushBlob(blob_id, opts); } diff --git a/src/api/bucket.h b/src/api/bucket.h index 7a97c004a..9a9fddb6e 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -125,6 +125,14 @@ class Bucket { * */ bool UnlockBlob(const std::string &blob_name, MdLockType lock_type); + /** + * Create \a blob_name EMPTY BLOB if it does not already exist. + * */ + Status TryCreateBlob(const std::string &blob_name, + BlobId &blob_id, + Context &ctx, + const IoClientContext &opts); + /** * Put \a blob_name Blob into the bucket * */ @@ -136,7 +144,7 @@ class Bucket { /** * Put \a blob_name Blob into the bucket. Load the blob from the - * I/O backend if it does not exist. + * I/O backend if it does not exist or is not fully loaded. * * @param blob_name the semantic name of the blob * @param blob the buffer to put final data in @@ -162,7 +170,7 @@ class Bucket { /** * Load \a blob_name Blob from the bucket. Load the blob from the - * I/O backend if it does not exist. + * I/O backend if it does not exist or is not fully loaded. * * @param blob_name the semantic name of the blob * @param blob the buffer to put final data in diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 6e09485ae..6abc54f42 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -332,6 +332,36 @@ Status MetadataManager::LocalBucketUnregisterBlobId( return Status(); } +/** + * Creates the blob metadata + * + * @param bkt_id id of the bucket + * @param blob_name semantic blob name + * */ +std::pair MetadataManager::LocalBucketTryCreateBlob( + BucketId bkt_id, + const lipc::charbuf &blob_name) { + size_t orig_blob_size = 0; + // Acquire MD write lock (modify blob_map_) + ScopedRwWriteLock md_lock(lock_); + // Get internal blob name + lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); + // Create unique ID for the Blob + BlobId blob_id; + blob_id.unique_ = header_->id_alloc_.fetch_add(1); + blob_id.node_id_ = rpc_->node_id_; + bool did_create = blob_id_map_->try_emplace(internal_blob_name, blob_id); + if (did_create) { + BlobInfo blob_info(HERMES->main_alloc_); + blob_info.bkt_id_ = bkt_id; + (*blob_info.name_) = blob_name; + blob_info.header_->blob_size_ = 0; + blob_id_map_->emplace(internal_blob_name, blob_id); + blob_map_->emplace(blob_id, std::move(blob_info)); + } + return std::pair(blob_id, did_create); +} + /** * Creates the blob metadata * @@ -433,21 +463,7 @@ bool MetadataManager::LocalLockBlob(BucketId bkt_id, // Acquire MD write lock (might modify blob_map_) BlobId blob_id = LocalGetBlobId(bkt_id, lipc::charbuf(blob_name)); if (blob_id.IsNull()) { - // Create blob if it DNE - ScopedRwWriteLock md_lock(lock_); - lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, - lipc::charbuf(blob_name)); - auto iter = blob_id_map_->find(internal_blob_name); - if (iter == blob_id_map_->end()) { - blob_id.unique_ = header_->id_alloc_.fetch_add(1); - blob_id.node_id_ = rpc_->node_id_; - BlobInfo blob_info(HERMES->main_alloc_); - blob_info.bkt_id_ = bkt_id; - (*blob_info.name_) = lipc::charbuf(blob_name); - blob_info.header_->blob_size_ = 0; - blob_id_map_->emplace(internal_blob_name, blob_id); - blob_map_->emplace(blob_id, std::move(blob_info)); - } + return false; } return LockMdObject(*blob_map_, blob_id, lock_type); } diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 0635b6e89..d856b8753 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -216,6 +216,16 @@ class MetadataManager { BlobId blob_id, const IoClientContext &opts); + /** + * Creates the blob metadata + * + * @param bkt_id id of the bucket + * @param blob_name semantic blob name + * */ + std::pair LocalBucketTryCreateBlob( + BucketId bkt_id, + const lipc::charbuf &blob_name); + /** * Get a blob from a bucket * From 256394dd900b512a174e55ea956561869d40450c Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 5 Feb 2023 19:43:06 -0600 Subject: [PATCH 124/511] Flushing goes to correct offsets --- adapter/filesystem/filesystem.cc | 12 ++++++------ adapter/filesystem/filesystem_io_client.h | 3 +-- adapter/mapper/abstract_mapper.h | 20 +++++++++++--------- src/api/bucket.cc | 8 ++++---- src/api/bucket.h | 4 ++-- src/metadata_manager.cc | 23 +++++++++++++++-------- src/metadata_manager.h | 6 ++---- 7 files changed, 41 insertions(+), 35 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index c52b0e74f..a03e3ad1b 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -79,21 +79,21 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, for (const auto &p : mapping) { const Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); - lipc::charbuf blob_name(p.CreateBlobName()); + lipc::charbuf blob_name(p.CreateBlobName(kPageSize)); BlobId blob_id; opts.type_ = type_; opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; opts.mode_ = stat.adapter_mode_; bkt->TryCreateBlob(blob_name.str(), blob_id, ctx, opts); - bkt->LockBlob(blob_name.str(), MdLockType::kExternalWrite); + bkt->LockBlob(blob_id, MdLockType::kExternalWrite); bkt->PartialPutOrCreate(blob_name.str(), blob_wrap, p.blob_off_, blob_id, opts, ctx); - bkt->UnlockBlob(blob_name.str(), MdLockType::kExternalWrite); + bkt->UnlockBlob(blob_id, MdLockType::kExternalWrite); data_offset += p.blob_size_; } if (opts.DoSeek()) { stat.st_ptr_ = off + data_offset; } @@ -122,14 +122,14 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, for (const auto &p : mapping) { Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); - lipc::charbuf blob_name(p.CreateBlobName()); + lipc::charbuf blob_name(p.CreateBlobName(kPageSize)); BlobId blob_id; opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; opts.type_ = type_; opts.mode_ = stat.adapter_mode_; bkt->TryCreateBlob(blob_name.str(), blob_id, ctx, opts); - bkt->LockBlob(blob_name.str(), MdLockType::kExternalRead); + bkt->LockBlob(blob_id, MdLockType::kExternalRead); bkt->PartialGetOrCreate(blob_name.str(), blob_wrap, p.blob_off_, @@ -137,7 +137,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, blob_id, opts, ctx); - bkt->UnlockBlob(blob_name.str(), MdLockType::kExternalRead); + bkt->UnlockBlob(blob_id, MdLockType::kExternalRead); data_offset += p.blob_size_; } if (opts.DoSeek()) { stat.st_ptr_ = off + data_offset; } diff --git a/adapter/filesystem/filesystem_io_client.h b/adapter/filesystem/filesystem_io_client.h index 290440a69..480602537 100644 --- a/adapter/filesystem/filesystem_io_client.h +++ b/adapter/filesystem/filesystem_io_client.h @@ -96,8 +96,7 @@ class FilesystemIoClient : public IoClient { BlobPlacement p; p.DecodeBlobName(blob_name); decode_opts.type_ = opts.type_; - decode_opts.backend_off_ = p.bucket_off_; - decode_opts.backend_size_ = p.blob_size_; + decode_opts.backend_off_ = p.page_ * p.blob_size_; return decode_opts; } diff --git a/adapter/mapper/abstract_mapper.h b/adapter/mapper/abstract_mapper.h index b426091ec..5ebeef802 100644 --- a/adapter/mapper/abstract_mapper.h +++ b/adapter/mapper/abstract_mapper.h @@ -36,20 +36,22 @@ struct BlobPlacement { int time_; /**< The order of the blob in a list of blobs */ /** create a BLOB name from index. */ - lipc::charbuf CreateBlobName() const { - lipc::charbuf buf(sizeof(page_)); - memcpy(buf.data_mutable(), &page_, sizeof(page_)); + lipc::charbuf CreateBlobName(size_t page_size) const { + lipc::charbuf buf(sizeof(page_) + sizeof(page_size)); + size_t off = 0; + memcpy(buf.data_mutable() + off, &page_, sizeof(page_)); + off += sizeof(page_); + memcpy(buf.data_mutable() + off, &page_size, sizeof(page_size)); return buf; } /** decode \a blob_name BLOB name to index. */ - void DecodeBlobName(const lipc::charbuf &blob_name) { - memcpy(&page_, blob_name.data(), sizeof(page_)); - } - - /** decode \a blob_name BLOB name to index. */ - void DecodeBlobName(const std::string &blob_name) { + template + void DecodeBlobName(const StringT &blob_name) { + size_t off = 0; memcpy(&page_, blob_name.data(), sizeof(page_)); + off += sizeof(page_); + memcpy(&blob_size_, blob_name.data() + off, sizeof(blob_size_)); } }; diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 771831342..d8fc47537 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -96,15 +96,15 @@ Status Bucket::GetBlobName(const BlobId &blob_id, std::string &blob_name) { /** * Lock the bucket * */ -bool Bucket::LockBlob(const std::string &blob_name, MdLockType lock_type) { - return mdm_->LocalLockBlob(id_, blob_name, lock_type); +bool Bucket::LockBlob(BlobId blob_id, MdLockType lock_type) { + return mdm_->LocalLockBlob(blob_id, lock_type); } /** * Unlock the bucket * */ -bool Bucket::UnlockBlob(const std::string &blob_name, MdLockType lock_type) { - return mdm_->LocalUnlockBlob(id_, blob_name, lock_type); +bool Bucket::UnlockBlob(BlobId blob_id, MdLockType lock_type) { + return mdm_->LocalUnlockBlob(blob_id, lock_type); } /** diff --git a/src/api/bucket.h b/src/api/bucket.h index 9a9fddb6e..80dc72377 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -118,12 +118,12 @@ class Bucket { /** * Lock the blob * */ - bool LockBlob(const std::string &blob_name, MdLockType lock_type); + bool LockBlob(BlobId blob_id, MdLockType lock_type); /** * Unlock the blob * */ - bool UnlockBlob(const std::string &blob_name, MdLockType lock_type); + bool UnlockBlob(BlobId blob_id, MdLockType lock_type); /** * Create \a blob_name EMPTY BLOB if it does not already exist. diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index 6abc54f42..e64c4f71c 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -108,6 +108,10 @@ void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { devices_ << header_->devices_; } +//////////////////////////// +/// Bucket Operations +//////////////////////////// + /** * Get or create a bucket with \a bkt_name bucket name * */ @@ -231,7 +235,7 @@ MetadataManager::LocalBucketGetContainedBlobIds(BucketId bkt_id) { } lipc::ShmRef> info = *iter; BucketInfo &bkt_info = *info->second_; - blob_ids.resize(bkt_info.blobs_->size()); + blob_ids.reserve(bkt_info.blobs_->size()); for (lipc::ShmRef blob_id : *bkt_info.blobs_) { blob_ids.emplace_back(*blob_id); } @@ -332,6 +336,10 @@ Status MetadataManager::LocalBucketUnregisterBlobId( return Status(); } +//////////////////////////// +/// Blob Operations +//////////////////////////// + /** * Creates the blob metadata * @@ -457,11 +465,8 @@ RPC std::string MetadataManager::LocalGetBlobName(BlobId blob_id) { /** * Lock the blob * */ -bool MetadataManager::LocalLockBlob(BucketId bkt_id, - const std::string &blob_name, +bool MetadataManager::LocalLockBlob(BlobId blob_id, MdLockType lock_type) { - // Acquire MD write lock (might modify blob_map_) - BlobId blob_id = LocalGetBlobId(bkt_id, lipc::charbuf(blob_name)); if (blob_id.IsNull()) { return false; } @@ -471,10 +476,8 @@ bool MetadataManager::LocalLockBlob(BucketId bkt_id, /** * Unlock the blob * */ -bool MetadataManager::LocalUnlockBlob(BucketId bkt_id, - const std::string &blob_name, +bool MetadataManager::LocalUnlockBlob(BlobId blob_id, MdLockType lock_type) { - BlobId blob_id = LocalGetBlobId(bkt_id, lipc::charbuf(blob_name)); if (blob_id.IsNull()) { return false; } @@ -539,6 +542,10 @@ bool MetadataManager::LocalDestroyBlob(BucketId bkt_id, return true; } +//////////////////////////// +/// VBucket Operations +//////////////////////////// + /** * Get or create \a vbkt_name VBucket * */ diff --git a/src/metadata_manager.h b/src/metadata_manager.h index d856b8753..61929f126 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -247,15 +247,13 @@ class MetadataManager { /** * Lock the blob * */ - RPC bool LocalLockBlob(BucketId bkt_id, - const std::string &blob_name, + RPC bool LocalLockBlob(BlobId blob_id, MdLockType lock_type); /** * Unlock the blob * */ - RPC bool LocalUnlockBlob(BucketId bkt_id, - const std::string &blob_name, + RPC bool LocalUnlockBlob(BlobId blob_id, MdLockType lock_type); /** From d8be3ce3fe19c5bd248bcd01fc5bc6ea62328fbd Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 03:07:13 -0600 Subject: [PATCH 125/511] Environment variable overrides --- adapter/filesystem/filesystem.cc | 4 ++-- adapter/filesystem/filesystem.h | 2 -- adapter/io_client/io_client.h | 1 + adapter/mapper/abstract_mapper.h | 2 +- adapter/mpiio/mpiio_io_client.cc | 2 +- adapter/posix/posix_io_client.cc | 2 +- adapter/stdio/stdio_io_client.cc | 2 +- adapter/test/posix/simple_io.cc | 2 +- src/api/bucket.cc | 11 +++++++++-- src/api/hermes.h | 11 +---------- src/config.h | 1 + src/config_client.cc | 28 +++++++++++++++++++++------- src/constants.h | 3 +++ src/utils.cc | 27 --------------------------- src/utils.h | 16 ++++++++++------ 15 files changed, 53 insertions(+), 61 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index a03e3ad1b..43f557eb1 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -84,7 +84,7 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, opts.type_ = type_; opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; - opts.mode_ = stat.adapter_mode_; + opts.adapter_mode_ = stat.adapter_mode_; bkt->TryCreateBlob(blob_name.str(), blob_id, ctx, opts); bkt->LockBlob(blob_id, MdLockType::kExternalWrite); bkt->PartialPutOrCreate(blob_name.str(), @@ -127,7 +127,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; opts.type_ = type_; - opts.mode_ = stat.adapter_mode_; + opts.adapter_mode_ = stat.adapter_mode_; bkt->TryCreateBlob(blob_name.str(), blob_id, ctx, opts); bkt->LockBlob(blob_id, MdLockType::kExternalRead); bkt->PartialGetOrCreate(blob_name.str(), diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index 5d9a4c593..d71930d46 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -74,8 +74,6 @@ struct AdapterStat : public IoClientStats { * For now, nothing additional than the typical IoClientContext. * */ struct FsIoOptions : public IoClientContext { - AdapterMode mode_; /**< Mode used for the adapter */ - /** Default constructor */ FsIoOptions() : IoClientContext() { flags_.SetBits(HERMES_FS_SEEK); diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index d696c5cb9..e509a77d3 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -56,6 +56,7 @@ struct IoClientObject { struct IoClientContext { // TODO(llogan): We should use an std::variant or union instead of large set AdapterType type_; /**< Client to forward I/O request to */ + AdapterMode adapter_mode_; /**< Current adapter mode for this obj */ hapi::PlacementPolicy dpe_; /**< data placement policy */ bitfield32_t flags_; /**< various I/O flags */ MPI_Datatype mpi_type_; /**< MPI data type */ diff --git a/adapter/mapper/abstract_mapper.h b/adapter/mapper/abstract_mapper.h index 5ebeef802..5a08f8e47 100644 --- a/adapter/mapper/abstract_mapper.h +++ b/adapter/mapper/abstract_mapper.h @@ -13,7 +13,7 @@ #ifndef HERMES_ABSTRACT_MAPPER_H #define HERMES_ABSTRACT_MAPPER_H -#include "utils.h" +#include "hermes_types.h" namespace hermes::adapter { diff --git a/adapter/mpiio/mpiio_io_client.cc b/adapter/mpiio/mpiio_io_client.cc index b8fa1da92..c82a52e01 100644 --- a/adapter/mpiio/mpiio_io_client.cc +++ b/adapter/mpiio/mpiio_io_client.cc @@ -123,7 +123,7 @@ void MpiioIoClient::ReadBlob(const lipc::charbuf &bkt_name, const IoClientContext &opts, IoStatus &status) { std::string filename = bkt_name.str(); - LOG(INFO) << "Read called for filename from destination: " << filename + LOG(INFO) << "Reading from: " << filename << " on offset: " << opts.backend_off_ << " and size: " << full_blob.size() << "." << " file_size:" << stdfs::file_size(filename) diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 65865dd8c..731f07bb8 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -110,7 +110,7 @@ void PosixIoClient::ReadBlob(const lipc::charbuf &bkt_name, const IoClientContext &opts, IoStatus &status) { (void) opts; - LOG(INFO) << "Writing to file: " << bkt_name.str() + LOG(INFO) << "Reading from file: " << bkt_name.str() << " offset: " << opts.backend_off_ << " size:" << full_blob.size() << "." << " file_size:" << stdfs::file_size(bkt_name.str()) diff --git a/adapter/stdio/stdio_io_client.cc b/adapter/stdio/stdio_io_client.cc index 3a9f55772..dcec01cd4 100644 --- a/adapter/stdio/stdio_io_client.cc +++ b/adapter/stdio/stdio_io_client.cc @@ -99,7 +99,7 @@ void StdioIoClient::ReadBlob(const lipc::charbuf &bkt_name, const IoClientContext &opts, IoStatus &status) { std::string filename = bkt_name.str(); - LOG(INFO) << "Read called for filename from destination: " << filename + LOG(INFO) << "Reading from file: " << filename << " on offset: " << opts.backend_off_ << " and size: " << opts.backend_size_ << "." << " file_size:" << stdfs::file_size(filename) << std::endl; diff --git a/adapter/test/posix/simple_io.cc b/adapter/test/posix/simple_io.cc index ad6564e0c..8aafd89b2 100644 --- a/adapter/test/posix/simple_io.cc +++ b/adapter/test/posix/simple_io.cc @@ -91,7 +91,7 @@ int main(int argc, char **argv) { } for (int i = 0; i < count; ++i) { - char nonce = i; + char nonce = i + 1; if (!do_read) { memset(buf, nonce, block_size); write(fd, buf, block_size); diff --git a/src/api/bucket.cc b/src/api/bucket.cc index d8fc47537..126aa2164 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -15,6 +15,8 @@ namespace hermes::api { +using hermes::adapter::AdapterMode; + /////////////////////////// ////// Bucket Operations ////////////////////////// @@ -208,7 +210,9 @@ Status Bucket::PartialPutOrCreate(const std::string &blob_name, // Modify the blob memcpy(full_blob.data() + blob_off, blob.data(), blob.size()); // Re-put the blob - Put(blob_name, full_blob, blob_id, ctx); + if (opts.adapter_mode_ != AdapterMode::kBypass) { + Put(blob_name, full_blob, blob_id, ctx); + } return Status(); } @@ -256,6 +260,9 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, full_blob.resize(opts.backend_size_); if (io_client) { io_client->ReadBlob(lipc::charbuf(name_), full_blob, opts, status); + if (opts.adapter_mode_ != AdapterMode::kBypass) { + Put(blob_name, full_blob, blob_id, ctx); + } } } // Ensure the blob can hold the update @@ -265,7 +272,7 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, // Modify the blob // TODO(llogan): we can avoid a copy here blob.resize(blob_size); - memcpy(blob.data() + blob_off, full_blob.data() + blob_off, blob.size()); + memcpy(blob.data(), full_blob.data() + blob_off, blob.size()); return Status(); } diff --git a/src/api/hermes.h b/src/api/hermes.h index e54f11a0e..d378323ac 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -17,6 +17,7 @@ #include "config_server.h" #include "constants.h" #include "hermes_types.h" +#include "utils.h" #include "communication_factory.h" #include "rpc.h" @@ -150,16 +151,6 @@ class Hermes { /** Finalize colocated mode */ void FinalizeColocated(); - - private: - /** Get an environment variable with null safety. */ - inline std::string GetEnvSafe(const char *env_name) { - char *val = getenv(env_name); - if (val == nullptr) { - return ""; - } - return val; - } }; #define TRANSPARENT_HERMES\ diff --git a/src/config.h b/src/config.h index cdd45ecb1..8da0c46f4 100644 --- a/src/config.h +++ b/src/config.h @@ -24,6 +24,7 @@ #include "hermes_types.h" #include "constants.h" +#include "utils.h" namespace hermes::config { diff --git a/src/config_client.cc b/src/config_client.cc index 7a74a13bb..6f4403879 100644 --- a/src/config_client.cc +++ b/src/config_client.cc @@ -27,8 +27,7 @@ void ClientConfig::ParseAdapterConfig(YAML::Node &yaml_conf, conf.mode_ = AdapterModeConv::to_enum(yaml_conf["mode"].as()); } if (yaml_conf["page_size"]) { - conf.page_size_ = ParseSize( - yaml_conf["page_size"].as()); + conf.page_size_ = ParseSize(yaml_conf["page_size"].as()); } SetAdapterConfig(path, conf); } @@ -36,15 +35,30 @@ void ClientConfig::ParseAdapterConfig(YAML::Node &yaml_conf, /** parse the YAML node */ void ClientConfig::ParseYAML(YAML::Node &yaml_conf) { if (yaml_conf["stop_daemon"]) { - stop_daemon_ = yaml_conf["stop_daemon"].as(); + std::string stop_env = GetEnvSafe(kHermesStopDaemon); + if (stop_env.size() == 0) { + stop_daemon_ = yaml_conf["stop_daemon"].as(); + } else { + std::istringstream(stop_env) >> stop_daemon_; + } } if (yaml_conf["base_adapter_mode"]) { - base_adapter_config_.mode_ = AdapterModeConv::to_enum( - yaml_conf["base_adapter_mode"].as()); + std::string mode_env = GetEnvSafe(kHermesAdapterMode); + if (mode_env.size() == 0) { + base_adapter_config_.mode_ = AdapterModeConv::to_enum( + yaml_conf["base_adapter_mode"].as()); + } else { + base_adapter_config_.mode_ = AdapterModeConv::to_enum(mode_env); + } } if (yaml_conf["file_page_size"]) { - base_adapter_config_.page_size_ = ParseSize( - yaml_conf["file_page_size"].as()); + std::string page_size_env = GetEnvSafe(kHermesAdapterMode); + if (page_size_env.size() == 0) { + base_adapter_config_.page_size_ = + ParseSize(yaml_conf["file_page_size"].as()); + } else { + base_adapter_config_.page_size_ = ParseSize(page_size_env); + } } if (yaml_conf["path_inclusions"]) { std::vector inclusions; diff --git a/src/constants.h b/src/constants.h index 77e9089ef..3e3123f23 100644 --- a/src/constants.h +++ b/src/constants.h @@ -21,6 +21,9 @@ static const lipc::allocator_id_t main_alloc_id(0, 1); static const char* kHermesServerConf = "HERMES_CONF"; static const char* kHermesClientConf = "HERMES_CLIENT_CONF"; +static const char* kHermesAdapterMode = "HERMES_ADAPTER_MODE"; +static const char* kHermesPageSize = "HERMES_PAGE_SIZE"; +static const char* kHermesStopDaemon = "HERMES_STOP_DAEMON"; static const size_t kMaxPathLength = 4096; static const int kMaxServerNamePrefix = 32; /**< max. server name prefix */ diff --git a/src/utils.cc b/src/utils.cc index 52217f007..2a6254d3f 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -19,33 +19,6 @@ namespace hermes { -size_t RoundUpToMultiple(size_t val, size_t multiple) { - if (multiple == 0) { - return val; - } - - size_t result = val; - size_t remainder = val % multiple; - - if (remainder != 0) { - result += multiple - remainder; - } - - return result; -} - -size_t RoundDownToMultiple(size_t val, size_t multiple) { - if (multiple == 0) { - return val; - } - - size_t result = val; - size_t remainder = val % multiple; - result -= remainder; - - return result; -} - /** print an error message for \a func function that failed */ diff --git a/src/utils.h b/src/utils.h index 702de8e01..e16d8f09a 100644 --- a/src/utils.h +++ b/src/utils.h @@ -14,16 +14,20 @@ #define HERMES_UTILS_H_ #include - -#include #include - -#include "hermes_types.h" +#include namespace hermes { -size_t RoundUpToMultiple(size_t val, size_t multiple); -size_t RoundDownToMultiple(size_t val, size_t multiple); +/** Get an environment variable with null safety. */ +static inline std::string GetEnvSafe(const char *env_name) { + char *val = getenv(env_name); + if (val == nullptr) { + return ""; + } + return val; +} + void FailedLibraryCall(std::string func); } // namespace hermes From 1545fca34f128acf806302bac75f18acdc737315 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 03:11:25 -0600 Subject: [PATCH 126/511] Read PageSize variable --- src/config_client.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config_client.cc b/src/config_client.cc index 6f4403879..d26a8951e 100644 --- a/src/config_client.cc +++ b/src/config_client.cc @@ -52,7 +52,7 @@ void ClientConfig::ParseYAML(YAML::Node &yaml_conf) { } } if (yaml_conf["file_page_size"]) { - std::string page_size_env = GetEnvSafe(kHermesAdapterMode); + std::string page_size_env = GetEnvSafe(kHermesPageSize); if (page_size_env.size() == 0) { base_adapter_config_.page_size_ = ParseSize(yaml_conf["file_page_size"].as()); From 8ce8027bbbe461f85478d834be71f43af7de3284 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 04:14:35 -0600 Subject: [PATCH 127/511] finalize_hermes script --- data_stager/CMakeLists.txt | 4 ---- src/CMakeLists.txt | 4 ++++ {data_stager => src/api}/finalize_hermes.cc | 12 ++++-------- src/api/hermes.cc | 3 +++ 4 files changed, 11 insertions(+), 12 deletions(-) rename {data_stager => src/api}/finalize_hermes.cc (76%) diff --git a/data_stager/CMakeLists.txt b/data_stager/CMakeLists.txt index 481562b51..d1d1b91fa 100644 --- a/data_stager/CMakeLists.txt +++ b/data_stager/CMakeLists.txt @@ -14,10 +14,6 @@ add_executable(stage_out ${CMAKE_CURRENT_SOURCE_DIR}/stage_out.cc) add_dependencies(stage_out hermes_data_stager) target_link_libraries(stage_out hermes_data_stager) -add_executable(finalize_hermes ${CMAKE_CURRENT_SOURCE_DIR}/finalize_hermes.cc) -add_dependencies(finalize_hermes hermes_posix_backend) -target_link_libraries(finalize_hermes hermes_posix_backend) - install( TARGETS hermes_data_stager diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 535f8ef1b..aa2667577 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -117,6 +117,10 @@ target_link_libraries(hermes_daemon hermes -ldl -lc MPI::MPI_CXX glog::glog) target_compile_definitions(hermes_daemon PRIVATE $<$:HERMES_ENABLE_TIMING>) +add_executable(finalize_hermes api/finalize_hermes.cc) +add_dependencies(finalize_hermes hermes) +target_link_libraries(finalize_hermes hermes) + #----------------------------------------------------------------------------- # Specify project header files to be installed #----------------------------------------------------------------------------- diff --git a/data_stager/finalize_hermes.cc b/src/api/finalize_hermes.cc similarity index 76% rename from data_stager/finalize_hermes.cc rename to src/api/finalize_hermes.cc index 087b6cf35..4fcae267f 100644 --- a/data_stager/finalize_hermes.cc +++ b/src/api/finalize_hermes.cc @@ -10,17 +10,13 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "filesystem/metadata_manager.h" #include "singleton.h" +#include "hermes.h" using hermes::Singleton; int main(int argc, char **argv) { - auto mdm = Singleton::GetInstance(); - setenv("HERMES_CLIENT", "1", true); - setenv("HERMES_STOP_DAEMON", "1", true); - MPI_Init(&argc, &argv); - mdm->InitializeHermes(true); - mdm->FinalizeHermes(); - MPI_Finalize(); + HERMES->Create(hermes::HermesType::kClient); + HERMES->client_config_.stop_daemon_ = true; + HERMES->Finalize(); } diff --git a/src/api/hermes.cc b/src/api/hermes.cc index e4c72f04f..005042499 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -42,6 +42,9 @@ void Hermes::Init(HermesType mode, } void Hermes::Finalize() { + if (!is_initialized_ || is_terminated_) { + return; + } switch (mode_) { case HermesType::kServer: { FinalizeServer(); From a92c908d2098676558c8c098d9327e2826d52fe3 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 04:15:04 -0600 Subject: [PATCH 128/511] Stash prefetchers elsewhere --- src/prefetcher.cc | 225 ----------------------------- src/prefetcher.h | 264 ---------------------------------- src/prefetcher_factory.h | 48 ------- src/prefetchers/apriori.cc | 13 -- src/prefetchers/apriori.h | 28 ---- src/prefetchers/sequential.cc | 145 ------------------- src/prefetchers/sequential.h | 52 ------- 7 files changed, 775 deletions(-) delete mode 100644 src/prefetcher.cc delete mode 100644 src/prefetcher.h delete mode 100644 src/prefetcher_factory.h delete mode 100644 src/prefetchers/apriori.cc delete mode 100644 src/prefetchers/apriori.h delete mode 100644 src/prefetchers/sequential.cc delete mode 100644 src/prefetchers/sequential.h diff --git a/src/prefetcher.cc b/src/prefetcher.cc deleted file mode 100644 index d766b4000..000000000 --- a/src/prefetcher.cc +++ /dev/null @@ -1,225 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "prefetcher_factory.h" -#include "metadata_manager.h" -#include "singleton.h" - -using hermes::api::Hermes; - -namespace hermes { - -bool Prefetcher::LogIoStat(Hermes *hermes, IoLogEntry &entry) { - RpcContext *rpc = &hermes->rpc_; - u32 target_node = HashToNode(hermes, entry); - bool result = false; - if (target_node == rpc->node_id) { - auto prefetcher = Singleton::GetInstance(); - prefetcher->Log(entry); - result = true; - } else { - result = RpcCall(rpc, target_node, - "LogIoStat", entry); - } - return result; -} - -/** - * HashToNode - * - * Determines which node an IoLogEntry should be keyed to. - * We hash IoLogEntries to nodes using only the BucketId. - * This way, IoLogEntries regarding a particular blob are - * always placed on the same node. - * - * This approach assumes that prefetching decisions are based - * solely on the bucket's access pattern, not patterns across-buckets. - * */ - -size_t Prefetcher::HashToNode(Hermes *hermes, IoLogEntry &entry) { - CommunicationContext *comm = &hermes->comm_; - size_t hash = std::hash{}(entry.bkt_id_.as_int); - return (hash % comm->num_nodes) + 1; -} - -void Prefetcher::Log(IoLogEntry &entry) { - LOG(INFO) << "Logging I/O stat" << std::endl; - lock_.lock(); - if (log_.size() == max_length_) { - log_.pop_front(); - } - timespec_get(&entry.timestamp_, TIME_UTC); - log_.emplace_back(entry); - lock_.unlock(); -} - -float Prefetcher::EstimateBlobMovementTime(BlobId blob_id) { - Arena arena = InitArenaAndAllocate(MEGABYTES(1)); - u32 *buffer_sizes = 0; - BufferIdArray id_array = GetBufferIdsFromBlobId(&arena, - &hermes_->context_, - &hermes_->rpc_, - blob_id, - &buffer_sizes); - std::vector buffer_ids(id_array.ids, - id_array.ids + id_array.length); - DestroyArena(&arena); - std::vector buffer_info = GetBufferInfo( - &hermes_->context_, &hermes_->rpc_, buffer_ids); - - float xfer_time = 0; - for (auto &info : buffer_info) { - xfer_time += static_cast(info.size) / MEGABYTES(info.bandwidth_mbps); - /*LOG(INFO) << "size: " << info.size / MEGABYTES(1) - << " bw: " << info.bandwidth_mbps - << " current total: " << xfer_time << std::endl;*/ - } - xfer_time *= 2; // x2 because movement reads, and then writes data - return xfer_time; -} - -bool HasOnlyDemotions(PrefetchDecision &decision, float &decay) { - decay = std::numeric_limits::infinity(); - if (decision.stats_.size() == 0) return false; - for (auto &prefetch_stat : decision.stats_) { - if (prefetch_stat.decay_ < 0) { - return false; - } - decay = std::min(decay, prefetch_stat.decay_); - } - return true; -} - -void Prefetcher::CalculateBlobScore(struct timespec &ts, - PrefetchDecision &decision) { - float est_xfer_time = decision.est_xfer_time_; - decision.new_score_ = -1; - decision.queue_later_ = false; - - float decay; - if (HasOnlyDemotions(decision, decay)) { - decision.new_score_ = GetBlobImportanceScore(&hermes_->context_, - &hermes_->rpc_, - decision.blob_id_); - decision.new_score_ *= decay; - if (decision.new_score_ < 0) { - decision.new_score_ = 0; - } - decision.decay_ = true; - return; - } - - for (auto &prefetch_stat : decision.stats_) { - if (prefetch_stat.decay_ >= 0) continue; - // Wait until the I/O for this Get seems to have completed - /*float time_left_on_io = prefetch_stat.TimeLeftOnIo( - est_xfer_time, &ts); - LOG(INFO) << "Blob id: " << decision.blob_id_.as_int - << " Time left before starting prefetch: " - << time_left_on_io << std::endl; - if (time_left_on_io > 0) { - decision.queue_later_ = true; - continue; - }*/ - float next_access_sec = prefetch_stat.TimeToNextIo(&ts); - LOG(INFO) << "Next access sec: " << next_access_sec << std::endl; - LOG(INFO) << "Est xfer time : " << est_xfer_time << std::endl; - // if (next_access_sec < est_xfer_time) continue; - float max_access_wait = std::max(max_wait_xfer_*est_xfer_time, - max_wait_sec_); - LOG(INFO) << "Max access wait: " << max_access_wait << std::endl; - float est_wait = (next_access_sec - est_xfer_time); - if (est_wait > max_access_wait) { - decision.queue_later_ = true; - continue; - } - float score = (max_access_wait - est_wait) / max_access_wait; - if (score > decision.new_score_) { - decision.new_score_ = score; - } - } -} - -void Prefetcher::Process() { - // Group log by I/O hint - lock_.lock(); - std::unordered_map> hint_logs; - for (auto &entry : log_) { - hint_logs[entry.pctx_.hint_].emplace_back(entry); - } - log_.erase(log_.begin(), log_.end()); - lock_.unlock(); - if (hint_logs.size() == 0 && queue_later_.size() == 0) { - return; - } - - // Based on the current log, determine what blobs to prefetch - PrefetchSchema schema; - for (auto &[hint, hint_log] : hint_logs) { - auto algorithm = PrefetcherFactory::Get(hint); - algorithm->Process(hint_log, schema); - } - - // Take into consideration old prefetching decisions - for (auto &[blob_id, decision] : queue_later_) { - schema.emplace(decision); - } - queue_later_.erase(queue_later_.begin(), queue_later_.end()); - - // Get the current time - struct timespec ts; - timespec_get(&ts, TIME_UTC); - - // Calculate new blob scores - for (auto &[blob_id, decision] : schema) { - if (decision.est_xfer_time_ == -1) { - decision.est_xfer_time_ = EstimateBlobMovementTime(blob_id); - } - CalculateBlobScore(ts, decision); - if (decision.new_score_ < 0) { - if (decision.queue_later_) { - queue_later_.emplace(blob_id, decision); - } - } - } - - // Process decay blobs first (make room) - for (auto &[blob_id, decision] : schema) { - if (!decision.decay_) { continue; } - LOG(INFO) << "Decaying Blob: " << blob_id.as_int - << " to score: " << decision.new_score_ << std::endl; - OrganizeBlob(&hermes_->context_, &hermes_->rpc_, - decision.bkt_id_, decision.blob_name_, - epsilon_, decision.new_score_); - } - - // TODO(llogan): a hack to help BORG shuffle data - struct timespec ts2; - while (PrefetchStat::DiffTimespec(&ts2, &ts) < 1) { - timespec_get(&ts2, TIME_UTC); - ABT_thread_yield(); - } - - // Calculate new blob scores - for (auto &[blob_id, decision] : schema) { - if (decision.decay_) { continue; } - if (decision.new_score_ < 0) { continue; } - LOG(INFO) << "Prefetching bkt_id: " << decision.bkt_id_.as_int - << " blob_id: " << decision.blob_name_ - << " score: " << decision.new_score_ << std::endl; - OrganizeBlob(&hermes_->context_, &hermes_->rpc_, - decision.bkt_id_, decision.blob_name_, - epsilon_, 1.0); - } -} - -} // namespace hermes diff --git a/src/prefetcher.h b/src/prefetcher.h deleted file mode 100644 index 7d062e9cb..000000000 --- a/src/prefetcher.h +++ /dev/null @@ -1,264 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_PREFETCHER_H_ -#define HERMES_SRC_PREFETCHER_H_ - -#include "hermes.h" -#include "hermes_types.h" -#include "rpc_thallium.h" -#include -#include -#include -#include -#include - -namespace hermes { - -using hermes::api::PrefetchContext; -using hermes::api::PrefetchHint; - -enum class IoType { - kNone, kPut, kGet -}; - -struct GlobalThreadID { - int rank_; - int tid_; - GlobalThreadID() : rank_(0), tid_(0) {} - explicit GlobalThreadID(int rank) : rank_(rank) { - ABT_unit_id tid_argo; - ABT_thread_self_id(&tid_argo); - tid_ = tid_argo; - } - - bool operator==(const GlobalThreadID &other) const { - return (rank_ == other.rank_ && tid_ == other.tid_); - } -}; - -struct UniqueBucket { - VBucketId vbkt_id_; - BucketId bkt_id_; - - UniqueBucket() = default; - UniqueBucket(VBucketId vbkt_id, BucketId bkt_id) : - vbkt_id_(vbkt_id), bkt_id_(bkt_id) {} - - bool operator==(const UniqueBucket &other) const { - return (vbkt_id_ == other.vbkt_id_ && - bkt_id_ == other.bkt_id_); - } -}; - -struct IoLogEntry { - VBucketId vbkt_id_; - BucketId bkt_id_; - BlobId blob_id_; - IoType type_; - off_t off_; - size_t size_; - PrefetchContext pctx_; - GlobalThreadID tid_; - bool historical_; - struct timespec timestamp_; -}; - -struct PrefetchStat { - float est_next_time_; - struct timespec start_; - float decay_; - - PrefetchStat() : est_next_time_(0), decay_(-1) {} - - explicit PrefetchStat(float est_next_time, struct timespec &start) : - est_next_time_(est_next_time), start_(start), decay_(-1) {} - - explicit PrefetchStat(float decay) : decay_(decay) {} - - float TimeLeftOnIo(float est_xfer_time, const struct timespec *cur) { - float diff = DiffTimespec(cur, &start_); - /*LOG(INFO) << "Time since I/O submitted: " << diff << std::endl; - LOG(INFO) << "Est I/O time: " << est_xfer_time << std::endl;*/ - return est_xfer_time - diff; - } - - float TimeToNextIo(const struct timespec *cur) { - float diff = DiffTimespec(cur, &start_); - return est_next_time_ - diff; - } - - static float DiffTimespec(const struct timespec *left, - const struct timespec *right) { - return (left->tv_sec - right->tv_sec) - + (left->tv_nsec - right->tv_nsec) / 1000000000.0; - } -}; - -struct PrefetchDecision { - BucketId bkt_id_; - BlobId blob_id_; - std::string blob_name_; - std::list stats_; - bool queue_later_; - float est_xfer_time_; - float new_score_; - bool decay_; - - PrefetchDecision() : queue_later_(false), - est_xfer_time_(-1), - new_score_(-1), - decay_(false) {} - void AddStat(float est_access_time, struct timespec &start) { - stats_.emplace_back(est_access_time, start); - } - void AddStat(float decay) { - stats_.emplace_back(decay); - } -}; - -class PrefetchSchema { - private: - std::unordered_map schema_; - - public: - void emplace(PrefetchDecision &decision) { - auto prior_decision_iter = schema_.find(decision.blob_id_); - if (prior_decision_iter == schema_.end()) { - schema_.emplace(decision.blob_id_, decision); - return; - } - auto &[blob_id, prior_decision] = (*prior_decision_iter); - prior_decision.est_xfer_time_ = decision.est_xfer_time_; - prior_decision.stats_.splice( - prior_decision.stats_.end(), - decision.stats_); - } - - std::unordered_map::iterator begin() { - return schema_.begin(); - } - - std::unordered_map::iterator end() { - return schema_.end(); - } -}; - -class PrefetchAlgorithm { - public: - virtual void Process(std::list &log, - PrefetchSchema &schema) = 0; -}; - -class Prefetcher { - private: - uint32_t max_length_; - thallium::mutex lock_; - std::list log_; - std::unordered_map queue_later_; - - public: - float max_wait_xfer_; - float max_wait_sec_; - float epsilon_; - - public: - std::shared_ptr hermes_; - - Prefetcher() : max_length_(4096), max_wait_xfer_(10), max_wait_sec_(60), - epsilon_(.05) {} - void SetHermes(std::shared_ptr &hermes) { hermes_ = hermes; } - void SetLogLength(uint32_t max_length) { max_length_ = max_length; } - void Log(IoLogEntry &entry); - static bool LogIoStat(api::Hermes *hermes, IoLogEntry &entry); - void Process(); - - private: - static size_t HashToNode(api::Hermes *hermes, IoLogEntry &entry); - float EstimateBlobMovementTime(BlobId blob_id); - void CalculateBlobScore(struct timespec &ts, - PrefetchDecision &decision); -}; - -/** RPC SERIALIZERS */ - -// IoType -template -void save(A &ar, IoType &hint) { - ar << static_cast(hint); -} -template -void load(A &ar, IoType &hint) { - int hint_i; - ar >> hint_i; - hint = static_cast(hint_i); -} - -// struct timespec -template -void save(A &ar, struct timespec &ts) { - ar << ts.tv_sec; - ar << ts.tv_nsec; -} -template -void load(A &ar, struct timespec &ts) { - ar >> ts.tv_sec; - ar >> ts.tv_nsec; -} - -// GlobalThreadID -template -void serialize(A &ar, GlobalThreadID &tid) { - ar & tid.rank_; - ar & tid.tid_; -} - -// IoLogEntry -template -void serialize(A &ar, IoLogEntry &entry) { - ar & entry.vbkt_id_; - ar & entry.bkt_id_; - ar & entry.blob_id_; - ar & entry.type_; - ar & entry.off_; - ar & entry.size_; - ar & entry.pctx_; - ar & entry.tid_; - // ar & entry.timestamp_; - ar & entry.historical_; -} - -} // namespace hermes - -namespace std { -template <> -struct hash { - std::size_t operator()(const hermes::GlobalThreadID &key) const { - size_t h1 = std::hash{}(key.rank_); - size_t h2 = std::hash{}(key.tid_); - size_t hash = h1^h2; - return hash; - } -}; - -template <> -struct hash { - std::size_t operator()(const hermes::UniqueBucket &key) const { - size_t h1 = std::hash{}(key.vbkt_id_); - size_t h2 = std::hash{}(key.bkt_id_); - size_t hash = h1^h2; - return hash; - } -}; -} // namespace std - -#endif // HERMES_SRC_PREFETCHER_H_ diff --git a/src/prefetcher_factory.h b/src/prefetcher_factory.h deleted file mode 100644 index d2be71a9b..000000000 --- a/src/prefetcher_factory.h +++ /dev/null @@ -1,48 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_PREFETCHER_FACTORY_H_ -#define HERMES_SRC_PREFETCHER_FACTORY_H_ - -#include "prefetcher.h" -#include - -#include "prefetchers/sequential.h" -#include "prefetchers/apriori.h" -#include "singleton.h" - -namespace hermes { - -class PrefetcherFactory { - public: - /** - * Return the instance of mapper given a type. Uses factory pattern. - * - * @param type, MapperType, type of mapper to be used by the STDIO adapter. - * @return Instance of mapper given a type. - */ - static PrefetchAlgorithm* Get(const PrefetchHint &type) { - switch (type) { - case PrefetchHint::kFileSequential: { - return Singleton::GetInstance(); - } - case PrefetchHint::kApriori: { - return Singleton::GetInstance(); - } - default: return nullptr; - } - } -}; - -} // namespace hermes - -#endif // HERMES_SRC_PREFETCHER_FACTORY_H_ diff --git a/src/prefetchers/apriori.cc b/src/prefetchers/apriori.cc deleted file mode 100644 index 710111506..000000000 --- a/src/prefetchers/apriori.cc +++ /dev/null @@ -1,13 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "apriori.h" diff --git a/src/prefetchers/apriori.h b/src/prefetchers/apriori.h deleted file mode 100644 index a9cdbe7dd..000000000 --- a/src/prefetchers/apriori.h +++ /dev/null @@ -1,28 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_PREFETCHERS_APRIORI_H_ -#define HERMES_SRC_PREFETCHERS_APRIORI_H_ - -#include "prefetcher.h" - -namespace hermes { - -class AprioriPrefetcher : public PrefetchAlgorithm { - public: - void Process(std::list &log, - PrefetchSchema &schema) {} -}; - -} // namespace hermes - -#endif // HERMES_SRC_PREFETCHERS_APRIORI_H_ diff --git a/src/prefetchers/sequential.cc b/src/prefetchers/sequential.cc deleted file mode 100644 index c47b45bbe..000000000 --- a/src/prefetchers/sequential.cc +++ /dev/null @@ -1,145 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "sequential.h" -#include "singleton.h" -#include "api/bucket.h" -#include - -using hermes::adapter::BlobPlacement; - -namespace hermes { - -void SequentialPrefetcher::Process(std::list &log, - PrefetchSchema &schema) { - auto prefetcher = Singleton::GetInstance(); - - // Increase each unique_bucket access count - for (auto &entry : log) { - UniqueBucket id(entry.vbkt_id_, entry.bkt_id_); - auto &state = state_[id]; - if (state.count_ == 0) { - state.first_access_ = entry.timestamp_; - } - ++state.count_; - } - - // Append time estimates and read-aheads to the schema - for (auto &entry : log) { - UniqueBucket id(entry.vbkt_id_, entry.bkt_id_); - auto &state = state_[id]; - float cur_runtime = PrefetchStat::DiffTimespec(&entry.timestamp_, - &state.first_access_); - float avg_time = cur_runtime / state.count_; - if (avg_time == 0) { - avg_time = prefetcher->max_wait_sec_ / 2.0; - } - LOG(INFO) << "Avg time: " << avg_time << std::endl; - - // Read-ahead the next few blobs - BlobId cur_id = entry.blob_id_; - for (int i = 0; i < entry.pctx_.read_ahead_; ++i) { - PrefetchDecision decision; - decision.bkt_id_ = entry.bkt_id_; - if (IsNullVBucketId(entry.vbkt_id_)) { - GetNextFromBucket(entry, decision, cur_id); - } else { - GetNextFromVbucket(entry, decision, cur_id); - } - if (IsNullBlobId(decision.blob_id_)) { - break; - } - decision.AddStat((i+1)*avg_time, entry.timestamp_); - schema.emplace(decision); - cur_id = decision.blob_id_; - } - - // Demote the previous blobs - cur_id = entry.blob_id_; - for (int i = 0; i < entry.pctx_.read_ahead_; ++i) { - PrefetchDecision decision; - if (IsNullVBucketId(entry.vbkt_id_)) { - GetPriorFromBucket(entry, decision, cur_id); - } else { - GetPriorFromVbucket(entry, decision, cur_id); - } - if (IsNullBlobId(decision.blob_id_)) { - break; - } - decision.AddStat(entry.pctx_.decay_); - schema.emplace(decision); - cur_id = decision.blob_id_; - } - } -} - -void SequentialPrefetcher::GetNextFromBucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobId &cur_id) { - // Get current blob name - auto prefetcher = Singleton::GetInstance(); - auto hermes = prefetcher->hermes_; - std::string blob_name = GetBlobNameFromId(&hermes->context_, - &hermes->rpc_, - cur_id); - - // Get next blob name - BlobPlacement p; - p.DecodeBlobName(blob_name); - p.page_ += 1; - decision.blob_name_ = p.CreateBlobName(); - - // Get the next blob ID from the bucket - decision.blob_id_ = GetBlobId(&hermes->context_, &hermes->rpc_, - decision.blob_name_, entry.bkt_id_, - false); -} - -void SequentialPrefetcher::GetNextFromVbucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobId &cur_id) { - // TODO(llogan): Not implemented for now. -} - -void SequentialPrefetcher::GetPriorFromBucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobId &cur_id) { - // Get current blob name - auto prefetcher = Singleton::GetInstance(); - auto hermes = prefetcher->hermes_; - std::string blob_name = GetBlobNameFromId(&hermes->context_, - &hermes->rpc_, - cur_id); - - // Get prior blob name - BlobPlacement p; - p.DecodeBlobName(blob_name); - if (p.page_ == 0) { - cur_id.as_int = 0; - return; - } - p.page_ -= 1; - decision.blob_name_ = p.CreateBlobName(); - - // Get the prior blob ID from the bucket - decision.blob_id_ = GetBlobId(&hermes->context_, &hermes->rpc_, - decision.blob_name_, entry.bkt_id_, - false); -} - -void SequentialPrefetcher::GetPriorFromVbucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobId &cur_id) { - // TODO(llogan): Not implemented for now. -} - -} // namespace hermes diff --git a/src/prefetchers/sequential.h b/src/prefetchers/sequential.h deleted file mode 100644 index da4fba7a3..000000000 --- a/src/prefetchers/sequential.h +++ /dev/null @@ -1,52 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ -#define HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ - -#include "prefetcher.h" - -namespace hermes { - -struct SequentialState { - struct timespec first_access_; - u32 count_; - - SequentialState() : count_(0) {} -}; - -class SequentialPrefetcher : public PrefetchAlgorithm { - private: - std::unordered_map state_; - - public: - void Process(std::list &log, - PrefetchSchema &schema); - - private: - void GetNextFromBucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobId &cur_id); - void GetNextFromVbucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobId &cur_id); - void GetPriorFromBucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobId &cur_id); - void GetPriorFromVbucket(IoLogEntry &entry, - PrefetchDecision &decision, - BlobId &cur_id); -}; - -} // namespace hermes - -#endif // HERMES_SRC_PREFETCHERS_SEQUENTIAL_H_ From e7c52146a5a31ed9e98b1357fb1047bd42bdfeb3 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 04:17:34 -0600 Subject: [PATCH 129/511] Stash vfd --- adapter/vfd/CMakeLists.txt | 189 ----- adapter/vfd/H5FDhermes.c | 1173 ----------------------------- adapter/vfd/H5FDhermes.h | 72 -- adapter/vfd/H5FDhermes_err.h | 211 ------ adapter/vfd/README.md | 102 --- gotcha_intercept/CMakeLists.txt | 76 -- gotcha_intercept/Readme | 3 - gotcha_intercept/gotcha_mpi_io.cc | 289 ------- gotcha_intercept/gotcha_mpi_io.h | 18 - gotcha_intercept/gotcha_posix.cc | 156 ---- gotcha_intercept/gotcha_posix.h | 18 - gotcha_intercept/gotcha_stdio.cc | 155 ---- gotcha_intercept/gotcha_stdio.h | 18 - gotcha_intercept/mpi_io.txt | 13 - gotcha_intercept/stdio.txt | 5 - 15 files changed, 2498 deletions(-) delete mode 100644 adapter/vfd/CMakeLists.txt delete mode 100644 adapter/vfd/H5FDhermes.c delete mode 100644 adapter/vfd/H5FDhermes.h delete mode 100644 adapter/vfd/H5FDhermes_err.h delete mode 100644 adapter/vfd/README.md delete mode 100644 gotcha_intercept/CMakeLists.txt delete mode 100644 gotcha_intercept/Readme delete mode 100644 gotcha_intercept/gotcha_mpi_io.cc delete mode 100644 gotcha_intercept/gotcha_mpi_io.h delete mode 100644 gotcha_intercept/gotcha_posix.cc delete mode 100644 gotcha_intercept/gotcha_posix.h delete mode 100644 gotcha_intercept/gotcha_stdio.cc delete mode 100644 gotcha_intercept/gotcha_stdio.h delete mode 100644 gotcha_intercept/mpi_io.txt delete mode 100644 gotcha_intercept/stdio.txt diff --git a/adapter/vfd/CMakeLists.txt b/adapter/vfd/CMakeLists.txt deleted file mode 100644 index cae8406c7..000000000 --- a/adapter/vfd/CMakeLists.txt +++ /dev/null @@ -1,189 +0,0 @@ -# CMakeLists files in this project can -# refer to the root source directory of the project as ${HDF5_HERMES_SOURCE_DIR} and -# to the root binary directory of the project as ${HDF5_HERMES_BINARY_DIR}. - -project(HDF5_HERMES_VFD) - -#------------------------------------------------------------------------------ -# Version information -#------------------------------------------------------------------------------ -set(HDF5_HERMES_VFD_VERSION_MAJOR ${HERMES_VERSION_MAJOR}) -set(HDF5_HERMES_VFD_VERSION_MINOR ${HERMES_VERSION_MINOR}) -set(HDF5_HERMES_VFD_VERSION_PATCH ${HERMES_VERSION_PATCH}) -set(HDF5_HERMES_VFD_PACKAGE "hdf5_hermes_vfd") -set(HDF5_HERMES_VFD_PACKAGE_NAME "HDF5_HERMES_VFD") -set(HDF5_HERMES_VFD_PACKAGE_VERSION "${HDF5_HERMES_VFD_VERSION_MAJOR}.${HDF5_HERMES_VFD_VERSION_MINOR}.${HDF5_HERMES_VFD_VERSION_PATCH}") -set(HDF5_HERMES_VFD_PACKAGE_VERSION_MAJOR "${HDF5_HERMES_VFD_VERSION_MAJOR}.${HDF5_HERMES_VFD_VERSION_MINOR}") -set(HDF5_HERMES_VFD_PACKAGE_VERSION_MINOR "${HDF5_HERMES_VFD_VERSION_PATCH}") -set(HDF5_HERMES_VFD_PACKAGE_STRING "${HDF5_HERMES_VFD_PACKAGE_NAME} ${HDF5_HERMES_VFD_PACKAGE_VERSION}") -set(HDF5_HERMES_VFD_PACKAGE_TARNAME "${HDF5_HERMES_VFD_PACKAGE}") - -# Dynamically loaded VFDs must be shared libraries -set(HDF5_HERMES_VFD_LIBTYPE SHARED) - -#----------------------------------------------------------------------------- -# Targets built within this project are exported at Install time for use -# by other projects. -#----------------------------------------------------------------------------- -if(NOT HDF5_HERMES_VFD_EXPORTED_TARGETS) - set(HDF5_HERMES_VFD_EXPORTED_TARGETS "${HDF5_HERMES_VFD_PACKAGE}-targets") -endif() - -set(HDF5_HERMES_VFD_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/H5FDhermes.h - ${CMAKE_CURRENT_SOURCE_DIR}/H5FDhermes.c - ) - -add_library(hdf5_hermes_vfd ${HDF5_HERMES_VFD_SRCS}) -set_target_properties(hdf5_hermes_vfd PROPERTIES LIBRARY_OUTPUT_DIRECTORY - ${HERMES_VFD_LIBRARY_DIR} -) -target_include_directories(hdf5_hermes_vfd PRIVATE ${CMAKE_SOURCE_DIR}/wrapper) -target_include_directories(hdf5_hermes_vfd - SYSTEM PUBLIC ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} -) - -target_link_libraries(hdf5_hermes_vfd - hermes_wrapper - MPI::MPI_C - ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES} -) - -set(HDF5_HERMES_VFD_EXPORTED_LIBS hdf5_hermes_vfd ${HDF5_HERMES_VFD_EXPORTED_LIBS} PARENT_SCOPE) - -#----------------------------------------------------------------------------- -# Specify project header files to be installed -#----------------------------------------------------------------------------- -set(HDF5_HERMES_VFD_HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/H5FDhermes.h -) - -#----------------------------------------------------------------------------- -# Add file(s) to CMake Install -#----------------------------------------------------------------------------- -install( - FILES - ${HDF5_HERMES_VFD_HEADERS} - DESTINATION - ${HERMES_INSTALL_INCLUDE_DIR} - COMPONENT - headers -) - -#----------------------------------------------------------------------------- -# Add Target(s) to CMake Install -#----------------------------------------------------------------------------- -install( - TARGETS - hdf5_hermes_vfd - EXPORT - ${HDF5_HERMES_VFD_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR}/${HERMES_VFD_DIR_NAME} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR}/${HERMES_VFD_DIR_NAME} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) - -#----------------------------------------------------------------------------- -# Add Target(s) to CMake Install for import into other projects -#----------------------------------------------------------------------------- -install( - EXPORT - ${HDF5_HERMES_VFD_EXPORTED_TARGETS} - DESTINATION - ${HERMES_INSTALL_DATA_DIR}/cmake/hdf5_hermes_vfd - FILE - ${HDF5_HERMES_VFD_EXPORTED_TARGETS}.cmake -) - -#----------------------------------------------------------------------------- -# Export all exported targets to the build tree for use by parent project - -if(NOT HDF5_HERMES_VFD_EXTERNALLY_CONFIGURED) - export( - TARGETS - ${HDF5_HERMES_VFD_EXPORTED_LIBS} - FILE - ${HDF5_HERMES_VFD_EXPORTED_TARGETS}.cmake - ) -endif() - -#------------------------------------------------------------------------------ -# Set variables for parent scope -#------------------------------------------------------------------------------ - -# Pkg-config configuration -if(CMAKE_BUILD_TYPE) - string(TOLOWER ${CMAKE_BUILD_TYPE} lower_cmake_build_type) -endif() - -# Hermes VFD package dependencies -foreach(pkg_dep ${HDF5_HERMES_VFD_EXT_PKG_DEPENDENCIES}) - set(HDF5_HERMES_VFD_PKG_DEPENDENCIES ${HDF5_HERMES_VFD_PKG_DEPENDENCIES} ${pkg_dep}) -endforeach() -set(HDF5_HERMES_VFD_PKG_DEPENDENCIES ${HDF5_HERMES_VFD_PKG_DEPENDENCIES} PARENT_SCOPE) - -# Hermes VFD private library dependencies -foreach(exported_lib ${HDF5_HERMES_VFD_EXPORTED_LIBS}) - if(lower_cmake_build_type MATCHES "debug") - get_target_property(HDF5_HERMES_VFD_LIBRARY ${exported_lib} DEBUG_OUTPUT_NAME) - else() - get_target_property(HDF5_HERMES_VFD_LIBRARY ${exported_lib} RELEASE_OUTPUT_NAME) - endif() - set(HDF5_HERMES_VFD_LIBRARIES "${HDF5_HERMES_VFD_LIBRARIES} -l${HDF5_HERMES_VFD_LIBRARY}") -endforeach() -set(HDF5_HERMES_VFD_LIBRARIES ${HDF5_HERMES_VFD_LIBRARIES} PARENT_SCOPE) -# Hermes VFD external library dependencies -# Need to generate -lib if not already passed -set(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES - ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES} - ${HDF5_HERMES_VFD_EXT_PKG_LIB_DEPENDENCIES} - PARENT_SCOPE -) -foreach(lib_dep ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES}) - # get library name - get_filename_component(lib_name ${lib_dep} NAME_WE) - if(lib_name MATCHES "^-l") - # lib_name found is -lxxx - set(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST} ${lib_name}) - else() - # lib_name is /path/to/lib so get library path and name - get_filename_component(lib_path ${lib_dep} PATH) - string(REGEX REPLACE "^lib" "" lib_name ${lib_name}) - set(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST} -L${lib_path} -l${lib_name}) - endif() -endforeach() -if(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST) - list(REMOVE_DUPLICATES HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST) -endif() -foreach(lib_dep ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES_LIST}) - set(HDF5_HERMES_VFD_LIB_DEPENDENCIES "${HDF5_HERMES_VFD_LIB_DEPENDENCIES} ${lib_dep}") -endforeach() -set(HDF5_HERMES_VFD_LIB_DEPENDENCIES ${HDF5_HERMES_VFD_LIB_DEPENDENCIES} PARENT_SCOPE) - -# External include dependencies -set(HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES - ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} - ${HDF5_HERMES_VFD_EXT_PKG_INCLUDE_DEPENDENCIES} - PARENT_SCOPE -) -if(HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES) - list(REMOVE_DUPLICATES HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES) -endif() -foreach(inc_dep ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES}) - set(HDF5_HERMES_VFD_INCLUDE_DEPENDENCIES "${HDF5_HERMES_VFD_INCLUDE_DEPENDENCIES} -I${inc_dep}") -endforeach() -set(HDF5_HERMES_VFD_INCLUDE_DEPENDENCIES ${HDF5_HERMES_VFD_INCLUDE_DEPENDENCIES} PARENT_SCOPE) - -set(HDF5_HERMES_VFD_INCLUDES_BUILD_TIME - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} - PARENT_SCOPE -) - -set(HDF5_HERMES_VFD_INCLUDES_INSTALL_TIME - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} - PARENT_SCOPE -) diff --git a/adapter/vfd/H5FDhermes.c b/adapter/vfd/H5FDhermes.c deleted file mode 100644 index 09ca87094..000000000 --- a/adapter/vfd/H5FDhermes.c +++ /dev/null @@ -1,1173 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright by The HDF Group. * - * Copyright by the Board of Trustees of the University of Illinois. * - * All rights reserved. * - * * - * This file is part of HDF5. The full HDF5 copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the root of the source code * - * distribution tree, or in https://www.hdfgroup.org/licenses. * - * If you do not have access to either file, you may request a copy from * - * help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* - * Programmer: Kimmy Mu - * March 2021 - * - * Purpose: The hermes file driver using only the HDF5 public API - * and buffer datasets in Hermes buffering systems with - * multiple storage tiers. - */ -#ifndef _GNU_SOURCE - #define _GNU_SOURCE -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -/* HDF5 header for dynamic plugin loading */ -#include "H5PLextern.h" - -#include "H5FDhermes.h" /* Hermes file driver */ -#include "H5FDhermes_err.h" /* error handling */ - -/* Necessary hermes headers */ -#include "hermes_wrapper.h" - -#define H5FD_HERMES (H5FD_hermes_init()) - -/* HDF5 doesn't currently have a driver init callback. Use - * macro to initialize driver if loaded as a plugin. - */ -#define H5FD_HERMES_INIT \ - do { \ - if (H5FD_HERMES_g < 0) \ - H5FD_HERMES_g = H5FD_HERMES; \ - } while (0) - -/* The driver identification number, initialized at runtime */ -static hid_t H5FD_HERMES_g = H5I_INVALID_HID; - -/* Identifiers for HDF5's error API */ -hid_t H5FDhermes_err_stack_g = H5I_INVALID_HID; -hid_t H5FDhermes_err_class_g = H5I_INVALID_HID; - -/* Whether Hermes is initialized */ -static htri_t hermes_initialized = FAIL; -static hbool_t mpi_is_initialized = FALSE; - -/* File operations */ -#define OP_UNKNOWN 0 -#define OP_READ 1 -#define OP_WRITE 2 - -/* POSIX I/O mode used as the third parameter to open/_open - * when creating a new file (O_CREAT is set). */ -#if defined(H5_HAVE_WIN32_API) -#define H5FD_HERMES_POSIX_CREATE_MODE_RW (_S_IREAD | _S_IWRITE) -#else -#define H5FD_HERMES_POSIX_CREATE_MODE_RW 0666 -#endif - -/* Define length of blob name, which is converted from page index */ -#define LEN_BLOB_NAME 10 - -#define BIT_SIZE_OF_UNSIGNED (sizeof(uint)*8) - -/* kHermesConf env variable is used to define path to kHermesConf in adapters. - * This is used for initialization of Hermes. */ -const char *kHermesConf = "HERMES_CONF"; - -/* The description of bit representation of blobs in Hermes buffering system. */ -typedef struct bitv_t { - uint *blobs; - size_t capacity; - size_t end_pos; -} bitv_t; - -/* The description of a file/bucket belonging to this driver. */ -typedef struct H5FD_hermes_t { - H5FD_t pub; /* public stuff, must be first */ - haddr_t eoa; /* end of allocated region */ - haddr_t eof; /* end of file; current file size */ - haddr_t pos; /* current file I/O position */ - int op; /* last operation */ - hbool_t persistence; /* write to file name on close */ - int fd; /* the filesystem file descriptor */ - size_t buf_size; - char *bktname; /* Copy of file name from open operation */ - BucketClass *bkt_handle; - int ref_count; - unsigned char *page_buf; - bitv_t blob_in_bucket; - unsigned flags; /* The flags passed from H5Fcreate/H5Fopen */ -} H5FD_hermes_t; - -/* Driver-specific file access properties */ -typedef struct H5FD_hermes_fapl_t { - hbool_t persistence; /* write to file name on flush */ - size_t page_size; /* page size */ -} H5FD_hermes_fapl_t; - -/* - * These macros check for overflow of various quantities. These macros - * assume that HDoff_t is signed and haddr_t and size_t are unsigned. - * - * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t' - * is too large to be represented by the second argument - * of the file seek function. - * - * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too - * large to be represented by the `size_t' type. - * - * REGION_OVERFLOW: Checks whether an address and size pair describe data - * which can be addressed entirely by the second - * argument of the file seek function. - */ -#define MAXADDR (((haddr_t)1 << (8 * sizeof(off_t) - 1)) - 1) -#define ADDR_OVERFLOW(A) (HADDR_UNDEF == (A) || ((A) & ~(haddr_t)MAXADDR)) -#define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR) -#define REGION_OVERFLOW(A, Z) \ - (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || HADDR_UNDEF == (A) + (Z) || \ - (off_t)((A) + (Z)) < (off_t)(A)) - -/* Prototypes */ -static herr_t H5FD__hermes_term(void); -static herr_t H5FD__hermes_fapl_free(void *_fa); -static H5FD_t *H5FD__hermes_open(const char *name, unsigned flags, - hid_t fapl_id, haddr_t maxaddr); -static herr_t H5FD__hermes_close(H5FD_t *_file); -static int H5FD__hermes_cmp(const H5FD_t *_f1, const H5FD_t *_f2); -static herr_t H5FD__hermes_query(const H5FD_t *_f1, unsigned long *flags); -static haddr_t H5FD__hermes_get_eoa(const H5FD_t *_file, H5FD_mem_t type); -static herr_t H5FD__hermes_set_eoa(H5FD_t *_file, H5FD_mem_t type, - haddr_t addr); -static haddr_t H5FD__hermes_get_eof(const H5FD_t *_file, H5FD_mem_t type); -static herr_t H5FD__hermes_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, - haddr_t addr, size_t size, void *buf); -static herr_t H5FD__hermes_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, - haddr_t addr, size_t size, const void *buf); - -static const H5FD_class_t H5FD_hermes_g = { - H5FD_HERMES_VALUE, /* value */ - H5FD_HERMES_NAME, /* name */ - MAXADDR, /* maxaddr */ - H5F_CLOSE_STRONG, /* fc_degree */ - H5FD__hermes_term, /* terminate */ - NULL, /* sb_size */ - NULL, /* sb_encode */ - NULL, /* sb_decode */ - sizeof(H5FD_hermes_fapl_t),/* fapl_size */ - NULL, /* fapl_get */ - NULL, /* fapl_copy */ - H5FD__hermes_fapl_free, /* fapl_free */ - 0, /* dxpl_size */ - NULL, /* dxpl_copy */ - NULL, /* dxpl_free */ - H5FD__hermes_open, /* open */ - H5FD__hermes_close, /* close */ - H5FD__hermes_cmp, /* cmp */ - H5FD__hermes_query, /* query */ - NULL, /* get_type_map */ - NULL, /* alloc */ - NULL, /* free */ - H5FD__hermes_get_eoa, /* get_eoa */ - H5FD__hermes_set_eoa, /* set_eoa */ - H5FD__hermes_get_eof, /* get_eof */ - NULL, /* get_handle */ - H5FD__hermes_read, /* read */ - H5FD__hermes_write, /* write */ - NULL, /* flush */ - NULL, /* truncate */ - NULL, /* lock */ - NULL, /* unlock */ - NULL, /* del */ - NULL, /* ctl */ - H5FD_FLMAP_DICHOTOMY /* fl_map */ -}; - -/* Check if the blob at POS is set */ -static bool check_blob(bitv_t *bits, size_t bit_pos) { - bool result = false; - - if (bit_pos >= bits->capacity) - return false; - - size_t unit_pos = bit_pos / BIT_SIZE_OF_UNSIGNED; - size_t blob_pos_in_unit = bit_pos % BIT_SIZE_OF_UNSIGNED; - result = bits->blobs[unit_pos] & (1 << blob_pos_in_unit); - - return result; -} - -/* Set the bit at POS and reallocate 2*capacity for blobs as needed */ -static void set_blob(bitv_t *bits, size_t bit_pos) { - if (bit_pos >= bits->capacity) { - size_t current_units = bits->capacity/BIT_SIZE_OF_UNSIGNED; - size_t need_units = bit_pos/BIT_SIZE_OF_UNSIGNED + 1; - bits->capacity = need_units * BIT_SIZE_OF_UNSIGNED * 2; - bits->blobs = realloc(bits->blobs, bits->capacity); - memset(&bits->blobs[current_units], 0, - sizeof(uint)*(need_units*2-current_units+1)); - } - - size_t unit_pos = bit_pos / BIT_SIZE_OF_UNSIGNED; - size_t blob_pos_in_unit = bit_pos % BIT_SIZE_OF_UNSIGNED; - bits->blobs[unit_pos] |= 1 << blob_pos_in_unit; - if (bit_pos > bits->end_pos) - bits->end_pos = bit_pos; -} - -/** Returns true if @p page_index is the last page in the file. */ -bool H5FD__hermes_is_last_page(H5FD_hermes_t *file, size_t page_index) { - size_t total_pages = (size_t)ceil(file->eof / (float)file->buf_size); - size_t last_page_index = total_pages > 0 ? total_pages - 1 : 0; - bool ret_value = page_index == last_page_index; - - return ret_value; -} - -/** Returns the size of page @page_index. This is only different from - * H5FD_hermes_t::buf_size if it's the last page in the file. */ -size_t H5FD__hermes_get_gap_size(H5FD_hermes_t *file, size_t page_index) { - size_t ret_value = file->buf_size; - if (H5FD__hermes_is_last_page(file, page_index)) { - ret_value = file->eof - (page_index * file->buf_size); - } - - return ret_value; -} - -/** - * If the Hermes VFD recieves a partial page update to an existing file, we - * first need to fill the page with exising data from the file with a read - * before the Blob can be buffered. We refer to these partial pages as "gaps." - */ -herr_t H5FD__hermes_read_gap(H5FD_hermes_t *file, size_t seek_offset, - unsigned char *read_ptr, size_t read_size) { - herr_t ret_value = SUCCEED; - - if (!(file->flags & H5F_ACC_CREAT || file->flags & H5F_ACC_TRUNC || - file->flags & H5F_ACC_EXCL)) { - if (file->fd > -1) { - if (flock(file->fd, LOCK_SH) == -1) { - H5FD_HERMES_SYS_GOTO_ERROR(H5E_IO, H5E_CANTLOCKFILE, FAIL, - file->bktname); - } - - ssize_t bytes_read = pread(file->fd, read_ptr, read_size, seek_offset); - if (bytes_read == -1 || - ((size_t)bytes_read != read_size && bytes_read != 0)) { - H5FD_HERMES_SYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, file->bktname); - } - - if (flock(file->fd, LOCK_UN) == -1) { - H5FD_HERMES_SYS_GOTO_ERROR(H5E_IO, H5E_CANTUNLOCKFILE, FAIL, - file->bktname); - } - } - } - -done: - H5FD_HERMES_FUNC_LEAVE; -} - -/*------------------------------------------------------------------------- - * Function: H5FD_hermes_init - * - * Purpose: Initialize this driver by registering the driver with the - * library. - * - * Return: Success: The driver ID for the hermes driver - * Failure: H5I_INVALID_HID - * - *------------------------------------------------------------------------- - */ -hid_t -H5FD_hermes_init(void) { - hid_t ret_value = H5I_INVALID_HID; /* Return value */ - - /* Initialize error reporting */ - if ((H5FDhermes_err_stack_g = H5Ecreate_stack()) < 0) - H5FD_HERMES_GOTO_ERROR(H5E_VFL, H5E_CANTINIT, H5I_INVALID_HID, - "can't create HDF5 error stack"); - if ((H5FDhermes_err_class_g = H5Eregister_class(H5FD_HERMES_ERR_CLS_NAME, - H5FD_HERMES_ERR_LIB_NAME, - H5FD_HERMES_ERR_VER)) < 0) - H5FD_HERMES_GOTO_ERROR(H5E_VFL, H5E_CANTINIT, H5I_INVALID_HID, - "can't register error class with HDF5 error API"); - - if (H5I_VFL != H5Iget_type(H5FD_HERMES_g)) - H5FD_HERMES_g = H5FDregister(&H5FD_hermes_g); - - /* Set return value */ - ret_value = H5FD_HERMES_g; - -done: - H5FD_HERMES_FUNC_LEAVE; -} /* end H5FD_hermes_init() */ - -/*--------------------------------------------------------------------------- - * Function: H5FD__hermes_term - * - * Purpose: Shut down the VFD - * - * Returns: SUCCEED (Can't fail) - * - *--------------------------------------------------------------------------- - */ -static herr_t -H5FD__hermes_term(void) { - herr_t ret_value = SUCCEED; - - /* Unregister from HDF5 error API */ - if (H5FDhermes_err_class_g >= 0) { - if (H5Eunregister_class(H5FDhermes_err_class_g) < 0) - H5FD_HERMES_GOTO_ERROR( - H5E_VFL, H5E_CLOSEERROR, FAIL, - "can't unregister error class from HDF5 error API"); - - /* Print the current error stack before destroying it */ - PRINT_ERROR_STACK; - - /* Destroy the error stack */ - if (H5Eclose_stack(H5FDhermes_err_stack_g) < 0) { - H5FD_HERMES_GOTO_ERROR(H5E_VFL, H5E_CLOSEERROR, FAIL, - "can't close HDF5 error stack"); - PRINT_ERROR_STACK; - } /* end if */ - - H5FDhermes_err_stack_g = H5I_INVALID_HID; - H5FDhermes_err_class_g = H5I_INVALID_HID; - } - - /* Reset VFL ID */ - H5FD_HERMES_g = H5I_INVALID_HID; - -done: - H5FD_HERMES_FUNC_LEAVE_API; -} /* end H5FD__hermes_term() */ - -/*------------------------------------------------------------------------- - * Function: H5Pset_fapl_hermes - * - * Purpose: Modify the file access property list to use the H5FD_HERMES - * driver defined in this source file. There are no driver - * specific properties. - * - * Return: SUCCEED/FAIL - * - *------------------------------------------------------------------------- - */ -herr_t -H5Pset_fapl_hermes(hid_t fapl_id, hbool_t persistence, size_t page_size) { - H5FD_hermes_fapl_t fa; /* Hermes VFD info */ - herr_t ret_value = SUCCEED; /* Return value */ - - /* Check argument */ - if (H5I_GENPROP_LST != H5Iget_type(fapl_id) || - TRUE != H5Pisa_class(fapl_id, H5P_FILE_ACCESS)) { - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, - "not a file access property list"); - } - - /* Set VFD info values */ - memset(&fa, 0, sizeof(H5FD_hermes_fapl_t)); - fa.persistence = persistence; - fa.page_size = page_size; - - /* Set the property values & the driver for the FAPL */ - if (H5Pset_driver(fapl_id, H5FD_HERMES, &fa) < 0) { - H5FD_HERMES_GOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, - "can't set Hermes VFD as driver"); - } - -done: - H5FD_HERMES_FUNC_LEAVE_API; -} /* end H5Pset_fapl_hermes() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_fapl_free - * - * Purpose: Frees the family-specific file access properties. - * - * Return: SUCCEED/FAIL - * - *------------------------------------------------------------------------- - */ -static herr_t H5FD__hermes_fapl_free(void *_fa) { - H5FD_hermes_fapl_t *fa = (H5FD_hermes_fapl_t *)_fa; - herr_t ret_value = SUCCEED; /* Return value */ - - free(fa); - - H5FD_HERMES_FUNC_LEAVE; -} - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_open - * - * Purpose: Create and/or opens a bucket in Hermes. - * - * Return: Success: A pointer to a new bucket data structure. - * Failure: NULL - * - *------------------------------------------------------------------------- - */ -static H5FD_t * -H5FD__hermes_open(const char *name, unsigned flags, hid_t fapl_id, - haddr_t maxaddr) { - H5FD_hermes_t *file = NULL; /* hermes VFD info */ - int fd = -1; /* File descriptor */ - int o_flags = 0; /* Flags for open() call */ - struct stat sb = {0}; - const H5FD_hermes_fapl_t *fa = NULL; - H5FD_hermes_fapl_t new_fa = {0}; - char *hermes_config = NULL; - H5FD_t *ret_value = NULL; /* Return value */ - - /* Sanity check on file offsets */ - assert(sizeof(off_t) >= sizeof(size_t)); - - H5FD_HERMES_INIT; - - /* Check arguments */ - if (!name || !*name) - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name"); - if (0 == maxaddr || HADDR_UNDEF == maxaddr) - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr"); - if (ADDR_OVERFLOW(maxaddr)) - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr"); - - /* Get the driver specific information */ - H5E_BEGIN_TRY { - fa = H5Pget_driver_info(fapl_id); - } - H5E_END_TRY; - if (!fa || (H5P_FILE_ACCESS_DEFAULT == fapl_id)) { - ssize_t config_str_len = 0; - char config_str_buf[128]; - if ((config_str_len = - H5Pget_driver_config_str(fapl_id, config_str_buf, 128)) < 0) { - printf("H5Pget_driver_config_str() error\n"); - } - char *saveptr = NULL; - char* token = strtok_r(config_str_buf, " ", &saveptr); - if (!strcmp(token, "true") || !strcmp(token, "TRUE") || - !strcmp(token, "True")) { - new_fa.persistence = true; - } - token = strtok_r(0, " ", &saveptr); - sscanf(token, "%zu", &(new_fa.page_size)); - fa = &new_fa; - } - - /* Initialize Hermes */ - if ((H5OPEN hermes_initialized) == FAIL) { - hermes_config = getenv(kHermesConf); - if (HermesInitHermes(hermes_config) < 0) { - H5FD_HERMES_GOTO_ERROR(H5E_SYM, H5E_UNINITIALIZED, NULL, - "Hermes initialization failed"); - } else { - hermes_initialized = TRUE; - } - } - - bool creating_file = false; - - /* Build the open flags */ - o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY; - if (H5F_ACC_TRUNC & flags) { - o_flags |= O_TRUNC; - } - if (H5F_ACC_CREAT & flags) { - o_flags |= O_CREAT; - creating_file = true; - } - if (H5F_ACC_EXCL & flags) { - o_flags |= O_EXCL; - } - - if (fa->persistence || !creating_file) { - // NOTE(chogan): We're either in persistent mode, or we're in scratch mode - // and dealing with an existing file. - if ((fd = open(name, o_flags, H5FD_HERMES_POSIX_CREATE_MODE_RW)) < 0) { - int myerrno = errno; - H5FD_HERMES_GOTO_ERROR( - H5E_FILE, H5E_CANTOPENFILE, NULL, - "unable to open file: name = '%s', errno = %d, error message = '%s'," - "flags = %x, o_flags = %x", name, myerrno, strerror(myerrno), flags, - (unsigned)o_flags); - } - - if (__fxstat(_STAT_VER, fd, &sb) < 0) { - H5FD_HERMES_SYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, - "unable to fstat file"); - } - } - - /* Create the new file struct */ - if (NULL == (file = calloc(1, sizeof(H5FD_hermes_t)))) { - H5FD_HERMES_GOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, - "unable to allocate file struct"); - } - - if (name && *name) { - file->bktname = strdup(name); - } - - file->persistence = fa->persistence; - file->fd = fd; - file->bkt_handle = HermesBucketCreate(name); - file->page_buf = malloc(fa->page_size); - file->buf_size = fa->page_size; - file->ref_count = 1; - file->op = OP_UNKNOWN; - file->blob_in_bucket.capacity = BIT_SIZE_OF_UNSIGNED; - file->blob_in_bucket.blobs = (uint *)calloc(1, sizeof(uint)); - file->blob_in_bucket.end_pos = 0; - file->flags = flags; - file->eof = (haddr_t)sb.st_size; - - /* Set return value */ - ret_value = (H5FD_t *)file; - -done: - if (NULL == ret_value) { - if (fd >= 0) - close(fd); - if (file) { - if (file->bkt_handle) { - HermesBucketDestroy(file->bkt_handle); - } - free(file->blob_in_bucket.blobs); - free(file->bktname); - free(file->page_buf); - free(file); - } - } /* end if */ - - H5FD_HERMES_FUNC_LEAVE_API; -} /* end H5FD__hermes_open() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_close - * - * Purpose: Closes an HDF5 file. - * - * Return: Success: SUCCEED - * Failure: FAIL, file not closed. - * - *------------------------------------------------------------------------- - */ -static herr_t H5FD__hermes_close(H5FD_t *_file) { - H5FD_hermes_t *file = (H5FD_hermes_t *)_file; - size_t blob_size = file->buf_size; - size_t i; - herr_t ret_value = SUCCEED; /* Return value */ - - /* Sanity check */ - assert(file); - - if (file->persistence) { - if (file->op == OP_WRITE) { - /* TODO: if there is user blobk, the logic is not working, - including offset, but not 0 */ - for (i = 0; i <= file->blob_in_bucket.end_pos; i++) { - /* Check if this blob exists */ - bool blob_exists = check_blob(&file->blob_in_bucket, i); - if (!blob_exists) - continue; - - char i_blob[LEN_BLOB_NAME]; - snprintf(i_blob, sizeof(i_blob), "%zu\n", i); - HermesBucketGet(file->bkt_handle, i_blob, blob_size, file->page_buf); - - bool is_last_page = H5FD__hermes_is_last_page(file, i); - size_t bytes_to_write = blob_size; - - if (is_last_page) { - size_t bytes_in_last_page = file->eof - (i * blob_size); - bytes_to_write = bytes_in_last_page; - } - - ssize_t bytes_written = pwrite(file->fd, file->page_buf, bytes_to_write, - i * blob_size); - assert(bytes_written == bytes_to_write); - } - } - if (close(file->fd) < 0) - H5FD_HERMES_SYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, - "unable to close file"); - } - - if (file->ref_count == 1) { - HermesBucketDestroy(file->bkt_handle); - } else { - HermesBucketClose(file->bkt_handle); - } - - /* Release the file info */ - free(file->blob_in_bucket.blobs); - free(file->page_buf); - free(file->bktname); - free(file); - -done: - H5FD_HERMES_FUNC_LEAVE_API; -} /* end H5FD__hermes_close() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_cmp - * - * Purpose: Compares two buckets belonging to this driver using an - * arbitrary (but consistent) ordering. - * - * Return: Success: A value like strcmp() - * Failure: never fails (arguments were checked by the - * caller). - * - *------------------------------------------------------------------------- - */ -static int H5FD__hermes_cmp(const H5FD_t *_f1, const H5FD_t *_f2) { - const H5FD_hermes_t *f1 = (const H5FD_hermes_t *)_f1; - const H5FD_hermes_t *f2 = (const H5FD_hermes_t *)_f2; - int ret_value = 0; - - ret_value = strcmp(f1->bktname, f2->bktname); - - H5FD_HERMES_FUNC_LEAVE; -} /* end H5FD__hermes_cmp() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_query - * - * Purpose: Set the flags that this VFL driver is capable of supporting. - * (listed in H5FDpublic.h) - * - * Return: SUCCEED (Can't fail) - * - *------------------------------------------------------------------------- - */ -static herr_t H5FD__hermes_query(const H5FD_t *_file, - unsigned long *flags /* out */) { - /* Set the VFL feature flags that this driver supports */ - /* Notice: the Mirror VFD Writer currently uses only the hermes driver as - * the underying driver -- as such, the Mirror VFD implementation copies - * these feature flags as its own. Any modifications made here must be - * reflected in H5FDmirror.c - * -- JOS 2020-01-13 - */ - herr_t ret_value = SUCCEED; - - if (flags) { - *flags = 0; - } /* end if */ - - H5FD_HERMES_FUNC_LEAVE; -} /* end H5FD__hermes_query() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_get_eoa - * - * Purpose: Gets the end-of-address marker for the file. The EOA marker - * is the first address past the last byte allocated in the - * format address space. - * - * Return: The end-of-address marker. - * - *------------------------------------------------------------------------- - */ -static haddr_t H5FD__hermes_get_eoa(const H5FD_t *_file, - H5FD_mem_t H5_ATTR_UNUSED type) { - haddr_t ret_value = HADDR_UNDEF; - - const H5FD_hermes_t *file = (const H5FD_hermes_t *)_file; - - ret_value = file->eoa; - - H5FD_HERMES_FUNC_LEAVE; -} /* end H5FD__hermes_get_eoa() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_set_eoa - * - * Purpose: Set the end-of-address marker for the file. This function is - * called shortly after an existing HDF5 file is opened in order - * to tell the driver where the end of the HDF5 data is located. - * - * Return: SUCCEED (Can't fail) - * - *------------------------------------------------------------------------- - */ -static herr_t H5FD__hermes_set_eoa(H5FD_t *_file, - H5FD_mem_t H5_ATTR_UNUSED type, - haddr_t addr) { - herr_t ret_value = SUCCEED; - - H5FD_hermes_t *file = (H5FD_hermes_t *)_file; - - file->eoa = addr; - - H5FD_HERMES_FUNC_LEAVE; -} /* end H5FD__hermes_set_eoa() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_get_eof - * - * Purpose: Returns the end-of-file marker, which is the greater of - * either the filesystem end-of-file or the HDF5 end-of-address - * markers. - * - * Return: End of file address, the first address past the end of the - * "file", either the filesystem file or the HDF5 file. - * - *------------------------------------------------------------------------- - */ -static haddr_t H5FD__hermes_get_eof(const H5FD_t *_file, - H5FD_mem_t H5_ATTR_UNUSED type) { - haddr_t ret_value = HADDR_UNDEF; - - const H5FD_hermes_t *file = (const H5FD_hermes_t *)_file; - - ret_value = file->eof; - - H5FD_HERMES_FUNC_LEAVE; -} /* end H5FD__hermes_get_eof() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_read - * - * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR - * into buffer BUF according to data transfer properties in - * DXPL_ID. Determine the number of file pages affected by this - * call from ADDR and SIZE. Utilize transfer buffer PAGE_BUF to - * read the data from Blobs. Exercise care for the first and last - * pages to prevent overwriting existing data. - * - * Return: Success: SUCCEED. Result is stored in caller-supplied - * buffer BUF. - * Failure: FAIL, Contents of buffer BUF are undefined. - * - *------------------------------------------------------------------------- - */ -static herr_t H5FD__hermes_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, - hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, - size_t size, void *buf /*out*/) { - H5FD_hermes_t *file = (H5FD_hermes_t *)_file; - size_t num_pages; /* Number of pages of transfer buffer */ - size_t start_page_index; /* First page index of tranfer buffer */ - size_t end_page_index; /* End page index of tranfer buffer */ - size_t transfer_size = 0; - size_t blob_size = file->buf_size; - size_t k; - haddr_t addr_end = addr+size-1; - herr_t ret_value = SUCCEED; /* Return value */ - - assert(file && file->pub.cls); - assert(buf); - - /* Check for overflow conditions */ - if (HADDR_UNDEF == addr) { - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "addr undefined, addr = %llu", - (unsigned long long)addr); - } - if (REGION_OVERFLOW(addr, size)) { - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, - "addr overflow, addr = %llu", - (unsigned long long)addr); - } - if (NULL == file->page_buf) { - H5FD_HERMES_GOTO_ERROR(H5E_INTERNAL, H5E_UNINITIALIZED, FAIL, - "transfer buffer not initialized"); - } - - /* Check easy cases */ - if (0 == size) - return 0; - if ((haddr_t)addr >= file->eof) { - memset(buf, 0, size); - return 0; - } - - start_page_index = addr/blob_size; - end_page_index = addr_end/blob_size; - num_pages = end_page_index - start_page_index + 1; - - for (k = start_page_index; k <= end_page_index; ++k) { - size_t bytes_in; - char k_blob[LEN_BLOB_NAME]; - snprintf(k_blob, sizeof(k_blob), "%zu\n", k); - /* Check if this blob exists */ - bool blob_exists = check_blob(&file->blob_in_bucket, k); - - /* Check if addr is in the range of (k*blob_size, (k+1)*blob_size) */ - /* NOTE: The range does NOT include the start address of page k, - but includes the end address of page k */ - if (addr > k*blob_size && addr < (k+1)*blob_size) { - /* Calculate the starting address of transfer buffer update within page - * k */ - size_t offset = addr - k*blob_size; - assert(offset > 0); - - if (addr_end <= (k+1)*blob_size-1) - bytes_in = size; - else - bytes_in = (k+1)*blob_size-addr; - - if (!blob_exists) { - size_t bytes_copy; - if (file->eof < (k+1)*blob_size-1) - bytes_copy = file->eof-k*blob_size; - else - bytes_copy = blob_size; - - size_t bytes_read = pread(file->fd, file->page_buf, bytes_copy, - k*blob_size); - if (bytes_read != bytes_copy) - H5FD_HERMES_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "pread failed"); - memcpy(buf, file->page_buf+offset, bytes_in); - - /* Write Blob k to Hermes buffering system */ - HermesBucketPut(file->bkt_handle, k_blob, file->page_buf, blob_size); - set_blob(&file->blob_in_bucket, k); - } else { - /* Read blob back to transfer buffer */ - HermesBucketGet(file->bkt_handle, k_blob, blob_size, file->page_buf); - - memcpy(buf, file->page_buf+offset, bytes_in); - } - transfer_size += bytes_in; - /* Check if addr_end is in the range of [k*blob_size, - * (k+1)*blob_size-1) */ - /* NOTE: The range includes the start address of page k, - but does NOT include the end address of page k */ - } else if (addr_end >= k*blob_size && addr_end < (k+1)*blob_size-1) { - bytes_in = addr_end-k*blob_size+1; - if (!blob_exists) { - size_t bytes_copy; - if (file->eof < (k+1)*blob_size-1) - bytes_copy = file->eof-k*blob_size; - else - bytes_copy = blob_size; - - ssize_t bytes_read = pread(file->fd, file->page_buf, bytes_copy, - k*blob_size); - if (bytes_read != bytes_copy) - H5FD_HERMES_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "pread failed"); - - memcpy((char *)buf + transfer_size, file->page_buf, bytes_in); - - /* Write Blob k to Hermes buffering system */ - HermesBucketPut(file->bkt_handle, k_blob, file->page_buf, blob_size); - set_blob(&file->blob_in_bucket, k); - } else { - /* Read blob back to transfer buffer */ - HermesBucketGet(file->bkt_handle, k_blob, blob_size, file->page_buf); - - /* Update transfer buffer */ - memcpy((char *)buf + transfer_size, file->page_buf, bytes_in); - } - transfer_size += bytes_in; - /* Page/Blob k is within the range of (addr, addr+size) */ - /* addr <= k*blob_size && addr_end >= (k+1)*blob_size-1 */ - } else { - if (!blob_exists) { - ssize_t bytes_read = pread(file->fd, (char *)buf + transfer_size, - blob_size, addr+transfer_size); - if (bytes_read != blob_size) - H5FD_HERMES_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "pread failed"); - - /* Write Blob k to Hermes buffering system */ - HermesBucketPut(file->bkt_handle, k_blob, (char *)buf + transfer_size, - blob_size); - set_blob(&file->blob_in_bucket, k); - } else { - /* Read blob back directly */ - HermesBucketGet(file->bkt_handle, k_blob, blob_size, - (char *)buf + transfer_size); - } - transfer_size += blob_size; - } - } - - /* Update current position */ - file->pos = addr+size; - file->op = OP_READ; - -done: - if (ret_value < 0) { - /* Reset last file I/O information */ - file->pos = HADDR_UNDEF; - file->op = OP_UNKNOWN; - } /* end if */ - - H5FD_HERMES_FUNC_LEAVE_API; -} /* end H5FD__hermes_read() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__hermes_write - * - * Purpose: Writes SIZE bytes of data contained in buffer BUF to Hermes - * buffering system according to data transfer properties in - * DXPL_ID. Determine the number of file pages affected by this - * call from ADDR and SIZE. Utilize transfer buffer PAGE_BUF to - * put the data into Blobs. Exercise care for the first and last - * pages to prevent overwriting existing data. - * - * Return: SUCCEED/FAIL - * - *------------------------------------------------------------------------- - */ -static herr_t H5FD__hermes_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, - hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, - size_t size, const void *buf) { - H5FD_hermes_t *file = (H5FD_hermes_t *)_file; - size_t start_page_index; /* First page index of tranfer buffer */ - size_t end_page_index; /* End page index of tranfer buffer */ - size_t transfer_size = 0; - size_t blob_size = file->buf_size; - size_t k; - haddr_t addr_end = addr+size-1; - herr_t ret_value = SUCCEED; /* Return value */ - - assert(file && file->pub.cls); - assert(buf); - - /* Check for overflow conditions */ - if (HADDR_UNDEF == addr) { - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "addr undefined, addr = %llu", - (unsigned long long)addr); - } - if (REGION_OVERFLOW(addr, size)) { - H5FD_HERMES_GOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, - "addr overflow, addr = %llu, size = %llu", - (unsigned long long)addr, (unsigned long long)size); - } - if (NULL == file->page_buf) { - H5FD_HERMES_GOTO_ERROR(H5E_INTERNAL, H5E_UNINITIALIZED, FAIL, - "transfer buffer not initialized"); - } - start_page_index = addr/blob_size; - end_page_index = addr_end/blob_size; - - for (k = start_page_index; k <= end_page_index; ++k) { - char k_blob[LEN_BLOB_NAME]; - snprintf(k_blob, sizeof(k_blob), "%zu\n", k); - bool blob_exists = check_blob(&file->blob_in_bucket, k); - size_t page_start = k * blob_size; - size_t next_page_start = (k + 1) * blob_size; - - /* Check if addr is in the range of (page_start, next_page_start) */ - /* NOTE: The range does NOT include the start address of page k, - but includes the end address of page k */ - if (addr > page_start && addr < next_page_start) { - size_t page_offset = addr - page_start; - size_t page_write_size; - - if (addr_end < next_page_start) { - /* addr + size is within the same page (only one page) */ - page_write_size = size; - } else { - /* More than one page. Only copy until the end of this page. */ - page_write_size = next_page_start - addr; - } - - /* Fill transfer buffer with existing data, if any. */ - if (blob_exists) { - HermesBucketGet(file->bkt_handle, k_blob, blob_size, file->page_buf); - } else { - /* Populate this page from the original file */ - size_t gap_size = H5FD__hermes_get_gap_size(file, k); - herr_t status = H5FD__hermes_read_gap(file, page_start, file->page_buf, - gap_size); - if (status != SUCCEED) { - H5FD_HERMES_GOTO_DONE(FAIL); - } - } - - memcpy(file->page_buf + page_offset, (char *)buf + transfer_size, - page_write_size); - transfer_size += page_write_size; - - /* Write Blob k to Hermes. */ - HermesBucketPut(file->bkt_handle, k_blob, file->page_buf, blob_size); - set_blob(&file->blob_in_bucket, k); - } else if (addr_end >= page_start && addr_end < next_page_start - 1) { - /* NOTE: The range includes the start address of page k, but does NOT - include the end address of page k */ - - /* Read blob back */ - if (blob_exists) { - HermesBucketGet(file->bkt_handle, k_blob, blob_size, file->page_buf); - } else { - /* Populate this page from the original file */ - size_t gap_size = H5FD__hermes_get_gap_size(file, k); - herr_t status = H5FD__hermes_read_gap(file, page_start, file->page_buf, - gap_size); - if (status != SUCCEED) { - H5FD_HERMES_GOTO_DONE(FAIL); - } - } - - /* Update transfer buffer */ - memcpy(file->page_buf, (char *)buf + transfer_size, - addr_end-page_start + 1); - transfer_size += addr_end-page_start + 1; - /* Write Blob k to Hermes. */ - HermesBucketPut(file->bkt_handle, k_blob, file->page_buf, blob_size); - set_blob(&file->blob_in_bucket, k); - } else if (addr <= page_start && addr_end >= next_page_start-1) { - /* The write spans this page entirely */ - /* Write Blob k to Hermes buffering system */ - HermesBucketPut(file->bkt_handle, k_blob, (char *)buf + transfer_size, - blob_size); - set_blob(&(file->blob_in_bucket), k); - transfer_size += blob_size; - } - } - - /* Update current position and eof */ - file->pos = addr+size; - file->op = OP_WRITE; - if (file->pos > file->eof) - file->eof = file->pos; - -done: - if (ret_value < 0) { - /* Reset last file I/O information */ - file->pos = HADDR_UNDEF; - file->op = OP_UNKNOWN; - } /* end if */ - - H5FD_HERMES_FUNC_LEAVE_API; -} /* end H5FD__hermes_write() */ - -/* - * Stub routines for dynamic plugin loading - */ -H5PL_type_t -H5PLget_plugin_type(void) { - return H5PL_TYPE_VFD; -} - -const void* -H5PLget_plugin_info(void) { - return &H5FD_hermes_g; -} - -/* NOTE(chogan): Question: Why do we intercept initialization and termination of - * HDF5 and MPI? Answer: We have to handle several possible cases in order to - * get the initialization and finalization order of Hermes correct. First, the - * HDF5 application using the Hermes VFD can be either an MPI application or a - * serial application. If it's a serial application, we simply initialize Hermes - * before initializing the HDF5 library by intercepting H5_init_library. See - * https://github.com/HDFGroup/hermes/issues/385 for an explanation of why we - * need to initialize Hermes before HDF5. - * - * If we're dealing with an MPI application, then there are two possibilities: - * the app called MPI_Init before any HDF5 calls, or it made at least one HDF5 - * call before calling MPI_Init. If HDF5 was called first, then we have to - * initialize MPI ourselves and then intercept the app's call to MPI_Init to - * ensure MPI_Init is not called twice. - * - * For finalization, there are two cases to handle: 1) The application called - * MPI_Finalize(). In this case we need to intercept MPI_Finalize and shut down - * Hermes before MPI is finalized because Hermes finalization requires MPI. 2) - * If the app is serial, we need to call MPI_Finalize ourselves, so we intercept - * H5_term_library().*/ - -herr_t H5_init_library() { - herr_t ret_value = SUCCEED; - - if (mpi_is_initialized == FALSE) { - int status = PMPI_Init(NULL, NULL); - if (status != MPI_SUCCESS) { - // NOTE(chogan): We can't use the HDF5 error reporting functions here - // because HDF5 isn't initialized yet. - fprintf(stderr, "Hermes VFD: can't initialize MPI\n"); - ret_value = FAIL; - } else { - mpi_is_initialized = TRUE; - } - } - - if (ret_value == SUCCEED) { - if (hermes_initialized == FAIL) { - char *hermes_config = getenv(kHermesConf); - int status = HermesInitHermes(hermes_config); - if (status == 0) { - hermes_initialized = TRUE; - } else { - fprintf(stderr, "Hermes VFD: can't initialize Hermes\n"); - ret_value = FAIL; - } - } - - if (hermes_initialized == TRUE) { - MAP_OR_FAIL(H5_init_library); - ret_value = real_H5_init_library_(); - } - } - - return ret_value; -} - -herr_t H5_term_library() { - MAP_OR_FAIL(H5_term_library); - herr_t ret_value = real_H5_term_library_(); - - if (hermes_initialized == TRUE) { - HermesFinalize(); - hermes_initialized = FALSE; - } - - if (mpi_is_initialized) { - MPI_Finalize(); - mpi_is_initialized = FALSE; - } - - return ret_value; -} - -/** Only Initialize MPI if it hasn't already been initialized. */ -int MPI_Init(int *argc, char ***argv) { - int status = MPI_SUCCESS; - if (mpi_is_initialized == FALSE) { - int status = PMPI_Init(argc, argv); - if (status == MPI_SUCCESS) { - mpi_is_initialized = TRUE; - } - } - - return status; -} - -int MPI_Finalize() { - MAP_OR_FAIL(H5_term_library); - real_H5_term_library_(); - - if (hermes_initialized == TRUE) { - HermesFinalize(); - hermes_initialized = FALSE; - } - - int status = PMPI_Finalize(); - if (status == MPI_SUCCESS) { - mpi_is_initialized = FALSE; - } - - return status; -} diff --git a/adapter/vfd/H5FDhermes.h b/adapter/vfd/H5FDhermes.h deleted file mode 100644 index 1f2edeca6..000000000 --- a/adapter/vfd/H5FDhermes.h +++ /dev/null @@ -1,72 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright by The HDF Group. * - * Copyright by the Board of Trustees of the University of Illinois. * - * All rights reserved. * - * * - * This file is part of HDF5. The full HDF5 copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the root of the source code * - * distribution tree, or in https://www.hdfgroup.org/licenses. * - * If you do not have access to either file, you may request a copy from * - * help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* - * Programmer: Kimmy Mu - * April 2021 - * - * Purpose: The public header file for the Hermes driver. - */ -#ifndef H5FDhermes_H -#define H5FDhermes_H - -#include -#include -#include - -#define H5FD_HERMES_NAME "hermes" -#define H5FD_HERMES_VALUE ((H5FD_class_value_t)(513)) - -#define HERMES_FORWARD_DECL(func_, ret_, args_) \ - typedef ret_(*real_t_##func_##_) args_; \ - ret_(*real_##func_##_) args_ = NULL; - -#define MAP_OR_FAIL(func_) \ - if (!(real_##func_##_)) { \ - real_##func_##_ = (real_t_##func_##_)dlsym(RTLD_NEXT, #func_); \ - if (!(real_##func_##_)) { \ - fprintf(stderr, "HERMES Adapter failed to map symbol: %s\n", #func_); \ - exit(1); \ - } \ - } - -#ifdef __cplusplus -extern "C" { -#endif - -hid_t H5FD_hermes_init(); -herr_t H5Pset_fapl_hermes(hid_t fapl_id, hbool_t persistence, size_t page_size); - -HERMES_FORWARD_DECL(H5_init_library, herr_t, ()); -HERMES_FORWARD_DECL(H5_term_library, herr_t, ()); - -HERMES_FORWARD_DECL(MPI_Init, int, (int *argc, char ***argv)); -HERMES_FORWARD_DECL(MPI_Finalize, int, (void)); - -#ifdef __cplusplus -} -#endif - -#endif /* end H5FDhermes_H */ diff --git a/adapter/vfd/H5FDhermes_err.h b/adapter/vfd/H5FDhermes_err.h deleted file mode 100644 index adc9fb550..000000000 --- a/adapter/vfd/H5FDhermes_err.h +++ /dev/null @@ -1,211 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright by The HDF Group. * - * All rights reserved. * - * * - * This file is part of the HDF5 HERMES Virtual File Driver. The full * - * copyright notice, including terms governing use, modification, and * - * redistribution, is contained in the COPYING file, which can be found at * - * the root of the source code distribution tree. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* - * Error handling for the HERMES VFD - */ - -#ifndef H5FDhermes_err_h -#define H5FDhermes_err_h - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include "H5Epublic.h" - -extern hid_t H5FDhermes_err_stack_g; -extern hid_t H5FDhermes_err_class_g; - -#define H5FD_HERMES_ERR_CLS_NAME "HDF5 HERMES VFD" -#define H5FD_HERMES_ERR_LIB_NAME "HDF5 HERMES VFD" -#define H5FD_HERMES_ERR_VER "0.1.0" - -#define SUCCEED 0 -#define FAIL (-1) - -#ifndef FALSE - #define FALSE false -#endif -#ifndef TRUE - #define TRUE true -#endif - -#define H5_ATTR_UNUSED __attribute__((unused)) - -/* Error macros */ - -/* - * Macro to push the current function to the current error stack - * and then goto the "done" label, which should appear inside the - * function. (compatible with v1 and v2 errors) - */ -#define H5FD_HERMES_GOTO_ERROR(err_major, err_minor, ret_val, ...) \ - do { \ - unsigned is_v2_err; \ - union { \ - H5E_auto1_t err_func_v1; \ - H5E_auto2_t err_func_v2; \ - } err_func; \ - \ - /* Determine version of error */ \ - (void)H5Eauto_is_v2(H5E_DEFAULT, &is_v2_err); \ - \ - if (is_v2_err) { \ - (void)H5Eget_auto2(H5E_DEFAULT, &err_func.err_func_v2, NULL); \ - } else { \ - (void)H5Eget_auto1(&err_func.err_func_v1, NULL); \ - } \ - /* Check whether automatic error reporting has been disabled */ \ - if ( (is_v2_err && err_func.err_func_v2) || \ - (!is_v2_err && err_func.err_func_v1) ) { \ - if (H5FDhermes_err_stack_g >= 0 && H5FDhermes_err_class_g >= 0) { \ - H5Epush2(H5FDhermes_err_stack_g, __FILE__, __func__, __LINE__, \ - H5FDhermes_err_class_g, err_major, err_minor, __VA_ARGS__); \ - } else { \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } \ - } \ - \ - ret_value = ret_val; \ - goto done; \ - } while (0) - -/* - * Macro to push the current function to the current error stack - * without calling goto. This is used for handling the case where - * an error occurs during cleanup past the "done" label inside a - * function so that an infinite loop does not occur where goto - * continually branches back to the label. (compatible with v1 - * and v2 errors) - */ -#define H5FD_HERMES_DONE_ERROR(err_major, err_minor, ret_val, ...) \ - do { \ - unsigned is_v2_err; \ - union { \ - H5E_auto1_t err_func_v1; \ - H5E_auto2_t err_func_v2; \ - } err_func; \ - \ - /* Determine version of error */ \ - (void)H5Eauto_is_v2(H5E_DEFAULT, &is_v2_err); \ - \ - if (is_v2_err) { \ - (void)H5Eget_auto2(H5E_DEFAULT, &err_func.err_func_v2, NULL); \ - } else { \ - (void)H5Eget_auto1(&err_func.err_func_v1, NULL); \ - } \ - /* Check whether automatic error reporting has been disabled */ \ - if ( (is_v2_err && err_func.err_func_v2) || \ - (!is_v2_err && err_func.err_func_v1) ) { \ - if (H5FDhermes_err_stack_g >= 0 && H5FDhermes_err_class_g >= 0) { \ - H5Epush2(H5FDhermes_err_stack_g, __FILE__, __func__, __LINE__, \ - H5FDhermes_err_class_g, err_major, err_minor, __VA_ARGS__); \ - } else { \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } \ - } \ - \ - ret_value = ret_val; \ - } while (0) - -/* - * Macro to print out the current error stack and then clear it - * for future use. (compatible with v1 and v2 errors) - */ -#define PRINT_ERROR_STACK \ - do { \ - unsigned is_v2_err; \ - union { \ - H5E_auto1_t err_func_v1; \ - H5E_auto2_t err_func_v2; \ - } err_func; \ - \ - /* Determine version of error */ \ - (void)H5Eauto_is_v2(H5E_DEFAULT, &is_v2_err); \ - \ - if (is_v2_err) { \ - (void)H5Eget_auto2(H5E_DEFAULT, &err_func.err_func_v2, NULL); \ - } else { \ - (void)H5Eget_auto1(&err_func.err_func_v1, NULL); \ - } \ - /* Check whether automatic error reporting has been disabled */ \ - if ( (is_v2_err && err_func.err_func_v2) || \ - (!is_v2_err && err_func.err_func_v1) ) { \ - if ((H5FDhermes_err_stack_g >= 0) && \ - (H5Eget_num(H5FDhermes_err_stack_g) > 0)) { \ - H5Eprint2(H5FDhermes_err_stack_g, NULL); \ - H5Eclear2(H5FDhermes_err_stack_g); \ - } \ - } \ - } while (0) - -#define H5FD_HERMES_SYS_GOTO_ERROR(err_major, err_minor, ret_val, str) \ - do { \ - int myerrno = errno; \ - H5FD_HERMES_GOTO_ERROR(err_major, err_minor, ret_val, \ - "%s, errno = %d, error message = '%s'", str, \ - myerrno, strerror(myerrno)); \ - } while (0) - -/* - * Macro to simply jump to the "done" label inside the function, - * setting ret_value to the given value. This is often used for - * short circuiting in functions when certain conditions arise. - */ -#define H5FD_HERMES_GOTO_DONE(ret_val) \ - do { \ - ret_value = ret_val; \ - goto done; \ - } while (0) - -/* - * Macro to return from a top-level API function, printing - * out the error stack on the way out. - * It should be ensured that this macro is only called once - * per HDF5 operation. If it is called multiple times per - * operation (e.g. due to calling top-level API functions - * internally), the error stack will be inconsistent/incoherent. - */ -#define H5FD_HERMES_FUNC_LEAVE_API \ - do { \ - PRINT_ERROR_STACK; \ - return ret_value; \ - } while (0) - -/* - * Macro to return from internal functions. - */ -#define H5FD_HERMES_FUNC_LEAVE \ - do { \ - return ret_value; \ - } while (0) - -#ifdef __cplusplus -} -#endif - -#endif /* H5FDhermes_err_h */ diff --git a/adapter/vfd/README.md b/adapter/vfd/README.md deleted file mode 100644 index b89c17050..000000000 --- a/adapter/vfd/README.md +++ /dev/null @@ -1,102 +0,0 @@ -# HDF5 Hermes VFD - -## 1. Description -The HDF5 Hermes VFD is a [Virtual File -Driver](https://portal.hdfgroup.org/display/HDF5/Virtual+File+Drivers) (VFD) for -HDF5 that can be used to interface with the Hermes API. The driver is built as a -plugin library that is external to HDF5. - -## 2. Dependencies -The Hermes VFD requires [HDF5](https://github.com/HDFGroup/hdf5) >= `1.13.0`, -which is the version that first introduced dynamically loadable VFDs. - -## 3. Usage -To use the HDF5 Hermes VFD in an HDF5 application, the driver can either be -linked with the application during compilation, or it can be dynamically loaded -via an environment variable. It is more convenient to load the VFD as a dynamic -plugin because it does not require code changes or recompilation. - -### Method 1: Dynamically loaded by environment variable (recommended) - -As of HDF5 `1.13.0` each file in an HDF5 app opened or created with the default -file access property list (FAPL) will use the VFD specified in the `HDF5_DRIVER` -environment variable rather than the default "sec2" (POSIX) driver. To use the -Hermes VFD, simply set - -```sh -HDF5_DRIVER=hermes -``` - -Now we must tell the HDF5 library where to find the Hermes VFD. That is done -with the following environment variable: - -```sh -HDF5_PLUGIN_PATH=/lib/hermes_vfd -``` - -The Hermes VFD has two configuration options. -1. persistence - if `true`, the HDF5 application will produce the same output - files with the Hermes VFD as it would without it. If `false`, the files are - buffered in Hermes during the application run, but are not persisted when the - application terminates. Thus, no files are produced. -2. page size - The Hermes VFD works by mapping HDF5 files into its internal data - structures. This happens in pages. The `page size` configuration option - allows the user to specify the size, in bytes, of these pages. If your app - does lots 2 MiB writes, then it's a good idea to set the page size to 2 - MiB. A smaller page size, 1 KiB for example, would convert each 2 MiB write - into 2048 1 KiB writes. However, be aware that using pages that are too large - can slow down metadata operations, which are usually less than 2 KiB. To - combat the tradeoff between small metadata pages and large raw data pages, - the Hermes VFD can be stacked underneath the [split VFD](https://docs.hdfgroup.org/hdf5/develop/group___f_a_p_l.html#ga502f1ad38f5143cf281df8282fef26ed). - - -These two configuration options are passed as a space-delimited string through -an environment variable: - -```sh -# Example of configuring the Hermes VFD with `persistent_mode=true` and -# `page_size=64KiB` -HDF5_DRIVER_CONFIG="true 65536" -``` - -Finally we need to provide a configuration file for Hermes itself, and -`LD_PRELOAD` the Hermes VFD so we can intercept HDF5 and MPI calls for proper -initialization and finalization: - -```sh -HERMES_CONF=/hermes.yaml -LD_PRELOAD=/hermes_vfd/libhdf5_hermes_vfd.so -``` - -Heres is a full example of running an HDF5 app with the Hermes VFD: - -```sh -HDF5_DRIVER=hermes \ - HDF5_PLUGIN_PATH=/hermes.yaml \ - LD_PRELOAD=/hermes_vfd/libhdf5_hermes_vfd.so \ - ./my_hdf5_app -``` - -### Method 2: Linked into application - -To link the Hermes VFD into an HDF5 application, the application should include -the `H5FDhermes.h` header and should link the installed VFD library, -`libhdf5_hermes_vfd.so`, into the application. Once this has been done, Hermes -VFD access can be set up by calling `H5Pset_fapl_hermes()` on a FAPL within the -HDF5 application. In this case, the `persistence` and `page_size` configuration -options are pass directly to this function: - -```C -herr_t H5Pset_fapl_hermes(hid_t fapl_id, hbool_t persistence, size_t page_size) -``` - -The resulting `fapl_id` should then be passed to each file open or creation for -which you wish to use the Hermes VFD. - -## 4. More Information -* [Hermes VFD performance results](https://github.com/HDFGroup/hermes/wiki/HDF5-Hermes-VFD) - -* [Hermes VFD with hdf5-iotest](https://github.com/HDFGroup/hermes/tree/master/benchmarks/HermesVFD) -* [HDF5 VFD Plugins RFC](https://github.com/HDFGroup/hdf5doc/blob/master/RFCs/HDF5_Library/VFL_DriverPlugins/RFC__A_Plugin_Interface_for_HDF5_Virtual_File_Drivers.pdf) diff --git a/gotcha_intercept/CMakeLists.txt b/gotcha_intercept/CMakeLists.txt deleted file mode 100644 index 16525634f..000000000 --- a/gotcha_intercept/CMakeLists.txt +++ /dev/null @@ -1,76 +0,0 @@ -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - -if(HERMES_BUILD_POSIX_IO) - add_library(gotcha_stdio gotcha_stdio.cc) - hermes_set_lib_options(gotcha_stdio "gotcha_stdio" ${HERMES_LIBTYPE}) - list(APPEND GOTCHA_MODULE_LIBS gotcha_stdio) - set(HERMES_EXPORTED_LIBS gotcha_stdio ${HERMES_EXPORTED_LIBS}) - # Add Target(s) to CMake Install - install( - TARGETS - gotcha_stdio - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) -endif() - -if(HERMES_BUILD_POSIX_IO) - add_library(gotcha_posix gotcha_posix.cc) - hermes_set_lib_options(gotcha_posix "gotcha_posix" ${HERMES_LIBTYPE}) - list(APPEND GOTCHA_MODULE_LIBS gotcha_posix) - set(HERMES_EXPORTED_LIBS gotcha_posix ${HERMES_EXPORTED_LIBS}) - # Add Target(s) to CMake Install - install( - TARGETS - gotcha_posix - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} - ) -endif() - -if(HERMES_BUILD_MPI_IO) - add_library(gotcha_mpi_io gotcha_mpi_io.cc) - hermes_set_lib_options(gotcha_mpi_io "gotcha_mpi_io" ${HERMES_LIBTYPE}) - list(APPEND GOTCHA_MODULE_LIBS gotcha_mpi_io) - set(HERMES_EXPORTED_LIBS gotcha_mpi_io ${HERMES_EXPORTED_LIBS}) - # Add Target(s) to CMake Install - install( - TARGETS - gotcha_mpi_io - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} - ) -endif() - -list(APPEND GOTCHA_MODULE_LIBS gotcha) -set(GOTCHA_MODULE_LIBS ${GOTCHA_MODULE_LIBS} PARENT_SCOPE) - -set(HERMES_EXPORTED_LIBS ${HERMES_EXPORTED_LIBS} PARENT_SCOPE) - -#------------------------------------------------------------------------------ -# Set variables for parent scope -#------------------------------------------------------------------------------ -# Used by config.cmake.build.in and Testing -set(HERMES_INCLUDES_BUILD_TIME - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - $HERMES_EXT_INCLUDE_DEPENDENCIES} - PARENT_SCOPE -) - -# Used by config.cmake.install.in -set(HERMES_INCLUDES_INSTALL_TIME - ${HERMES_INSTALL_INCLUDE_DIR} - ${HERMES_EXT_INCLUDE_DEPENDENCIES} - PARENT_SCOPE -) - diff --git a/gotcha_intercept/Readme b/gotcha_intercept/Readme deleted file mode 100644 index d919e30af..000000000 --- a/gotcha_intercept/Readme +++ /dev/null @@ -1,3 +0,0 @@ -The text file (*.txt) in this folder specifies the functions that are -called in hermes and supported to be intercepted by GOTCHA library. -Each text file lists the functions that will be intercepted from that group. diff --git a/gotcha_intercept/gotcha_mpi_io.cc b/gotcha_intercept/gotcha_mpi_io.cc deleted file mode 100644 index 015e55aae..000000000 --- a/gotcha_intercept/gotcha_mpi_io.cc +++ /dev/null @@ -1,289 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -extern "C" { -#include "gotcha_mpi_io.h" -} - -#include -#include - -#include "gotcha/gotcha.h" -#include "gotcha/gotcha_types.h" - -#define FUNC_COUNT(wraps) ((sizeof(wraps) / sizeof(wraps[0]))) - -gotcha_wrappee_handle_t orig_MPI_Finalize_handle; -typedef int (hermes_MPI_Finalize_fp)(void); -int hermes_MPI_Finalize(void); - -gotcha_wrappee_handle_t orig_MPI_Init_handle; -typedef int (hermes_MPI_Init_fp)(int *argc, char ***argv); -int hermes_MPI_Init(int *argc, char ***argv); - -gotcha_wrappee_handle_t orig_MPI_File_close_handle; -typedef int (hermes_MPI_File_close_fp)(MPI_File *fh); -int hermes_MPI_File_close(MPI_File *fh); - -gotcha_wrappee_handle_t orig_MPI_File_open_handle; -typedef int (hermes_MPI_File_open_fp)(MPI_Comm comm, char *filename, int amode, - MPI_Info info, MPI_File *fh); -int hermes_MPI_File_open(MPI_Comm comm, char *filename, int amode, - MPI_Info info, MPI_File *fh); - -gotcha_wrappee_handle_t orig_MPI_File_seek_handle; -typedef int (hermes_MPI_File_seek_fp)(MPI_File fh, MPI_Offset offset, - int whence); -int hermes_MPI_File_seek(MPI_File fh, MPI_Offset offset, int whence); - -gotcha_wrappee_handle_t orig_MPI_File_read_handle; -typedef int (hermes_MPI_File_read_fp)(MPI_File fh, void *buf, int count, - MPI_Datatype datatype, MPI_Status *status); -int hermes_MPI_File_read(MPI_File fh, void *buf, int count, - MPI_Datatype datatype, MPI_Status *status); - -gotcha_wrappee_handle_t orig_MPI_File_write_handle; -typedef int (hermes_MPI_File_write_fp)(MPI_File fh, void *buf, int count, - MPI_Datatype datatype, - MPI_Status *status); -int hermes_MPI_File_write(MPI_File fh, void *buf, int count, - MPI_Datatype datatype, MPI_Status *status); - -gotcha_wrappee_handle_t orig_MPI_File_read_at_handle; -typedef int (hermes_MPI_File_read_at_fp)(MPI_File fh, MPI_Offset offset, - void *buf, int count, - MPI_Datatype datatype, - MPI_Status *status); -int hermes_MPI_File_read_at(MPI_File fh, MPI_Offset offset, void *buf, - int count, MPI_Datatype datatype, - MPI_Status *status); - -gotcha_wrappee_handle_t orig_MPI_File_write_at_handle; -typedef int (hermes_MPI_File_write_at_fp)(MPI_File fh, MPI_Offset offset, - void *buf, int count, - MPI_Datatype datatype, - MPI_Status *status); -int hermes_MPI_File_write_at(MPI_File fh, MPI_Offset offset, void *buf, - int count, MPI_Datatype datatype, - MPI_Status *status); - -struct gotcha_binding_t wrap_mpi_io[] = { - { "MPI_Finalize", (void *)hermes_MPI_Finalize, - &orig_MPI_Finalize_handle }, - { "MPI_Init", (void *)hermes_MPI_Init, &orig_MPI_Init_handle }, - { "MPI_File_close", (void *)hermes_MPI_File_close, - &orig_MPI_File_close_handle }, - { "MPI_File_open", (void *)hermes_MPI_File_open, - &orig_MPI_File_open_handle }, - { "MPI_File_seek", (void *)hermes_MPI_File_seek, - &orig_MPI_File_seek_handle }, - { "MPI_File_read", (void *)hermes_MPI_File_read, - &orig_MPI_File_read_handle }, - { "MPI_File_write", (void *)hermes_MPI_File_write, - &orig_MPI_File_write_handle }, - { "MPI_File_read_at", (void *)hermes_MPI_File_read_at, - &orig_MPI_File_read_at_handle }, - { "MPI_File_write_at", (void *)hermes_MPI_File_write_at, - &orig_MPI_File_write_at_handle }, -}; - -void init_gotcha_mpi_io() { - gotcha_wrap(wrap_mpi_io, FUNC_COUNT(wrap_mpi_io), "hermes"); -} - -int hermes_MPI_Finalize(void) { - /** check if path matches prefix */ - bool path_match = 1; - int ret = 0; - - printf("In wrapper hermes_MPI_Finalize\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function MPI_Finalize()\n"); - fflush(stdout); - } - - hermes_MPI_Finalize_fp *orig_MPI_Finalize = - (hermes_MPI_Finalize_fp *)gotcha_get_wrappee(orig_MPI_Finalize_handle); - ret = orig_MPI_Finalize(); - - return ret; -} - -int hermes_MPI_Init(int *argc, char ***argv) { - /** check if path matches prefix */ - bool path_match = 1; - int ret = 0; - - printf("In wrapper hermes_MPI_Init\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function MPI_Init()\n"); - fflush(stdout); - } - - hermes_MPI_Init_fp *orig_MPI_Init = - (hermes_MPI_Init_fp *)gotcha_get_wrappee(orig_MPI_Init_handle); - ret = orig_MPI_Init(argc, argv); - - return ret; -} - -int hermes_MPI_File_close(MPI_File *fh) { - /** check if path matches prefix */ - bool path_match = 1; - int ret = 0; - - printf("In wrapper hermes_MPI_File_close\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function MPI_File_close()\n"); - fflush(stdout); - } - - hermes_MPI_File_close_fp *orig_MPI_File_close = - (hermes_MPI_File_close_fp *)gotcha_get_wrappee(orig_MPI_File_close_handle); - ret = orig_MPI_File_close(fh); - - return ret; -} - -int hermes_MPI_File_open(MPI_Comm comm, char *filename, int amode, - MPI_Info info, MPI_File *fh) { - /** check if path matches prefix */ - bool path_match = 1; - int ret = 0; - - printf("In wrapper hermes_MPI_File_open\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function MPI_File_open()\n"); - fflush(stdout); - } - - hermes_MPI_File_open_fp *orig_hermes_MPI_File_open = - (hermes_MPI_File_open_fp *)gotcha_get_wrappee(orig_MPI_File_open_handle); - ret = orig_hermes_MPI_File_open(comm, filename, amode, info, fh); - - return ret; -} - -int hermes_MPI_File_seek(MPI_File fh, MPI_Offset offset, int whence) { - /** check if path matches prefix */ - bool path_match = 1; - int ret = 0; - - printf("In wrapper hermes_MPI_File_seek\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function MPI_File_seek()\n"); - fflush(stdout); - } - hermes_MPI_File_seek_fp *orig_hermes_MPI_File_seek = - (hermes_MPI_File_seek_fp *)gotcha_get_wrappee(orig_MPI_File_seek_handle); - ret = orig_hermes_MPI_File_seek(fh, offset, whence); - - return ret; -} - -int hermes_MPI_File_read(MPI_File fh, void *buf, int count, - MPI_Datatype datatype, MPI_Status *status) { - /** check if path matches prefix */ - bool path_match = 1; - int ret = 0; - - printf("In wrapper hermes_MPI_File_read\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function MPI_File_read()\n"); - fflush(stdout); - } - - hermes_MPI_File_read_fp *orig_MPI_File_read = - (hermes_MPI_File_read_fp *)gotcha_get_wrappee(orig_MPI_File_read_handle); - ret = orig_MPI_File_read(fh, buf, count, datatype, status); - - return ret; -} - -int hermes_MPI_File_write(MPI_File fh, void *buf, int count, - MPI_Datatype datatype, MPI_Status *status) { - /** check if path matches prefix */ - bool path_match = 1; - int ret = 0; - - printf("In wrapper hermes_MPI_File_write\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function MPI_File_write()\n"); - fflush(stdout); - } - - hermes_MPI_File_write_fp *orig_MPI_File_write = - (hermes_MPI_File_write_fp *)gotcha_get_wrappee(orig_MPI_File_write_handle); - ret = orig_MPI_File_write(fh, buf, count, datatype, status); - - return ret; -} - -int hermes_MPI_File_read_at(MPI_File fh, MPI_Offset offset, void *buf, - int count, MPI_Datatype datatype, - MPI_Status *status) { - /** check if path matches prefix */ - bool path_match = 1; - int ret = 0; - - printf("In wrapper hermes_MPI_File_read_at\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function MPI_File_read_at()\n"); - fflush(stdout); - } - - hermes_MPI_File_read_at_fp *orig_MPI_File_read_at = - (hermes_MPI_File_read_at_fp *) - gotcha_get_wrappee(orig_MPI_File_read_at_handle); - ret = orig_MPI_File_read_at(fh, offset, buf, count, datatype, status); - - return ret; -} - -int hermes_MPI_File_write_at(MPI_File fh, MPI_Offset offset, void *buf, - int count, MPI_Datatype datatype, - MPI_Status *status) { - /** check if path matches prefix */ - bool path_match = 1; - int ret = 0; - - printf("In wrapper hermes_MPI_File_write_at\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function MPI_File_write_at()\n"); - fflush(stdout); - } - - hermes_MPI_File_write_at_fp *orig_MPI_File_write_at = - (hermes_MPI_File_write_at_fp *) - gotcha_get_wrappee(orig_MPI_File_write_at_handle); - ret = orig_MPI_File_write_at(fh, offset, buf, count, datatype, status); - - return ret; -} diff --git a/gotcha_intercept/gotcha_mpi_io.h b/gotcha_intercept/gotcha_mpi_io.h deleted file mode 100644 index f32ee6253..000000000 --- a/gotcha_intercept/gotcha_mpi_io.h +++ /dev/null @@ -1,18 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef GOTCHA_MPI_IO_H_ -#define GOTCHA_MPI_IO_H_ - -void init_gotcha_mpi_io(); - -#endif // GOTCHA_MPI_IO_H_ diff --git a/gotcha_intercept/gotcha_posix.cc b/gotcha_intercept/gotcha_posix.cc deleted file mode 100644 index 4e9868531..000000000 --- a/gotcha_intercept/gotcha_posix.cc +++ /dev/null @@ -1,156 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -extern "C" { -#include "gotcha_posix.h" -} - -#include -#include - -#include "gotcha/gotcha.h" -#include "gotcha/gotcha_types.h" - -#define FUNC_COUNT(wraps) ((sizeof(wraps) / sizeof(wraps[0]))) - -gotcha_wrappee_handle_t orig_pwrite_handle; -typedef ssize_t (hermes_pwrite_fp)(int fd, const void *buf, size_t count, - off_t offset); -ssize_t hermes_pwrite(int fd, const void *buf, size_t count, off_t offset); - -gotcha_wrappee_handle_t orig_pread_handle; -typedef ssize_t (hermes_pread_fp)(int fd, void *buf, size_t count, - off_t offset); -ssize_t hermes_pread(int fd, void *buf, size_t count, off_t offset); - -gotcha_wrappee_handle_t orig_lseek_handle; -typedef off_t (hermes_lseek_fp)(int fd, off_t offset, int whence); -off_t hermes_lseek(int fd, off_t offset, int whence); - -gotcha_wrappee_handle_t orig_write_handle; -typedef ssize_t (hermes_write_fp)(int fd, const void *buf, size_t count); -ssize_t hermes_write(int fd, const void *buf, size_t count); - -gotcha_wrappee_handle_t orig_read_handle; -typedef ssize_t (hermes_read_fp)(int fd, void *buf, size_t count); -ssize_t hermes_read(int fd, void *buf, size_t count); - -struct gotcha_binding_t wrap_posix[] = { - { "pwrite", (void *)hermes_pwrite, &orig_pwrite_handle }, - { "pread", (void *)hermes_pread, &orig_pread_handle }, - { "lseek", (void *)hermes_lseek, &orig_lseek_handle }, - { "write", (void *)hermes_write, &orig_write_handle }, - { "read", (void *)hermes_read, &orig_read_handle }, -}; - -void init_gotcha_posix() { - gotcha_wrap(wrap_posix, FUNC_COUNT(wrap_posix), "hermes"); -} - -ssize_t hermes_pwrite(int fd, const void *buf, size_t count, off_t offset) { - /** check if path matches prefix */ - bool path_match = 1; - ssize_t ret = 0; - - printf("In wrapper hermes_pwrite\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function pwrite()\n"); - fflush(stdout); - } - - hermes_pwrite_fp *orig_pwrite = - (hermes_pwrite_fp *)gotcha_get_wrappee(orig_pwrite_handle); - ret = orig_pwrite(fd, buf, count, offset); - - return ret; -} - -ssize_t hermes_pread(int fd, void *buf, size_t count, off_t offset) { - /** check if path matches prefix */ - bool path_match = 1; - ssize_t ret = 0; - - printf("In wrapper hermes_pread\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function pread()\n"); - fflush(stdout); - } - - hermes_pread_fp *orig_pread = - (hermes_pread_fp *)gotcha_get_wrappee(orig_pread_handle); - ret = orig_pread(fd, buf, count, offset); - - return ret; -} - -off_t hermes_lseek(int fd, off_t offset, int whence) { - /** check if path matches prefix */ - bool path_match = 1; - off_t ret = 0; - - printf("In wrapper hermes_lseek\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function lseek()\n"); - fflush(stdout); - } - - hermes_lseek_fp *orig_lseek = - (hermes_lseek_fp *)gotcha_get_wrappee(orig_lseek_handle); - ret = orig_lseek(fd, offset, whence); - - return ret; -} - -ssize_t hermes_write(int fd, const void *buf, size_t count) { - /** check if path matches prefix */ - bool path_match = 1; - ssize_t ret = 0; - - printf("In wrapper hermes_write\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function write()\n"); - fflush(stdout); - } - hermes_write_fp *orig_write = - (hermes_write_fp *)gotcha_get_wrappee(orig_write_handle); - ret = orig_write(fd, buf, count); - - return ret; -} - -ssize_t hermes_read(int fd, void *buf, size_t count) { - /** check if path matches prefix */ - bool path_match = 1; - ssize_t ret = 0; - - printf("In wrapper hermes_read\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function read()\n"); - fflush(stdout); - } - - hermes_read_fp *orig_read = - (hermes_read_fp *)gotcha_get_wrappee(orig_read_handle); - ret = orig_read(fd, buf, count); - - return ret; -} diff --git a/gotcha_intercept/gotcha_posix.h b/gotcha_intercept/gotcha_posix.h deleted file mode 100644 index 46ee5efcc..000000000 --- a/gotcha_intercept/gotcha_posix.h +++ /dev/null @@ -1,18 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef GOTCHA_POSIX_H_ -#define GOTCHA_POSIX_H_ - -void init_gotcha_posix(); - -#endif // GOTCHA_POSIX_H_ diff --git a/gotcha_intercept/gotcha_stdio.cc b/gotcha_intercept/gotcha_stdio.cc deleted file mode 100644 index d42422bd4..000000000 --- a/gotcha_intercept/gotcha_stdio.cc +++ /dev/null @@ -1,155 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -extern "C" { -#include "gotcha_stdio.h" -} - -#include - -#include "gotcha/gotcha.h" -#include "gotcha/gotcha_types.h" - -#define FUNC_COUNT(wraps) ((sizeof(wraps) / sizeof(wraps[0]))) - -gotcha_wrappee_handle_t orig_fopen_handle; -typedef FILE * (hermes_fopen_fp)(const char *filename, const char * mode); -FILE * hermes_fopen(const char *filename, const char * mode); - -gotcha_wrappee_handle_t orig_fclose_handle; -typedef int (hermes_fclose_fp)(FILE *stream); -int hermes_fclose(FILE *stream); - -gotcha_wrappee_handle_t orig_fwrite_handle; -typedef size_t (hermes_fwrite_fp)(const void *ptr, size_t size, size_t count, - FILE *stream); -size_t hermes_fwrite(const void *ptr, size_t size, size_t count, FILE *stream); - -gotcha_wrappee_handle_t orig_fread_handle; -typedef size_t (hermes_fread_fp)(void * ptr, size_t size, size_t count, - FILE *stream); -size_t hermes_fread(void * ptr, size_t size, size_t count, FILE *stream); - -gotcha_wrappee_handle_t orig_fseek_handle; -typedef size_t (hermes_fseek_fp)(FILE * stream, long int offset, int origin); -size_t hermes_fseek(FILE * stream, long int offset, int origin); - -struct gotcha_binding_t wrap_stdio[] = { - { "fopen", (void *)hermes_fopen, &orig_fopen_handle }, - { "fclose", (void *)hermes_fclose, &orig_fclose_handle }, - { "fwrite", (void *)hermes_fwrite, &orig_fwrite_handle }, - { "fread", (void *)hermes_fread, &orig_fread_handle }, - { "fseek", (void *)hermes_fseek, &orig_fseek_handle }, -}; - -void init_gotcha_stdio() { - gotcha_wrap(wrap_stdio, FUNC_COUNT(wrap_stdio), "hermes"); -} - -FILE * hermes_fopen(const char *filename, const char * mode) { - /** check if path matches prefix */ - bool path_match = 1; - FILE *fp = nullptr; - - printf("In wrapper hermes_fopen\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function fopen()\n"); - fflush(stdout); - } - hermes_fopen_fp *orig_fopen = - (hermes_fopen_fp *)gotcha_get_wrappee(orig_fopen_handle); - fp = orig_fopen(filename, mode); - - return fp; -} - -int hermes_fclose(FILE *stream) { - /** check if path matches prefix */ - bool path_match = 1; - int ret = 0; - - printf("In wrapper hermes_fclose\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function fclose()\n"); - fflush(stdout); - } - - hermes_fclose_fp *orig_fclose = - (hermes_fclose_fp *)gotcha_get_wrappee(orig_fclose_handle); - ret = orig_fclose(stream); - - return ret; -} - -size_t hermes_fwrite(const void *ptr, size_t size, size_t count, FILE *stream) { - /** check if path matches prefix */ - bool path_match = 1; - size_t ret = 0; - - printf("In wrapper hermes_fwrite\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function fwrite()\n"); - fflush(stdout); - } - - hermes_fwrite_fp *orig_fwrite = - (hermes_fwrite_fp *)gotcha_get_wrappee(orig_fwrite_handle); - ret = orig_fwrite(ptr, size, count, stream); - - return ret; -} - -size_t hermes_fread(void * ptr, size_t size, size_t count, FILE *stream) { - /** check if path matches prefix */ - bool path_match = 1; - size_t ret = 0; - - printf("In wrapper hermes_fread\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function fread()\n"); - fflush(stdout); - } - - hermes_fread_fp *orig_fread = - (hermes_fread_fp *)gotcha_get_wrappee(orig_fread_handle); - ret = orig_fread(ptr, size, count, stream); - - return ret; -} - -size_t hermes_fseek(FILE * stream, long int offset, int origin) { - /** check if path matches prefix */ - bool path_match = 1; - size_t ret = 0; - - printf("In wrapper hermes_fseek\n"); - fflush(stdout); - - if (path_match) { - printf("Intercepting function fseek()\n"); - fflush(stdout); - } - - hermes_fseek_fp *orig_fseek = - (hermes_fseek_fp *)gotcha_get_wrappee(orig_fseek_handle); - ret = orig_fseek(stream, offset, origin); - - return ret; -} diff --git a/gotcha_intercept/gotcha_stdio.h b/gotcha_intercept/gotcha_stdio.h deleted file mode 100644 index 1be3c0b08..000000000 --- a/gotcha_intercept/gotcha_stdio.h +++ /dev/null @@ -1,18 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef GOTCHA_STDIO_H_ -#define GOTCHA_STDIO_H_ - -void init_gotcha_stdio(); - -#endif // GOTCHA_STDIO_H_ diff --git a/gotcha_intercept/mpi_io.txt b/gotcha_intercept/mpi_io.txt deleted file mode 100644 index ca307aee1..000000000 --- a/gotcha_intercept/mpi_io.txt +++ /dev/null @@ -1,13 +0,0 @@ -int MPI_Finalize () -int MPI_Init (int *argc, char ***argv) -int MPI_File_close (MPI_File *fh) -int MPI_File_open (MPI_Comm comm, char *filename, int amode, MPI_Info info, MPI_File *fh) -int MPI_File_seek (MPI_File fh, MPI_Offset offset, int whence); -int MPI_File_read (MPI_File fh, void *buf, int count, MPI_Datatype datatype, - MPI_Status *status) -int MPI_File_write (MPI_File fh, void *buf, int count, MPI_Datatype datatype, - MPI_Status *status) -int MPI_File_read_at (MPI_File fh, MPI_Offset offset, void *buf, - int count, MPI_Datatype datatype, MPI_Status *status); -int MPI_File_write_at (MPI_File fh, MPI_Offset offset, void *buf, - int count, MPI_Datatype datatype, MPI_Status *status); diff --git a/gotcha_intercept/stdio.txt b/gotcha_intercept/stdio.txt deleted file mode 100644 index 2acbd5500..000000000 --- a/gotcha_intercept/stdio.txt +++ /dev/null @@ -1,5 +0,0 @@ -FILE * fopen (const char *filename, const char * mode) -int fclose (FILE *stream) -size_t fwrite (const void *ptr, size_t size, size_t count, FILE *stream) -size_t fread (void * ptr, size_t size, size_t count, FILE *stream) -int fseek (FILE * stream, long int offset, int origin); From 186eb8b22064c1b91ec644a32dd55a05e4c65677 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 04:17:58 -0600 Subject: [PATCH 130/511] Stash pubsub --- adapter/pubsub/CMakeLists.txt | 33 ------ adapter/pubsub/datastructures.h | 58 ---------- adapter/pubsub/metadata_manager.cc | 60 ---------- adapter/pubsub/metadata_manager.h | 136 ---------------------- adapter/pubsub/pubsub.cc | 177 ----------------------------- adapter/pubsub/pubsub.h | 129 --------------------- 6 files changed, 593 deletions(-) delete mode 100644 adapter/pubsub/CMakeLists.txt delete mode 100644 adapter/pubsub/datastructures.h delete mode 100644 adapter/pubsub/metadata_manager.cc delete mode 100644 adapter/pubsub/metadata_manager.h delete mode 100644 adapter/pubsub/pubsub.cc delete mode 100644 adapter/pubsub/pubsub.h diff --git a/adapter/pubsub/CMakeLists.txt b/adapter/pubsub/CMakeLists.txt deleted file mode 100644 index 35a88f503..000000000 --- a/adapter/pubsub/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -project(PubSubAdapter VERSION ${HERMES_PACKAGE_VERSION}) - -set(HERMES_PUBSUB_ADAPTER_DIR ${HERMES_ADAPTER_DIR}/pubsub) - -set(PUBSUB_ADAPTER_PUBLIC_HEADER pubsub.h) -set(PUBSUB_ADAPTER_PRIVATE_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/metadata_manager.h - ${CMAKE_CURRENT_SOURCE_DIR}/datastructures.h - ${HERMES_ADAPTER_DIR}/constants.h) -set(PUBSUB_ADAPTER_SRC pubsub.cc metadata_manager.cc) - -add_library(hermes_pubsub SHARED ${PUBSUB_ADAPTER_PRIVATE_HEADER} ${PUBSUB_ADAPTER_PUBLIC_HEADER} ${PUBSUB_ADAPTER_SRC}) -target_include_directories(hermes_pubsub PRIVATE ${HERMES_ADAPTER_DIR}) -add_dependencies(hermes_pubsub hermes) -target_link_libraries(hermes_pubsub hermes MPI::MPI_CXX glog::glog) - -#----------------------------------------------------------------------------- -# Add Target(s) to CMake Install -#----------------------------------------------------------------------------- -install( - TARGETS - hermes_pubsub - EXPORT - ${HERMES_EXPORTED_TARGETS} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} -) -#----------------------------------------------------------------------------- -# Add Target(s) to Coverage -#----------------------------------------------------------------------------- -if(HERMES_ENABLE_COVERAGE) - set_coverage_flags(hermes_pubsub) -endif() diff --git a/adapter/pubsub/datastructures.h b/adapter/pubsub/datastructures.h deleted file mode 100644 index 1bbe8a226..000000000 --- a/adapter/pubsub/datastructures.h +++ /dev/null @@ -1,58 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_PUBSUB_ADAPTER_DATASTRUCTURES_H -#define HERMES_PUBSUB_ADAPTER_DATASTRUCTURES_H - -/** - * Standard header - */ -#include - -/** - * Internal header - */ -#include -#include -#include - -/** - * Namespace simplification. - */ -namespace hapi = hermes::api; - -namespace hermes::adapter::pubsub { - -/** - * Struct that defines the metadata required for the pubsub adapter. - */ -struct ClientMetadata { - /** bucket associated with the topic */ - std::shared_ptr st_bkid; - u64 last_subscribed_blob; /**< Current blob being used */ - timespec st_atim; /**< time of last access */ - /** - * Constructor - */ - ClientMetadata() - : st_bkid(), - last_subscribed_blob(0), - st_atim() {} /* default constructor */ - explicit ClientMetadata(const struct ClientMetadata &st) - : st_bkid(st.st_bkid), - last_subscribed_blob(st.last_subscribed_blob), - st_atim(st.st_atim) {} /**< parameterized constructor */ -}; - -} // namespace hermes::adapter::pubsub - -#endif // HERMES_PUBSUB_ADAPTER_DATASTRUCTURES_H diff --git a/adapter/pubsub/metadata_manager.cc b/adapter/pubsub/metadata_manager.cc deleted file mode 100644 index 28c755796..000000000 --- a/adapter/pubsub/metadata_manager.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "metadata_manager.h" - -/** - * Namespace declarations for cleaner code. - */ -using hermes::adapter::pubsub::MetadataManager; -using hermes::adapter::pubsub::MetadataManager; - -bool MetadataManager::Create(const std::string& topic, - const ClientMetadata&stat) { - LOG(INFO) << "Create metadata for topic: " << topic << std::endl; - auto ret = metadata.emplace(topic, stat); - return ret.second; -} - -bool MetadataManager::Update(const std::string& topic, - const ClientMetadata&stat) { - LOG(INFO) << "Update metadata for topic: " << topic << std::endl; - auto iter = metadata.find(topic); - if (iter != metadata.end()) { - metadata.erase(iter); - auto ret = metadata.emplace(topic, stat); - return ret.second; - } else { - return false; - } -} - -std::pair MetadataManager::Find( - const std::string& topic) { - typedef std::pair MetadataReturn; - auto iter = metadata.find(topic); - if (iter == metadata.end()) - return MetadataReturn(ClientMetadata(), false); - else - return MetadataReturn(iter->second, true); -} - -bool MetadataManager::Delete(const std::string& topic) { - LOG(INFO) << "Delete metadata for topic: " << topic << std::endl; - auto iter = metadata.find(topic); - if (iter != metadata.end()) { - metadata.erase(iter); - return true; - } else { - return false; - } -} diff --git a/adapter/pubsub/metadata_manager.h b/adapter/pubsub/metadata_manager.h deleted file mode 100644 index 28eb1918f..000000000 --- a/adapter/pubsub/metadata_manager.h +++ /dev/null @@ -1,136 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_PUBSUB_ADAPTER_METADATA_MANAGER_H -#define HERMES_PUBSUB_ADAPTER_METADATA_MANAGER_H - -/** - * Standard headers - */ -#include - -#include - -/** - * Internal headers - */ -#include "datastructures.h" - -using hermes::adapter::pubsub::ClientMetadata; - -namespace hermes::adapter::pubsub { -/** - * Metadata manager for PubSub adapter - */ -class MetadataManager { - private: - /** - * Private members - */ - std::unordered_map metadata; - /** - * hermes attribute to initialize Hermes - */ - std::shared_ptr hermes; - /** - * references of how many times hermes was tried to initialize. - */ - std::atomic ref; - - public: - int mpi_rank; /**< rank of MPI processor */ - /** - * Constructor - */ - explicit MetadataManager(bool is_mpi = true) : metadata(), ref(0) { - if (is_mpi) { - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - } else { - // branch exists for testing puropses - mpi_rank = 0; - } - } - /** - * Get the instance of hermes. - */ - std::shared_ptr& GetHermes() { return hermes; } - - /** - * Initialize hermes. - */ - void InitializeHermes(const char* config_file) { - if (ref == 0) { - hermes = hapi::InitHermes(config_file, false, true); - } - ref++; - } - - /** - * Finalize hermes if reference is equal to one. Else just - * decrement the ref counter. - */ - void FinalizeHermes() { - if (ref == 1) { - hermes->Finalize(); - } - ref--; - } - - /** - check if this application is client or core - */ - bool isClient() { return hermes->IsApplicationCore(); } - - /** - * \brief Create a metadata entry for pubsub adapter for a given topic. - * \param topic name of the managed topic. - * \param stat current metadata of the topic. - * \return true, if operation was successful. - * false, if operation was unsuccessful. - */ - bool Create(const std::string& topic, const ClientMetadata& stat); - - /** - * \brief Update existing metadata entry for pubsub adapter for a given file - * handler. - * \param topic name of the managed topic. - * \param stat current metadata of the topic to replace previous one. - * \return true, if operation was successful. - * false, if operation was unsuccessful or entry doesn't exist. - * \remark Update call will not degenerate into a create call - * if topic is not being tracked. - */ - bool Update(const std::string& topic, const ClientMetadata& stat); - - /** - * \brief Delete existing metadata entry for pubsub adapter for a given file - * handler. - * \param topic name of the managed topic. - * \return true, if operation was successful. - * false, if operation was unsuccessful. - */ - bool Delete(const std::string& topic); - - /** - * \brief Find existing metadata entry for pubsub adapter for a given file - * handler. - * \param topic name of the managed topic. - * \return The metadata entry if exist. - * - * The bool in pair indicates whether metadata entry exists or not. - */ - std::pair Find(const std::string& topic); -}; - -} // namespace hermes::adapter::pubsub - -#endif // HERMES_PUBSUB_ADAPTER_METADATA_MANAGER_H diff --git a/adapter/pubsub/pubsub.cc b/adapter/pubsub/pubsub.cc deleted file mode 100644 index 21c739fd6..000000000 --- a/adapter/pubsub/pubsub.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "pubsub.h" - -namespace hapi = hapi; - -hapi::Status hermes::pubsub::mpiInit(int argc, char **argv) { - LOG(INFO) << "Starting MPI" << std::endl; - int mpi_threads_provided; - MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &mpi_threads_provided); - if (mpi_threads_provided < MPI_THREAD_MULTIPLE) { - fprintf(stderr, "Didn't receive appropriate MPI threading specification\n"); - return hapi::Status(hermes::INVALID_FILE); - } - return hapi::Status(hermes::HERMES_SUCCESS); -} - -hapi::Status hermes::pubsub::connect(const std::string &config_file) { - LOG(INFO) << "Connecting adapter" << std::endl; - auto mdm = hermes::Singleton - ::GetInstance(); - try { - mdm->InitializeHermes(config_file.c_str()); - if (mdm->isClient()) { - return hapi::Status(hermes::HERMES_SUCCESS); - } else { - return hapi::Status(hermes::INVALID_FILE); - } - } catch (const std::exception& e) { - LOG(FATAL) << "Could not connect to hermes daemon" <::GetInstance(); - try { - mdm->FinalizeHermes(); - return hapi::Status(hermes::HERMES_SUCCESS); - } catch (const std::exception& e) { - LOG(FATAL) << "Could not disconnect from hermes" <::GetInstance(); - auto existing = mdm->Find(topic); - if (!existing.second) { - LOG(INFO) << "Topic not currently tracked" << std::endl; - ClientMetadata stat; - struct timespec ts{}; - timespec_get(&ts, TIME_UTC); - stat.st_atim = ts; - stat.st_bkid = std::make_shared(topic, mdm->GetHermes(), ctx); - if (!stat.st_bkid->IsValid()) return hapi::Status(hermes::INVALID_BUCKET); - if (!mdm->Create(topic, stat)) return hapi::Status(hermes::INVALID_BUCKET); - } else { - LOG(INFO) << "Topic is tracked, attaching to it" << std::endl; - struct timespec ts{}; - timespec_get(&ts, TIME_UTC); - existing.first.st_atim = ts; - if (!mdm->Update(topic, existing.first)) { - return hapi::Status(hermes::INVALID_BUCKET); - } - } - return hapi::Status(hermes::HERMES_SUCCESS); -} - -hapi::Status hermes::pubsub::detach(const std::string& topic) { - LOG(INFO) << "Detaching from topic: " << topic << std::endl; - hapi::Context ctx; - auto mdm = hermes::Singleton - ::GetInstance(); - auto existing = mdm->Find(topic); - if (existing.second) { - mdm->Delete(topic); - return existing.first.st_bkid->Release(ctx); - } - return hapi::Status(hermes::INVALID_BUCKET); -} - -hapi::Status hermes::pubsub::publish(const std::string& topic, - const hapi::Blob& message) { - LOG(INFO) << "Publish to : " << topic << std::endl; - auto mdm = hermes::Singleton - ::GetInstance(); - auto metadata = mdm->Find(topic); - - if (!metadata.second) { - if (attach(topic) == hermes::HERMES_SUCCESS) { - metadata = mdm->Find(topic); - } else { - return hapi::Status(hermes::INVALID_BUCKET); - } - } - - hapi::Context ctx; - struct timespec ts{}; - timespec_get(&ts, TIME_UTC); - - std::string blob_name = std::to_string(mdm->mpi_rank) + "_" + - std::to_string(ts.tv_nsec); - LOG(INFO) << "Publishing to blob with id " << blob_name << std::endl; - auto status = metadata.first.st_bkid->Put(blob_name, message, ctx); - if (status.Failed()) { - return hapi::Status(hermes::INVALID_BLOB); - } - - metadata.first.st_atim = ts; - mdm->Update(topic, metadata.first); - - return hapi::Status(hermes::HERMES_SUCCESS); -} - -std::pair hermes::pubsub::subscribe( - const std::string& topic) { - LOG(INFO) << "Subscribe to : " << topic << std::endl; - typedef std::pair SubscribeReturn; - - auto mdm = hermes::Singleton - ::GetInstance(); - auto metadata = mdm->Find(topic); - - if (!metadata.second) { - if (attach(topic) == hermes::HERMES_SUCCESS) { - metadata = mdm->Find(topic); - } else { - return SubscribeReturn(hapi::Blob(), - hapi::Status(hermes::INVALID_BUCKET)); - } - } - - hapi::Context ctx; - u64 index = metadata.first.last_subscribed_blob; - - hapi::Blob read_data(0); - LOG(INFO) << "Subscribing to " << topic << " at blob id " << index - << std::endl; - auto bucket = metadata.first.st_bkid; - auto exiting_blob_size = bucket->GetNext(index, read_data, ctx); - read_data.resize(exiting_blob_size); - - if (bucket->GetNext(index, read_data, ctx) != exiting_blob_size) { - return SubscribeReturn(hapi::Blob(), - hapi::Status(hermes::BLOB_NOT_IN_BUCKET)); - } - - metadata.first.last_subscribed_blob++; - struct timespec ts{}; - timespec_get(&ts, TIME_UTC); - metadata.first.st_atim = ts; - mdm->Update(topic, metadata.first); - - return SubscribeReturn(read_data, - hapi::Status(hermes::HERMES_SUCCESS)); -} diff --git a/adapter/pubsub/pubsub.h b/adapter/pubsub/pubsub.h deleted file mode 100644 index 8ee1e0106..000000000 --- a/adapter/pubsub/pubsub.h +++ /dev/null @@ -1,129 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_PUBSUB_H -#define HERMES_PUBSUB_H - -/** - * Standard header - */ - -#include - -/** - * Dependent library headers - */ -#include - -/** - * Internal headers - */ -#include -#include - -#include "../constants.h" -#include "metadata_manager.h" -#include "singleton.h" - -namespace hermes::pubsub { - -/** - * \brief Helper function to initialize MPI - * - * \return The return code/status - * - */ -hapi::Status mpiInit(int argc, char** argv); - -/** - * \brief Connects to the Hermes instance - * - * \param config_file Path to the config file of Hermes - * - * \return The return code/status - * - */ -hapi::Status connect(const std::string& config_file); - -/** - * \brief Connects to the Hermes instance - * - * \return The return code/status - * - * \pre Assumes that the config file path is loaded into a environment variable - * defined in constants.h under kHermesConf - * - */ -hapi::Status connect(); - -/** - * \brief Connects from the Hermes instance - * - * \return The return code/status - */ -hapi::Status disconnect(); - -/** - * \brief Attaches to a topic, creating it if it doesnt exists. - * - * \param topic The name of the topic - * - * \return The return code/status - * - */ -hapi::Status attach(const std::string& topic); - -/** - * \brief Detaches from the topic. Cleaning up all metadata - * - * \param topic The name of the topic - * - * \return The return code/status - * - * \pre Detaching doesnt delete the topic - * - */ -hapi::Status detach(const std::string& topic); - -/** - * \brief Puts a message to a topic - * - * \param topic The name of the topic - * \param message the data buffer - * - * \return The return code/status - * - * \remark Using std::vector as equivalent to Blob - * - */ -hapi::Status publish(const std::string& topic, - const std::vector& message); - -/** - * \brief Retrieves the next message from the topic - * - * \param topic The name of the topic - * - * \return A pair of: - * the return code/status - * and, if successful, the subscribed message. - * - * \remark Message order is tracked by Hermes. Current message is tracked - * per-process by a metadata manager - * - */ -std::pair, hapi::Status> subscribe( - const std::string& topic); - -} // namespace hermes::pubsub - -#endif // HERMES_PUBSUB_H From 0257254278f5ed7e4b511ba85b404fc9bb273a1e Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 04:43:10 -0600 Subject: [PATCH 131/511] Removed path_inclusion / exclusion from server config --- adapter/test/data/hermes.yaml | 45 -- adapter/test/data/hermes_ares.yaml | 47 -- adapter/test/data/hermes_client.yaml | 5 + adapter/test/data/hermes_server.yaml | 132 ++++ adapter/test/data/hermes_small.yaml | 46 -- adapter/test/gcc_hermes.sh | 16 + adapter/test/gcc_hermes_mode.sh | 15 + adapter/test/posix/CMakeLists.txt | 8 - adapter/test/pubsub/CMakeLists.txt | 49 -- adapter/test/pubsub/pubsub_end_to_end_test.cc | 64 -- .../pubsub/pubsub_end_to_end_test_sync.cc | 68 -- adapter/test/pubsub/pubsub_metadata_test.cc | 52 -- adapter/test/pubsub/pubsub_topic_test.cc | 41 - adapter/test/pubsub/test_utils.h | 31 - adapter/test/vfd/CMakeLists.txt | 68 -- adapter/test/vfd/hermes_vfd_basic_test.cc | 718 ------------------ adapter/test/vfd/hermes_vfd_test.cc | 585 -------------- config/hermes_server_default.yaml | 14 +- src/config_server.cc | 9 - src/config_server.h | 13 - src/config_server_default.h | 14 +- 21 files changed, 170 insertions(+), 1870 deletions(-) delete mode 100644 adapter/test/data/hermes.yaml delete mode 100644 adapter/test/data/hermes_ares.yaml create mode 100644 adapter/test/data/hermes_client.yaml create mode 100644 adapter/test/data/hermes_server.yaml delete mode 100644 adapter/test/data/hermes_small.yaml create mode 100644 adapter/test/gcc_hermes.sh create mode 100644 adapter/test/gcc_hermes_mode.sh delete mode 100644 adapter/test/pubsub/CMakeLists.txt delete mode 100644 adapter/test/pubsub/pubsub_end_to_end_test.cc delete mode 100644 adapter/test/pubsub/pubsub_end_to_end_test_sync.cc delete mode 100644 adapter/test/pubsub/pubsub_metadata_test.cc delete mode 100644 adapter/test/pubsub/pubsub_topic_test.cc delete mode 100644 adapter/test/pubsub/test_utils.h delete mode 100644 adapter/test/vfd/CMakeLists.txt delete mode 100644 adapter/test/vfd/hermes_vfd_basic_test.cc delete mode 100644 adapter/test/vfd/hermes_vfd_test.cc diff --git a/adapter/test/data/hermes.yaml b/adapter/test/data/hermes.yaml deleted file mode 100644 index c17827c11..000000000 --- a/adapter/test/data/hermes.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# Test configuration - -num_devices: 4 -num_targets: 4 - -capacities_mb: [4096, 8192, 16384, 32768] -block_sizes_kb: [4, 4, 4, 4] -num_slabs: [4, 4, 4, 4] - -slab_unit_sizes: [ - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32] -] - -desired_slab_percentages: [ - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25] -] - -bandwidths_mbps: [6000, 300, 150, 70] -latencies_us: [15, 250000, 500000, 1000000] - -buffer_pool_arena_percentage: 0.85 -metadata_arena_percentage: 0.08 -transient_arena_percentage: 0.07 - -max_buckets_per_node: 16 -max_vbuckets_per_node: 32 -system_view_state_update_interval_ms: 1000 - -mount_points: ["", "./", "./", "./"] -swap_mount: "./" -num_buffer_organizer_retries: 3 -rpc_server_base_name: "localhost" -rpc_protocol: "ofi+sockets" -rpc_port: 8080 -buffer_organizer_port: 8081 -rpc_host_number_range: [] -rpc_num_threads: 1 -buffer_organizer_num_threads: 4 -buffer_pool_shmem_name: "/hermes_buffer_pool_" diff --git a/adapter/test/data/hermes_ares.yaml b/adapter/test/data/hermes_ares.yaml deleted file mode 100644 index 336e34ffc..000000000 --- a/adapter/test/data/hermes_ares.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# Test configuration - -num_devices: 4 -num_targets: 4 - -capacities_mb: [16384, 16384, 65536, 131072] -block_sizes_kb: [4, 4, 4, 4] -num_slabs: [4, 4, 4, 4] - -slab_unit_sizes: [ - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32] -] - -desired_slab_percentages: [ - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25] -] - -bandwidths_mbps: [6000, 4000, 2000, 200] -latencies_us: [15, 250000, 500000, 1000000] - -buffer_pool_arena_percentage: 0.85 -metadata_arena_percentage: 0.08 -transient_arena_percentage: 0.07 - -max_buckets_per_node: 16 -max_vbuckets_per_node: 8 -system_view_state_update_interval_ms: 1000 - -mount_points: ["", "./", "./", "./"] -swap_mount: "./" -num_buffer_organizer_retries: 3 -rpc_server_base_name: "ares-comp-" -rpc_server_suffix: "-40g" -rpc_protocol: "ofi+sockets" -rpc_domain: "" -rpc_port: 8080 -buffer_organizer_port: 8081 -rpc_host_number_range: [20-23] -rpc_num_threads: 4 -buffer_organizer_num_threads: 4 -buffer_pool_shmem_name: "/hermes_buffer_pool_" \ No newline at end of file diff --git a/adapter/test/data/hermes_client.yaml b/adapter/test/data/hermes_client.yaml new file mode 100644 index 000000000..19e887cab --- /dev/null +++ b/adapter/test/data/hermes_client.yaml @@ -0,0 +1,5 @@ +stop_daemon: false +path_inclusions: ["/home"] +path_exclusions: ["/"] +file_page_size: 1024KB +base_adapter_mode: kDefault \ No newline at end of file diff --git a/adapter/test/data/hermes_server.yaml b/adapter/test/data/hermes_server.yaml new file mode 100644 index 000000000..91b964968 --- /dev/null +++ b/adapter/test/data/hermes_server.yaml @@ -0,0 +1,132 @@ +# Example Hermes configuration file + +### Define properties of the storage devices +devices: + # The name of the device. + # It can be whatever the user wants, there are no special names + ram: + # The mount point of each device. RAM should be the empty string. For block + # devices, this is the directory where Hermes will create buffering files. For + # object storage or cloud targets, this will be a url. + mount_point: "" + + # The maximum buffering capacity in MiB of each device. Here we say that all 4 + # devices get 50 MiB of buffering capacity. + capacity: 5000MB + + # The size of the smallest available buffer in KiB. In general this should be + # the page size of your system for byte addressable storage, and the block size + # of the storage device for block addressable storage. + block_size: 4KB + + # The number of blocks (the size of which is chosen in block_sizes_kb) that each + # device should contain for each slab (controlled by num_slabs). This allows for + # precise control of the distibution of buffer sizes. + slab_units: [1, 4, 16, 32] + + # The maximum theoretical bandwidth (as advertised by the manufacturer) in + # Possible units: KBps, MBps, GBps + bandwidth: 6000MBps + + # The latency of each device (as advertised by the manufacturer). + # Possible units: ns, us, ms, s + latency: 15us + + # For each device, indicate '1' if it is shared among nodes (e.g., burst + # buffers), or '0' if it is per node (e.g., local NVMe). + is_shared_device: false + + # For each device, the minimum and maximum percent capacity threshold at which + # the BufferOrganizer will trigger. Decreasing the maximum thresholds will cause + # the BufferOrganizer to move data to lower devices, making more room in faster + # devices (ideal for write-heavy workloads). Conversely, increasing the minimum + # threshold will cause data to be moved from slower devices into faster devices + # (ideal for read-heavy workloads). For example, a maximum capacity threshold of + # 0.8 would have the effect of always keeping 20% of the device's space free for + # incoming writes. Conversely, a minimum capacity threshold of 0.3 would ensure + # that the device is always at least 30% occupied. + borg_capacity_thresh: [0.0, 1.0] + + nvme: + mount_point: "./" + capacity: 50MB + block_size: 4KB + slab_units: [ 1, 4, 16, 32 ] + bandwidth: 1GBps + latency: 600us + is_shared_device: false + borg_capacity_thresh: [ 0.0, 1.0 ] + + ssd: + mount_point: "./" + capacity: 50MB + block_size: 4KB + slab_units: [ 1, 4, 16, 32 ] + bandwidth: 500MBps + latency: 1200us + is_shared_device: false + borg_capacity_thresh: [ 0.0, 1.0 ] + + pfs: + mount_point: "./" + capacity: inf + block_size: 64KB # The stripe size of PFS + slab_units: [ 1, 4, 16, 32 ] + bandwidth: 100MBps # Per-device bandwidth + latency: 200ms + is_shared_device: true + borg_capacity_thresh: [ 0.0, 1.0 ] + +### Define properties of RPCs +rpc: + # A path to a file containing a list of server names, 1 per line. If your + # servers are named according to a pattern (e.g., server-1, server-2, etc.), + # prefer the `rpc_server_base_name` and `rpc_host_number_range` options. If this + # option is not empty, it will override anything in `rpc_server_base_name`. + host_file: "" + + # Host names are constructed as "base_name + + # host_number + rpc_server_suffix." Each entry in the rpc_host_number_range_list + # can be either a single number, or a range, which is 2 numbers separated by a + # hyphen (-). For example the list {01, 03-05, 07, 08-10} will be expanded to + # {01, 03, 04, 05, 07, 08, 09, 10}. + base_name: "localhost" + host_number_range: [] + suffix: "" + + # The RPC protocol. This must come from the documentation of the specific RPC + # library in use. + protocol: "ofi+sockets" + + # RPC domain name for verbs transport. Blank for tcp. + domain: "" + + # Desired RPC port number. + port: 8080 + + # The number of handler threads for each RPC server. + num_threads: 1 + +### Define properties of the BORG +buffer_organizer: + # The number of threads used in the background organization of internal Hermes buffers. + num_threads: 4 + + # Desired RPC port number for buffer organizer. + port: 8081 + +### Define the default data placement policy +dpe: + # Choose Random, RoundRobin, or MinimizeIoTime + default_placement_policy: "MinimizeIoTime" + + # If true (1) the RoundRobin placement policy algorithm will split each Blob + # into a random number of smaller Blobs. + default_rr_split: 0 + +# The shared memory prefix for the hermes shared memory segment. A user name +# will be automatically appended. +shmem_name: "/hermes_shm_" + +# The interval in milliseconds at which to update the global system view. +system_view_state_update_interval_ms: 1000 \ No newline at end of file diff --git a/adapter/test/data/hermes_small.yaml b/adapter/test/data/hermes_small.yaml deleted file mode 100644 index d72ad420a..000000000 --- a/adapter/test/data/hermes_small.yaml +++ /dev/null @@ -1,46 +0,0 @@ -# Test configuration - -num_devices: 4 -num_targets: 4 - -#2 is used for RAM because some space is taken by the Arena. -capacities_mb: [2, 1, 1, 1] -block_sizes_kb: [4, 4, 4, 4] -num_slabs: [4, 4, 4, 4] - -slab_unit_sizes: [ - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], - [1, 4, 16, 32], -] - -desired_slab_percentages: [ - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], - [0.25, 0.25, 0.25, 0.25], -] - -bandwidths_mbps: [6000, 300, 150, 70] -latencies_us: [15, 250000, 500000, 1000000] - -buffer_pool_arena_percentage: 0.85 -metadata_arena_percentage: 0.08 -transient_arena_percentage: 0.07 - -max_buckets_per_node: 16 -max_vbuckets_per_node: 8 -system_view_state_update_interval_ms: 1000 - -mount_points: ["", "./", "./", "./"] -swap_mount: "./" -num_buffer_organizer_retries: 3 -rpc_server_base_name: "localhost" -rpc_protocol: "ofi+sockets" -rpc_port: 8080 -buffer_organizer_port: 8081 -rpc_host_number_range: [] -rpc_num_threads: 1 -buffer_organizer_num_threads: 4 -buffer_pool_shmem_name: "/hermes_buffer_pool_" diff --git a/adapter/test/gcc_hermes.sh b/adapter/test/gcc_hermes.sh new file mode 100644 index 000000000..c920d45c7 --- /dev/null +++ b/adapter/test/gcc_hermes.sh @@ -0,0 +1,16 @@ +#!/bin/bash +CMAKE_BINARY_DIR=$1 +CMAKE_SOURCE_DIR=$2 +EXEC=$3 +TAG_NAME=$4 +TAGS=$5 +MODE=$6 +DO_PATH_EXCLUDE=$7 + +LSAN_OPTIONS=suppressions="${CMAKE_SOURCE_DIR}/test/data/asan.supp" \ +ADAPTER_MODE="${MODE}" \ +SET_PATH="${DO_PATH_EXCLUDE}" \ +HERMES_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml" \ +HERMES_CLIENT_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml" \ +COMMAND="${CMAKE_BINARY_DIR}/bin/${exec}" \ +"${COMMAND}" "${TAGS}" --reporter compact -d yes diff --git a/adapter/test/gcc_hermes_mode.sh b/adapter/test/gcc_hermes_mode.sh new file mode 100644 index 000000000..8a9655ff7 --- /dev/null +++ b/adapter/test/gcc_hermes_mode.sh @@ -0,0 +1,15 @@ +#!/bin/bash +CMAKE_BINARY_DIR=$1 +CMAKE_SOURCE_DIR=$2 +EXEC=$3 +TAG_NAME=$4 +TAGS=$5 +MODE=$6 +path + +LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp +ADAPTER_MODE=${mode} +SET_PATH=${path} +HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml + +COMMAND="${CMAKE_BINARY_DIR}/bin/${exec}" \ No newline at end of file diff --git a/adapter/test/posix/CMakeLists.txt b/adapter/test/posix/CMakeLists.txt index 7b7ac5b58..a52aafeb6 100644 --- a/adapter/test/posix/CMakeLists.txt +++ b/adapter/test/posix/CMakeLists.txt @@ -9,14 +9,6 @@ endfunction() function(gcc_hermes_mode exec tag_name tags mode path) set(test_name Test${exec}_${tag_name}_${mode}_${path}) add_test(NAME ${test_name} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) - set_property(TEST ${test_name} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT ADAPTER_MODE=${mode}) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT SET_PATH=${path}) endfunction() #------------------------------------------------------------------------------ diff --git a/adapter/test/pubsub/CMakeLists.txt b/adapter/test/pubsub/CMakeLists.txt deleted file mode 100644 index 32f868453..000000000 --- a/adapter/test/pubsub/CMakeLists.txt +++ /dev/null @@ -1,49 +0,0 @@ -#------------------------------------------------------------------------------ -# PubSub Adapter tests -#------------------------------------------------------------------------------ -add_executable(pubsub_metadata_test ${CMAKE_CURRENT_SOURCE_DIR}/pubsub_metadata_test.cc) -add_test(NAME "pubsub_metadata_test" COMMAND "${CMAKE_BINARY_DIR}/bin/pubsub_metadata_test") -target_link_libraries(pubsub_metadata_test ${LIBRT} hermes MPI::MPI_CXX - $<$:thallium> hermes_pubsub) -add_dependencies(pubsub_metadata_test hermes_pubsub) - -set(SINGLE_NODE_PUBSUB_TESTS pubsub_topic_test pubsub_end_to_end_test) -set(MULTI_NODE_PUBSUB_TESTS pubsub_end_to_end_test_sync) -set(EXTENDED_PUBSUB_TESTS ${SINGLE_NODE_PUBSUB_TESTS} ${MULTI_NODE_PUBSUB_TESTS} pubsub_metadata_test) - -foreach(program ${SINGLE_NODE_PUBSUB_TESTS}) - add_executable(${program} ${CMAKE_CURRENT_SOURCE_DIR}/${program}.cc) - add_dependencies(${program} hermes_pubsub) - target_link_libraries(${program} ${LIBRT} hermes MPI::MPI_CXX - $<$:thallium> hermes_pubsub) - target_compile_definitions(${program} - PRIVATE $<$:HERMES_RPC_THALLIUM>) - mpi_daemon(${program} 1 "" "" 1) -endforeach() - -foreach(program ${MULTI_NODE_PUBSUB_TESTS}) - add_executable(${program} ${CMAKE_CURRENT_SOURCE_DIR}/${program}.cc) - add_dependencies(${program} hermes_pubsub) - target_link_libraries(${program} ${LIBRT} hermes MPI::MPI_CXX - $<$:thallium> hermes_pubsub) - target_compile_definitions(${program} - PRIVATE $<$:HERMES_RPC_THALLIUM>) - mpi_daemon(${program} 2 "" "" 1) -endforeach() - -foreach(program ${EXTENDED_PUBSUB_TESTS}) - target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_DIR}) - target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_TEST_DIR}) -endforeach() - -if(HERMES_INSTALL_TESTS) - foreach(program ${EXTENDED_PUBSUB_TESTS}) - install( - TARGETS - ${program} - LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} - ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} - RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR} - ) - endforeach() -endif() diff --git a/adapter/test/pubsub/pubsub_end_to_end_test.cc b/adapter/test/pubsub/pubsub_end_to_end_test.cc deleted file mode 100644 index 15ffa4d04..000000000 --- a/adapter/test/pubsub/pubsub_end_to_end_test.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "test_utils.h" - -int main(int argc, char **argv) { - hermes::pubsub::mpiInit(argc, argv); - - char *config_file = 0; - if (argc == 2) { - config_file = argv[1]; - } else { - config_file = getenv(kHermesConf); - } - - auto connect_ret = hermes::pubsub::connect(config_file); - Assert(connect_ret.Succeeded()); - - if (connect_ret.Succeeded()) { - auto attach_ret = hermes::pubsub::attach("test"); - Assert(attach_ret.Succeeded()); - - hapi::Blob data1(4*1024, rand() % 255); - hapi::Blob data2(4*1024, rand() % 255); - hapi::Blob data3(4*1024, rand() % 255); - - auto publish_ret = hermes::pubsub::publish("test", data1); - Assert(publish_ret.Succeeded()); - - auto subscribe_ret_1 = hermes::pubsub::subscribe("test"); - Assert(subscribe_ret_1.second.Succeeded()); - Assert(data1 == subscribe_ret_1.first); - - publish_ret = hermes::pubsub::publish("test", data2); - Assert(publish_ret.Succeeded()); - - publish_ret = hermes::pubsub::publish("test", data3); - Assert(publish_ret.Succeeded()); - - // this subscribe reads data2; - hermes::pubsub::subscribe("test"); - - auto subscribe_ret_2 = hermes::pubsub::subscribe("test"); - Assert(subscribe_ret_2.second.Succeeded()); - Assert(data3 == subscribe_ret_2.first); - - auto detach_ret = hermes::pubsub::detach("test"); - Assert(detach_ret.Succeeded()); - } - auto disconnect_ret = hermes::pubsub::disconnect(); - Assert(disconnect_ret.Succeeded()); - - MPI_Finalize(); -} diff --git a/adapter/test/pubsub/pubsub_end_to_end_test_sync.cc b/adapter/test/pubsub/pubsub_end_to_end_test_sync.cc deleted file mode 100644 index 6e5839e08..000000000 --- a/adapter/test/pubsub/pubsub_end_to_end_test_sync.cc +++ /dev/null @@ -1,68 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "test_utils.h" - -int main(int argc, char **argv) { - hermes::pubsub::mpiInit(argc, argv); - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - int comm_size; - MPI_Comm_size(MPI_COMM_WORLD, &comm_size); - - char *config_file = 0; - if (argc == 2) { - config_file = argv[1]; - } else { - config_file = getenv(kHermesConf); - } - - auto connect_ret = hermes::pubsub::connect(config_file); - - if (connect_ret.Succeeded()) { - auto attach_ret = hermes::pubsub::attach("test"); - Assert(attach_ret.Succeeded()); - - std::vector full_data; - hapi::Blob data1(4*1024, rand() % 255); - hapi::Blob data2(4*1024, rand() % 255); - hapi::Blob data3(4*1024, rand() % 255); - full_data.push_back(data1); - full_data.push_back(data2); - full_data.push_back(data3); - - for (const auto& data : full_data) { - auto publish_ret = hermes::pubsub::publish("test", data); - Assert(publish_ret.Succeeded()); - } - - auto hermes = hermes::Singleton - ::GetInstance()->GetHermes(); - MPI_Comm comm = *(MPI_Comm*)hermes->GetAppCommunicator(); - MPI_Barrier(comm); - - unsigned long num_messages = full_data.size(); - std::pair subscribe_ret; - for (unsigned long i = 0; i < num_messages*comm_size; i++) { - subscribe_ret = hermes::pubsub::subscribe("test"); - Assert(subscribe_ret.second.Succeeded()); - } - - auto detach_ret = hermes::pubsub::detach("test"); - Assert(detach_ret.Succeeded()); - } - auto disconnect_ret = hermes::pubsub::disconnect(); - Assert(disconnect_ret.Succeeded()); - - MPI_Finalize(); -} diff --git a/adapter/test/pubsub/pubsub_metadata_test.cc b/adapter/test/pubsub/pubsub_metadata_test.cc deleted file mode 100644 index 051fc2ab2..000000000 --- a/adapter/test/pubsub/pubsub_metadata_test.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "singleton.h" -#include "test_utils.h" - -int main() { - auto mdm = hermes::Singleton - ::GetInstance(false); - ClientMetadata stat; - struct timespec ts{}; - timespec_get(&ts, TIME_UTC); - stat.st_atim = ts; - - auto create_ret = mdm->Create("test", stat); - Assert(create_ret == true); - create_ret = mdm->Create("test", stat); - Assert(create_ret == false); - - auto find_ret = mdm->Find("test"); - Assert(find_ret.second == true); - Assert(find_ret.first.st_atim.tv_nsec == ts.tv_nsec); - - struct timespec ts1{}; - timespec_get(&ts1, TIME_UTC); - stat.st_atim = ts1; - auto update_ret = mdm->Update("test", stat); - Assert(update_ret == true); - find_ret = mdm->Find("test"); - Assert(find_ret.second == true); - Assert(find_ret.first.st_atim.tv_nsec >= ts.tv_nsec); - Assert(find_ret.first.st_atim.tv_nsec == ts1.tv_nsec); - - auto delete_ret = mdm->Delete("test"); - Assert(delete_ret == true); - delete_ret = mdm->Delete("test"); - Assert(delete_ret == false); - find_ret = mdm->Find("test"); - Assert(find_ret.second == false); - update_ret = mdm->Update("test", stat); - Assert(update_ret == false); -} diff --git a/adapter/test/pubsub/pubsub_topic_test.cc b/adapter/test/pubsub/pubsub_topic_test.cc deleted file mode 100644 index aa8de63ac..000000000 --- a/adapter/test/pubsub/pubsub_topic_test.cc +++ /dev/null @@ -1,41 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include "test_utils.h" - -int main(int argc, char **argv) { - hermes::pubsub::mpiInit(argc, argv); - - char *config_file = 0; - if (argc == 2) { - config_file = argv[1]; - } else { - config_file = getenv(kHermesConf); - } - - auto connect_ret = hermes::pubsub::connect(config_file); - Assert(connect_ret.Succeeded()); - - auto attach_ret = hermes::pubsub::attach("test"); - Assert(attach_ret.Succeeded()); - - auto detach_ret = hermes::pubsub::detach("test"); - Assert(detach_ret.Succeeded()); - - auto disconnect_ret = hermes::pubsub::disconnect(); - Assert(disconnect_ret.Succeeded()); - - MPI_Finalize(); - - return 0; -} diff --git a/adapter/test/pubsub/test_utils.h b/adapter/test/pubsub/test_utils.h deleted file mode 100644 index 2fcece367..000000000 --- a/adapter/test/pubsub/test_utils.h +++ /dev/null @@ -1,31 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_PUBSUB_TEST_UTILS_H_ -#define HERMES_PUBSUB_TEST_UTILS_H_ - -namespace hermes::pubsub::testing { - -void Assert(bool expr, const char *file, int lineno, const char *message) { - if (!expr) { - fprintf(stderr, "Assertion failed at %s: line %d: %s\n", file, lineno, - message); - exit(-1); - } -} - -#define Assert(expr) \ - hermes::pubsub::testing::Assert((expr), __FILE__, __LINE__, #expr) - -} // namespace hermes::pubsub::testing - -#endif // HERMES_PUBSUB_TEST_UTILS_H_ diff --git a/adapter/test/vfd/CMakeLists.txt b/adapter/test/vfd/CMakeLists.txt deleted file mode 100644 index 3903fc5a8..000000000 --- a/adapter/test/vfd/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -set(HERMES_VFD_DIR ${HERMES_ADAPTER_DIR}/vfd) - -set(hermes_vfd_tests - hermes_vfd_test -) - -add_executable(hermes_vfd_test ${CMAKE_CURRENT_SOURCE_DIR}/hermes_vfd_test.cc) -target_include_directories(hermes_vfd_test PRIVATE ${HERMES_VFD_DIR}) -target_include_directories(hermes_vfd_test PRIVATE ${HERMES_ADAPTER_TEST_DIR}) -target_include_directories(hermes_vfd_test - SYSTEM PRIVATE ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} -) - -target_link_libraries(hermes_vfd_test - hermes - Catch2::Catch2 - MPI::MPI_CXX - glog::glog - stdc++fs - ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES} -) - -if(HERMES_USE_ADDRESS_SANITIZER) - execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=libasan.so - OUTPUT_VARIABLE LIBASAN_PATH - RESULT_VARIABLE ASAN_PRINT_FILE_NAME_RESULT - OUTPUT_STRIP_TRAILING_WHITESPACE) - - if(ASAN_PRINT_FILE_NAME_RESULT EQUAL 0) - message(STATUS "Found libasan.so at ${LIBASAN_PATH}") - else() - message(FATAL_ERROR - "Couldn't find the path to libasan.so which is required by the Hermes HDF5 VFD tests. \ - Recompile with HERMES_ENABLE_ADDRESS_SANITIZER=OFF") - endif() -endif() - -function(set_vfd_test_properties test_name) - set_property(TEST ${test_name} - PROPERTY ENVIRONMENT HERMES_CONF=${HERMES_ADAPTER_TEST_DIR}/data/hermes.yaml) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT HDF5_PLUGIN_PATH=${HERMES_VFD_LIBRARY_DIR}) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT HDF5_DRIVER=hermes) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT LD_PRELOAD=${LIBASAN_PATH}:$) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) -endfunction() - -add_test(NAME "TestVfd" COMMAND hermes_vfd_test --reporter compact -d yes) -set_vfd_test_properties("TestVfd") -set_property(TEST "TestVfd" APPEND - PROPERTY ENVIRONMENT HDF5_DRIVER_CONFIG=true\ 65536) - -add_test(NAME "TestVfdScratchMode" COMMAND hermes_vfd_test "[scratch]" --reporter compact -d yes) -set_vfd_test_properties("TestVfdScratchMode") -set_property(TEST "TestVfdScratchMode" APPEND - PROPERTY ENVIRONMENT HDF5_DRIVER_CONFIG=false\ 65536) - -# IOR tests -if(HERMES_HAVE_IOR) - set(IOR_TEST_NAME "TestVfdIor") - add_test(NAME ${IOR_TEST_NAME} COMMAND ${IOR_EXE} -a HDF5 -w -W -r -R) - set_vfd_test_properties(${IOR_TEST_NAME}) - set_property(TEST ${IOR_TEST_NAME} APPEND - PROPERTY ENVIRONMENT HDF5_DRIVER_CONFIG=true\ 262144) -endif() diff --git a/adapter/test/vfd/hermes_vfd_basic_test.cc b/adapter/test/vfd/hermes_vfd_basic_test.cc deleted file mode 100644 index 67f8b9277..000000000 --- a/adapter/test/vfd/hermes_vfd_basic_test.cc +++ /dev/null @@ -1,718 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -using hermes::adapter::vfd::test::MuteHdf5Errors; - -/** Returns a number in the range [1, upper_bound] */ -static inline size_t Random1ToUpperBound(size_t upper_bound) { - size_t result = ((size_t)GenNextRandom() % upper_bound) + 1; - - return result; -} - -/** Returns a string in the range ["0", "upper_bound") */ -static inline std::string RandomDatasetName(size_t upper_bound) { - size_t dset_index = Random1ToUpperBound(upper_bound) - 1; - std::string result = std::to_string(dset_index); - - return result; -} - -TEST_CASE("H5FOpen", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_open]" - "[repetition=1][file=1]") { - Pretest(); - SECTION("open non-existent file") { - MuteHdf5Errors mute; - test::TestOpen(info.new_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid == H5I_INVALID_HID); - test::TestOpen(info.new_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid == H5I_INVALID_HID); - } - - SECTION("truncate existing file") { - test::TestOpen(info.existing_file, H5F_ACC_TRUNC, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("open existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("create existing file exclusively") { - MuteHdf5Errors mute; - test::TestOpen(info.existing_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid == H5I_INVALID_HID); - } - - Posttest(); -} - -TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - Pretest(); - - SECTION("overwrite dataset in existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWritePartial1d("0", info.write_data.data(), 0, - info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("write to new file") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWriteDataset("0", info.write_data); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("write to existing file with truncate") { - test::TestOpen(info.existing_file, H5F_ACC_TRUNC, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWriteDataset("0", info.write_data); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("add dataset to existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWriteDataset(std::to_string(info.num_iterations), - info.write_data); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - Pretest(); - SECTION("read from non-existing file") { - MuteHdf5Errors mute; - test::TestOpen(info.new_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid == H5I_INVALID_HID); - } - - SECTION("read first dataset from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestRead("0", info.read_data, 0, info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("read last dataset of existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestRead(std::to_string(info.num_iterations - 1), info.read_data, 0, - info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); -} - -TEST_CASE("BatchedWriteSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - Pretest(); - SECTION("write to new file") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestWriteDataset(std::to_string(i), info.write_data); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("overwrite first dataset") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - test::TestWriteDataset("0", info.write_data); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestWritePartial1d("0", info.write_data.data(), 0, - info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); -} - -TEST_CASE("BatchedReadSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - Pretest(); - SECTION("read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - std::vector buf(info.nelems_per_dataset, 0.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestRead(std::to_string(i), buf, 0, info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("read from existing file always at start") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestRead("0", info.read_data, 0, info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); -} - -TEST_CASE("BatchedReadRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - Pretest(); - SECTION("read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - std::vector buf(info.nelems_per_dataset, 0.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - u32 dataset = GenNextRandom() % info.num_iterations; - test::TestRead(std::to_string(dataset), buf, 0, info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); -} - -TEST_CASE("BatchedUpdateRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - Pretest(); - SECTION("update entire dataset in existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - u32 dataset = GenNextRandom() % info.num_iterations; - test::TestWritePartial1d(std::to_string(dataset), info.write_data.data(), - 0, info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("update partial dataset in existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - u32 dataset = GenNextRandom() % info.num_iterations; - // NOTE(chogan): Subtract 1 from size so we're always writing at least 1 - // element - hsize_t offset = GenNextRandom() % (info.write_data.size() - 1); - hsize_t elements_to_write = info.write_data.size() - offset; - test::TestWritePartial1d(std::to_string(dataset), info.write_data.data(), - offset, elements_to_write); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); -} - -TEST_CASE("BatchedWriteRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - Pretest(); - - SECTION("write to new file always at the start") { - MuteHdf5Errors mute; - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); - std::vector data(request_size, 2.0f); - test::TestWritePartial1d(std::to_string(i), data.data(), 0, request_size); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("BatchedReadSequentialRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - Pretest(); - - SECTION("read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); - size_t starting_element = info.nelems_per_dataset - request_size; - std::vector data(request_size, 1.5f); - test::TestRead(std::to_string(i), data, starting_element, request_size); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("read from existing file always at start") { - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); - std::vector data(request_size, 3.0f); - test::TestRead(std::to_string(i), data, 0, request_size); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("BatchedReadRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - Pretest(); - - SECTION("read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - std::vector data(info.nelems_per_dataset, 5.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = RandomDatasetName(info.num_iterations); - size_t starting_element = Random1ToUpperBound(info.nelems_per_dataset); - size_t request_elements = - Random1ToUpperBound(info.nelems_per_dataset - starting_element); - std::vector data(request_elements, 3.8f); - test::TestRead(dset_name, data, starting_element, request_elements); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - Pretest(); - - SECTION("write to existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - std::vector data(info.nelems_per_dataset, 8.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = RandomDatasetName(info.num_iterations); - size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); - test::TestWritePartial1d(dset_name, data.data(), 0, request_size); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("BatchedWriteTemporalFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=fixed]") { - Pretest(); - - SECTION("write to existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::TestWritePartial1d(std::to_string(i), info.write_data.data(), 0, - info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("write to new file always at start") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::TestWriteDataset(std::to_string(i), info.write_data); - } - test::TestClose(); - } - - Posttest(); -} - -TEST_CASE("BatchedWriteTemporalVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=variable]") { - Pretest(); - - SECTION("write to existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t sleep_interval_ms = - GenNextRandom() % (info.temporal_interval_ms + 2); - usleep(sleep_interval_ms * 1000); - test::TestWritePartial1d(std::to_string(i), info.write_data.data(), 0, - info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("write to new file always at start") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t sleep_interval_ms = - GenNextRandom() % (info.temporal_interval_ms + 2); - usleep(sleep_interval_ms * 1000); - test::TestWriteDataset(std::to_string(i), info.write_data); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("BatchedMixedSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_mixed]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - Pretest(); - - SECTION("read after write on new file") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = std::to_string(i); - test::TestWriteDataset(dset_name, info.write_data); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("alternate write and read existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = std::to_string(i); - - if (i % 2 == 0) { - test::TestWritePartial1d(dset_name, info.write_data.data(), 0, - info.nelems_per_dataset); - } else { - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - } - } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("update after read existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = std::to_string(i); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - test::TestWritePartial1d(dset_name, info.write_data.data(), 0, - info.nelems_per_dataset); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("read all after write all on new file in single open") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = std::to_string(i); - test::TestWriteDataset(dset_name, info.write_data); - } - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = std::to_string(i); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("read all after write all on new file in different open") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestWriteDataset(std::to_string(i), info.write_data); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - - test::TestOpen(info.new_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestRead(std::to_string(i), info.read_data, 0, - info.nelems_per_dataset); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); -} - -TEST_CASE("SingleMixed", "[process=" + std::to_string(info.comm_size) + - "][operation=single_mixed]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - Pretest(); - - SECTION("read after write from new file") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - std::string dset_name("0"); - test::TestWriteDataset(dset_name, info.write_data); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("update after read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - std::string dset_name("0"); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - test::TestWritePartial1d(dset_name, info.write_data.data(), 0, - info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("read after write from new file different opens") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - std::string dset_name("0"); - test::TestWriteDataset(dset_name, info.write_data); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - - test::TestOpen(info.new_file, H5F_ACC_RDWR); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("CompactDatasets") { - Pretest(); - - SECTION("create many and read randomly") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - size_t num_elements = KILOBYTES(32) / sizeof(f32); - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::vector data(num_elements); - for (size_t i = 0; i < data.size(); ++i) { - data[i] = GenRandom0to1(); - } - test::TestMakeCompactDataset(std::to_string(i), data); - } - - std::vector read_buf(num_elements, 0.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = RandomDatasetName(info.num_iterations); - test::TestRead(dset_name, read_buf, 0, num_elements); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("PartialUpdateToLastPage") { - Pretest(); - - SECTION("beginning of last page") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWritePartial1d(std::to_string(info.num_iterations - 1), - info.write_data.data(), 0, - info.nelems_per_dataset / 2); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("in middle of last page") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWritePartial1d(std::to_string(info.num_iterations - 1), - info.write_data.data(), - info.nelems_per_dataset / 4, - info.nelems_per_dataset / 2); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - SECTION("at end of last page") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWritePartial1d(std::to_string(info.num_iterations - 1), - info.write_data.data(), - info.nelems_per_dataset / 2, - info.nelems_per_dataset / 2); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); -} - -TEST_CASE("ScratchMode", "[scratch]") { - Pretest(); - - SECTION("created files shouldn't persist") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestWriteDataset(std::to_string(i), info.write_data); - } - - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = RandomDatasetName(info.num_iterations); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - } - - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - - if (info.scratch_mode) { - REQUIRE(!stdfs::exists(info.new_file)); - } - } - - Posttest(); -} diff --git a/adapter/test/vfd/hermes_vfd_test.cc b/adapter/test/vfd/hermes_vfd_test.cc deleted file mode 100644 index 9d743353d..000000000 --- a/adapter/test/vfd/hermes_vfd_test.cc +++ /dev/null @@ -1,585 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "hermes_types.h" -#include "adapter_test_utils.h" -#include "catch_config.h" - -namespace stdfs = std::filesystem; -using hermes::f32; -using hermes::u32; - -namespace hermes::adapter::vfd::test { - -/** - A structure to represent test arguments -*/ -struct Arguments { - std::string filename = "test"; /**< test file name */ - std::string directory = "/tmp"; /**< test directory name */ - size_t request_size = 65536; /**< test request size */ -}; - -/** - A structure to represent test information -*/ -struct TestInfo { - static const int element_size = sizeof(f32); /**< test element size */ - - // int rank = 0; - int comm_size = 1; /**< communicator size */ - std::vector write_data; /**< test data for writing */ - std::vector read_data; /**< test data for reading */ - std::string new_file; /**< new file name */ - std::string existing_file; /**< existing file name */ - std::string new_file_cmp; /**< new file name to compare */ - std::string existing_file_cmp; /**< existing file name to compare */ - std::string hdf5_extension = ".h5"; /**< HDF5 file extention to use */ - size_t num_iterations = 64; /**< number of iterations */ - // int offset_seed = 1; - // unsigned int rs_seed = 1; - // unsigned int temporal_interval_seed = 5; - size_t total_size; /**< total size */ - // size_t stride_size = 512; - unsigned int temporal_interval_ms = 1; /**< interval in milliseconds */ - // size_t small_min = 1; - // size_t small_max = KILOBYTES(4); - // size_t medium_min = KILOBYTES(4) + 1; - // size_t medium_max = KILOBYTES(256); - // size_t large_min = KILOBYTES(256) + 1; - // size_t large_max = MEGABYTES(3); - size_t nelems_per_dataset; /**< number of elements per dataset */ - bool scratch_mode = false; /**< flag for scratch mode */ -}; - -/** - * Temporarily disable printing of the HDF5 error stack. - * - * Some tests intentionally trigger HDF5 errors, and in those cases we don't - * want to clutter the output with HDF5 error messages. - */ -class MuteHdf5Errors { - H5E_auto2_t old_func; /**< error handler callback function */ - void *old_client_data; /**< pointer to client data for old_func */ - - public: - MuteHdf5Errors() { - // Save old error handler - H5Eget_auto(H5E_DEFAULT, &old_func, &old_client_data); - - // Turn off error stack printing - H5Eset_auto(H5E_DEFAULT, NULL, NULL); - } - - ~MuteHdf5Errors() { - // Restore previous error handler - H5Eset_auto(H5E_DEFAULT, old_func, old_client_data); - } -}; - -/** - * HDF5 identifiers required for reads and writes. - */ -struct RwIds { - hid_t dset_id; /**< dataset ID */ - hid_t dspace_id; /**< data space ID */ - hid_t mspace_id; /**< memory space ID */ -}; - -/** - * The I/O API for this adapter layer. - * - * Ideally we would have a high level Adapter I/O API that each adapter inherits - * from so that the adapter tests can reuse more code. This is a step in that - * direction. - */ -struct Hdf5Api { - /** - * A file access property list representing the sec2 (POSIX) VFD. - */ - hid_t sec2_fapl; - - Hdf5Api() : sec2_fapl(H5I_INVALID_HID) { - sec2_fapl = H5Pcreate(H5P_FILE_ACCESS); - REQUIRE(sec2_fapl != H5I_INVALID_HID); - REQUIRE(H5Pset_fapl_sec2(sec2_fapl) >= 0); - } - - ~Hdf5Api() { - REQUIRE(H5Pclose(sec2_fapl) >= 0); - sec2_fapl = H5I_INVALID_HID; - } - - /** - * Open an existing file using the default VFD. Since the tests are run with - * HDF5_DRIVER=hermes, the default VFD will be the Hermes VFD. - */ - hid_t Open(const std::string &fname, unsigned flags) { - hid_t result = H5Fopen(fname.c_str(), flags, H5P_DEFAULT); - - return result; - } - - /** - * Open an existing file using the POSIX VFD. This will bypass Hermes. - */ - hid_t OpenPosix(const std::string &fname, unsigned flags) { - hid_t result = H5Fopen(fname.c_str(), flags, sec2_fapl); - - return result; - } - - /** - * Create a file using the default VFD. - */ - hid_t Create(const std::string &fname, unsigned flags) { - hid_t result = H5Fcreate(fname.c_str(), flags, H5P_DEFAULT, H5P_DEFAULT); - - return result; - } - - /** - * Create a file using the POSIX VFD. - */ - hid_t CreatePosix(const std::string &fname, unsigned flags) { - hid_t result = H5Fcreate(fname.c_str(), flags, H5P_DEFAULT, sec2_fapl); - - return result; - } - - /** - * Boilerplate necessary before calling H5Dread or H5Dwrite. - */ - RwIds RwPreamble(hid_t hid, const std::string &dset_name, hsize_t offset, - hsize_t nelems, hsize_t stride = 1) { - hid_t dset_id = H5Dopen2(hid, dset_name.c_str(), H5P_DEFAULT); - - hid_t memspace_id = H5Screate_simple(1, &nelems, NULL); - REQUIRE(memspace_id != H5I_INVALID_HID); - - if (dset_id == H5I_INVALID_HID) { - dset_id = H5Dcreate2(hid, dset_name.c_str(), H5T_NATIVE_FLOAT, - memspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - } - - REQUIRE(dset_id != H5I_INVALID_HID); - hid_t dspace_id = H5Dget_space(dset_id); - REQUIRE(dspace_id != H5I_INVALID_HID); - herr_t status = H5Sselect_hyperslab(dspace_id, H5S_SELECT_SET, &offset, - &stride, &nelems, NULL); - REQUIRE(status >= 0); - - RwIds result = {dset_id, dspace_id, memspace_id}; - - return result; - } - - /** - * Cleanup code required after H5Dread and H5Dwrite. - */ - void RwCleanup(RwIds *ids) { - REQUIRE(H5Sclose(ids->mspace_id) >= 0); - REQUIRE(H5Sclose(ids->dspace_id) >= 0); - REQUIRE(H5Dclose(ids->dset_id) >= 0); - } - - /** - * Reads @p nelems elements from the object represented by @p hid into @p buf, - * starting at element @p offset. - */ - void Read(hid_t hid, const std::string &dset_name, std::vector &buf, - hsize_t offset, hsize_t nelems) { - RwIds ids = RwPreamble(hid, dset_name, offset, nelems); - herr_t status = H5Dread(ids.dset_id, H5T_NATIVE_FLOAT, ids.mspace_id, - ids.dspace_id, H5P_DEFAULT, buf.data()); - REQUIRE(status >= 0); - - RwCleanup(&ids); - } - /** - Create a 1-dimensional dataset using \a data vector. - */ - void MakeDataset(hid_t hid, const std::string &dset_name, - const std::vector &data, bool compact = false) { - MakeDataset(hid, dset_name, data.data(), data.size(), compact); - } - - /** - * Create a 1-dimensional dataset named @p dset_name in object @p hid with @p - * nelems elements from the array @p data. - */ - void MakeDataset(hid_t hid, const std::string &dset_name, const f32 *data, - hsize_t nelems, bool compact = false) { - hid_t dcpl = H5P_DEFAULT; - herr_t status = 0; - - if (compact) { - REQUIRE(nelems * sizeof(f32) <= KILOBYTES(64)); - dcpl = H5Pcreate(H5P_DATASET_CREATE); - REQUIRE(dcpl != H5I_INVALID_HID); - status = H5Pset_layout(dcpl, H5D_COMPACT); - REQUIRE(status >= 0); - } - - hid_t memspace_id = H5Screate_simple(1, &nelems, NULL); - REQUIRE(memspace_id != H5I_INVALID_HID); - - hid_t dset_id = H5Dcreate2(hid, dset_name.c_str(), H5T_NATIVE_FLOAT, - memspace_id, H5P_DEFAULT, dcpl, H5P_DEFAULT); - REQUIRE(dset_id != H5I_INVALID_HID); - - hid_t dspace_id = H5Dget_space(dset_id); - REQUIRE(dspace_id != H5I_INVALID_HID); - - status = H5Dwrite(dset_id, H5T_NATIVE_FLOAT, memspace_id, - dspace_id, H5P_DEFAULT, data); - REQUIRE(status >= 0); - REQUIRE(H5Sclose(memspace_id) >= 0); - REQUIRE(H5Sclose(dspace_id) >= 0); - REQUIRE(H5Dclose(dset_id) >= 0); - - if (compact) { - REQUIRE(H5Pclose(dcpl) >= 0); - } - } - - /** - * Write @p nelems elements to the dataset @p dset_name in file @p hid - * starting at element @p offset. The dataset will be created if it doesn't - * already exist. - */ - void WritePartial1d(hid_t hid, const std::string &dset_name, - const f32 *data, hsize_t offset, hsize_t nelems) { - RwIds ids = RwPreamble(hid, dset_name, offset, nelems); - herr_t status = H5Dwrite(ids.dset_id, H5T_NATIVE_FLOAT, ids.mspace_id, - ids.dspace_id, H5P_DEFAULT, data); - REQUIRE(status >= 0); - - RwCleanup(&ids); - } - /** - Close HDF5 file. - */ - herr_t Close(hid_t id) { - herr_t result = H5Fclose(id); - - return result; - } -}; - -// xoshiro128+ random number generation. 2x speedup over std::mt19937: -// https://prng.di.unimi.it/xoshiro128plus.c - -static inline u32 RotateLeft(const u32 x, int k) { - u32 result = (x << k) | (x >> (32 - k)); - - return result; -} - -static u32 random_state[4] = {111, 222, 333, 444}; - -u32 GenNextRandom() { - const u32 random = random_state[0] + random_state[3]; - - const u32 t = random_state[1] << 9; - - random_state[2] ^= random_state[0]; - random_state[3] ^= random_state[1]; - random_state[1] ^= random_state[2]; - random_state[0] ^= random_state[3]; - - random_state[2] ^= t; - - random_state[3] = RotateLeft(random_state[3], 11); - - return random; -} - -/** - * Return a random float in the range [0.0f, 1.0f] - */ -f32 GenRandom0to1() { - u32 random_u32 = GenNextRandom(); - - f32 result = (random_u32 >> 8) * 0x1.0p-24f; - - return result; -} - -/** - * Create an HDF5 file called @p fname with @p num_datasets datasets, each with - * @p num_dataset_elems elements. - */ -void GenHdf5File(std::string fname, size_t num_dataset_elems, - size_t num_datasets) { - std::vector data(num_dataset_elems * num_datasets); - - for (size_t i = 0; i < data.size(); ++i) { - data[i] = GenRandom0to1(); - } - - Hdf5Api api; - f32 *at = data.data(); - - hid_t file_id = api.CreatePosix(fname, H5F_ACC_TRUNC); - REQUIRE(file_id != H5I_INVALID_HID); - - for (size_t i = 0; i < num_datasets; ++i) { - api.MakeDataset(file_id, std::to_string(i), at, num_dataset_elems); - at += num_dataset_elems; - } - - REQUIRE(api.Close(file_id) > -1); -} - -} // namespace hermes::adapter::vfd::test - -hermes::adapter::vfd::test::Arguments args; -hermes::adapter::vfd::test::TestInfo info; - -using hermes::adapter::vfd::test::GenHdf5File; -using hermes::adapter::vfd::test::GenNextRandom; -using hermes::adapter::vfd::test::GenRandom0to1; - -/** - * Called in the Catch2 main function (see catch_config.h) before any tests are - * run. Initialize sizes, filenames, and read/write buffers. - */ -int init(int* argc, char*** argv) { - MPI_Init(argc, argv); - if (args.request_size % info.element_size != 0) { - LOG(FATAL) << "request_size must be a multiple of " << info.element_size; - } - info.nelems_per_dataset = args.request_size / info.element_size; - - info.write_data.resize(info.nelems_per_dataset); - for (size_t i = 0; i < info.write_data.size(); ++i) { - info.write_data[i] = GenRandom0to1(); - } - info.read_data.resize(info.nelems_per_dataset); - for (size_t i = 0; i < info.read_data.size(); ++i) { - info.read_data[i] = 0.0f; - } - - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - std::string suffix = std::to_string(getpid()) + info.hdf5_extension; - info.new_file = fullpath.string() + "_new_" + suffix; - info.existing_file = fullpath.string() + "_ext_" + suffix; - info.new_file_cmp = fullpath.string() + "_new_cmp_" + suffix; - info.existing_file_cmp = fullpath.string() + "_ext_cmp_" + suffix; - - char *driver_config = getenv("HDF5_DRIVER_CONFIG"); - if (driver_config) { - std::string looking_for("false"); - std::string conf_str(driver_config); - if (!conf_str.compare(0, looking_for.size(), looking_for)) { - info.scratch_mode = true; - } - } - - return 0; -} - -/** - * Called from catch_config.h after all tests are run. - */ -int finalize() { - MPI_Finalize(); - return 0; -} - -/** - * Remove all files generated by the tests - */ -void CleanupFiles() { - if (stdfs::exists(info.new_file)) - stdfs::remove(info.new_file); - if (stdfs::exists(info.new_file_cmp)) - stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file)) - stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); -} - -/** - * Called before each individual test. - * - * Generates files for tests that operate on existing files. - */ -int Pretest() { - CleanupFiles(); - - GenHdf5File(info.existing_file, info.nelems_per_dataset, info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(info.total_size > 0); - - return 0; -} - -/** - * Use h5diff to ensure that the resulting files from the Hermes VFD and the - * POSIX VFD are the same. - */ -void CheckResults(const std::string &file1, const std::string &file2) { - if (stdfs::exists(file1) && stdfs::exists(file2)) { - std::string h5diff_cmd = "h5diff " + file1 + " " + file2; - int status = system(h5diff_cmd.c_str()); - if (status != 0) { - LOG(ERROR) << "Failing h5diff command: " << h5diff_cmd; - } - REQUIRE(status == 0); - } -} - -/** - * Called after each individual test. - */ -int Posttest() { - if (!info.scratch_mode) { - // NOTE(chogan): This is necessary so that h5diff doesn't use the Hermes VFD - // in CheckResults. We don't need to reset LD_PRELOAD because it only has an - // effect when an application first starts. - unsetenv("LD_PRELOAD"); - unsetenv("HDF5_DRIVER"); - CheckResults(info.new_file, info.new_file_cmp); - CheckResults(info.existing_file, info.existing_file_cmp); - setenv("HDF5_DRIVER", "hermes", 1); - } - - CleanupFiles(); - - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -using hermes::adapter::vfd::test::Hdf5Api; - -/** - * The functions in this namespace perform operations on 2 files: the "main" - * file, which is the one going through the Hermes VFD, and a comparison file - * (with a "_cmp" suffix) which goes through the POSIX VFD. The idea is to - * perfrom each test on 2 files (Hermes VFD and POSIX VFD) and then compare the - * results at the end with h5diff. In persistent mode, the file produced by the - * Hermes VFD should be exactly the same as the one produced by the POSIX VFD. - */ -namespace test { - -hid_t hermes_hid; /**< Hermes handle ID */ -hid_t sec2_hid; /**< POSIX driver handle ID */ -herr_t hermes_herr; /**< Hermes error return value */ -/** - Test creating and opening a new file. -*/ -void TestOpen(const std::string &path, unsigned flags, bool create = false) { - Hdf5Api api; - - std::string cmp_path; - if (path == info.new_file) { - cmp_path = info.new_file_cmp; - } else { - cmp_path = info.existing_file_cmp; - } - - if (create) { - hermes_hid = api.Create(path, flags); - sec2_hid = api.CreatePosix(cmp_path, flags); - } else { - hermes_hid = api.Open(path, flags); - sec2_hid = api.OpenPosix(cmp_path, flags); - } - bool is_same = - (sec2_hid != H5I_INVALID_HID && hermes_hid != H5I_INVALID_HID) || - (sec2_hid == H5I_INVALID_HID && hermes_hid == H5I_INVALID_HID); - - REQUIRE(is_same); -} -/** - Test Close() calls. -*/ -void TestClose() { - Hdf5Api api; - hermes_herr = api.Close(hermes_hid); - herr_t status = api.Close(sec2_hid); - REQUIRE(status == hermes_herr); -} - -/** - Test writing partial 1-D dataset. -*/ -void TestWritePartial1d(const std::string &dset_name, const f32 *data, - hsize_t offset, hsize_t nelems) { - Hdf5Api api; - api.WritePartial1d(test::hermes_hid, dset_name, data, offset, nelems); - api.WritePartial1d(test::sec2_hid, dset_name, data, offset, nelems); -} - -/** - Test making dataset. -*/ -void TestWriteDataset(const std::string &dset_name, - const std::vector &data) { - Hdf5Api api; - api.MakeDataset(test::hermes_hid, dset_name, data); - api.MakeDataset(test::sec2_hid, dset_name, data); -} - - -/** - Test making compact dataset. -*/ -void TestMakeCompactDataset(const std::string &dset_name, - const std::vector &data) { - Hdf5Api api; - api.MakeDataset(test::hermes_hid, dset_name, data, true); - api.MakeDataset(test::sec2_hid, dset_name, data, true); -} - -/** - Test reading dataset. -*/ -void TestRead(const std::string &dset_name, std::vector &buf, - hsize_t offset, hsize_t nelems) { - Hdf5Api api; - api.Read(test::hermes_hid, dset_name, buf, offset, nelems); - std::vector sec2_read_buf(nelems, 0.0f); - api.Read(test::sec2_hid, dset_name, sec2_read_buf, offset, nelems); - - REQUIRE(std::equal(buf.begin(), buf.begin() + nelems, sec2_read_buf.begin())); -} -} // namespace test - -#include "hermes_vfd_basic_test.cc" diff --git a/config/hermes_server_default.yaml b/config/hermes_server_default.yaml index b24350557..91b964968 100644 --- a/config/hermes_server_default.yaml +++ b/config/hermes_server_default.yaml @@ -129,16 +129,4 @@ dpe: shmem_name: "/hermes_shm_" # The interval in milliseconds at which to update the global system view. -system_view_state_update_interval_ms: 1000 - -#Paths which are ignored when buffering data -path_exclusions: [ - "/bin/", "/boot/", "/dev/", "/etc/", - "/lib/", "/opt/", "/proc/", "/sbin/", - "/sys/", "/usr/", "/var/", "/run/", - "pipe", "socket:", "anon_inode:" -] - -#Paths which are never ignored when buffering data -path_inclusions: ["/var/opt/cray/dws/mounts/"] - +system_view_state_update_interval_ms: 1000 \ No newline at end of file diff --git a/src/config_server.cc b/src/config_server.cc index a8cec5681..7f1cf3b7e 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -145,15 +145,6 @@ void ServerConfig::ParseYAML(YAML::Node &yaml_conf) { if (yaml_conf["shmem_name"]) { shmem_name_ = yaml_conf["shmem_name"].as(); } - - if (yaml_conf["path_exclusions"]) { - ParseVector(yaml_conf["path_exclusions"], - path_exclusions); - } - if (yaml_conf["path_inclusions"]) { - ParseVector(yaml_conf["path_inclusions"], - path_inclusions); - } } /** Load the default configuration */ diff --git a/src/config_server.h b/src/config_server.h index d0593602b..5586a6e75 100644 --- a/src/config_server.h +++ b/src/config_server.h @@ -203,19 +203,6 @@ class ServerConfig : public BaseConfig { */ std::string shmem_name_; - /** - * Paths prefixed with the following directories are not tracked in Hermes - * Exclusion list used by darshan at - * darshan/darshan-runtime/lib/darshan-core.c - */ - std::vector path_exclusions; - - /** - * Paths prefixed with the following directories are tracked by Hermes even if - * they share a root with a path listed in path_exclusions - */ - std::vector path_inclusions; - public: ServerConfig() = default; void LoadDefault(); diff --git a/src/config_server_default.h b/src/config_server_default.h index 837f7265f..d19b4a203 100644 --- a/src/config_server_default.h +++ b/src/config_server_default.h @@ -132,17 +132,5 @@ const char* kServerDefaultConfigStr = "shmem_name: \"/hermes_shm_\"\n" "\n" "# The interval in milliseconds at which to update the global system view.\n" -"system_view_state_update_interval_ms: 1000\n" -"\n" -"#Paths which are ignored when buffering data\n" -"path_exclusions: [\n" -" \"/bin/\", \"/boot/\", \"/dev/\", \"/etc/\",\n" -" \"/lib/\", \"/opt/\", \"/proc/\", \"/sbin/\",\n" -" \"/sys/\", \"/usr/\", \"/var/\", \"/run/\",\n" -" \"pipe\", \"socket:\", \"anon_inode:\"\n" -"]\n" -"\n" -"#Paths which are never ignored when buffering data\n" -"path_inclusions: [\"/var/opt/cray/dws/mounts/\"]\n" -"\n"; +"system_view_state_update_interval_ms: 1000\n"; #endif // HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ \ No newline at end of file From a714c70085f585c37108380d6416d0fd9d899d29 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 05:52:13 -0600 Subject: [PATCH 132/511] Nearly finished with test automation --- adapter/test/CMakeLists.txt | 54 +++++++++++-------- adapter/test/gcc.sh | 29 ++++++++++ adapter/test/gcc_hermes.sh | 37 +++++++++---- adapter/test/gcc_hermes_mode.sh | 35 ++++++++---- adapter/test/mpi.sh | 31 +++++++++++ adapter/test/{run_hermes.sh => mpi_hermes.sh} | 5 +- adapter/test/mpiio/mpiio_adapter_test.cpp | 2 +- adapter/test/posix/CMakeLists.txt | 17 +----- adapter/test/stdio/CMakeLists.txt | 27 ---------- ci/lint.sh | 4 +- src/CMakeLists.txt | 7 +-- 11 files changed, 158 insertions(+), 90 deletions(-) create mode 100644 adapter/test/gcc.sh create mode 100644 adapter/test/mpi.sh rename adapter/test/{run_hermes.sh => mpi_hermes.sh} (88%) diff --git a/adapter/test/CMakeLists.txt b/adapter/test/CMakeLists.txt index f17bb010f..20d80c04c 100644 --- a/adapter/test/CMakeLists.txt +++ b/adapter/test/CMakeLists.txt @@ -3,39 +3,51 @@ set(ADAPTER_COMMON ${CMAKE_CURRENT_SOURCE_DIR}/catch_config.h) set(HERMES_ADAPTER_TEST_DIR ${HERMES_ADAPTER_DIR}/test) find_package(Catch2 REQUIRED) +find_program(BASH_PROGRAM bash) function(gcc exec args) - add_test(NAME Test${exec} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${args}) - set_property(TEST Test${exec} - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) - set_property(TEST Test${exec} APPEND - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) + set(test_name Test${exec} COMMAND) + set(script ${CMAKE_SOURCE_DIR}/adapter/test/gcc.sh) + add_test(NAME ${test_name} COMMAND ${BASH_PROGRAM} ${script} + "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" + "${exec}" "${args}") endfunction() function(mpi exec mpi_proc args) - add_test(NAME Test${exec}_${mpi_proc} - COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${mpi_proc} - "${CMAKE_BINARY_DIR}/bin/${exec}" ${args} -d yes) - set_property(TEST Test${exec}_${mpi_proc} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) - set_property(TEST Test${exec}_${mpi_proc} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) + set(test_name Test${exec}_${mpi_proc} COMMAND) + set(script ${CMAKE_SOURCE_DIR}/adapter/test/mpi.sh) + add_test(NAME ${test_name} COMMAND ${BASH_PROGRAM} ${script} + "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" + "${MPIEXEC_EXECUTABLE}" "${MPIEXEC_NUMPROC_FLAG}" "${mpi_proc}" + "${exec}" "${args}") endfunction() -find_program(BASH_PROGRAM bash) +function(gcc_hermes exec tag_name tags conf async) + set(test_name Test${exec}_${tag_name}_${async} COMMAND) + set(script ${CMAKE_SOURCE_DIR}/adapter/test/gcc_hermes.sh) + add_test(NAME ${test_name} COMMAND ${BASH_PROGRAM} ${script} + "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" + "${exec}" "${tag_name}" "${tags}" "${conf}" "${async}") +endfunction() + +function(gcc_hermes_mode exec tag_name tags mode path) + set(test_name Test${exec}_${tag_name}_${mode}_${path}) + set(script ${CMAKE_SOURCE_DIR}/adapter/test/gcc_hermes_mode.sh) + add_test(NAME ${test_name} COMMAND ${BASH_PROGRAM} ${script} + "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" + "${exec}" "${tag_name}" "${tags}" "${mode}" "${path}") +endfunction() function(mpi_daemon test_exec test_mpi_proc test_args arg_name daemon_procs) #MPI_EXEC=$1 TEST_EXEC=$2 TEST_PROCS=$3 HERMES_EXEC=$4 HERMES_PROCS=$5 HERMES_CONF=$6 - add_test(Test${test_exec}_${test_mpi_proc}_${arg_name} ${BASH_PROGRAM} - ${CMAKE_SOURCE_DIR}/adapter/test/run_hermes.sh ${MPIEXEC_EXECUTABLE} + set(script ${CMAKE_SOURCE_DIR}/adapter/test/mpi_hermes.sh) + add_test(Test${test_exec}_${test_mpi_proc}_${arg_name} + ${BASH_PROGRAM} ${script} + ${MPIEXEC_EXECUTABLE} ${CMAKE_BINARY_DIR}/bin/${test_exec} ${test_mpi_proc} ${CMAKE_BINARY_DIR}/bin/hermes_daemon ${daemon_procs} - ${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml + hermes ${test_args}) - set_property(TEST Test${test_exec}_${test_mpi_proc}_${arg_name} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) - set_property(TEST Test${test_exec}_${test_mpi_proc}_${arg_name} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) endfunction() enable_testing() @@ -49,7 +61,7 @@ if(HERMES_ENABLE_POSIX_ADAPTER) endif() if(HERMES_ENABLE_MPIIO_ADAPTER) - # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/mpiio) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/mpiio) endif() if(HERMES_ENABLE_PUBSUB_ADAPTER) diff --git a/adapter/test/gcc.sh b/adapter/test/gcc.sh new file mode 100644 index 000000000..e73b98faf --- /dev/null +++ b/adapter/test/gcc.sh @@ -0,0 +1,29 @@ +#!/bin/bash +CMAKE_SOURCE_DIR=$1 +CMAKE_BINARY_DIR=$2 +EXEC_NAME=$3 +ARGS=$4 +SLEEP_TIME=3 + +export HERMES_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes_client.yaml" +export HERMES_CLIENT_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes_server.yaml" + +# Start the Hermes daemon +echo "STARTING DAEMON" +${CMAKE_BINARY_DIR}/bin/hermes_daemon & +echo "WAITING FOR DAEMON" +sleep ${SLEEP_TIME} + +# Run the program +echo "RUNNING PROGRAM" +export LSAN_OPTIONS=suppressions="${CMAKE_SOURCE_DIR}/test/data/asan.supp" +export COMMAND="${CMAKE_BINARY_DIR}/bin/${EXEC_NAME}" +echo "RUNNING PROGRAM" +"${COMMAND}" "${ARGS}" +status=$? + +# Finalize the Hermes daemon +${CMAKE_BINARY_DIR}/bin/finalize_hermes + +# Exit with status +exit $status \ No newline at end of file diff --git a/adapter/test/gcc_hermes.sh b/adapter/test/gcc_hermes.sh index c920d45c7..a067ae8d3 100644 --- a/adapter/test/gcc_hermes.sh +++ b/adapter/test/gcc_hermes.sh @@ -1,16 +1,31 @@ #!/bin/bash -CMAKE_BINARY_DIR=$1 -CMAKE_SOURCE_DIR=$2 -EXEC=$3 +CMAKE_SOURCE_DIR=$1 +CMAKE_BINARY_DIR=$2 +EXEC_NAME=$3 TAG_NAME=$4 TAGS=$5 -MODE=$6 -DO_PATH_EXCLUDE=$7 +CONF=$6 +ASYNC=$7 +SLEEP_TIME=3 -LSAN_OPTIONS=suppressions="${CMAKE_SOURCE_DIR}/test/data/asan.supp" \ -ADAPTER_MODE="${MODE}" \ -SET_PATH="${DO_PATH_EXCLUDE}" \ -HERMES_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml" \ -HERMES_CLIENT_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml" \ -COMMAND="${CMAKE_BINARY_DIR}/bin/${exec}" \ +export HERMES_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/${CONF}_client.yaml" +export HERMES_CLIENT_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/${CONF}_server.yaml" + +# Start the Hermes daemon +echo "STARTING DAEMON" +${CMAKE_BINARY_DIR}/bin/hermes_daemon & +echo "WAITING FOR DAEMON" +sleep ${SLEEP_TIME} + +# Run the program +echo "RUNNING PROGRAM" +export LSAN_OPTIONS=suppressions="${CMAKE_SOURCE_DIR}/test/data/asan.supp" +export COMMAND="${CMAKE_BINARY_DIR}/bin/${EXEC_NAME}" "${COMMAND}" "${TAGS}" --reporter compact -d yes +status=$? + +# Finalize the Hermes daemon +${CMAKE_BINARY_DIR}/bin/finalize_hermes + +# Exit with status +exit $status \ No newline at end of file diff --git a/adapter/test/gcc_hermes_mode.sh b/adapter/test/gcc_hermes_mode.sh index 8a9655ff7..1d29a19fb 100644 --- a/adapter/test/gcc_hermes_mode.sh +++ b/adapter/test/gcc_hermes_mode.sh @@ -1,15 +1,32 @@ #!/bin/bash -CMAKE_BINARY_DIR=$1 -CMAKE_SOURCE_DIR=$2 -EXEC=$3 +CMAKE_SOURCE_DIR=$1 +CMAKE_BINARY_DIR=$2 +EXEC_NAME=$3 TAG_NAME=$4 TAGS=$5 MODE=$6 -path +DO_PATH_EXCLUDE=$7 +SLEEP_TIME=3 -LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp -ADAPTER_MODE=${mode} -SET_PATH=${path} -HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml +export HERMES_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes_client.yaml" +export HERMES_CLIENT_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes_server.yaml" -COMMAND="${CMAKE_BINARY_DIR}/bin/${exec}" \ No newline at end of file +# Start the Hermes daemon +echo "STARTING DAEMON" +${CMAKE_BINARY_DIR}/bin/hermes_daemon & +echo "WAITING FOR DAEMON" +sleep ${SLEEP_TIME} + +# Run the program +export LSAN_OPTIONS=suppressions="${CMAKE_SOURCE_DIR}/test/data/asan.supp" +export ADAPTER_MODE="${MODE}" +export SET_PATH="${DO_PATH_EXCLUDE}" +export COMMAND="${CMAKE_BINARY_DIR}/bin/${EXEC_NAME}" +"${COMMAND}" "${TAGS}" --reporter compact -d yes +status=$? + +# Finalize the Hermes daemon +${CMAKE_BINARY_DIR}/bin/finalize_hermes + +# Exit with status +exit $status \ No newline at end of file diff --git a/adapter/test/mpi.sh b/adapter/test/mpi.sh new file mode 100644 index 000000000..bef52213e --- /dev/null +++ b/adapter/test/mpi.sh @@ -0,0 +1,31 @@ +#!/bin/bash +CMAKE_SOURCE_DIR=$1 +CMAKE_BINARY_DIR=$2 +MPIEXEC_EXECUTABLE=$3 +MPIEXEC_NUMPROC_FLAG=$4 +MPI_PROC=$5 +EXEC_NAME=$6 +ARGS=$7 +SLEEP_TIME=3 + +export HERMES_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/${CONF}_client.yaml" +export HERMES_CLIENT_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/${CONF}_server.yaml" + +# Start the Hermes daemon +echo "STARTING DAEMON" +${CMAKE_BINARY_DIR}/bin/hermes_daemon & +echo "WAITING FOR DAEMON" +sleep ${SLEEP_TIME} + +# Run the program +export LSAN_OPTIONS=suppressions="${CMAKE_SOURCE_DIR}/test/data/asan.supp" +export MPI_COMMAND="${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPI_PROC}" +export COMMAND="${MPI_COMMAND} ${CMAKE_BINARY_DIR}/bin/${exec}" +"${COMMAND}" "${ARGS}" -d yes +status=$? + +# Finalize the Hermes daemon +${CMAKE_BINARY_DIR}/bin/finalize_hermes + +# Exit with status +exit $status \ No newline at end of file diff --git a/adapter/test/run_hermes.sh b/adapter/test/mpi_hermes.sh similarity index 88% rename from adapter/test/run_hermes.sh rename to adapter/test/mpi_hermes.sh index cfa45b668..289737b1e 100644 --- a/adapter/test/run_hermes.sh +++ b/adapter/test/mpi_hermes.sh @@ -5,10 +5,13 @@ TEST_EXEC=$2 TEST_PROCS=$3 HERMES_EXEC=$4 HERMES_PROCS=$5 -HERMES_CONF=$6 +CONF=$6 TEST_ARGS="${@:7}" SLEEP_TIME=3 +export HERMES_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/${CONF}_server.yaml" +export HERMES_CLIENT_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/${CONF}_client.yaml" + error_ct=0 if [[ ! -f "$MPI_EXEC" ]]; then echo "MPI_EXEC ${MPI_EXEC} does not exists." >&2 diff --git a/adapter/test/mpiio/mpiio_adapter_test.cpp b/adapter/test/mpiio/mpiio_adapter_test.cpp index b5e07f6be..80ea998b1 100644 --- a/adapter/test/mpiio/mpiio_adapter_test.cpp +++ b/adapter/test/mpiio/mpiio_adapter_test.cpp @@ -155,7 +155,7 @@ int pretest() { // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.shared_new_file_cmp); // INTERCEPTOR_LIST->hermes_flush_exclusion.insert( - info.shared_existing_file_cmp); + // info.shared_existing_file_cmp); #endif return 0; } diff --git a/adapter/test/posix/CMakeLists.txt b/adapter/test/posix/CMakeLists.txt index a52aafeb6..ecece0379 100644 --- a/adapter/test/posix/CMakeLists.txt +++ b/adapter/test/posix/CMakeLists.txt @@ -1,16 +1,3 @@ -function(gcc_hermes exec tag_name tags conf) - add_test(NAME Test${exec}_${tag_name} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) - set_property(TEST Test${exec}_${tag_name} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/${conf}.yaml) - set_property(TEST Test${exec}_${tag_name} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) -endfunction() - -function(gcc_hermes_mode exec tag_name tags mode path) - set(test_name Test${exec}_${tag_name}_${mode}_${path}) - add_test(NAME ${test_name} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) -endfunction() - #------------------------------------------------------------------------------ # Posix Adapter tests #------------------------------------------------------------------------------ @@ -25,8 +12,8 @@ add_executable(hermes_posix_adapter_test posix_adapter_test.cpp ${ADAPTER_COMMON target_link_libraries(hermes_posix_adapter_test hermes_posix) add_dependencies(hermes_posix_adapter_test hermes_posix hermes_daemon) set_target_properties(hermes_posix_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -gcc_hermes(hermes_posix_adapter_test "" "~[request_size=range-large]" hermes) -gcc_hermes(hermes_posix_adapter_test "large" "[request_size=range-large]" hermes) +gcc_hermes(hermes_posix_adapter_test "" "~[request_size=range-large]" hermes 0) +gcc_hermes(hermes_posix_adapter_test "large" "[request_size=range-large]" hermes 0) add_executable(hermes_posix_adapter_mpi_test posix_adapter_mpi_test.cpp ${ADAPTER_COMMON}) target_link_libraries(hermes_posix_adapter_mpi_test hermes_posix) diff --git a/adapter/test/stdio/CMakeLists.txt b/adapter/test/stdio/CMakeLists.txt index 485d2c7fd..c6707093f 100644 --- a/adapter/test/stdio/CMakeLists.txt +++ b/adapter/test/stdio/CMakeLists.txt @@ -1,30 +1,3 @@ -function(gcc_hermes exec tag_name tags conf async) - set(TEST_NAME Test${exec}_${tag_name}_${async}) - add_test(NAME ${TEST_NAME} - COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) - set_property(TEST ${TEST_NAME} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/${conf}.yaml) - set_property(TEST ${TEST_NAME} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) - - if ("${async}" STREQUAL "async") - set_property(TEST ${TEST_NAME} APPEND PROPERTY ENVIRONMENT HERMES_ASYNC_FLUSH=1) - endif() -endfunction() - -function(gcc_hermes_mode exec tag_name tags mode path) - set(test_name Test${exec}_${tag_name}_${mode}_${path}) - add_test(NAME ${test_name} COMMAND "${CMAKE_BINARY_DIR}/bin/${exec}" ${tags} --reporter compact -d yes) - set_property(TEST ${test_name} - PROPERTY ENVIRONMENT HERMES_CONF=${CMAKE_SOURCE_DIR}/adapter/test/data/hermes.yaml) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT LSAN_OPTIONS=suppressions=${CMAKE_SOURCE_DIR}/test/data/asan.supp) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT ADAPTER_MODE=${mode}) - set_property(TEST ${test_name} APPEND - PROPERTY ENVIRONMENT SET_PATH=${path}) -endfunction() - include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src) diff --git a/ci/lint.sh b/ci/lint.sh index 86fa44a0f..63ecafd32 100644 --- a/ci/lint.sh +++ b/ci/lint.sh @@ -6,7 +6,7 @@ cpplint --recursive \ --exclude="${HERMES_ROOT}/src/config_server_default.h" \ --exclude="${HERMES_ROOT}/src/config_client_default.h" \ --exclude="${ADAPTER}/posix/posix_api.h" \ ---exclude="${ADAPTER}/stdio/real_api.h" \ ---exclude="${ADAPTER}/mpiio/real_api.h" \ +--exclude="${ADAPTER}/stdio/stdio_api.h" \ +--exclude="${ADAPTER}/mpiio/mpiio_api.h" \ "${HERMES_ROOT}/adapter" "${HERMES_ROOT}/benchmarks" "${HERMES_ROOT}/data_stager" \ "${HERMES_ROOT}/src" "${HERMES_ROOT}/test" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aa2667577..4f15808e1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,9 +54,6 @@ set(HERMES_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/api/vbucket.cc ${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cc ${CMAKE_CURRENT_SOURCE_DIR}/buffer_organizer.cc - #${CMAKE_CURRENT_SOURCE_DIR}/prefetcher.cc - #${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/sequential.cc - #${CMAKE_CURRENT_SOURCE_DIR}/prefetchers/apriori.cc ${CMAKE_CURRENT_SOURCE_DIR}/data_placement_engine.cc ${CMAKE_CURRENT_SOURCE_DIR}/dpe/random.cc ${CMAKE_CURRENT_SOURCE_DIR}/dpe/round_robin.cc @@ -121,6 +118,10 @@ add_executable(finalize_hermes api/finalize_hermes.cc) add_dependencies(finalize_hermes hermes) target_link_libraries(finalize_hermes hermes) +add_executable(wait_for_daemon_start api/wait_for_daemon_start.cc) +add_dependencies(wait_for_daemon_start hermes) +target_link_libraries(wait_for_daemon_start hermes) + #----------------------------------------------------------------------------- # Specify project header files to be installed #----------------------------------------------------------------------------- From ab60cb80576bf9ed2f7618d8ad1c2b8352cbec5f Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 07:26:12 -0600 Subject: [PATCH 133/511] Remove all EasyGlobalSingleton types --- adapter/mapper/mapper_factory.h | 2 +- adapter/mpiio/mpiio_api.h | 2 +- adapter/mpiio/mpiio_fs_api.h | 2 +- adapter/mpiio/mpiio_io_client.h | 2 +- adapter/posix/posix_fs_api.h | 2 +- adapter/posix/posix_io_client.h | 2 +- adapter/stdio/stdio_api.cc | 5 ++++ adapter/stdio/stdio_api.h | 18 -------------- adapter/stdio/stdio_fs_api.h | 2 +- adapter/stdio/stdio_io_client.h | 2 +- adapter/test/CMakeLists.txt | 21 ++++++++-------- adapter/test/gcc_hermes_mode.sh | 1 + adapter/test/mpi.sh | 10 ++++---- adapter/test/mpi_hermes.sh | 41 ++++++++++++++++++------------- adapter/test/stdio/CMakeLists.txt | 2 +- src/CMakeLists.txt | 4 --- 16 files changed, 55 insertions(+), 63 deletions(-) diff --git a/adapter/mapper/mapper_factory.h b/adapter/mapper/mapper_factory.h index a007a55fe..d0858fc6a 100644 --- a/adapter/mapper/mapper_factory.h +++ b/adapter/mapper/mapper_factory.h @@ -33,7 +33,7 @@ class MapperFactory { AbstractMapper* Get(const MapperType& type) { switch (type) { case MapperType::kBalancedMapper: { - return hermes::EasyGlobalSingleton::GetInstance(); + return hermes::EasySingleton::GetInstance(); } default: { // TODO(llogan): @error_handling Mapper not implemented diff --git a/adapter/mpiio/mpiio_api.h b/adapter/mpiio/mpiio_api.h index c34e2cd7e..aee4ac984 100644 --- a/adapter/mpiio/mpiio_api.h +++ b/adapter/mpiio/mpiio_api.h @@ -299,7 +299,7 @@ class MpiioApi { /** Simplify access to the stateless MpiioFs Singleton */ #define HERMES_MPIIO_API \ - hermes::EasyGlobalSingleton::GetInstance() + hermes::EasySingleton::GetInstance() #define HERMES_MPIIO_API_T hermes::adapter::fs::MpiioApi* #endif // HERMES_ADAPTER_MPIIO_H diff --git a/adapter/mpiio/mpiio_fs_api.h b/adapter/mpiio/mpiio_fs_api.h index bc9c39335..f547309ec 100644 --- a/adapter/mpiio/mpiio_fs_api.h +++ b/adapter/mpiio/mpiio_fs_api.h @@ -469,7 +469,7 @@ class MpiioFs : public Filesystem { /** Simplify access to the stateless StdioFs Singleton */ #define HERMES_MPIIO_FS \ - hermes::EasyGlobalSingleton::GetInstance() + hermes::EasySingleton::GetInstance() #define HERMES_STDIO_FS_T hermes::adapter::fs::MpiioFs* #endif // HERMES_ADAPTER_MPIIO_MPIIO_FS_API_H_ diff --git a/adapter/mpiio/mpiio_io_client.h b/adapter/mpiio/mpiio_io_client.h index 0808869f6..637023851 100644 --- a/adapter/mpiio/mpiio_io_client.h +++ b/adapter/mpiio/mpiio_io_client.h @@ -91,7 +91,7 @@ class MpiioIoClient : public hermes::adapter::fs::FilesystemIoClient { /** Simplify access to the stateless StdioIoClient Singleton */ #define HERMES_MPIIO_IO_CLIENT \ - hermes::EasyGlobalSingleton::GetInstance() + hermes::EasySingleton::GetInstance() #define HERMES_MPIIO_IO_CLIENT_T hermes::adapter::fs::MpiioIoClient* #endif // HERMES_ADAPTER_MPIIO_MPIIO_IO_CLIENT_H_ diff --git a/adapter/posix/posix_fs_api.h b/adapter/posix/posix_fs_api.h index 4ba9a94bd..b2ef541f3 100644 --- a/adapter/posix/posix_fs_api.h +++ b/adapter/posix/posix_fs_api.h @@ -58,7 +58,7 @@ class PosixFs : public hermes::adapter::fs::Filesystem { /** Simplify access to the stateless PosixFs Singleton */ #define HERMES_POSIX_FS \ - hermes::EasyGlobalSingleton::GetInstance() + hermes::EasySingleton::GetInstance() #define HERMES_POSIX_FS_T hermes::adapter::fs::PosixFs* } // namespace hermes::adapter::fs diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h index 40620d661..fe9738a21 100644 --- a/adapter/posix/posix_io_client.h +++ b/adapter/posix/posix_io_client.h @@ -92,7 +92,7 @@ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { /** Simplify access to the stateless PosixIoClient Singleton */ #define HERMES_POSIX_IO_CLIENT \ - hermes::EasyGlobalSingleton::GetInstance() + hermes::EasySingleton::GetInstance() #define HERMES_POSIX_IO_CLIENT_T hermes::adapter::fs::PosixIoClient* #endif // HERMES_ADAPTER_POSIX_POSIX_IO_CLIENT_H_ diff --git a/adapter/stdio/stdio_api.cc b/adapter/stdio/stdio_api.cc index 7e18ff194..d072ebcd9 100644 --- a/adapter/stdio/stdio_api.cc +++ b/adapter/stdio/stdio_api.cc @@ -36,6 +36,7 @@ extern "C" { */ FILE *HERMES_DECL(fopen)(const char *path, const char *mode) { + TRANSPARENT_HERMES auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; if (fs_api->IsPathTracked(path)) { @@ -49,6 +50,7 @@ FILE *HERMES_DECL(fopen)(const char *path, const char *mode) { } FILE *HERMES_DECL(fopen64)(const char *path, const char *mode) { + TRANSPARENT_HERMES auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; if (fs_api->IsPathTracked(path)) { @@ -62,6 +64,7 @@ FILE *HERMES_DECL(fopen64)(const char *path, const char *mode) { } FILE *HERMES_DECL(fdopen)(int fd, const char *mode) { + TRANSPARENT_HERMES auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; std::shared_ptr stat; @@ -74,6 +77,7 @@ FILE *HERMES_DECL(fdopen)(int fd, const char *mode) { } FILE *HERMES_DECL(freopen)(const char *path, const char *mode, FILE *stream) { + TRANSPARENT_HERMES auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; if (fs_api->IsFpTracked(stream)) { @@ -85,6 +89,7 @@ FILE *HERMES_DECL(freopen)(const char *path, const char *mode, FILE *stream) { } FILE *HERMES_DECL(freopen64)(const char *path, const char *mode, FILE *stream) { + TRANSPARENT_HERMES auto real_api = HERMES_STDIO_API; auto fs_api = HERMES_STDIO_FS; if (fs_api->IsFpTracked(stream)) { diff --git a/adapter/stdio/stdio_api.h b/adapter/stdio/stdio_api.h index 371c086d3..30a6da7ee 100644 --- a/adapter/stdio/stdio_api.h +++ b/adapter/stdio/stdio_api.h @@ -26,8 +26,6 @@ } extern "C" { -typedef int (*MPI_Init_t)(int * argc, char *** argv); -typedef int (*MPI_Finalize_t)( void); typedef FILE * (*fopen_t)(const char * path, const char * mode); typedef FILE * (*fopen64_t)(const char * path, const char * mode); typedef FILE * (*fdopen_t)(int fd, const char * mode); @@ -61,10 +59,6 @@ namespace hermes::adapter::fs { /** Pointers to the real stdio API */ class StdioApi { public: - /** MPI_Init */ - MPI_Init_t MPI_Init = nullptr; - /** MPI_Finalize */ - MPI_Finalize_t MPI_Finalize = nullptr; /** fopen */ fopen_t fopen = nullptr; /** fopen64 */ @@ -120,18 +114,6 @@ class StdioApi { StdioApi() { void *is_intercepted = (void*)dlsym(RTLD_DEFAULT, "stdio_intercepted"); - if (is_intercepted) { - MPI_Init = (MPI_Init_t)dlsym(RTLD_NEXT, "MPI_Init"); - } else { - MPI_Init = (MPI_Init_t)dlsym(RTLD_DEFAULT, "MPI_Init"); - } - REQUIRE_API(MPI_Init) - if (is_intercepted) { - MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_NEXT, "MPI_Finalize"); - } else { - MPI_Finalize = (MPI_Finalize_t)dlsym(RTLD_DEFAULT, "MPI_Finalize"); - } - REQUIRE_API(MPI_Finalize) if (is_intercepted) { fopen = (fopen_t)dlsym(RTLD_NEXT, "fopen"); } else { diff --git a/adapter/stdio/stdio_fs_api.h b/adapter/stdio/stdio_fs_api.h index 62f1053d2..f0b870951 100644 --- a/adapter/stdio/stdio_fs_api.h +++ b/adapter/stdio/stdio_fs_api.h @@ -98,7 +98,7 @@ class StdioFs : public hermes::adapter::fs::Filesystem { /** Simplify access to the stateless StdioFs Singleton */ #define HERMES_STDIO_FS \ - hermes::EasyGlobalSingleton::GetInstance() + hermes::EasySingleton::GetInstance() #define HERMES_STDIO_FS_T hermes::adapter::fs::StdioFs* } // namespace hermes::adapter::fs diff --git a/adapter/stdio/stdio_io_client.h b/adapter/stdio/stdio_io_client.h index 2ad97e602..81a52901b 100644 --- a/adapter/stdio/stdio_io_client.h +++ b/adapter/stdio/stdio_io_client.h @@ -91,7 +91,7 @@ class StdioIoClient : public hermes::adapter::fs::FilesystemIoClient { /** Simplify access to the stateless StdioIoClient Singleton */ #define HERMES_STDIO_IO_CLIENT \ - hermes::EasyGlobalSingleton::GetInstance() + hermes::EasySingleton::GetInstance() #define HERMES_STDIO_IO_CLIENT_T hermes::adapter::fs::StdioIoClient* #endif // HERMES_ADAPTER_STDIO_STDIO_IO_CLIENT_H_ diff --git a/adapter/test/CMakeLists.txt b/adapter/test/CMakeLists.txt index 20d80c04c..6ebae34a9 100644 --- a/adapter/test/CMakeLists.txt +++ b/adapter/test/CMakeLists.txt @@ -41,23 +41,24 @@ endfunction() function(mpi_daemon test_exec test_mpi_proc test_args arg_name daemon_procs) #MPI_EXEC=$1 TEST_EXEC=$2 TEST_PROCS=$3 HERMES_EXEC=$4 HERMES_PROCS=$5 HERMES_CONF=$6 set(script ${CMAKE_SOURCE_DIR}/adapter/test/mpi_hermes.sh) - add_test(Test${test_exec}_${test_mpi_proc}_${arg_name} + add_test(Test${test_exec}_${test_mpi_proc}_${arg_name} COMMAND ${BASH_PROGRAM} ${script} - ${MPIEXEC_EXECUTABLE} - ${CMAKE_BINARY_DIR}/bin/${test_exec} ${test_mpi_proc} - ${CMAKE_BINARY_DIR}/bin/hermes_daemon ${daemon_procs} - hermes - ${test_args}) + "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" + "${MPIEXEC_EXECUTABLE}" + "${daemon_procs}" + "${test_mpi_proc}" + "${test_exec}" + "${test_args}") endfunction() enable_testing() -if(HERMES_ENABLE_STDIO_ADAPTER) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/stdio) +if(HERMES_ENABLE_POSIX_ADAPTER) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/posix) endif() -if(HERMES_ENABLE_POSIX_ADAPTER) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/posix) +if(HERMES_ENABLE_STDIO_ADAPTER) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/stdio) endif() if(HERMES_ENABLE_MPIIO_ADAPTER) diff --git a/adapter/test/gcc_hermes_mode.sh b/adapter/test/gcc_hermes_mode.sh index 1d29a19fb..252332131 100644 --- a/adapter/test/gcc_hermes_mode.sh +++ b/adapter/test/gcc_hermes_mode.sh @@ -18,6 +18,7 @@ echo "WAITING FOR DAEMON" sleep ${SLEEP_TIME} # Run the program +echo "RUNNING PROGRAM" export LSAN_OPTIONS=suppressions="${CMAKE_SOURCE_DIR}/test/data/asan.supp" export ADAPTER_MODE="${MODE}" export SET_PATH="${DO_PATH_EXCLUDE}" diff --git a/adapter/test/mpi.sh b/adapter/test/mpi.sh index bef52213e..c0a3edf58 100644 --- a/adapter/test/mpi.sh +++ b/adapter/test/mpi.sh @@ -8,8 +8,8 @@ EXEC_NAME=$6 ARGS=$7 SLEEP_TIME=3 -export HERMES_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/${CONF}_client.yaml" -export HERMES_CLIENT_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/${CONF}_server.yaml" +export HERMES_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes_client.yaml" +export HERMES_CLIENT_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes_server.yaml" # Start the Hermes daemon echo "STARTING DAEMON" @@ -18,10 +18,10 @@ echo "WAITING FOR DAEMON" sleep ${SLEEP_TIME} # Run the program +echo "RUNNING PROGRAM" export LSAN_OPTIONS=suppressions="${CMAKE_SOURCE_DIR}/test/data/asan.supp" -export MPI_COMMAND="${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPI_PROC}" -export COMMAND="${MPI_COMMAND} ${CMAKE_BINARY_DIR}/bin/${exec}" -"${COMMAND}" "${ARGS}" -d yes +${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPI_PROC} \ +${CMAKE_BINARY_DIR}/bin/${EXEC_NAME} "${ARGS}" -d yes status=$? # Finalize the Hermes daemon diff --git a/adapter/test/mpi_hermes.sh b/adapter/test/mpi_hermes.sh index 289737b1e..a1a00e81a 100644 --- a/adapter/test/mpi_hermes.sh +++ b/adapter/test/mpi_hermes.sh @@ -1,16 +1,18 @@ #!/bin/bash -MPI_EXEC=$1 -TEST_EXEC=$2 -TEST_PROCS=$3 -HERMES_EXEC=$4 -HERMES_PROCS=$5 -CONF=$6 -TEST_ARGS="${@:7}" +CMAKE_SOURCE_DIR=$1 +CMAKE_BINARY_DIR=$2 +$MPI_EXEC=$3 +DAEMON_PROCS=$4 +TEST_PROCS=$5 +EXEC_NAME=$6 +TEST_ARGS=$7 SLEEP_TIME=3 -export HERMES_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/${CONF}_server.yaml" -export HERMES_CLIENT_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/${CONF}_client.yaml" +export HERMES_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes_server.yaml" +export HERMES_CLIENT_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes_client.yaml" +export TEST_EXEC="${CMAKE_BINARY_DIR}/bin/${EXEC_NAME}" +export DAEMON_EXEC="${CMAKE_BINARY_DIR}/bin/hermes_daemon" error_ct=0 if [[ ! -f "$MPI_EXEC" ]]; then @@ -21,8 +23,8 @@ if [[ ! -f "${TEST_EXEC}" ]]; then echo "TEST_EXEC ${TEST_EXEC} does not exists." >&2 error_ct=$((error_ct + 1)) fi -if [[ ! -f "${HERMES_EXEC}" ]]; then - echo "HERMES_EXEC ${HERMES_EXEC} does not exists." >&2 +if [[ ! -f "${DAEMON_EXEC}" ]]; then + echo "DAEMON_EXEC ${DAEMON_EXEC} does not exists." >&2 error_ct=$((error_ct + 1)) fi if [[ ! -f "${HERMES_CONF}" ]]; then @@ -34,19 +36,24 @@ if [ $error_ct -gt 0 ]; then exit $error_ct fi -echo "${MPI_EXEC} -n ${HERMES_PROCS} ${HERMES_EXEC} ${HERMES_CONF} &" -${MPI_EXEC} -n ${HERMES_PROCS} ${HERMES_EXEC} ${HERMES_CONF} & -HERMES_EXEC_PID=$! -echo "process spawned ${HERMES_EXEC_PID}" +# Spawn the hermes daemon +echo "STARTING HERMES DAEMON" +echo "${MPI_EXEC} -n ${HERMES_PROCS} ${DAEMON_EXEC} ${HERMES_CONF} &" +${MPI_EXEC} -n ${HERMES_PROCS} ${DAEMON_EXEC} ${HERMES_CONF} & +DAEMON_EXEC_PID=$! +echo "process spawned ${DAEMON_EXEC_PID}" +# Wait for daemon echo "Started hermes daemon with ${HERMES_PROCS} procs. sleeping for ${SLEEP_TIME} seconds" sleep ${SLEEP_TIME} +# Run program +echo "RUNNING PROGRAM" echo "${MPI_EXEC} -n ${TEST_PROCS} ${TEST_EXEC} ${TEST_ARGS}" ${MPI_EXEC} -n ${TEST_PROCS} ${TEST_EXEC} ${TEST_ARGS} status=$? -echo "Killing Hermes daemon with PID ${HERMES_EXEC_PID}" -kill ${HERMES_EXEC_PID} +echo "Killing Hermes daemon with PID ${DAEMON_EXEC_PID}" +kill ${DAEMON_EXEC_PID} if [ $status -gt 0 ]; then echo "Test failed with code $status!" >&2 exit $status diff --git a/adapter/test/stdio/CMakeLists.txt b/adapter/test/stdio/CMakeLists.txt index c6707093f..1aa5ab298 100644 --- a/adapter/test/stdio/CMakeLists.txt +++ b/adapter/test/stdio/CMakeLists.txt @@ -6,7 +6,7 @@ include_directories( # STDIO Adapter Internal tests #------------------------------------------------------------------------------ add_executable(stdio_adapter_mapper_test stdio_adapter_mapper_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(stdio_adapter_mapper_test hermes_stdio) +target_link_libraries(stdio_adapter_mapper_test stdc++fs hermes_stdio) add_dependencies(stdio_adapter_mapper_test hermes_stdio) gcc(stdio_adapter_mapper_test "") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4f15808e1..3d6956b52 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -118,10 +118,6 @@ add_executable(finalize_hermes api/finalize_hermes.cc) add_dependencies(finalize_hermes hermes) target_link_libraries(finalize_hermes hermes) -add_executable(wait_for_daemon_start api/wait_for_daemon_start.cc) -add_dependencies(wait_for_daemon_start hermes) -target_link_libraries(wait_for_daemon_start hermes) - #----------------------------------------------------------------------------- # Specify project header files to be installed #----------------------------------------------------------------------------- From a6c2386ff5e6d2d2c63e8ea4fd192c58939abd59 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 07:32:53 -0600 Subject: [PATCH 134/511] Fix some LD_PRELOAD issues caused by EasyGlobalSingleton --- test/CMakeLists.txt | 14 ++++++++++---- test/mpi.sh | 31 +++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 test/mpi.sh diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2ceee255f..41737c040 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,6 +17,8 @@ set(API_TESTS test_bucket test_vbucket) +find_program(BASH_PROGRAM bash) + foreach(program ${API_TESTS}) add_executable(${program} ${program}.cc main_mpi.cc) add_dependencies(${program} hermes) @@ -26,9 +28,13 @@ foreach(program ${API_TESTS}) $<$:thallium> glog::glog Catch2::Catch2) + set(script ${CMAKE_SOURCE_DIR}/test/mpi.sh) add_test(NAME "Test${program}" - COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2 - "${CMAKE_BINARY_DIR}/bin/${program}") - set_tests_properties("Test${program}" PROPERTIES ENVIRONMENT - LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_SOURCE_DIR}/data/asan.supp) + COMMAND ${BASH_PROGRAM} ${script} + ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} + ${MPIEXEC_EXECUTABLE} + ${MPIEXEC_NUMPROC_FLAG} + 2 + ${program} + "") endforeach() \ No newline at end of file diff --git a/test/mpi.sh b/test/mpi.sh new file mode 100644 index 000000000..c0a3edf58 --- /dev/null +++ b/test/mpi.sh @@ -0,0 +1,31 @@ +#!/bin/bash +CMAKE_SOURCE_DIR=$1 +CMAKE_BINARY_DIR=$2 +MPIEXEC_EXECUTABLE=$3 +MPIEXEC_NUMPROC_FLAG=$4 +MPI_PROC=$5 +EXEC_NAME=$6 +ARGS=$7 +SLEEP_TIME=3 + +export HERMES_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes_client.yaml" +export HERMES_CLIENT_CONF="${CMAKE_SOURCE_DIR}/adapter/test/data/hermes_server.yaml" + +# Start the Hermes daemon +echo "STARTING DAEMON" +${CMAKE_BINARY_DIR}/bin/hermes_daemon & +echo "WAITING FOR DAEMON" +sleep ${SLEEP_TIME} + +# Run the program +echo "RUNNING PROGRAM" +export LSAN_OPTIONS=suppressions="${CMAKE_SOURCE_DIR}/test/data/asan.supp" +${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPI_PROC} \ +${CMAKE_BINARY_DIR}/bin/${EXEC_NAME} "${ARGS}" -d yes +status=$? + +# Finalize the Hermes daemon +${CMAKE_BINARY_DIR}/bin/finalize_hermes + +# Exit with status +exit $status \ No newline at end of file From 729f344bf3497ec394a663330ef15d4d3eea8f1d Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 09:15:01 -0600 Subject: [PATCH 135/511] integrate data structures --- CMake/FindLabStor.cmake | 20 +- CMakeLists.txt | 17 +- benchmarks/put_get_bench.cc | 4 +- code_generators/preamble.py | 4 +- hermes_shm/CMakeLists.txt | 60 ++ .../include/hermes_shm/constants/constants.h | 33 + .../data_structure_singleton_macros.h | 15 + .../include/hermes_shm/constants/macros.h | 43 + .../hermes_shm/constants/singleton_macros.h | 12 + .../data_structures/data_structure.h | 36 + .../data_structures/internal/shm_archive.h | 119 +++ .../internal/shm_archive_or_t.h | 263 ++++++ .../data_structures/internal/shm_container.h | 98 +++ .../internal/shm_container_extend_macro.h | 243 ++++++ .../internal/shm_container_macro.h | 348 ++++++++ .../internal/shm_deserialize.h | 84 ++ .../data_structures/internal/shm_macros.h | 94 +++ .../internal/shm_null_container.h | 119 +++ .../data_structures/internal/shm_ref.h | 193 +++++ .../data_structures/internal/shm_smart_ptr.h | 176 ++++ .../template/shm_container_base_example.h | 414 ++++++++++ .../template/shm_container_base_template.h | 343 ++++++++ .../template/shm_container_extend_example.h | 308 +++++++ .../template/shm_container_extend_template.h | 238 ++++++ .../include/hermes_shm/data_structures/pair.h | 195 +++++ .../data_structures/smart_ptr/manual_ptr.h | 126 +++ .../hermes_shm/data_structures/string.h | 315 +++++++ .../hermes_shm/data_structures/struct.h | 455 ++++++++++ .../data_structures/thread_unsafe/list.h | 531 ++++++++++++ .../thread_unsafe/unordered_map.h | 554 +++++++++++++ .../data_structures/thread_unsafe/vector.h | 781 ++++++++++++++++++ .../hermes_shm/introspect/system_info.h | 52 ++ .../hermes_shm/memory/allocator/allocator.h | 509 ++++++++++++ .../memory/allocator/allocator_factory.h | 108 +++ .../memory/allocator/malloc_allocator.h | 112 +++ .../hermes_shm/memory/allocator/mp_page.h | 31 + .../memory/allocator/multi_page_allocator.h | 204 +++++ .../memory/allocator/stack_allocator.h | 118 +++ .../hermes_shm/memory/backend/array_backend.h | 57 ++ .../memory/backend/memory_backend.h | 103 +++ .../memory/backend/memory_backend_factory.h | 117 +++ .../hermes_shm/memory/backend/null_backend.h | 73 ++ .../hermes_shm/memory/backend/posix_mmap.h | 124 +++ .../memory/backend/posix_shm_mmap.h | 149 ++++ hermes_shm/include/hermes_shm/memory/memory.h | 397 +++++++++ .../hermes_shm/memory/memory_manager.h | 217 +++++ hermes_shm/include/hermes_shm/thread/lock.h | 34 + .../include/hermes_shm/thread/lock/mutex.h | 61 ++ .../include/hermes_shm/thread/lock/rwlock.h | 113 +++ .../include/hermes_shm/thread/pthread.h | 113 +++ hermes_shm/include/hermes_shm/thread/thread.h | 60 ++ .../hermes_shm/thread/thread_factory.h | 64 ++ .../hermes_shm/thread/thread_manager.h | 57 ++ hermes_shm/include/hermes_shm/types/argpack.h | 226 +++++ hermes_shm/include/hermes_shm/types/atomic.h | 244 ++++++ hermes_shm/include/hermes_shm/types/basic.h | 152 ++++ .../include/hermes_shm/types/bitfield.h | 67 ++ hermes_shm/include/hermes_shm/types/charbuf.h | 196 +++++ .../include/hermes_shm/types/messages.h | 62 ++ .../include/hermes_shm/types/tuple_base.h | 239 ++++++ .../include/hermes_shm/util/auto_trace.h | 44 + hermes_shm/include/hermes_shm/util/debug.h | 90 ++ hermes_shm/include/hermes_shm/util/error.h | 73 ++ hermes_shm/include/hermes_shm/util/errors.h | 75 ++ .../include/hermes_shm/util/formatter.h | 113 +++ .../include/hermes_shm/util/partitioner.h | 169 ++++ .../include/hermes_shm/util/path_parser.h | 63 ++ .../include/hermes_shm/util/singleton.h | 47 ++ hermes_shm/include/hermes_shm/util/timer.h | 109 +++ hermes_shm/src/CMakeLists.txt | 45 + hermes_shm/src/data_structure_singleton.cc | 11 + hermes_shm/src/memory/malloc_allocator.cc | 93 +++ hermes_shm/src/memory/memory_intercept.cc | 85 ++ hermes_shm/src/memory/memory_intercept.h | 10 + hermes_shm/src/memory/memory_manager.cc | 60 ++ hermes_shm/src/memory/multi_page_allocator.cc | 104 +++ hermes_shm/src/memory/stack_allocator.cc | 90 ++ hermes_shm/src/thread/mutex.cc | 110 +++ hermes_shm/src/thread/rwlock.cc | 206 +++++ hermes_shm/test/CMakeLists.txt | 6 + hermes_shm/test/unit/CMakeLists.txt | 11 + .../test/unit/allocators/CMakeLists.txt | 19 + hermes_shm/test/unit/allocators/allocator.cc | 150 ++++ .../test/unit/allocators/allocator_thread.cc | 56 ++ hermes_shm/test/unit/allocators/test_init.cc | 37 + hermes_shm/test/unit/allocators/test_init.h | 66 ++ hermes_shm/test/unit/basic_test.h | 81 ++ .../test/unit/data_structures/CMakeLists.txt | 10 + .../data_structures/backend/CMakeLists.txt | 22 + .../unit/data_structures/backend/backend.cc | 43 + .../data_structures/backend/memory_manager.cc | 92 +++ .../data_structures/backend/memory_slots.cc | 66 ++ .../unit/data_structures/backend/test_init.cc | 31 + .../data_structures/containers/CMakeLists.txt | 56 ++ .../unit/data_structures/containers/list.cc | 73 ++ .../unit/data_structures/containers/list.h | 184 +++++ .../data_structures/containers/manual_ptr.cc | 61 ++ .../unit/data_structures/containers/pair.cc | 56 ++ .../unit/data_structures/containers/slist.cc | 72 ++ .../data_structures/containers/smart_ptr.h | 76 ++ .../unit/data_structures/containers/string.cc | 64 ++ .../data_structures/containers/test_init.cc | 48 ++ .../data_structures/containers/test_init.h | 63 ++ .../unit/data_structures/containers/tuple.cc | 75 ++ .../containers/unordered_map.cc | 239 ++++++ .../containers/unordered_map_thread.cc | 98 +++ .../unit/data_structures/containers/vector.cc | 95 +++ .../unit/data_structures/containers/vector.h | 29 + .../containers_mpi/CMakeLists.txt | 28 + .../containers_mpi/list_vec_mpi.cc | 102 +++ .../containers_mpi/test_init.cc | 66 ++ .../containers_mpi/test_init.h | 53 ++ .../unit/data_structures/lock/CMakeLists.txt | 19 + .../test/unit/data_structures/lock/lock.cc | 125 +++ .../unit/data_structures/lock/test_init.cc | 31 + hermes_shm/test/unit/main.cc | 42 + hermes_shm/test/unit/main_mpi.cc | 44 + hermes_shm/test/unit/types/CMakeLists.txt | 17 + hermes_shm/test/unit/types/test_argpack.cc | 172 ++++ hermes_shm/test/unit/types/test_init.cc | 31 + src/CMakeLists.txt | 10 +- src/api/hermes.cc | 4 +- src/data_structures.h | 30 +- src/dpe/random.cc | 1 + src/dpe/round_robin.cc | 2 +- src/hermes_types.h | 2 +- src/rpc_thallium_serialization.h | 1 - test/basic_test.h | 6 +- 128 files changed, 14605 insertions(+), 57 deletions(-) create mode 100644 hermes_shm/CMakeLists.txt create mode 100644 hermes_shm/include/hermes_shm/constants/constants.h create mode 100644 hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h create mode 100644 hermes_shm/include/hermes_shm/constants/macros.h create mode 100644 hermes_shm/include/hermes_shm/constants/singleton_macros.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/data_structure.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/pair.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/string.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/struct.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h create mode 100644 hermes_shm/include/hermes_shm/introspect/system_info.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/allocator.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/mp_page.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/multi_page_allocator.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h create mode 100644 hermes_shm/include/hermes_shm/memory/backend/array_backend.h create mode 100644 hermes_shm/include/hermes_shm/memory/backend/memory_backend.h create mode 100644 hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h create mode 100644 hermes_shm/include/hermes_shm/memory/backend/null_backend.h create mode 100644 hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h create mode 100644 hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h create mode 100644 hermes_shm/include/hermes_shm/memory/memory.h create mode 100644 hermes_shm/include/hermes_shm/memory/memory_manager.h create mode 100644 hermes_shm/include/hermes_shm/thread/lock.h create mode 100644 hermes_shm/include/hermes_shm/thread/lock/mutex.h create mode 100644 hermes_shm/include/hermes_shm/thread/lock/rwlock.h create mode 100644 hermes_shm/include/hermes_shm/thread/pthread.h create mode 100644 hermes_shm/include/hermes_shm/thread/thread.h create mode 100644 hermes_shm/include/hermes_shm/thread/thread_factory.h create mode 100644 hermes_shm/include/hermes_shm/thread/thread_manager.h create mode 100644 hermes_shm/include/hermes_shm/types/argpack.h create mode 100644 hermes_shm/include/hermes_shm/types/atomic.h create mode 100644 hermes_shm/include/hermes_shm/types/basic.h create mode 100644 hermes_shm/include/hermes_shm/types/bitfield.h create mode 100644 hermes_shm/include/hermes_shm/types/charbuf.h create mode 100644 hermes_shm/include/hermes_shm/types/messages.h create mode 100644 hermes_shm/include/hermes_shm/types/tuple_base.h create mode 100644 hermes_shm/include/hermes_shm/util/auto_trace.h create mode 100644 hermes_shm/include/hermes_shm/util/debug.h create mode 100644 hermes_shm/include/hermes_shm/util/error.h create mode 100644 hermes_shm/include/hermes_shm/util/errors.h create mode 100644 hermes_shm/include/hermes_shm/util/formatter.h create mode 100644 hermes_shm/include/hermes_shm/util/partitioner.h create mode 100644 hermes_shm/include/hermes_shm/util/path_parser.h create mode 100644 hermes_shm/include/hermes_shm/util/singleton.h create mode 100644 hermes_shm/include/hermes_shm/util/timer.h create mode 100644 hermes_shm/src/CMakeLists.txt create mode 100644 hermes_shm/src/data_structure_singleton.cc create mode 100644 hermes_shm/src/memory/malloc_allocator.cc create mode 100644 hermes_shm/src/memory/memory_intercept.cc create mode 100644 hermes_shm/src/memory/memory_intercept.h create mode 100644 hermes_shm/src/memory/memory_manager.cc create mode 100644 hermes_shm/src/memory/multi_page_allocator.cc create mode 100644 hermes_shm/src/memory/stack_allocator.cc create mode 100644 hermes_shm/src/thread/mutex.cc create mode 100644 hermes_shm/src/thread/rwlock.cc create mode 100644 hermes_shm/test/CMakeLists.txt create mode 100644 hermes_shm/test/unit/CMakeLists.txt create mode 100644 hermes_shm/test/unit/allocators/CMakeLists.txt create mode 100644 hermes_shm/test/unit/allocators/allocator.cc create mode 100644 hermes_shm/test/unit/allocators/allocator_thread.cc create mode 100644 hermes_shm/test/unit/allocators/test_init.cc create mode 100644 hermes_shm/test/unit/allocators/test_init.h create mode 100644 hermes_shm/test/unit/basic_test.h create mode 100644 hermes_shm/test/unit/data_structures/CMakeLists.txt create mode 100644 hermes_shm/test/unit/data_structures/backend/CMakeLists.txt create mode 100644 hermes_shm/test/unit/data_structures/backend/backend.cc create mode 100644 hermes_shm/test/unit/data_structures/backend/memory_manager.cc create mode 100644 hermes_shm/test/unit/data_structures/backend/memory_slots.cc create mode 100644 hermes_shm/test/unit/data_structures/backend/test_init.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/CMakeLists.txt create mode 100644 hermes_shm/test/unit/data_structures/containers/list.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/list.h create mode 100644 hermes_shm/test/unit/data_structures/containers/manual_ptr.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/pair.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/slist.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/smart_ptr.h create mode 100644 hermes_shm/test/unit/data_structures/containers/string.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/test_init.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/test_init.h create mode 100644 hermes_shm/test/unit/data_structures/containers/tuple.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/unordered_map.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/vector.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/vector.h create mode 100644 hermes_shm/test/unit/data_structures/containers_mpi/CMakeLists.txt create mode 100644 hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc create mode 100644 hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc create mode 100644 hermes_shm/test/unit/data_structures/containers_mpi/test_init.h create mode 100644 hermes_shm/test/unit/data_structures/lock/CMakeLists.txt create mode 100644 hermes_shm/test/unit/data_structures/lock/lock.cc create mode 100644 hermes_shm/test/unit/data_structures/lock/test_init.cc create mode 100644 hermes_shm/test/unit/main.cc create mode 100644 hermes_shm/test/unit/main_mpi.cc create mode 100644 hermes_shm/test/unit/types/CMakeLists.txt create mode 100644 hermes_shm/test/unit/types/test_argpack.cc create mode 100644 hermes_shm/test/unit/types/test_init.cc diff --git a/CMake/FindLabStor.cmake b/CMake/FindLabStor.cmake index 1b08efa2a..aa23f5165 100644 --- a/CMake/FindLabStor.cmake +++ b/CMake/FindLabStor.cmake @@ -1,15 +1,15 @@ -# Find labstor header and library. +# Find hermes_shm header and library. # # This module defines the following uncached variables: -# LabStor_FOUND, if false, do not try to use labstor. -# LabStor_INCLUDE_DIRS, where to find labstor.h. -# LabStor_LIBRARIES, the libraries to link against to use the labstor library -# LabStor_LIBRARY_DIRS, the directory where the labstor library is found. +# LabStor_FOUND, if false, do not try to use hermes_shm. +# LabStor_INCLUDE_DIRS, where to find hermes_shm.h. +# LabStor_LIBRARIES, the libraries to link against to use the hermes_shm library +# LabStor_LIBRARY_DIRS, the directory where the hermes_shm library is found. find_path( LabStor_INCLUDE_DIR - labstor/labstor.h + hermes_shm/hermes_shm.h ) if( LabStor_INCLUDE_DIR ) @@ -17,7 +17,7 @@ if( LabStor_INCLUDE_DIR ) find_library( LabStor_LIBRARY - NAMES labstor_data_structures + NAMES hermes_shm_data_structures ) if( LabStor_LIBRARY ) @@ -29,15 +29,15 @@ if( LabStor_INCLUDE_DIR ) set(LabStor_LIBRARIES ${LabStor_LIBRARY}) endif(LabStor_LIBRARY) else(LabStor_INCLUDE_DIR) - message(STATUS "Findlabstor: Could not find labstor.h") + message(STATUS "Findlabstor: Could not find hermes_shm.h") endif(LabStor_INCLUDE_DIR) if(LabStor_FOUND) if(NOT LabStor_FIND_QUIETLY) - message(STATUS "Findlabstor: Found both labstor.h and liblabstor.a") + message(STATUS "Findlabstor: Found both hermes_shm.h and liblabstor.a") endif(NOT LabStor_FIND_QUIETLY) else(LabStor_FOUND) if(LabStor_FIND_REQUIRED) - message(STATUS "Findlabstor: Could not find labstor.h and/or liblabstor.a") + message(STATUS "Findlabstor: Could not find hermes_shm.h and/or liblabstor.a") endif(LabStor_FIND_REQUIRED) endif(LabStor_FOUND) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1430282e5..cc56516ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -297,13 +297,6 @@ endif() find_path(GLOG_INCLUDE_DIRS NAME glog PATH_SUFFIXES include/) include_directories(${GLOG_INCLUDE_DIRS}) -# LabStor -find_package(LabStor REQUIRED) -if(LabStor_FOUND) - message(STATUS "found Labstor at ${LabStor_DIR}") -endif() -include_directories(${LabStor_INCLUDE_DIR}) - # GFLAGS if(HERMES_ENABLE_GFLAGS) find_package(gflags REQUIRED) @@ -406,15 +399,9 @@ endif() set(HERMES_EXPORTED_LIBS "") +include_directories(${CMAKE_SOURCE_DIR}/hermes_shm/include) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src) - -if(HERMES_HAVE_GOTCHA) - # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/gotcha_intercept) -endif() - -if(HERMES_BUILD_BUFFER_POOL_VISUALIZER AND SDL2_FOUND) - # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/buffer_pool_visualizer) -endif() +add_subdirectory(${CMAKE_SOURCE_DIR}/hermes_shm) # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/data_stager) diff --git a/benchmarks/put_get_bench.cc b/benchmarks/put_get_bench.cc index 92fa16e2c..40237bf58 100644 --- a/benchmarks/put_get_bench.cc +++ b/benchmarks/put_get_bench.cc @@ -11,13 +11,13 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include +#include #include #include "hermes.h" #include "bucket.h" namespace hapi = hermes::api; -using Timer = labstor::HighResMonotonicTimer; +using Timer = hermes_shm::HighResMonotonicTimer; void GatherTimes(std::string test_name, Timer &t) { MPI_Barrier(MPI_COMM_WORLD); diff --git a/code_generators/preamble.py b/code_generators/preamble.py index f728bfc0c..b55ea20d1 100644 --- a/code_generators/preamble.py +++ b/code_generators/preamble.py @@ -45,9 +45,9 @@ * Anthony Kougkas , * Xian-He Sun * - * This file is part of LabStor + * This file is part of HermesShm * - * LabStor is free software: you can redistribute it and/or modify + * HermesShm 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. diff --git a/hermes_shm/CMakeLists.txt b/hermes_shm/CMakeLists.txt new file mode 100644 index 000000000..2fe0d0424 --- /dev/null +++ b/hermes_shm/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +include_directories(${CMAKE_SOURCE_DIR}/include) + +###################OPTIONS +option(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" ON) +option(BUILD_MPI_TESTS "Build tests which depend on MPI" ON) +option(BUILD_OpenMP_TESTS "Build tests which depend on OpenMP" ON) +option(BUILD_Boost_TESTS "Build tests which depend on libboost" ON) + +##################CMAKE MODULES +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake) + +##################OPTIMIZATION +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + message("IN DEBUG MODE") + set(CMAKE_CXX_FLAGS "-g -O0") +elseif(CMAKE_BUILD_TYPE STREQUAL "Release") + message("IN RELEASE MODE") + set(CMAKE_CXX_FLAGS "-g -O3") +endif() +function(make_gprof exec_name exec_dir) + message("gprof -b -A -p -q ${exec_dir}/${exec_name} gmon.out > gprof_out.txt") + add_custom_target( + ${exec_name}_gprof + COMMAND gprof -b -A -p -q ${exec_dir}/${exec_name} gmon.out) +endfunction() + +##################REQUIRED EXTERNAL LIBRARIES + +# YAML-CPP +find_package(yaml-cpp REQUIRED) +message(STATUS "found yaml-cpp at ${yaml-cpp_DIR}") + +# Catch2 +find_package(Catch2 3.0.1 REQUIRED) +message(STATUS "found catch2.h at ${Catch2_CXX_INCLUDE_DIRS}") + +# MPICH +if(BUILD_MPI_TESTS) + find_package(MPI REQUIRED COMPONENTS C CXX) + message(STATUS "found mpi.h at ${MPI_CXX_INCLUDE_DIRS}") +endif() + +# OpenMP +if(BUILD_OpenMP_TESTS) + find_package(OpenMP REQUIRED COMPONENTS C CXX) + message(STATUS "found omp.h at ${OpenMP_CXX_INCLUDE_DIRS}") +endif() + +##################Build HermesShm main packages +add_subdirectory(src) + +##################MODULES & TESTS +set(TEST_MAIN ${CMAKE_SOURCE_DIR}/test/unit) +enable_testing() +add_subdirectory(test) \ No newline at end of file diff --git a/hermes_shm/include/hermes_shm/constants/constants.h b/hermes_shm/include/hermes_shm/constants/constants.h new file mode 100644 index 000000000..7328f1199 --- /dev/null +++ b/hermes_shm/include/hermes_shm/constants/constants.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_CONSTANTS_CONSTANTS_H_ +#define HERMES_SHM_CONSTANTS_CONSTANTS_H_ + +#include + +const char kLabStorRuntimeUrl[] = "labstor_runtime_url"; + +#endif // HERMES_SHM_CONSTANTS_CONSTANTS_H_ diff --git a/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h b/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h new file mode 100644 index 000000000..0390fefa1 --- /dev/null +++ b/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h @@ -0,0 +1,15 @@ +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_CONSTANTS_DATA_STRUCTURE_SINGLETON_MACROS_H_H +#define HERMES_SHM_INCLUDE_HERMES_SHM_CONSTANTS_DATA_STRUCTURE_SINGLETON_MACROS_H_H + +#include + +#define HERMES_SHM_SYSTEM_INFO scs::Singleton::GetInstance() +#define HERMES_SHM_SYSTEM_INFO_T hermes_shm::SystemInfo* + +#define HERMES_SHM_MEMORY_MANAGER scs::Singleton::GetInstance() +#define HERMES_SHM_MEMORY_MANAGER_T hermes_shm::ipc::MemoryManager* + +#define HERMES_SHM_THREAD_MANAGER scs::Singleton::GetInstance() +#define HERMES_SHM_THREAD_MANAGER_T hermes_shm::ThreadManager* + +#endif // include_labstor_constants_data_structure_singleton_macros_h diff --git a/hermes_shm/include/hermes_shm/constants/macros.h b/hermes_shm/include/hermes_shm/constants/macros.h new file mode 100644 index 000000000..31c39002e --- /dev/null +++ b/hermes_shm/include/hermes_shm/constants/macros.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_MACROS_H +#define HERMES_SHM_MACROS_H + +#define KILOBYTES(n) ((size_t)(n) * (1<<10)) +#define MEGABYTES(n) ((size_t)(n) * (1<<20)) +#define GIGABYTES(n) ((size_t)(n) * (1<<30)) + +#define TYPE_BITS(type) ((sizeof(type)*8)) + +#define TYPE_WRAP(...) (__VA_ARGS__) + +#define TYPE_UNWRAP(X) ESC(ISH X) +#define ISH(...) ISH __VA_ARGS__ +#define ESC(...) ESC_(__VA_ARGS__) +#define ESC_(...) VAN ## __VA_ARGS__ +#define VANISH + +#endif // HERMES_SHM_MACROS_H diff --git a/hermes_shm/include/hermes_shm/constants/singleton_macros.h b/hermes_shm/include/hermes_shm/constants/singleton_macros.h new file mode 100644 index 000000000..517ccb37d --- /dev/null +++ b/hermes_shm/include/hermes_shm/constants/singleton_macros.h @@ -0,0 +1,12 @@ +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_CONSTANTS_SINGLETON_MACROS_H_H +#define HERMES_SHM_INCLUDE_HERMES_SHM_CONSTANTS_SINGLETON_MACROS_H_H + +#include + +#define HERMES_SHM_IPC_MANAGER scs::Singleton::GetInstance() +#define HERMES_SHM_IPC_MANAGER_T hermes_shm::IpcManager* + +#define HERMES_SHM_CONFIGURATION_MANAGER scs::Singleton::GetInstance() +#define HERMES_SHM_CONFIGURATION_MANAGER_T hermes_shm::ConfigurationManager* + +#endif // include_labstor_constants_singleton_macros_h diff --git a/hermes_shm/include/hermes_shm/data_structures/data_structure.h b/hermes_shm/include/hermes_shm/data_structures/data_structure.h new file mode 100644 index 000000000..cc200ae83 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/data_structure.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_DATA_STRUCTURES_DATA_STRUCTURE_H_ +#define HERMES_SHM_DATA_STRUCTURES_DATA_STRUCTURE_H_ + +#include "internal/shm_archive.h" +#include "internal/shm_container.h" +#include "internal/shm_smart_ptr.h" +#include "internal/shm_macros.h" +#include "internal/shm_container.h" + +#endif // HERMES_SHM_DATA_STRUCTURES_DATA_STRUCTURE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h new file mode 100644 index 000000000..01473c036 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_DATA_STRUCTURES_SHM_ARCHIVE_H_ +#define HERMES_SHM_DATA_STRUCTURES_SHM_ARCHIVE_H_ + +#include "hermes_shm/memory/memory_manager.h" +#include "shm_macros.h" + +namespace hermes_shm::ipc { + +/** + * Indicates that a data structure can be stored directly in memory or + * shared memory. + * */ +class ShmPredictable {}; + +/** + * Indicates that a data structure can be archived in shared memory + * and has a corresponding TypedPointer override. + * */ +class ShmArchiveable : public ShmPredictable { + /** + * Initialize a SHM data structure in shared-memory. + * Constructors may wrap around these. + * */ + // void shm_init(...); + + /** + * Destroys the shared-memory allocated by the object. + * Destructors may wrap around this. + * */ + // void shm_destroy(); + + /** + * Deep copy of an object. Wrapped by copy constructor + * */ + // void shm_strong_copy(const CLASS_NAME &other); + // SHM_INHERIT_COPY_OPS(CLASS_NAME) + + /** + * Copies only the object's pointers. + * */ + // void WeakCopy(const CLASS_NAME &other); + + /** + * Moves the object's contents into another object + * */ + // void shm_weak_move(CLASS_NAME &other); + // SHM_INHERIT_MOVE_OPS(CLASS_NAME) + + /** + * Store object into a TypedPointer + * */ + // void shm_serialize(TypedPointer &ar) const; + // SHM_SERIALIZE_OPS(TYPED_CLASS) + + /** + * Construct object from a TypedPointer. + * */ + // void shm_deserialize(const TypedPointer &ar); + // SHM_DESERIALIZE_OPS(TYPED_CLASS) +}; + +/** + * Enables a specific TypedPointer type to be serialized + * */ +#define SHM_SERIALIZE_OPS(TYPED_CLASS)\ + void operator>>(lipc::TypedPointer &ar) const {\ + shm_serialize(ar);\ + }\ + void operator>>(lipc::TypedAtomicPointer &ar) const {\ + shm_serialize(ar);\ + } + +/** + * Enables a specific TypedPointer type to be deserialized + * */ +#define SHM_DESERIALIZE_OPS(TYPED_CLASS)\ + void operator<<(const lipc::TypedPointer &ar) {\ + shm_deserialize(ar);\ + }\ + void operator<<(\ + const lipc::TypedAtomicPointer &ar) {\ + shm_deserialize(ar);\ + } + +/** Enables serialization + deserialization for data structures */ +#define SHM_SERIALIZE_DESERIALIZE_OPS(AR_TYPE)\ + SHM_SERIALIZE_OPS(AR_TYPE)\ + SHM_DESERIALIZE_OPS(AR_TYPE) + + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_DATA_STRUCTURES_SHM_ARCHIVE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h new file mode 100644 index 000000000..bc3d9f5b3 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_DATA_STRUCTURES_SHM_AR_H_ +#define HERMES_SHM_DATA_STRUCTURES_SHM_AR_H_ + +#include "hermes_shm/memory/memory.h" +#include "hermes_shm/data_structures/data_structure.h" +#include "hermes_shm/types/tuple_base.h" + +namespace hermes_shm::ipc { + +/** + * Constructs a TypedPointer in-place + * */ +template +class _ShmHeaderOrT_Header { + public: + typedef typename T::header_t header_t; + header_t obj_hdr_; + + public: + /** Default constructor */ + _ShmHeaderOrT_Header() = default; + + /** Construct + store object */ + template + explicit _ShmHeaderOrT_Header(Allocator *alloc, Args&& ...args) { + T(obj_hdr_, alloc, std::forward(args)...).UnsetDestructable(); + } + + /** Construct + store object (hermes_shm rval argpack) */ + template + void PiecewiseInit(Allocator *alloc, + ArgPackT &&args) { + T obj; + PassArgPack::Call( + MergeArgPacks::Merge(make_argpack(obj, obj_hdr_, alloc), + std::forward(args)), + [](auto&& ...Args) constexpr { + Allocator::ConstructObj(std::forward(Args)...); + }); + obj.UnsetDestructable(); + } + + /** Destructor */ + ~_ShmHeaderOrT_Header() = default; + + /** Shm destructor */ + void shm_destroy(Allocator *alloc) { + auto ar = internal_ref(alloc); + T obj; + obj.shm_deserialize(ar); + obj.shm_destroy(); + } + + /** Returns a reference to the internal object */ + TypedPointer internal_ref(Allocator *alloc) { + return TypedPointer(alloc->Convert(&obj_hdr_)); + } + + /** Returns a reference to the internal object */ + TypedPointer internal_ref(Allocator *alloc) const { + return TypedPointer(alloc->Convert(&obj_hdr_)); + } + + /** Move constructor */ + _ShmHeaderOrT_Header(_ShmHeaderOrT_Header &&other) noexcept + : obj_hdr_(std::move(other.obj_hdr_)) {} + + /** Move assignment operator */ + _ShmHeaderOrT_Header& operator=(_ShmHeaderOrT_Header &&other) noexcept { + obj_hdr_ = std::move(other.obj_hdr_); + return *this; + } + + /** Copy constructor */ + _ShmHeaderOrT_Header(const _ShmHeaderOrT_Header &other) + : obj_hdr_(other.obj_hdr_) { + } + + /** Copy assignment operator */ + _ShmHeaderOrT_Header& operator=(const _ShmHeaderOrT_Header &other) { + obj_hdr_ = other.obj_hdr_; + } +}; + +/** + * Constructs an object in-place + * */ +template +class _ShmHeaderOrT_T { + public: + char obj_[sizeof(T)]; /**< Store object without constructing */ + + public: + /** Default constructor */ + _ShmHeaderOrT_T() { + Allocator::ConstructObj(internal_ref(nullptr)); + } + + /** Construct + store object (C++ argpack) */ + template + explicit _ShmHeaderOrT_T(Allocator *alloc, Args&& ...args) { + Allocator::ConstructObj( + internal_ref(alloc), std::forward(args)...); + } + + /** Construct + store object (hermes_shm rval argpack) */ + template + void PiecewiseInit(Allocator *alloc, + ArgPackT &&args) { + hermes_shm::PassArgPack::Call( + MergeArgPacks::Merge( + make_argpack(internal_ref(alloc)), + std::forward(args)), + [](auto&& ...Args) constexpr { + Allocator::ConstructObj(std::forward(Args)...); + }); + } + + /** Shm destructor */ + void shm_destroy(Allocator *alloc) {} + + /** Destructor. Does nothing. */ + ~_ShmHeaderOrT_T() = default; + + /** Returns a reference to the internal object */ + T& internal_ref(Allocator *alloc) { + (void) alloc; + return reinterpret_cast(obj_); + } + + /** Returns a reference to the internal object */ + T& internal_ref(Allocator *alloc) const { + (void) alloc; + return reinterpret_cast(obj_); + } + + /** Move constructor */ + _ShmHeaderOrT_T(_ShmHeaderOrT_T &&other) noexcept { + Allocator::ConstructObj<_ShmHeaderOrT_T>( + obj_, std::move(other.internal_ref())); + } + + /** Move assignment operator */ + _ShmHeaderOrT_T& operator=(_ShmHeaderOrT_T &&other) noexcept { + internal_ref() = std::move(other.internal_ref()); + return *this; + } + + /** Copy constructor */ + _ShmHeaderOrT_T(const _ShmHeaderOrT_T &other) { + Allocator::ConstructObj<_ShmHeaderOrT_T>( + obj_, other); + } + + /** Copy assignment operator */ + _ShmHeaderOrT_T& operator=(const _ShmHeaderOrT_T &other) { + internal_ref() = other.internal_ref(); + return *this; + } +}; + +/** + * Whether or not to use _ShmHeaderOrT or _ShmHeaderOrT_T + * */ +#define SHM_MAKE_HEADER_OR_T(T) \ + SHM_X_OR_Y(T, _ShmHeaderOrT_Header, _ShmHeaderOrT_T) + +/** + * Used for data structures which intend to store: + * 1. An archive if the data type is SHM_ARCHIVEABLE + * 2. The raw type if the data type is anything else + * + * E.g., used in unordered_map for storing collision entries. + * E.g., used in a list for storing list entries. + * */ +template +class ShmHeaderOrT { + public: + typedef SHM_ARCHIVE_OR_REF(T) T_Ar; + typedef SHM_MAKE_HEADER_OR_T(T) T_Hdr; + T_Hdr obj_; + + /** Default constructor */ + ShmHeaderOrT() = default; + + /** Construct + store object */ + template + explicit ShmHeaderOrT(Args&& ...args) + : obj_(std::forward(args)...) {} + + /** Construct + store object (hermes_shm rval argpack) */ + template + void PiecewiseInit(Allocator *alloc, ArgPackT &&args) { + obj_.PiecewiseInit(alloc, std::forward(args)); + } + + /** Destructor */ + ~ShmHeaderOrT() = default; + + /** Returns a reference to the internal object */ + T_Ar internal_ref(Allocator *alloc) { + return obj_.internal_ref(alloc); + } + + /** Returns a reference to the internal object */ + T_Ar internal_ref(Allocator *alloc) const { + return obj_.internal_ref(alloc); + } + + /** Shm destructor */ + void shm_destroy(Allocator *alloc) { + obj_.shm_destroy(alloc); + } + + /** Move constructor */ + ShmHeaderOrT(ShmHeaderOrT &&other) noexcept + : obj_(std::move(other.obj_)) {} + + /** Move assignment operator */ + ShmHeaderOrT& operator=(ShmHeaderOrT &&other) noexcept { + obj_ = std::move(other.obj_); + return *this; + } + + /** Copy constructor */ + ShmHeaderOrT(const ShmHeaderOrT &other) + : obj_(other.obj_) {} + + /** Copy assignment operator */ + ShmHeaderOrT& operator=(const ShmHeaderOrT &other) { + obj_ = other.obj_; + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_DATA_STRUCTURES_SHM_AR_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h new file mode 100644 index 000000000..6fffc637a --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_SHM_CONTAINER_H_ +#define HERMES_SHM_SHM_CONTAINER_H_ + +#include "hermes_shm/memory/memory_manager.h" +#include "hermes_shm/constants/macros.h" +#include "shm_container_macro.h" +#include "shm_macros.h" +#include "shm_archive.h" +#include "shm_ref.h" +#include "shm_deserialize.h" + +namespace lipc = hermes_shm::ipc; + +namespace hermes_shm::ipc { + +/** Bits used for determining how to destroy an object */ +/// The container's header has been allocated +#define SHM_CONTAINER_VALID BIT_OPT(uint16_t, 0) +/// The container header is initialized +#define SHM_CONTAINER_DATA_VALID BIT_OPT(uint16_t, 1) +/// The header was allocated by this container +#define SHM_CONTAINER_HEADER_DESTRUCTABLE BIT_OPT(uint16_t, 2) +/// The container should free all data when destroyed +#define SHM_CONTAINER_DESTRUCTABLE BIT_OPT(uint16_t, 3) + +/** The shared-memory header used for data structures */ +template +struct ShmHeader; + +/** The ShmHeader used for base containers */ +struct ShmBaseHeader { + bitfield32_t flags_; + + /** Default constructor */ + ShmBaseHeader() = default; + + /** Copy constructor */ + ShmBaseHeader(const ShmBaseHeader &other) {} + + /** Copy assignment operator */ + ShmBaseHeader& operator=(const ShmBaseHeader &other) { + return *this; + } + + /** + * Disable copying of the flag field, as all flags + * pertain to a particular ShmHeader allocation. + * */ + void strong_copy(const ShmBaseHeader &other) {} + + /** Publicize bitfield operations */ + INHERIT_BITFIELD_OPS(flags_, uint16_t) +}; + +/** The ShmHeader used for wrapper containers */ +struct ShmWrapperHeader {}; + +/** + * ShmContainers all have a header, which is stored in + * shared memory as a TypedPointer. + * */ +class ShmContainer : public ShmArchiveable {}; + +/** Typed nullptr */ +template +static inline T* typed_nullptr() { + return reinterpret_cast(NULL); +} + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_SHM_CONTAINER_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h new file mode 100644 index 000000000..fa6376515 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h @@ -0,0 +1,243 @@ +#ifndef HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ +#define HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ +#define SHM_CONTAINER_EXTEND_TEMPLATE(CLASS_NAME,TYPED_CLASS,TYPED_HEADER)\ +public:\ +/**====================================\ + * Variables & Types\ + *===================================*/\ +\ +typedef TYPE_UNWRAP(TYPED_HEADER) header_t; /**< Required by all ShmContainers */\ +header_t *header_; /**< The shared-memory header for this container */\ +ContainerT obj_; /**< The object being wrapped around */\ +\ +public:\ +/**====================================\ + * Constructors\ + * ===================================*/\ +\ +/** Constructor. Allocate header with default allocator. */\ +template\ +explicit TYPE_UNWRAP(CLASS_NAME)(Args &&...args) {\ +shm_init(std::forward(args)...);\ +}\ +\ +/** Constructor. Allocate header with default allocator. */\ +template\ +void shm_init(Args &&...args) {\ +}\ +\ +/**====================================\ + * Serialization\ + * ===================================*/\ +\ +/** Serialize into a Pointer */\ +void shm_serialize(TypedPointer &ar) const {\ + obj_.shm_serialize(ar);\ +}\ +\ +/** Serialize into an AtomicPointer */\ +void shm_serialize(TypedAtomicPointer &ar) const {\ + obj_.shm_serialize(ar);\ +}\ +\ +/** Override << operators */\ +SHM_SERIALIZE_OPS((TYPE_UNWRAP(TYPED_CLASS)))\ +\ +/**====================================\ + * Deserialization\ + * ===================================*/\ +\ +/** Deserialize object from a raw pointer */\ +bool shm_deserialize(const TypedPointer &ar) {\ + return obj_.shm_deserialize(ar);\ +}\ +\ +/** Deserialize object from allocator + offset */\ +bool shm_deserialize(Allocator *alloc, OffsetPointer header_ptr) {\ + return obj_.shm_deserialize(alloc, header_ptr);\ +}\ +\ +/** Deserialize object from another object (weak copy) */\ +bool shm_deserialize(const TYPE_UNWRAP(CLASS_NAME) &other) {\ + return obj_.shm_deserialize(other);\ +}\ +\ +/** Deserialize object from allocator + header */\ +bool shm_deserialize(Allocator *alloc,\ + TYPE_UNWRAP(TYPED_HEADER) *header) {\ + return obj_.shm_deserialize(alloc, header);\ +}\ +\ +/** Constructor. Deserialize the object from the reference. */\ +template\ +void shm_init(lipc::ShmRef &obj) {\ + shm_deserialize(obj->GetAllocator(), obj->header_);\ +}\ +\ +/** Override >> operators */\ +SHM_DESERIALIZE_OPS ((TYPE_UNWRAP(TYPED_CLASS)))\ +\ +/**====================================\ + * Destructors\ + * ===================================*/\ +\ +/** Destructor */\ +~TYPE_UNWRAP(CLASS_NAME)() {\ + obj_.shm_destroy(true);\ +}\ +\ +/** Shm Destructor */\ +void shm_destroy(bool destroy_header = true) {\ + obj_.shm_destroy(false);\ + if (!IsValid()) { return; }\ + if (IsDataValid()) {\ + shm_destroy_main();\ + }\ + UnsetDataValid();\ + if (destroy_header &&\ + obj_.header_->OrBits(SHM_CONTAINER_HEADER_DESTRUCTABLE)) {\ + GetAllocator()->template\ + FreePtr(header_);\ + UnsetValid();\ + }\ +}\ +\ +/**====================================\ + * Move Operations\ + * ===================================*/\ +\ +/** Move constructor */\ +TYPE_UNWRAP(CLASS_NAME)(TYPE_UNWRAP(CLASS_NAME) &&other) noexcept\ +: obj_(std::move(other)) {}\ +\ +/** Move assignment operator */\ +TYPE_UNWRAP(CLASS_NAME)& operator=(TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ +obj_ = std::move(other.obj_);\ +return *this;\ +}\ +\ +/** Move shm_init constructor */\ +void shm_init_main(TYPE_UNWRAP(TYPED_HEADER) *header,\ + lipc::Allocator *alloc,\ + TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ + shm_weak_move(header, alloc, other);\ +}\ +\ +/** Move operation */\ +void shm_weak_move(TYPE_UNWRAP(TYPED_HEADER) *header,\ + lipc::Allocator *alloc,\ + TYPE_UNWRAP(CLASS_NAME) &other) {\ + obj_.shm_weak_move(header, alloc, other);\ +}\ +\ +/**====================================\ + * Copy Operations\ + * ===================================*/\ +\ +/** Copy constructor */\ +TYPE_UNWRAP(CLASS_NAME)(const TYPE_UNWRAP(CLASS_NAME) &other) noexcept {\ + shm_init(other);\ +}\ +\ +/** Copy assignment constructor */\ +TYPE_UNWRAP(CLASS_NAME) &operator=(const TYPE_UNWRAP(CLASS_NAME) &other) {\ + if (this != &other) {\ + shm_strong_copy(\ + typed_nullptr(),\ + typed_nullptr(),\ + other);\ + }\ + return *this;\ +}\ +\ +/** Copy shm_init constructor */\ +void shm_init_main(TYPE_UNWRAP(TYPED_HEADER) *header,\ + lipc::Allocator *alloc,\ + const TYPE_UNWRAP(CLASS_NAME) &other) {\ + shm_strong_copy(header, alloc, other);\ +}\ +\ +/** Strong Copy operation */\ +void shm_strong_copy(TYPE_UNWRAP(TYPED_HEADER) *header, lipc::Allocator *alloc,\ + const TYPE_UNWRAP(CLASS_NAME) &other) {\ + if (other.IsNull()) { return; }\ + shm_destroy(false);\ + shm_strong_copy_main(header, alloc, other);\ + SetDestructable();\ +}\ +\ +/**====================================\ + * Container Flag Operations\ + * ===================================*/\ +\ +/** Sets this object as destructable */\ +void SetDestructable() {\ + obj_.SetDestructable();\ +}\ +\ +/** Sets this object as not destructable */\ +void UnsetDestructable() {\ + obj_.UnsetDestructable();\ +}\ +\ +/** Check if this container is destructable */\ +bool IsDestructable() const {\ + return obj_.IsDestructable();\ +}\ +\ +/** Check if container has a valid header */\ +bool IsValid() const {\ + return obj_.IsValid();\ +}\ +\ +/** Set container header invalid */\ +void UnsetValid() {\ + obj_.UnsetValid();\ +}\ +\ +/**====================================\ + * Header Flag Operations\ + * ===================================*/\ +\ +/** Check if header's data is valid */\ +bool IsDataValid() const {\ + return obj_.IsDataValid();\ +}\ +\ +/** Check if header's data is valid */\ +void UnsetDataValid() const {\ + return obj_.UnsetDataValid();\ +}\ +\ +/** Check if null */\ +bool IsNull() const {\ + return obj_.IsNull();\ +}\ +\ +/** Get a typed pointer to the object */\ +template\ +POINTER_T GetShmPointer() const {\ + return GetAllocator()->template\ + Convert(header_);\ +}\ +\ +/**====================================\ + * Query Operations\ + * ===================================*/\ +\ +/** Get the allocator for this container */\ +Allocator* GetAllocator() {\ + return obj_.GetAllocator();\ +}\ +\ +/** Get the allocator for this container */\ +Allocator* GetAllocator() const {\ + return obj_.GetAllocator();\ +}\ +\ +/** Get the shared-memory allocator id */\ +allocator_id_t GetAllocatorId() const {\ + return GetAllocator()->GetId();\ +}\ + +#endif // HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h new file mode 100644 index 000000000..fa354b1e9 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h @@ -0,0 +1,348 @@ +#ifndef HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ +#define HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ +#define SHM_CONTAINER_TEMPLATE(CLASS_NAME,TYPED_CLASS,TYPED_HEADER)\ +public:\ +/**====================================\ + * Variables & Types\ + * ===================================*/\ +\ +typedef TYPE_UNWRAP(TYPED_HEADER) header_t; /** Header type query */\ +header_t *header_; /**< Header of the shared-memory data structure */\ +lipc::Allocator *alloc_; /**< lipc::Allocator used for this data structure */\ +hermes_shm::bitfield32_t flags_; /**< Flags used data structure status */\ +\ +public:\ +/**====================================\ + * Constructors\ + * ===================================*/\ +\ +/** Constructor. Allocate header with default allocator. */\ +template\ +explicit TYPE_UNWRAP(CLASS_NAME)(Args&& ...args) {\ +shm_init(std::forward(args)...);\ +}\ +\ +/** Constructor. Allocate header with default allocator. */\ +template\ +void shm_init(Args&& ...args) {\ + shm_destroy(false);\ + shm_init_main(lipc::typed_nullptr(),\ + lipc::typed_nullptr(),\ + std::forward(args)...);\ +}\ +\ +/** Constructor. Allocate header with specific allocator. */\ +template\ +void shm_init(lipc::Allocator *alloc, Args&& ...args) {\ + shm_destroy(false);\ + shm_init_main(lipc::typed_nullptr(),\ + alloc,\ + std::forward(args)...);\ +}\ +\ +/** Constructor. Initialize an already-allocated header. */\ +template\ +void shm_init(TYPE_UNWRAP(TYPED_HEADER) &header,\ + lipc::Allocator *alloc, Args&& ...args) {\ + shm_destroy(false);\ + shm_init_main(&header, alloc, std::forward(args)...);\ +}\ +\ +/** Initialize the data structure's allocator */\ +inline void shm_init_allocator(lipc::Allocator *alloc) {\ + if (IsValid()) { return; }\ + if (alloc == nullptr) {\ + alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator();\ + } else {\ + alloc_ = alloc;\ + }\ +}\ +\ +/**\ + * Initialize a data structure's header.\ + * A container will never re-set or re-allocate its header once it has\ + * been set the first time.\ + * */\ +template\ +void shm_init_header(TYPE_UNWRAP(TYPED_HEADER) *header,\ + Args&& ...args) {\ + if (IsValid()) {\ + header_->SetBits(SHM_CONTAINER_DATA_VALID);\ + } else if (header == nullptr) {\ + lipc::Pointer p;\ + header_ = alloc_->template\ + AllocateConstructObjs(\ + 1, p, std::forward(args)...);\ + header_->SetBits(\ + SHM_CONTAINER_DATA_VALID |\ + SHM_CONTAINER_HEADER_DESTRUCTABLE);\ + flags_.SetBits(\ + SHM_CONTAINER_VALID |\ + SHM_CONTAINER_DESTRUCTABLE);\ + } else {\ + lipc::Pointer header_ptr;\ + header_ = header;\ + lipc::Allocator::ConstructObj(\ + *header_, std::forward(args)...);\ + header_->SetBits(\ + SHM_CONTAINER_DATA_VALID);\ + flags_.SetBits(\ + SHM_CONTAINER_VALID |\ + SHM_CONTAINER_DESTRUCTABLE);\ + }\ +}\ +\ +/**====================================\ + * Serialization\ + * ===================================*/\ +\ +/** Serialize into a Pointer */\ +void shm_serialize(lipc::TypedPointer &ar) const {\ + ar = alloc_->template\ + Convert(header_);\ + shm_serialize_main();\ +}\ +\ +/** Serialize into an AtomicPointer */\ +void shm_serialize(lipc::TypedAtomicPointer &ar) const {\ + ar = alloc_->template\ + Convert(header_);\ + shm_serialize_main();\ +}\ +\ +/** Override << operators */\ +SHM_SERIALIZE_OPS((TYPE_UNWRAP(TYPED_CLASS)))\ +\ +/**====================================\ + * Deserialization\ + * ===================================*/\ +\ +/** Deserialize object from a raw pointer */\ +bool shm_deserialize(const lipc::TypedPointer &ar) {\ + return shm_deserialize(\ + HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_),\ + ar.ToOffsetPointer()\ + );\ +}\ +\ +/** Deserialize object from allocator + offset */\ +bool shm_deserialize(lipc::Allocator *alloc, lipc::OffsetPointer header_ptr) {\ + if (header_ptr.IsNull()) { return false; }\ + return shm_deserialize(alloc,\ + alloc->Convert<\ + TYPE_UNWRAP(TYPED_HEADER),\ + lipc::OffsetPointer>(header_ptr));\ +}\ +\ +/** Deserialize object from another object (weak copy) */\ +bool shm_deserialize(const TYPE_UNWRAP(CLASS_NAME) &other) {\ + if (other.IsNull()) { return false; }\ + return shm_deserialize(other.GetAllocator(), other.header_);\ +}\ +\ +/** Deserialize object from allocator + header */\ +bool shm_deserialize(lipc::Allocator *alloc,\ + TYPE_UNWRAP(TYPED_HEADER) *header) {\ + flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE);\ + alloc_ = alloc;\ + header_ = header;\ + flags_.SetBits(SHM_CONTAINER_VALID);\ + shm_deserialize_main();\ + return true;\ +}\ +\ +/** Constructor. Deserialize the object from the reference. */\ +template\ +void shm_init(lipc::ShmRef &obj) {\ + shm_deserialize(obj->GetAllocator(), obj->header_);\ +}\ +\ +/** Override >> operators */\ +SHM_DESERIALIZE_OPS((TYPE_UNWRAP(TYPED_CLASS)))\ +\ +/**====================================\ + * Destructors\ + * ===================================*/\ +\ +/** Destructor */\ +~TYPE_UNWRAP(CLASS_NAME)() {\ + if (IsDestructable()) {\ + shm_destroy(true);\ + }\ +}\ +\ +/** Shm Destructor */\ +void shm_destroy(bool destroy_header = true) {\ + if (!IsValid()) { return; }\ + if (IsDataValid()) {\ + shm_destroy_main();\ + }\ + UnsetDataValid();\ + if (destroy_header &&\ + header_->OrBits(SHM_CONTAINER_HEADER_DESTRUCTABLE)) {\ + alloc_->FreePtr(header_);\ + UnsetValid();\ + }\ +}\ +\ +/**====================================\ + * Move Operations\ + * ===================================*/\ +\ +/** Move constructor */\ +TYPE_UNWRAP(CLASS_NAME)(TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ +shm_weak_move(\ + lipc::typed_nullptr(),\ + lipc::typed_nullptr(),\ + other);\ +}\ +\ +/** Move assignment operator */\ +TYPE_UNWRAP(CLASS_NAME)& operator=(TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ +if (this != &other) {\ +shm_weak_move(\ + lipc::typed_nullptr(),\ + lipc::typed_nullptr(),\ + other);\ +}\ +return *this;\ +}\ +\ +/** Move shm_init constructor */\ +void shm_init_main(TYPE_UNWRAP(TYPED_HEADER) *header,\ + lipc::Allocator *alloc,\ + TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ + shm_weak_move(header, alloc, other);\ +}\ +\ +/** Move operation */\ +void shm_weak_move(TYPE_UNWRAP(TYPED_HEADER) *header,\ + lipc::Allocator *alloc,\ + TYPE_UNWRAP(CLASS_NAME) &other) {\ + if (other.IsNull()) { return; }\ + if (IsValid() && other.GetAllocator() != GetAllocator()) {\ + shm_strong_copy(header, alloc, other);\ + other.shm_destroy(true);\ + return;\ + }\ + shm_destroy(false);\ + shm_weak_move_main(header, alloc, other);\ + if (!other.IsDestructable()) {\ + UnsetDestructable();\ + }\ + other.UnsetDataValid();\ + other.shm_destroy(true);\ +}\ +\ +/**====================================\ + * Copy Operations\ + * ===================================*/\ +\ +/** Copy constructor */\ +TYPE_UNWRAP(CLASS_NAME)(const TYPE_UNWRAP(CLASS_NAME) &other) noexcept {\ + shm_init(other);\ +}\ +\ +/** Copy assignment constructor */\ +TYPE_UNWRAP(CLASS_NAME)& operator=(const TYPE_UNWRAP(CLASS_NAME) &other) {\ + if (this != &other) {\ + shm_strong_copy(\ + lipc::typed_nullptr(),\ + lipc::typed_nullptr(),\ + other);\ + }\ + return *this;\ +}\ +\ +/** Copy shm_init constructor */\ +void shm_init_main(TYPE_UNWRAP(TYPED_HEADER) *header,\ + lipc::Allocator *alloc,\ + const TYPE_UNWRAP(CLASS_NAME) &other) {\ + shm_strong_copy(header, alloc, other);\ +}\ +\ +/** Strong Copy operation */\ +void shm_strong_copy(TYPE_UNWRAP(TYPED_HEADER) *header,\ + lipc::Allocator *alloc,\ + const TYPE_UNWRAP(CLASS_NAME) &other) {\ + if (other.IsNull()) { return; }\ + shm_destroy(false);\ + shm_strong_copy_main(header, alloc, other);\ + SetDestructable();\ +}\ +\ +/**====================================\ + * Container Flag Operations\ + * ===================================*/\ +\ +/** Sets this object as destructable */\ +void SetDestructable() {\ + flags_.SetBits(SHM_CONTAINER_DESTRUCTABLE);\ +}\ +\ +/** Sets this object as not destructable */\ +void UnsetDestructable() {\ + flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE);\ +}\ +\ +/** Check if this container is destructable */\ +bool IsDestructable() const {\ + return flags_.OrBits(SHM_CONTAINER_DESTRUCTABLE);\ +}\ +\ +/** Check if container has a valid header */\ +bool IsValid() const {\ + return flags_.OrBits(SHM_CONTAINER_VALID);\ +}\ +\ +/** Set container header invalid */\ +void UnsetValid() {\ + flags_.UnsetBits(SHM_CONTAINER_VALID |\ + SHM_CONTAINER_DESTRUCTABLE | SHM_CONTAINER_HEADER_DESTRUCTABLE);\ +}\ +\ +/**====================================\ + * Header Flag Operations\ + * ===================================*/\ +\ +/** Check if header's data is valid */\ +bool IsDataValid() const {\ + return header_->OrBits(SHM_CONTAINER_DATA_VALID);\ +}\ +\ +/** Check if header's data is valid */\ +void UnsetDataValid() const {\ + header_->UnsetBits(SHM_CONTAINER_DATA_VALID);\ +}\ +\ +/** Check if null */\ +bool IsNull() const {\ + return !IsValid() || !IsDataValid();\ +}\ +\ +/** Get a typed pointer to the object */\ +template\ +POINTER_T GetShmPointer() const {\ + return alloc_->Convert(header_);\ +}\ +\ +/**====================================\ + * Query Operations\ + * ===================================*/\ +\ +/** Get the allocator for this container */\ +lipc::Allocator* GetAllocator() {\ + return alloc_;\ +}\ +\ +/** Get the allocator for this container */\ +lipc::Allocator* GetAllocator() const {\ + return alloc_;\ +}\ +\ +/** Get the shared-memory allocator id */\ +lipc::allocator_id_t GetAllocatorId() const {\ + return alloc_->GetId();\ +}\ + +#endif // HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h new file mode 100644 index 000000000..c193984fa --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h @@ -0,0 +1,84 @@ +// +// Created by lukemartinlogan on 1/24/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ + +#include "hermes_shm/memory/memory_manager.h" + +namespace hermes_shm::ipc { + +/** + * The parameters used to deserialize an object. + * */ +template +struct ShmDeserialize { + public: + typedef typename ContainerT::header_t header_t; + Allocator *alloc_; + header_t *header_; + + public: + /** Default constructor */ + ShmDeserialize() = default; + + /** Construct from TypedPointer */ + ShmDeserialize(const TypedPointer &ar) { + alloc_ = HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_); + header_ = alloc_->Convert< + TypedPointer, + OffsetPointer>(ar.ToOffsetPointer()); + } + + /** Construct from allocator + offset pointer */ + ShmDeserialize(Allocator *alloc, TypedOffsetPointer &ar) { + alloc_ = alloc; + header_ = alloc_->Convert< + TypedPointer, + OffsetPointer>(ar.ToOffsetPointer()); + } + + /** Construct from allocator + offset pointer */ + ShmDeserialize(Allocator *alloc, header_t *header) { + alloc_ = alloc; + header_ = header; + } + + /** Copy constructor */ + ShmDeserialize(const ShmDeserialize &other) { + shm_strong_copy(other); + } + + /** Copy assign operator */ + ShmDeserialize& operator=(const ShmDeserialize &other) { + shm_strong_copy(other); + return *this; + } + + /** Copy operation */ + void shm_strong_copy(const ShmDeserialize &other) { + alloc_ = other.alloc_; + header_ = other.header_; + } + + /** Move constructor */ + ShmDeserialize(ShmDeserialize &&other) { + shm_weak_move(other); + } + + /** Move assign operator */ + ShmDeserialize& operator=(ShmDeserialize &&other) { + shm_weak_move(); + return *this; + } + + /** Move operation */ + void shm_weak_move(ShmDeserialize &other) { + shm_strong_copy(other); + } +}; + +} // namespace hermes_shm::ipc + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h new file mode 100644 index 000000000..e62738172 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_MEMORY_SHM_MACROS_H_ +#define HERMES_SHM_MEMORY_SHM_MACROS_H_ + +#include + +/** + * Determine whether or not \a T type is designed for shared memory + * */ +#define IS_SHM_ARCHIVEABLE(T) \ + std::is_base_of::value + +/** + * Determine whether or not \a T type is a SHM smart pointer + * */ +#define IS_SHM_SMART_POINTER(T) \ + std::is_base_of::value + +/** + * SHM_X_OR_Y: X if T is SHM_SERIALIZEABLE, Y otherwise + * */ +#define SHM_X_OR_Y(T, X, Y) \ + typename std::conditional< \ + IS_SHM_ARCHIVEABLE(T), \ + X, Y>::type + +/** + * SHM_T_OR_PTR_T: Returns T if SHM_ARCHIVEABLE, and T* otherwise. Used + * internally by lipc::ShmRef. + * + * @param T: The type being stored in the shmem data structure + * */ +#define SHM_T_OR_PTR_T(T) \ + SHM_X_OR_Y(T, T, T*) + +/** + * ShmHeaderOrT: Returns TypedPointer if SHM_ARCHIVEABLE, and T + * otherwise. Used to construct an lipc::ShmRef. + * + * @param T The type being stored in the shmem data structure + * */ +#define SHM_ARCHIVE_OR_T(T) \ + SHM_X_OR_Y(T, lipc::TypedPointer, T) + +/** + * SHM_T_OR_SHM_STRUCT_T: Used by unique_ptr and manual_ptr to internally + * store either a shm-compatible type or a POD (piece of data) type. + * + * @param T: The type being stored in the shmem data structure + * */ +#define SHM_T_OR_SHM_STRUCT_T(T) \ + SHM_X_OR_Y(T, T, ShmStruct) + +/** + * SHM_T_OR_CONST_T: Determines whether or not an object should be + * a constant or not. + * */ +#define SHM_CONST_T_OR_T(T, IS_CONST) \ + typename std::conditional< \ + IS_CONST, \ + const T, T>::type + +/** + * SHM_ARCHIVE_OR_REF: Return value of shm_ar::internal_ref(). + * */ +#define SHM_ARCHIVE_OR_REF(T)\ + SHM_X_OR_Y(T, TypedPointer, T&) + +#endif // HERMES_SHM_MEMORY_SHM_MACROS_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h new file mode 100644 index 000000000..f03aed0ba --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h @@ -0,0 +1,119 @@ +// +// Created by lukemartinlogan on 1/27/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ + +#include "shm_container.h" +#include + +namespace hermes_shm::ipc { + +/** forward declaration for string */ +class NullContainer; + +/** + * MACROS used to simplify the string namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ +#define CLASS_NAME NullContainer +#define TYPED_CLASS NullContainer +#define TYPED_HEADER ShmHeader + +/** string shared-memory header */ +template<> +struct ShmHeader : public ShmBaseHeader { + /** Default constructor */ + ShmHeader() = default; + + /** Copy constructor */ + ShmHeader(const ShmHeader &other) { + strong_copy(other); + } + + /** Copy assignment operator */ + ShmHeader& operator=(const ShmHeader &other) { + if (this != &other) { + strong_copy(other); + } + return *this; + } + + /** Strong copy operation */ + void strong_copy(const ShmHeader &other) {} + + /** Move constructor */ + ShmHeader(ShmHeader &&other) { + weak_move(other); + } + + /** Move operator */ + ShmHeader& operator=(ShmHeader &&other) { + if (this != &other) { + weak_move(other); + } + return *this; + } + + /** Move operation */ + void weak_move(ShmHeader &other) { + strong_copy(other); + } +}; + +/** + * A string of characters. + * */ +class NullContainer : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) + + public: + //////////////////////////// + /// SHM Overrides + //////////////////////////// + + /** Default constructor */ + NullContainer() = default; + + /** Default shm constructor */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header); + } + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, + NullContainer &other) {} + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, + const NullContainer &other) {} + + /** + * Destroy the shared-memory data. + * */ + void shm_destroy_main() {} + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} +}; + +} // namespace hermes_shm::ipc + +namespace std { + +} // namespace std + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h new file mode 100644 index 000000000..896a54329 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h @@ -0,0 +1,193 @@ +// +// Created by lukemartinlogan on 1/15/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ + +#include "hermes_shm/constants/macros.h" +#include "shm_macros.h" +#include "shm_archive.h" + +namespace hermes_shm::ipc { + +/** + * A ShmReference to a shared-memory object + * */ +template +struct _ShmRefShm { + T obj_; + + /** Default constructor */ + _ShmRefShm() = default; + + /** Destructor */ + ~_ShmRefShm() { + obj_.UnsetDestructable(); + } + + /** Constructor. */ + explicit _ShmRefShm(TypedPointer other) { + obj_.shm_deserialize(other); + } + + /** Copy constructor */ + _ShmRefShm(const _ShmRefShm &other) { + obj_.shm_deserialize(other.obj_); + } + + /** Move constructor */ + _ShmRefShm(_ShmRefShm &&other) noexcept { + obj_.shm_deserialize(other.obj_); + } + + /** Copy assign operator */ + _ShmRefShm& operator=(const _ShmRefShm &other) { + if (this != &other) { + obj_.shm_deserialize(other.obj_); + } + return *this; + } + + /** Move assign operator */ + _ShmRefShm& operator=(_ShmRefShm &&other) noexcept { + if (this != &other) { + obj_.shm_deserialize(other.obj_); + } + return *this; + } + + /** Get ShmReference to the internal data structure */ + T& get_ref() { + return obj_; + } + + /** Get a constant ShmReference */ + const T& get_ref_const() const { + return obj_; + } +}; + +/** + * A ShmReference to a POD type stored in shared memory. + * */ +template +struct _ShmRefNoShm { + T *obj_; + + /** Default constructor */ + _ShmRefNoShm() = default; + + /** Constructor. */ + explicit _ShmRefNoShm(T &other) { + obj_ = &other; + } + + /** Copy constructor */ + _ShmRefNoShm(const _ShmRefNoShm &other) { + obj_ = other.obj_; + } + + /** Move constructor */ + _ShmRefNoShm(_ShmRefNoShm &&other) noexcept { + obj_ = other.obj_; + } + + /** Copy assign operator */ + _ShmRefNoShm& operator=(const _ShmRefNoShm &other) { + if (this != &other) { + obj_ = other.obj_; + } + return *this; + } + + /** Move assign operator */ + _ShmRefNoShm& operator=(_ShmRefNoShm &&other) noexcept { + if (this != &other) { + obj_ = other.obj_; + } + return *this; + } + + /** Get ShmReference to the internal data structure */ + T& get_ref() { + return *obj_; + } + + /** Get a constant ShmReference */ + const T& get_ref_const() const { + return *obj_; + } +}; + +/** Determine whether ShmRef stores _ShmRefShm or _ShmRefNoShm */ +#define CHOOSE_SHM_ShmRef_TYPE(T) SHM_X_OR_Y(T, _ShmRefShm, _ShmRefNoShm) + +/** + * A Reference to a shared-memory object or a simple object + * stored in shared-memory. + * */ +template +struct ShmRef { + typedef CHOOSE_SHM_ShmRef_TYPE(T) T_ShmRef; + T_ShmRef obj_; + + /** Constructor. */ + template + explicit ShmRef(Args&& ...args) : obj_(std::forward(args)...) {} + + /** Default constructor */ + ShmRef() = default; + + /** Copy Constructor */ + ShmRef(const ShmRef &other) : obj_(other.obj_) {} + + /** Copy assign operator */ + ShmRef& operator=(const ShmRef &other) { + obj_ = other.obj_; + return *this; + } + + /** Move Constructor */ + ShmRef(ShmRef &&other) noexcept : obj_(std::move(other.obj_)) {} + + /** Move assign operator */ + ShmRef& operator=(ShmRef &&other) noexcept { + obj_ = std::move(other.obj_); + return *this; + } + + /** Get ShmReference to the internal data structure */ + T& get_ref() { + return obj_.get_ref(); + } + + /** Get a constant ShmReference */ + const T& get_ref_const() const { + return obj_.get_ref_const(); + } + + /** DeShmReference operator */ + T& operator*() { + return get_ref(); + } + + /** Constant deShmReference operator */ + const T& operator*() const { + return get_ref_const(); + } + + /** Pointer operator */ + T* operator->() { + return &get_ref(); + } + + /** Constant pointer operator */ + const T* operator->() const { + return &get_ref_const(); + } +}; + +} // namespace hermes_shm::ipc + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h new file mode 100644 index 000000000..1f03cc9e5 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ +#define HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ + +#include "hermes_shm/memory/memory.h" +#include "hermes_shm/memory/allocator/allocator.h" +#include "hermes_shm/memory/memory_manager.h" +#include "hermes_shm/data_structures/internal/shm_macros.h" +#include + +#include "hermes_shm/data_structures/internal/shm_archive.h" + +namespace hermes_shm::ipc { + +/** + * Indicates a data structure represents a memory paradigm for Shm. + * */ +class ShmSmartPointer : public ShmArchiveable {}; + +/** + * A base class used for creating shared-memory pointer management + * classes (manual_ptr, unique_ptr, shared_ptr). + * + * Smart pointers are not stored directly in shared memory. They are + * wrappers around shared-memory objects which manage the construction + * and destruction of objects. + * */ +template +class ShmSmartPtr : public ShmSmartPointer { + public: + T obj_; /**< The stored shared-memory object */ + + public: + /** Default constructor */ + ShmSmartPtr() = default; + + /** Sets this pointer to NULL */ + void SetNull() { + obj_.SetNull(); + } + + /** Checks if this pointer is null */ + bool IsNull() const { + return obj_.IsNull(); + } + + /** Gets a pointer to the internal object */ + T* get() { + return &obj_; + } + + /** Gets a pointer to the internal object */ + T* get() const { + return &obj_; + } + + /** Gets a pointer to the internal object */ + T* get_const() const { + return &obj_; + } + + /** Gets a reference to the internal object */ + T& get_ref() { + return obj_; + } + + /** Gets a reference to the internal object */ + T& get_ref() const { + return obj_; + } + + /** Gets a reference to the internal object */ + const T& get_ref_const() const { + return obj_; + } + + /** Dereference operator */ + T& operator*() { + return get_ref(); + } + + /** Constant dereference operator */ + const T& operator*() const { + return get_ref_const(); + } + + /** Pointer operator */ + T* operator->() { + return get(); + } + + /** Constant pointer operator */ + const T* operator->() const { + return get_const(); + } + + /** Destroy the data allocated by this pointer */ + void shm_destroy() { + obj_.shm_destroy(); + } +}; + + + +} // namespace hermes_shm::ipc + +/** + * Namespace simplification for a SHM data structure pointer + * */ +#define SHM_SMART_PTR_TEMPLATE(T) \ + using ShmSmartPtr::shm_destroy;\ + using ShmSmartPtr::obj_;\ + using ShmSmartPtr::get;\ + using ShmSmartPtr::get_ref;\ + using ShmSmartPtr::get_const;\ + using ShmSmartPtr::get_ref_const;\ + using ShmSmartPtr::SetNull;\ + using ShmSmartPtr::IsNull; + +/** + * A macro for defining shared memory serializations + * */ +#define SHM_SERIALIZE_WRAPPER(AR_TYPE)\ + void shm_serialize(lipc::TypedPointer &type) const {\ + obj_.shm_serialize(type);\ + }\ + void shm_serialize(lipc::TypedAtomicPointer &type) const {\ + obj_.shm_serialize(type);\ + }\ + SHM_SERIALIZE_OPS(AR_TYPE) + +/** + * A macro for defining shared memory deserializations + * */ +#define SHM_DESERIALIZE_WRAPPER(AR_TYPE)\ + void shm_deserialize(const lipc::TypedPointer &type) {\ + obj_.shm_deserialize(type);\ + }\ + void shm_deserialize(const lipc::TypedAtomicPointer &type) {\ + obj_.shm_deserialize(type);\ + }\ + SHM_DESERIALIZE_OPS(AR_TYPE) + +/** + * A macro for defining shared memory (de)serializations + * */ +#define SHM_SERIALIZE_DESERIALIZE_WRAPPER(AR_TYPE)\ + SHM_SERIALIZE_WRAPPER(AR_TYPE)\ + SHM_DESERIALIZE_WRAPPER(AR_TYPE) + +#endif // HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h new file mode 100644 index 000000000..fa752bf21 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h @@ -0,0 +1,414 @@ +// +// Created by lukemartinlogan on 1/24/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ + +#include "hermes_shm/data_structures/internal/shm_container.h" + +namespace honey { + +class ShmContainerExample; + +#define CLASS_NAME ShmContainerExample +#define TYPED_CLASS ShmContainerExample +#define TYPED_HEADER ShmHeader + +template +class ShmHeader; + +template<> + class ShmHeader : public lipc::ShmBaseHeader { +}; + +class ShmContainerExample { + public: + /**==================================== + * Variables & Types + * ===================================*/ + + typedef TYPED_HEADER header_t; /** Header type query */ + header_t *header_; /**< Header of the shared-memory data structure */ + lipc::Allocator *alloc_; /**< lipc::Allocator used for this data structure */ + hermes_shm::bitfield32_t flags_; /**< Flags used data structure status */ + + public: + /**==================================== + * Shm Overrides + * ===================================*/ + + /** Default constructor */ + CLASS_NAME() = default; + + /** Default shm constructor */ + void shm_init_main(TYPED_HEADER *header, + lipc::Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header); + } + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + lipc::Allocator *alloc, + CLASS_NAME &other) { + shm_init_main(header, alloc); + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + lipc::Allocator *alloc, + const CLASS_NAME &other) { + shm_init_main(header, alloc); + } + + /** Destroy the shared-memory data. */ + void shm_destroy_main() {} + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} + + /**==================================== + * Constructors + * ===================================*/ + + /** Constructor. Allocate header with default allocator. */ + template + explicit CLASS_NAME(Args&& ...args) { + shm_init(std::forward(args)...); + } + + /** Constructor. Allocate header with default allocator. */ + template + void shm_init(Args&& ...args) { + shm_destroy(false); + shm_init_main(lipc::typed_nullptr(), + lipc::typed_nullptr(), + std::forward(args)...); + } + + /** Constructor. Allocate header with specific allocator. */ + template + void shm_init(lipc::Allocator *alloc, Args&& ...args) { + shm_destroy(false); + shm_init_main(lipc::typed_nullptr(), + alloc, + std::forward(args)...); + } + + /** Constructor. Initialize an already-allocated header. */ + template + void shm_init(TYPED_HEADER &header, + lipc::Allocator *alloc, Args&& ...args) { + shm_destroy(false); + shm_init_main(&header, alloc, std::forward(args)...); + } + + /** Initialize the data structure's allocator */ + inline void shm_init_allocator(lipc::Allocator *alloc) { + if (IsValid()) { return; } + if (alloc == nullptr) { + alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + } else { + alloc_ = alloc; + } + } + + /** + * Initialize a data structure's header. + * A container will never re-set or re-allocate its header once it has + * been set the first time. + * */ + template + void shm_init_header(TYPED_HEADER *header, + Args&& ...args) { + if (IsValid()) { + header_->SetBits(SHM_CONTAINER_DATA_VALID); + } else if (header == nullptr) { + lipc::Pointer p; + header_ = alloc_->template + AllocateConstructObjs( + 1, p, std::forward(args)...); + header_->SetBits( + SHM_CONTAINER_DATA_VALID | + SHM_CONTAINER_HEADER_DESTRUCTABLE); + flags_.SetBits( + SHM_CONTAINER_VALID | + SHM_CONTAINER_DESTRUCTABLE); + } else { + lipc::Pointer header_ptr; + header_ = header; + lipc::Allocator::ConstructObj( + *header_, std::forward(args)...); + header_->SetBits( + SHM_CONTAINER_DATA_VALID); + flags_.SetBits( + SHM_CONTAINER_VALID | + SHM_CONTAINER_DESTRUCTABLE); + } + } + + /**==================================== + * Serialization + * ===================================*/ + + /** Serialize into a Pointer */ + void shm_serialize(lipc::TypedPointer &ar) const { + ar = alloc_->template + Convert(header_); + shm_serialize_main(); + } + + /** Serialize into an AtomicPointer */ + void shm_serialize(lipc::TypedAtomicPointer &ar) const { + ar = alloc_->template + Convert(header_); + shm_serialize_main(); + } + + /** Override << operators */ + SHM_SERIALIZE_OPS((TYPED_CLASS)) + + /**==================================== + * Deserialization + * ===================================*/ + + /** Deserialize object from a raw pointer */ + bool shm_deserialize(const lipc::TypedPointer &ar) { + return shm_deserialize( + HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_), + ar.ToOffsetPointer() + ); + } + + /** Deserialize object from allocator + offset */ + bool shm_deserialize(lipc::Allocator *alloc, lipc::OffsetPointer header_ptr) { + if (header_ptr.IsNull()) { return false; } + return shm_deserialize(alloc, + alloc->Convert< + TYPED_HEADER, + lipc::OffsetPointer>(header_ptr)); + } + + /** Deserialize object from another object (weak copy) */ + bool shm_deserialize(const CLASS_NAME &other) { + if (other.IsNull()) { return false; } + return shm_deserialize(other.GetAllocator(), other.header_); + } + + /** Deserialize object from allocator + header */ + bool shm_deserialize(lipc::Allocator *alloc, + TYPED_HEADER *header) { + flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE); + alloc_ = alloc; + header_ = header; + flags_.SetBits(SHM_CONTAINER_VALID); + shm_deserialize_main(); + return true; + } + + /** Constructor. Deserialize the object from the reference. */ + template + void shm_init(lipc::ShmRef &obj) { + shm_deserialize(obj->GetAllocator(), obj->header_); + } + + /** Override >> operators */ + SHM_DESERIALIZE_OPS((TYPED_CLASS)) + + /**==================================== + * Destructors + * ===================================*/ + + /** Destructor */ + ~CLASS_NAME() { + if (IsDestructable()) { + shm_destroy(true); + } + } + + /** Shm Destructor */ + void shm_destroy(bool destroy_header = true) { + if (!IsValid()) { return; } + if (IsDataValid()) { + shm_destroy_main(); + } + UnsetDataValid(); + if (destroy_header && + header_->OrBits(SHM_CONTAINER_HEADER_DESTRUCTABLE)) { + alloc_->FreePtr(header_); + UnsetValid(); + } + } + + /**==================================== + * Move Operations + * ===================================*/ + + /** Move constructor */ + CLASS_NAME(CLASS_NAME &&other) noexcept { + shm_weak_move( + lipc::typed_nullptr(), + lipc::typed_nullptr(), + other); + } + + /** Move assignment operator */ + CLASS_NAME& operator=(CLASS_NAME &&other) noexcept { + if (this != &other) { + shm_weak_move( + lipc::typed_nullptr(), + lipc::typed_nullptr(), + other); + } + return *this; + } + + /** Move shm_init constructor */ + void shm_init_main(TYPED_HEADER *header, + lipc::Allocator *alloc, + CLASS_NAME &&other) noexcept { + shm_weak_move(header, alloc, other); + } + + /** Move operation */ + void shm_weak_move(TYPED_HEADER *header, + lipc::Allocator *alloc, + CLASS_NAME &other) { + if (other.IsNull()) { return; } + if (IsValid() && other.GetAllocator() != GetAllocator()) { + shm_strong_copy(header, alloc, other); + other.shm_destroy(true); + return; + } + shm_destroy(false); + shm_weak_move_main(header, alloc, other); + if (!other.IsDestructable()) { + UnsetDestructable(); + } + other.UnsetDataValid(); + other.shm_destroy(true); + } + + /**==================================== + * Copy Operations + * ===================================*/ + + /** Copy constructor */ + CLASS_NAME(const CLASS_NAME &other) noexcept { + shm_init(other); + } + + /** Copy assignment constructor */ + CLASS_NAME& operator=(const CLASS_NAME &other) { + if (this != &other) { + shm_strong_copy( + lipc::typed_nullptr(), + lipc::typed_nullptr(), + other); + } + return *this; + } + + /** Copy shm_init constructor */ + void shm_init_main(TYPED_HEADER *header, + lipc::Allocator *alloc, + const CLASS_NAME &other) { + shm_strong_copy(header, alloc, other); + } + + /** Strong Copy operation */ + void shm_strong_copy(TYPED_HEADER *header, + lipc::Allocator *alloc, + const CLASS_NAME &other) { + if (other.IsNull()) { return; } + shm_destroy(false); + shm_strong_copy_main(header, alloc, other); + SetDestructable(); + } + + /**==================================== + * Container Flag Operations + * ===================================*/ + + /** Sets this object as destructable */ + void SetDestructable() { + flags_.SetBits(SHM_CONTAINER_DESTRUCTABLE); + } + + /** Sets this object as not destructable */ + void UnsetDestructable() { + flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE); + } + + /** Check if this container is destructable */ + bool IsDestructable() const { + return flags_.OrBits(SHM_CONTAINER_DESTRUCTABLE); + } + + /** Check if container has a valid header */ + bool IsValid() const { + return flags_.OrBits(SHM_CONTAINER_VALID); + } + + /** Set container header invalid */ + void UnsetValid() { + flags_.UnsetBits(SHM_CONTAINER_VALID | + SHM_CONTAINER_DESTRUCTABLE | SHM_CONTAINER_HEADER_DESTRUCTABLE); + } + + /**==================================== + * Header Flag Operations + * ===================================*/ + + /** Check if header's data is valid */ + bool IsDataValid() const { + return header_->OrBits(SHM_CONTAINER_DATA_VALID); + } + + /** Check if header's data is valid */ + void UnsetDataValid() const { + header_->UnsetBits(SHM_CONTAINER_DATA_VALID); + } + + /** Check if null */ + bool IsNull() const { + return !IsValid() || !IsDataValid(); + } + + /** Get a typed pointer to the object */ + template + POINTER_T GetShmPointer() const { + return alloc_->Convert(header_); + } + + /**==================================== + * Query Operations + * ===================================*/ + + /** Get the allocator for this container */ + lipc::Allocator* GetAllocator() { + return alloc_; + } + + /** Get the allocator for this container */ + lipc::Allocator* GetAllocator() const { + return alloc_; + } + + /** Get the shared-memory allocator id */ + lipc::allocator_id_t GetAllocatorId() const { + return alloc_->GetId(); + } +}; + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h new file mode 100644 index 000000000..f942eafed --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h @@ -0,0 +1,343 @@ +public: +/**==================================== + * Variables & Types + * ===================================*/ + +typedef TYPED_HEADER header_t; /** Header type query */ +header_t *header_; /**< Header of the shared-memory data structure */ +lipc::Allocator *alloc_; /**< lipc::Allocator used for this data structure */ +hermes_shm::bitfield32_t flags_; /**< Flags used data structure status */ + +public: +/**==================================== + * Constructors + * ===================================*/ + +/** Constructor. Allocate header with default allocator. */ +template +explicit CLASS_NAME(Args&& ...args) { +shm_init(std::forward(args)...); +} + +/** Constructor. Allocate header with default allocator. */ +template +void shm_init(Args&& ...args) { + shm_destroy(false); + shm_init_main(lipc::typed_nullptr(), + lipc::typed_nullptr(), + std::forward(args)...); +} + +/** Constructor. Allocate header with specific allocator. */ +template +void shm_init(lipc::Allocator *alloc, Args&& ...args) { + shm_destroy(false); + shm_init_main(lipc::typed_nullptr(), + alloc, + std::forward(args)...); +} + +/** Constructor. Initialize an already-allocated header. */ +template +void shm_init(TYPED_HEADER &header, + lipc::Allocator *alloc, Args&& ...args) { + shm_destroy(false); + shm_init_main(&header, alloc, std::forward(args)...); +} + +/** Initialize the data structure's allocator */ +inline void shm_init_allocator(lipc::Allocator *alloc) { + if (IsValid()) { return; } + if (alloc == nullptr) { + alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + } else { + alloc_ = alloc; + } +} + +/** + * Initialize a data structure's header. + * A container will never re-set or re-allocate its header once it has + * been set the first time. + * */ +template +void shm_init_header(TYPED_HEADER *header, + Args&& ...args) { + if (IsValid()) { + header_->SetBits(SHM_CONTAINER_DATA_VALID); + } else if (header == nullptr) { + lipc::Pointer p; + header_ = alloc_->template + AllocateConstructObjs( + 1, p, std::forward(args)...); + header_->SetBits( + SHM_CONTAINER_DATA_VALID | + SHM_CONTAINER_HEADER_DESTRUCTABLE); + flags_.SetBits( + SHM_CONTAINER_VALID | + SHM_CONTAINER_DESTRUCTABLE); + } else { + lipc::Pointer header_ptr; + header_ = header; + lipc::Allocator::ConstructObj( + *header_, std::forward(args)...); + header_->SetBits( + SHM_CONTAINER_DATA_VALID); + flags_.SetBits( + SHM_CONTAINER_VALID | + SHM_CONTAINER_DESTRUCTABLE); + } +} + +/**==================================== + * Serialization + * ===================================*/ + +/** Serialize into a Pointer */ +void shm_serialize(lipc::TypedPointer &ar) const { + ar = alloc_->template + Convert(header_); + shm_serialize_main(); +} + +/** Serialize into an AtomicPointer */ +void shm_serialize(lipc::TypedAtomicPointer &ar) const { + ar = alloc_->template + Convert(header_); + shm_serialize_main(); +} + +/** Override << operators */ +SHM_SERIALIZE_OPS((TYPED_CLASS)) + +/**==================================== + * Deserialization + * ===================================*/ + +/** Deserialize object from a raw pointer */ +bool shm_deserialize(const lipc::TypedPointer &ar) { + return shm_deserialize( + HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_), + ar.ToOffsetPointer() + ); +} + +/** Deserialize object from allocator + offset */ +bool shm_deserialize(lipc::Allocator *alloc, lipc::OffsetPointer header_ptr) { + if (header_ptr.IsNull()) { return false; } + return shm_deserialize(alloc, + alloc->Convert< + TYPED_HEADER, + lipc::OffsetPointer>(header_ptr)); +} + +/** Deserialize object from another object (weak copy) */ +bool shm_deserialize(const CLASS_NAME &other) { + if (other.IsNull()) { return false; } + return shm_deserialize(other.GetAllocator(), other.header_); +} + +/** Deserialize object from allocator + header */ +bool shm_deserialize(lipc::Allocator *alloc, + TYPED_HEADER *header) { + flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE); + alloc_ = alloc; + header_ = header; + flags_.SetBits(SHM_CONTAINER_VALID); + shm_deserialize_main(); + return true; +} + +/** Constructor. Deserialize the object from the reference. */ +template +void shm_init(lipc::ShmRef &obj) { + shm_deserialize(obj->GetAllocator(), obj->header_); +} + +/** Override >> operators */ +SHM_DESERIALIZE_OPS((TYPED_CLASS)) + +/**==================================== + * Destructors + * ===================================*/ + +/** Destructor */ +~CLASS_NAME() { + if (IsDestructable()) { + shm_destroy(true); + } +} + +/** Shm Destructor */ +void shm_destroy(bool destroy_header = true) { + if (!IsValid()) { return; } + if (IsDataValid()) { + shm_destroy_main(); + } + UnsetDataValid(); + if (destroy_header && + header_->OrBits(SHM_CONTAINER_HEADER_DESTRUCTABLE)) { + alloc_->FreePtr(header_); + UnsetValid(); + } +} + +/**==================================== + * Move Operations + * ===================================*/ + +/** Move constructor */ +CLASS_NAME(CLASS_NAME &&other) noexcept { +shm_weak_move( + lipc::typed_nullptr(), + lipc::typed_nullptr(), + other); +} + +/** Move assignment operator */ +CLASS_NAME& operator=(CLASS_NAME &&other) noexcept { +if (this != &other) { +shm_weak_move( + lipc::typed_nullptr(), + lipc::typed_nullptr(), + other); +} +return *this; +} + +/** Move shm_init constructor */ +void shm_init_main(TYPED_HEADER *header, + lipc::Allocator *alloc, + CLASS_NAME &&other) noexcept { + shm_weak_move(header, alloc, other); +} + +/** Move operation */ +void shm_weak_move(TYPED_HEADER *header, + lipc::Allocator *alloc, + CLASS_NAME &other) { + if (other.IsNull()) { return; } + if (IsValid() && other.GetAllocator() != GetAllocator()) { + shm_strong_copy(header, alloc, other); + other.shm_destroy(true); + return; + } + shm_destroy(false); + shm_weak_move_main(header, alloc, other); + if (!other.IsDestructable()) { + UnsetDestructable(); + } + other.UnsetDataValid(); + other.shm_destroy(true); +} + +/**==================================== + * Copy Operations + * ===================================*/ + +/** Copy constructor */ +CLASS_NAME(const CLASS_NAME &other) noexcept { + shm_init(other); +} + +/** Copy assignment constructor */ +CLASS_NAME& operator=(const CLASS_NAME &other) { + if (this != &other) { + shm_strong_copy( + lipc::typed_nullptr(), + lipc::typed_nullptr(), + other); + } + return *this; +} + +/** Copy shm_init constructor */ +void shm_init_main(TYPED_HEADER *header, + lipc::Allocator *alloc, + const CLASS_NAME &other) { + shm_strong_copy(header, alloc, other); +} + +/** Strong Copy operation */ +void shm_strong_copy(TYPED_HEADER *header, + lipc::Allocator *alloc, + const CLASS_NAME &other) { + if (other.IsNull()) { return; } + shm_destroy(false); + shm_strong_copy_main(header, alloc, other); + SetDestructable(); +} + +/**==================================== + * Container Flag Operations + * ===================================*/ + +/** Sets this object as destructable */ +void SetDestructable() { + flags_.SetBits(SHM_CONTAINER_DESTRUCTABLE); +} + +/** Sets this object as not destructable */ +void UnsetDestructable() { + flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE); +} + +/** Check if this container is destructable */ +bool IsDestructable() const { + return flags_.OrBits(SHM_CONTAINER_DESTRUCTABLE); +} + +/** Check if container has a valid header */ +bool IsValid() const { + return flags_.OrBits(SHM_CONTAINER_VALID); +} + +/** Set container header invalid */ +void UnsetValid() { + flags_.UnsetBits(SHM_CONTAINER_VALID | + SHM_CONTAINER_DESTRUCTABLE | SHM_CONTAINER_HEADER_DESTRUCTABLE); +} + +/**==================================== + * Header Flag Operations + * ===================================*/ + +/** Check if header's data is valid */ +bool IsDataValid() const { + return header_->OrBits(SHM_CONTAINER_DATA_VALID); +} + +/** Check if header's data is valid */ +void UnsetDataValid() const { + header_->UnsetBits(SHM_CONTAINER_DATA_VALID); +} + +/** Check if null */ +bool IsNull() const { + return !IsValid() || !IsDataValid(); +} + +/** Get a typed pointer to the object */ +template +POINTER_T GetShmPointer() const { + return alloc_->Convert(header_); +} + +/**==================================== + * Query Operations + * ===================================*/ + +/** Get the allocator for this container */ +lipc::Allocator* GetAllocator() { + return alloc_; +} + +/** Get the allocator for this container */ +lipc::Allocator* GetAllocator() const { + return alloc_; +} + +/** Get the shared-memory allocator id */ +lipc::allocator_id_t GetAllocatorId() const { + return alloc_->GetId(); +} \ No newline at end of file diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h new file mode 100644 index 000000000..4a3311630 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h @@ -0,0 +1,308 @@ +// +// Created by lukemartinlogan on 1/24/23. +// + +/** + * Let's say we want a data structure + * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_INHERIT_EXAMPLE_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_INHERIT_EXAMPLE_H_ + +#define CLASS_NAME ShmContainerExtendExample +#define TYPED_CLASS ShmContainerExtendExample +#define TYPED_HEADER ShmHeader> + +#include "hermes_shm/data_structures/internal/shm_container.h" + +namespace hermes_shm::ipc { + +template +class ShmContainerExtendExample; + +template +class ShmHeader> +: public ShmWrapperHeader { + typename ContainerT::header_t obj_; +}; + +template +class ShmContainerExtendExample : public ShmContainer { + public: + /**==================================== + * Variables & Types + *===================================*/ + + typedef TYPED_HEADER header_t; /**< Required by all ShmContainers */ + header_t *header_; /**< The shared-memory header for this container */ + ContainerT obj_; /**< The object being wrapped around */ + + public: + /**==================================== + * Shm Overrides + * ===================================*/ + + /** Default constructor */ + CLASS_NAME() = default; + + /** Default shm constructor */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc) { + } + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, CLASS_NAME &other) { + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const CLASS_NAME &other) { + } + + /** Destroy the shared-memory data. */ + void shm_destroy_main() {} + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} + + /**==================================== + * Constructors + * ===================================*/ + + /** Constructor. Allocate header with default allocator. */ + template + explicit CLASS_NAME(Args &&...args) { + shm_init(std::forward(args)...); + } + + /** Constructor. Allocate header with default allocator. */ + template + void shm_init(Args &&...args) { + } + + /**==================================== + * Serialization + * ===================================*/ + + /** Serialize into a Pointer */ + void shm_serialize(TypedPointer &ar) const { + obj_.shm_serialize(ar); + } + + /** Serialize into an AtomicPointer */ + void shm_serialize(TypedAtomicPointer &ar) const { + obj_.shm_serialize(ar); + } + + /** Override << operators */ + SHM_SERIALIZE_OPS((TYPED_CLASS)) + + /**==================================== + * Deserialization + * ===================================*/ + + /** Deserialize object from a raw pointer */ + bool shm_deserialize(const TypedPointer &ar) { + return obj_.shm_deserialize(ar); + } + + /** Deserialize object from allocator + offset */ + bool shm_deserialize(Allocator *alloc, OffsetPointer header_ptr) { + return obj_.shm_deserialize(alloc, header_ptr); + } + + /** Deserialize object from another object (weak copy) */ + bool shm_deserialize(const CLASS_NAME &other) { + return obj_.shm_deserialize(other); + } + + /** Deserialize object from allocator + header */ + bool shm_deserialize(Allocator *alloc, + TYPED_HEADER *header) { + return obj_.shm_deserialize(alloc, header); + } + + /** Constructor. Deserialize the object from the reference. */ + template + void shm_init(lipc::ShmRef &obj) { + shm_deserialize(obj->GetAllocator(), obj->header_); + } + + /** Override >> operators */ + SHM_DESERIALIZE_OPS ((TYPED_CLASS)) + + /**==================================== + * Destructors + * ===================================*/ + + /** Destructor */ + ~CLASS_NAME() { + obj_.shm_destroy(true); + } + + /** Shm Destructor */ + void shm_destroy(bool destroy_header = true) { + obj_.shm_destroy(false); + if (!IsValid()) { return; } + if (IsDataValid()) { + shm_destroy_main(); + } + UnsetDataValid(); + if (destroy_header && + obj_.header_->OrBits(SHM_CONTAINER_HEADER_DESTRUCTABLE)) { + GetAllocator()->template + FreePtr(header_); + UnsetValid(); + } + } + + /**==================================== + * Move Operations + * ===================================*/ + + /** Move constructor */ + CLASS_NAME(CLASS_NAME &&other) noexcept + : obj_(std::move(other)) {} + + /** Move assignment operator */ + CLASS_NAME& operator=(CLASS_NAME &&other) noexcept { + obj_ = std::move(other.obj_); + return *this; + } + + /** Move shm_init constructor */ + void shm_init_main(TYPED_HEADER *header, + lipc::Allocator *alloc, + CLASS_NAME &&other) noexcept { + shm_weak_move(header, alloc, other); + } + + /** Move operation */ + void shm_weak_move(TYPED_HEADER *header, + lipc::Allocator *alloc, + CLASS_NAME &other) { + obj_.shm_weak_move(header, alloc, other); + } + + /**==================================== + * Copy Operations + * ===================================*/ + + /** Copy constructor */ + CLASS_NAME(const CLASS_NAME &other) noexcept { + shm_init(other); + } + + /** Copy assignment constructor */ + CLASS_NAME &operator=(const CLASS_NAME &other) { + if (this != &other) { + shm_strong_copy( + typed_nullptr(), + typed_nullptr(), + other); + } + return *this; + } + + /** Copy shm_init constructor */ + void shm_init_main(TYPED_HEADER *header, + lipc::Allocator *alloc, + const CLASS_NAME &other) { + shm_strong_copy(header, alloc, other); + } + + /** Strong Copy operation */ + void shm_strong_copy(TYPED_HEADER *header, lipc::Allocator *alloc, + const CLASS_NAME &other) { + if (other.IsNull()) { return; } + shm_destroy(false); + shm_strong_copy_main(header, alloc, other); + SetDestructable(); + } + + /**==================================== + * Container Flag Operations + * ===================================*/ + + /** Sets this object as destructable */ + void SetDestructable() { + obj_.SetDestructable(); + } + + /** Sets this object as not destructable */ + void UnsetDestructable() { + obj_.UnsetDestructable(); + } + + /** Check if this container is destructable */ + bool IsDestructable() const { + return obj_.IsDestructable(); + } + + /** Check if container has a valid header */ + bool IsValid() const { + return obj_.IsValid(); + } + + /** Set container header invalid */ + void UnsetValid() { + obj_.UnsetValid(); + } + + /**==================================== + * Header Flag Operations + * ===================================*/ + + /** Check if header's data is valid */ + bool IsDataValid() const { + return obj_.IsDataValid(); + } + + /** Check if header's data is valid */ + void UnsetDataValid() const { + return obj_.UnsetDataValid(); + } + + /** Check if null */ + bool IsNull() const { + return obj_.IsNull(); + } + + /** Get a typed pointer to the object */ + template + POINTER_T GetShmPointer() const { + return GetAllocator()->template + Convert(header_); + } + + /**==================================== + * Query Operations + * ===================================*/ + + /** Get the allocator for this container */ + Allocator* GetAllocator() { + return obj_.GetAllocator(); + } + + /** Get the allocator for this container */ + Allocator* GetAllocator() const { + return obj_.GetAllocator(); + } + + /** Get the shared-memory allocator id */ + allocator_id_t GetAllocatorId() const { + return GetAllocator()->GetId(); + } +}; + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_INHERIT_EXAMPLE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h new file mode 100644 index 000000000..68925e847 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h @@ -0,0 +1,238 @@ +public: +/**==================================== + * Variables & Types + *===================================*/ + +typedef TYPED_HEADER header_t; /**< Required by all ShmContainers */ +header_t *header_; /**< The shared-memory header for this container */ +ContainerT obj_; /**< The object being wrapped around */ + +public: +/**==================================== + * Constructors + * ===================================*/ + +/** Constructor. Allocate header with default allocator. */ +template +explicit CLASS_NAME(Args &&...args) { +shm_init(std::forward(args)...); +} + +/** Constructor. Allocate header with default allocator. */ +template +void shm_init(Args &&...args) { +} + +/**==================================== + * Serialization + * ===================================*/ + +/** Serialize into a Pointer */ +void shm_serialize(TypedPointer &ar) const { + obj_.shm_serialize(ar); +} + +/** Serialize into an AtomicPointer */ +void shm_serialize(TypedAtomicPointer &ar) const { + obj_.shm_serialize(ar); +} + +/** Override << operators */ +SHM_SERIALIZE_OPS((TYPED_CLASS)) + +/**==================================== + * Deserialization + * ===================================*/ + +/** Deserialize object from a raw pointer */ +bool shm_deserialize(const TypedPointer &ar) { + return obj_.shm_deserialize(ar); +} + +/** Deserialize object from allocator + offset */ +bool shm_deserialize(Allocator *alloc, OffsetPointer header_ptr) { + return obj_.shm_deserialize(alloc, header_ptr); +} + +/** Deserialize object from another object (weak copy) */ +bool shm_deserialize(const CLASS_NAME &other) { + return obj_.shm_deserialize(other); +} + +/** Deserialize object from allocator + header */ +bool shm_deserialize(Allocator *alloc, + TYPED_HEADER *header) { + return obj_.shm_deserialize(alloc, header); +} + +/** Constructor. Deserialize the object from the reference. */ +template +void shm_init(lipc::ShmRef &obj) { + shm_deserialize(obj->GetAllocator(), obj->header_); +} + +/** Override >> operators */ +SHM_DESERIALIZE_OPS ((TYPED_CLASS)) + +/**==================================== + * Destructors + * ===================================*/ + +/** Destructor */ +~CLASS_NAME() { + obj_.shm_destroy(true); +} + +/** Shm Destructor */ +void shm_destroy(bool destroy_header = true) { + obj_.shm_destroy(false); + if (!IsValid()) { return; } + if (IsDataValid()) { + shm_destroy_main(); + } + UnsetDataValid(); + if (destroy_header && + obj_.header_->OrBits(SHM_CONTAINER_HEADER_DESTRUCTABLE)) { + GetAllocator()->template + FreePtr(header_); + UnsetValid(); + } +} + +/**==================================== + * Move Operations + * ===================================*/ + +/** Move constructor */ +CLASS_NAME(CLASS_NAME &&other) noexcept +: obj_(std::move(other)) {} + +/** Move assignment operator */ +CLASS_NAME& operator=(CLASS_NAME &&other) noexcept { +obj_ = std::move(other.obj_); +return *this; +} + +/** Move shm_init constructor */ +void shm_init_main(TYPED_HEADER *header, + lipc::Allocator *alloc, + CLASS_NAME &&other) noexcept { + shm_weak_move(header, alloc, other); +} + +/** Move operation */ +void shm_weak_move(TYPED_HEADER *header, + lipc::Allocator *alloc, + CLASS_NAME &other) { + obj_.shm_weak_move(header, alloc, other); +} + +/**==================================== + * Copy Operations + * ===================================*/ + +/** Copy constructor */ +CLASS_NAME(const CLASS_NAME &other) noexcept { + shm_init(other); +} + +/** Copy assignment constructor */ +CLASS_NAME &operator=(const CLASS_NAME &other) { + if (this != &other) { + shm_strong_copy( + typed_nullptr(), + typed_nullptr(), + other); + } + return *this; +} + +/** Copy shm_init constructor */ +void shm_init_main(TYPED_HEADER *header, + lipc::Allocator *alloc, + const CLASS_NAME &other) { + shm_strong_copy(header, alloc, other); +} + +/** Strong Copy operation */ +void shm_strong_copy(TYPED_HEADER *header, lipc::Allocator *alloc, + const CLASS_NAME &other) { + if (other.IsNull()) { return; } + shm_destroy(false); + shm_strong_copy_main(header, alloc, other); + SetDestructable(); +} + +/**==================================== + * Container Flag Operations + * ===================================*/ + +/** Sets this object as destructable */ +void SetDestructable() { + obj_.SetDestructable(); +} + +/** Sets this object as not destructable */ +void UnsetDestructable() { + obj_.UnsetDestructable(); +} + +/** Check if this container is destructable */ +bool IsDestructable() const { + return obj_.IsDestructable(); +} + +/** Check if container has a valid header */ +bool IsValid() const { + return obj_.IsValid(); +} + +/** Set container header invalid */ +void UnsetValid() { + obj_.UnsetValid(); +} + +/**==================================== + * Header Flag Operations + * ===================================*/ + +/** Check if header's data is valid */ +bool IsDataValid() const { + return obj_.IsDataValid(); +} + +/** Check if header's data is valid */ +void UnsetDataValid() const { + return obj_.UnsetDataValid(); +} + +/** Check if null */ +bool IsNull() const { + return obj_.IsNull(); +} + +/** Get a typed pointer to the object */ +template +POINTER_T GetShmPointer() const { + return GetAllocator()->template + Convert(header_); +} + +/**==================================== + * Query Operations + * ===================================*/ + +/** Get the allocator for this container */ +Allocator* GetAllocator() { + return obj_.GetAllocator(); +} + +/** Get the allocator for this container */ +Allocator* GetAllocator() const { + return obj_.GetAllocator(); +} + +/** Get the shared-memory allocator id */ +allocator_id_t GetAllocatorId() const { + return GetAllocator()->GetId(); +} \ No newline at end of file diff --git a/hermes_shm/include/hermes_shm/data_structures/pair.h b/hermes_shm/include/hermes_shm/data_structures/pair.h new file mode 100644 index 000000000..a75d7a743 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/pair.h @@ -0,0 +1,195 @@ +// +// Created by lukemartinlogan on 1/15/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_PAIR_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_PAIR_H_ + +#include "data_structure.h" +#include "internal/shm_archive_or_t.h" + +namespace hermes_shm::ipc { + +/** forward declaration for string */ +template +class pair; + +/** + * MACROS used to simplify the string namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ +#define CLASS_NAME pair +#define TYPED_CLASS pair +#define TYPED_HEADER ShmHeader + +/** pair shared-memory header */ +template +struct ShmHeader : public ShmBaseHeader { + ShmHeaderOrT first_; + ShmHeaderOrT second_; + + /** Default constructor */ + ShmHeader() = default; + + /** Constructor. Default shm allocate. */ + explicit ShmHeader(Allocator *alloc) + : first_(alloc), second_(alloc) {} + + /** Piecewise constructor. */ + template + explicit ShmHeader(Allocator *alloc, + PiecewiseConstruct &&hint, + FirstArgPackT &&first, + SecondArgPackT &&second) { + (void) hint; + first_.PiecewiseInit(alloc, std::forward(first)); + second_.PiecewiseInit(alloc, std::forward(second)); + } + + /** Move constructor. */ + explicit ShmHeader(Allocator *alloc, + FirstT &&first, + SecondT &&second) + : first_(alloc, std::forward(first)), + second_(alloc, std::forward(second)) {} + + /** Copy constructor. */ + explicit ShmHeader(Allocator *alloc, + const FirstT &first, + const SecondT &second) + : first_(alloc, first), second_(alloc, second) {} + + /** Shm destructor */ + void shm_destroy(Allocator *alloc) { + first_.shm_destroy(alloc); + second_.shm_destroy(alloc); + } +}; + +/** + * A string of characters. + * */ +template +class pair : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) + + public: + lipc::ShmRef first_; + lipc::ShmRef second_; + + public: + /** Default constructor */ + pair() = default; + + /** Default shm constructor */ + void shm_init_main(TYPED_HEADER *header, Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header, alloc); + } + + /** Construct pair by moving parameters */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, + FirstT &&first, SecondT &&second) { + shm_init_allocator(alloc); + shm_init_header(header, + alloc_, + std::forward(first), + std::forward(second)); + first_ = lipc::ShmRef(header_->first_.internal_ref(alloc_)); + second_ = lipc::ShmRef(header_->second_.internal_ref(alloc_)); + } + + /** Construct pair by copying parameters */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, + const FirstT &first, const SecondT &second) { + shm_init_allocator(alloc); + shm_init_header(header, + alloc_, first, second); + first_ = lipc::ShmRef(header_->first_.internal_ref(alloc_)); + second_ = lipc::ShmRef(header_->second_.internal_ref(alloc_)); + } + + /** Construct pair piecewise */ + template + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, + PiecewiseConstruct &&hint, + FirstArgPackT &&first, + SecondArgPackT &&second) { + shm_init_allocator(alloc); + shm_init_header(header, + alloc_, + std::forward(hint), + std::forward(first), + std::forward(second)); + first_ = lipc::ShmRef(header_->first_.internal_ref(alloc_)); + second_ = lipc::ShmRef(header_->second_.internal_ref(alloc_)); + } + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, pair &other) { + shm_init_main(header, + alloc, + std::move(*other.first_), + std::move(*other.second_)); + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const pair &other) { + shm_init_main(header, + alloc, *other.first_, *other.second_); + } + + /** + * Destroy the shared-memory data. + * */ + void shm_destroy_main() { + header_->shm_destroy(alloc_); + } + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() { + first_ = lipc::ShmRef(header_->first_.internal_ref(alloc_)); + second_ = lipc::ShmRef(header_->second_.internal_ref(alloc_)); + } + + /** Get the first object */ + FirstT& GetFirst() { return *first_; } + + /** Get the first object (const) */ + FirstT& GetFirst() const { return *first_; } + + /** Get the second object */ + SecondT& GetSecond() { return *second_; } + + /** Get the second object (const) */ + SecondT& GetSecond() const { return *second_; } + + /** Get the first object (treated as key) */ + FirstT& GetKey() { return *first_; } + + /** Get the first object (treated as key) (const) */ + FirstT& GetKey() const { return *first_; } + + /** Get the second object (treated as value) */ + SecondT& GetVal() { return *second_; } + + /** Get the second object (treated as value) (const) */ + SecondT& GetVal() const { return *second_; } +}; + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +} // namespace hermes_shm::ipc + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_PAIR_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h b/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h new file mode 100644 index 000000000..a86cbb50e --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_DATA_STRUCTURES_PTR_H_ +#define HERMES_SHM_DATA_STRUCTURES_PTR_H_ + +#include "hermes_shm/memory/memory.h" +#include "hermes_shm/data_structures/data_structure.h" +#include "hermes_shm/data_structures/internal/shm_archive_or_t.h" + +namespace hermes_shm::ipc { + +/** + * MACROS to simplify the ptr namespace + * */ +#define CLASS_NAME manual_ptr +#define TYPED_CLASS manual_ptr + +/** + * Creates a unique instance of a shared-memory data structure + * and deletes eventually. + * */ +template +class manual_ptr : public ShmSmartPtr { + public: + SHM_SMART_PTR_TEMPLATE(T); + + public: + /** Default constructor does nothing */ + manual_ptr() = default; + + /** Allocates + constructs an object in shared memory */ + template + void shm_init(Args&& ...args) { + obj_.shm_init(std::forward(args)...); + obj_.UnsetDestructable(); + } + + /** Destructor. Does not free data. */ + ~manual_ptr() { + obj_.UnsetDestructable(); + } + + /** Copy constructor */ + manual_ptr(const manual_ptr &other) { + obj_.shm_deserialize(other.obj_); + } + + /** Copy assignment operator */ + manual_ptr& operator=(const manual_ptr &other) { + if (this != &other) { + obj_.shm_deserialize(other.obj_); + } + return *this; + } + + /** Move constructor */ + manual_ptr(manual_ptr&& other) noexcept { + obj_ = std::move(other.obj_); + } + + /** Constructor. From a TypedPointer */ + explicit manual_ptr(const TypedPointer &ar) { + obj_.shm_deserialize(ar); + } + + /** Constructor. From a TypedAtomicPointer */ + explicit manual_ptr(const TypedAtomicPointer &ar) { + obj_.shm_deserialize(ar); + } + + /** (De)serialize the obj from a TypedPointer */ + SHM_SERIALIZE_DESERIALIZE_WRAPPER((T)); +}; + +template +using mptr = manual_ptr; + +template +static mptr make_mptr(Args&& ...args) { + mptr ptr; + ptr.shm_init(std::forward(args)...); + return ptr; +} + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS + +namespace std { + +/** Hash function for ptr */ +template +struct hash> { + size_t operator()(const hermes_shm::ipc::manual_ptr &obj) const { + return std::hash{}(obj.get_ref_const()); + } +}; + +} // namespace std + +#endif // HERMES_SHM_DATA_STRUCTURES_PTR_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/string.h b/hermes_shm/include/hermes_shm/data_structures/string.h new file mode 100644 index 000000000..61131057f --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/string.h @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_DATA_STRUCTURES_LOCKLESS_STRING_H_ +#define HERMES_SHM_DATA_STRUCTURES_LOCKLESS_STRING_H_ + +#include "data_structure.h" +#include + +namespace hermes_shm::ipc { + +/** forward declaration for string */ +class string; + +/** + * MACROS used to simplify the string namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ +#define CLASS_NAME string +#define TYPED_CLASS string +#define TYPED_HEADER ShmHeader + +/** string shared-memory header */ +template<> +struct ShmHeader : public ShmBaseHeader { + size_t length_; + AtomicPointer text_; + + /** Default constructor */ + ShmHeader() = default; + + /** Copy constructor */ + ShmHeader(const ShmHeader &other) { + strong_copy(other); + } + + /** Copy assignment operator */ + ShmHeader& operator=(const ShmHeader &other) { + if (this != &other) { + strong_copy(other); + } + return *this; + } + + /** Strong copy operation */ + void strong_copy(const ShmHeader &other) { + length_ = other.length_; + text_ = other.text_; + } + + /** Move constructor */ + ShmHeader(ShmHeader &&other) { + weak_move(other); + } + + /** Move operator */ + ShmHeader& operator=(ShmHeader &&other) { + if (this != &other) { + weak_move(other); + } + return *this; + } + + /** Move operation */ + void weak_move(ShmHeader &other) { + strong_copy(other); + } +}; + +/** + * A string of characters. + * */ +class string : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) + + public: + char *text_; + size_t length_; + + public: + //////////////////////////// + /// SHM Overrides + //////////////////////////// + + /** Default constructor */ + string() : length_(0) {} + + /** Default shm constructor */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header); + } + + /** Construct from a C-style string with allocator in shared memory */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, const char *text) { + size_t length = strlen(text); + shm_init_main(header, alloc, length); + _create_str(text, length); + } + + /** Construct for an std::string with allocator in shared-memory */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, const std::string &text) { + shm_init_main(header, alloc, text.size()); + _create_str(text.data(), text.size()); + } + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, string &other) { + shm_init_main(header, alloc); + header_->length_ = other.header_->length_; + header_->text_ = other.header_->text_; + shm_deserialize_main(); + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const string &other) { + shm_init_main(header, alloc, other.size()); + _create_str(other.data(), other.size()); + shm_deserialize_main(); + } + + /** Construct by concatenating two string in shared-memory */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, + const string &text1, const string &text2) { + size_t length = text1.size() + text2.size(); + shm_init_main(header, alloc, length); + memcpy(text_, + text1.data(), text1.size()); + memcpy(text_ + text1.size(), + text2.data(), text2.size()); + text_[length] = 0; + } + + /** + * Construct a string of specific length and allocator in shared memory + * */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, size_t length) { + shm_init_allocator(alloc); + shm_init_header(header); + text_ = alloc_->template + AllocatePtr( + length + 1, + header_->text_); + header_->length_ = length; + length_ = length; + text_[length] = 0; + } + + /** + * Destroy the shared-memory data. + * */ + void shm_destroy_main() { + if (length_) { + alloc_->Free(header_->text_); + length_ = 0; + } + } + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() { + text_ = alloc_->template + Convert(header_->text_); + length_ = header_->length_; + } + + //////////////////////////// + /// String Operations + //////////////////////////// + + /** Get character at index i in the string */ + char& operator[](size_t i) const { + return text_[i]; + } + + /** Convert into a std::string */ + std::string str() const { + return {text_, length_}; + } + + /** Add two strings together */ + string operator+(const std::string &other) { + string tmp(other); + return string(GetAllocator(), *this, tmp); + } + + /** Add two strings together */ + string operator+(const string &other) { + return string(GetAllocator(), *this, other); + } + + /** Get the size of the current string */ + size_t size() const { + return length_; + } + + /** Get a constant reference to the C-style string */ + char* c_str() const { + return text_; + } + + /** Get a constant reference to the C-style string */ + char* data() const { + return text_; + } + + /** Get a mutable reference to the C-style string */ + char* data_mutable() { + return text_; + } + + /** + * Comparison operators + * */ + + int _strncmp(const char *a, size_t len_a, + const char *b, size_t len_b) const { + if (len_a != len_b) { + return int((int64_t)len_a - (int64_t)len_b); + } + int sum = 0; + for (size_t i = 0; i < len_a; ++i) { + sum += a[i] - b[i]; + } + return sum; + } + +#define HERMES_SHM_STR_CMP_OPERATOR(op) \ + bool operator op(const char *other) const { \ + return _strncmp(data(), size(), other, strlen(other)) op 0; \ + } \ + bool operator op(const std::string &other) const { \ + return _strncmp(data(), size(), other.data(), other.size()) op 0; \ + } \ + bool operator op(const string &other) const { \ + return _strncmp(data(), size(), other.data(), other.size()) op 0; \ + } + + HERMES_SHM_STR_CMP_OPERATOR(==) + HERMES_SHM_STR_CMP_OPERATOR(!=) + HERMES_SHM_STR_CMP_OPERATOR(<) + HERMES_SHM_STR_CMP_OPERATOR(>) + HERMES_SHM_STR_CMP_OPERATOR(<=) + HERMES_SHM_STR_CMP_OPERATOR(>=) + +#undef HERMES_SHM_STR_CMP_OPERATOR + + private: + inline void _create_str(const char *text, size_t length) { + memcpy(text_, text, length); + text_[length] = 0; + } +}; + +/** Consider the string as an uniterpreted set of bytes */ +typedef string charbuf; + +} // namespace hermes_shm::ipc + +namespace std { + +/** Hash function for string */ +template<> +struct hash { + size_t operator()(const hermes_shm::ipc::string &text) const { + size_t sum = 0; + for (size_t i = 0; i < text.size(); ++i) { + auto shift = static_cast(i % sizeof(size_t)); + auto c = static_cast((unsigned char)text[i]); + sum = 31*sum + (c << shift); + } + return sum; + } +}; + +} // namespace std + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif // HERMES_SHM_DATA_STRUCTURES_LOCKLESS_STRING_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/struct.h b/hermes_shm/include/hermes_shm/data_structures/struct.h new file mode 100644 index 000000000..5fb314896 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/struct.h @@ -0,0 +1,455 @@ +// +// Created by lukemartinlogan on 1/26/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_STRUCT_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_STRUCT_H_ + +#include "hermes_shm/data_structures/internal/shm_container.h" +#include "hermes_shm/data_structures/internal/shm_archive_or_t.h" +#include "hermes_shm/data_structures/internal/shm_null_container.h" +#include "hermes_shm/types/tuple_base.h" + +#define CLASS_NAME ShmStruct +#define TYPED_CLASS ShmStruct +#define TYPED_HEADER ShmHeader> + +namespace hermes_shm::ipc { + +/** Tuple forward declaration */ +template +class ShmStruct; + +/** Tuple SHM header */ +template +struct ShmHeader> { + /**< All object headers */ + hermes_shm::tuple_wrap hdrs_; + + /** Default initialize headers */ + ShmHeader() = default; + + /** Piecewise initialize all headers */ + template + explicit ShmHeader(Allocator *alloc, Args&& ...args) { + ForwardIterateTuple::Apply( + hdrs_, + [alloc, args=make_argpack(std::forward(args)...)] + (auto i, auto &obj_hdr) constexpr { + obj_hdr.PiecewiseInit(alloc, args.template Forward()); + }); + } + + /** Get the internal reference to the ith object */ + template + decltype(auto) internal_ref(Allocator *alloc) { + return hdrs_.template Get().internal_ref(alloc); + } + + /** Destructor */ + void shm_destroy(Allocator *alloc) { + hermes_shm::ForwardIterateTuple::Apply( + hdrs_, + [alloc](size_t i, auto &obj_hdr) constexpr { + obj_hdr.shm_destroy(alloc); + } + ); + } +}; + +/** A tuple of objects to store in shared memory */ +template +class ShmStruct : public ShmContainer { + public: + /**==================================== + * Variables & Types + *===================================*/ + + typedef TYPED_HEADER header_t; /**< Index to header type */ + header_t *header_; /**< The shared-memory header */ + Allocator *alloc_; /**< Allocator used for the header */ + hermes_shm::tuple + objs_; /**< Constructed objects */ + + public: + /**==================================== + * Shm Overrides + * ===================================*/ + + /** Default constructor */ + CLASS_NAME() = delete; + + /** Default shm constructor */ + template + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc) { + shm_init_header(header, alloc); + } + + /** Piecewise shm constructor */ + template + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, + Args&& ...args) { + shm_init_header(header, alloc, + std::forward(args)...); + } + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, CLASS_NAME &other) { + shm_init_header(header, alloc, std::move(other)); + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const CLASS_NAME &other) { + shm_init_header(header, alloc, other); + } + + /** Destroy the shared-memory data. */ + void shm_destroy_main() {} + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} + + /**==================================== + * Constructors + * ===================================*/ + + /** Constructor. Allocate header with default allocator. */ + template + explicit CLASS_NAME(Args&& ...args) { + shm_init(std::forward(args)...); + } + + /** Constructor. Allocate header with default allocator. */ + template + void shm_init(Args&& ...args) { + shm_destroy(false); + shm_init_main(typed_nullptr(), + typed_nullptr(), + std::forward(args)...); + } + + /** Constructor. Initialize an already-allocated header. */ + template + void shm_init(TYPED_HEADER &header, + lipc::Allocator *alloc, Args&& ...args) { + shm_destroy(false); + shm_init_main(&header, alloc, std::forward(args)...); + } + + /** Initialize the allocator */ + void shm_init_allocator(Allocator *alloc) { + if (alloc == nullptr) { + alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + } else { + alloc_ = alloc; + } + } + + /** Default initialize a data structure's header. */ + void shm_init_header(TYPED_HEADER *header, + Allocator *alloc) { + if (IsValid()) { return; } + shm_init_allocator(alloc); + if (header != nullptr) { + header_ = header; + Allocator::ConstructObj(*header_); + } else { + throw std::runtime_error("Header must be non-null during init of struct"); + } + } + + /** Piecewise initialize a data structure's header. */ + template + void shm_init_header(TYPED_HEADER *header, + Allocator *alloc, + Args&& ...args) { + if (IsValid()) { return; } + shm_init_allocator(alloc); + if (header == nullptr) { + throw std::runtime_error("Header must be non-null during init of struct"); + } + header_ = header; + Allocator::ConstructObj( + *header_, + alloc_, std::forward(args)...); + // TODO(llogan): pass headers to each container? + } + + /**==================================== + * Serialization + * ===================================*/ + + /** Serialize into a Pointer */ + void shm_serialize(TypedPointer &ar) const { + ar = GetAllocator()->template + Convert(header_); + shm_serialize_main(); + } + + /** Serialize into an AtomicPointer */ + void shm_serialize(TypedAtomicPointer &ar) const { + ar = GetAllocator()->template + Convert(header_); + shm_serialize_main(); + } + + /** Override << operators */ + SHM_SERIALIZE_OPS((TYPED_CLASS)) + + /**==================================== + * Deserialization + * ===================================*/ + + /** Deserialize object from a raw pointer */ + bool shm_deserialize(const TypedPointer &ar) { + return shm_deserialize( + HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_), + ar.ToOffsetPointer() + ); + } + + /** Deserialize object from allocator + offset */ + bool shm_deserialize(Allocator *alloc, OffsetPointer header_ptr) { + if (header_ptr.IsNull()) { return false; } + return shm_deserialize(alloc, + alloc->Convert< + TYPED_HEADER, + OffsetPointer>(header_ptr)); + } + + /** Deserialize object from another object (weak copy) */ + bool shm_deserialize(const CLASS_NAME &other) { + if (other.IsNull()) { return false; } + return shm_deserialize(other.GetAllocator(), other.header_); + } + + /** Deserialize object from allocator + header */ + bool shm_deserialize(Allocator *alloc, + TYPED_HEADER *header) { + /*alloc_ = alloc; + header_ = header; + hermes_shm::ForwardIterateTuple::Apply( + objs_, + [this, alloc](size_t i, auto &obj_) constexpr { + if constexpr(IS_SHM_ARCHIVEABLE(decltype(obj_))) { + obj_->shm_deserialize(alloc, this->header_->template Get()); + } + } + ); + shm_deserialize_main(); + return true;*/ + } + + /** Constructor. Deserialize the object from the reference. */ + template + void shm_init(lipc::ShmRef &obj) { + shm_deserialize(obj->GetAllocator(), obj->header_); + } + + /** Override >> operators */ + SHM_DESERIALIZE_OPS ((TYPED_CLASS)) + + /**==================================== + * Destructors + * ===================================*/ + + /** Destructor */ + ~CLASS_NAME() { + shm_destroy(true); + } + + /** Shm Destructor */ + void shm_destroy(bool destroy_header = true) { + /*hermes_shm::ReverseIterateTuple::Apply( + objs_, + [destroy_header](size_t i, auto &obj_) constexpr { + if constexpr(IS_SHM_ARCHIVEABLE(decltype(obj_))) { + obj_.shm_destroy(destroy_header); + } + } + );*/ + } + + /**==================================== + * Move Operations + * ===================================*/ + + /** Move constructor */ + CLASS_NAME(CLASS_NAME &&other) noexcept { + shm_weak_move( + typed_nullptr(), + typed_nullptr(), + other); + } + + /** Move assignment operator */ + CLASS_NAME& operator=(CLASS_NAME &&other) noexcept { + shm_weak_move( + typed_nullptr(), + typed_nullptr(), + other); + return *this; + } + + /** Move shm_init constructor */ + void shm_init_main(TYPED_HEADER *header, + lipc::Allocator *alloc, + CLASS_NAME &&other) noexcept { + shm_weak_move(header, alloc, other); + } + + /** Move operation */ + void shm_weak_move(TYPED_HEADER *header, + lipc::Allocator *alloc, + CLASS_NAME &other) { + /*hermes_shm::ForwardIterateTuple::Apply( + objs_, + [header, alloc, other](size_t i, auto &obj_) constexpr { + if constexpr(IS_SHM_ARCHIVEABLE(decltype(obj_))) { + obj_.shm_weak_move(header, alloc, other.objs_.template Get()); + } else { + obj_ = std::move(other.objs_.template Get()); + } + } + );*/ + } + + /**==================================== + * Copy Operations + * ===================================*/ + + /** Copy constructor */ + CLASS_NAME(const CLASS_NAME &other) noexcept { + shm_init(other); + } + + /** Copy assignment constructor */ + CLASS_NAME &operator=(const CLASS_NAME &other) { + if (this != &other) { + shm_strong_copy( + typed_nullptr(), + typed_nullptr(), + other); + } + return *this; + } + + /** Copy shm_init constructor */ + void shm_init_main(TYPED_HEADER *header, + lipc::Allocator *alloc, + const CLASS_NAME &other) { + shm_strong_copy(header, alloc, other); + } + + /** Strong Copy operation */ + void shm_strong_copy(TYPED_HEADER *header, lipc::Allocator *alloc, + const CLASS_NAME &other) { + /*hermes_shm::ForwardIterateTuple::Apply( + objs_, + [header, alloc, other](size_t i, auto &obj_) constexpr { + if constexpr(IS_SHM_ARCHIVEABLE(decltype(obj_))) { + obj_.shm_strong_copy(header, alloc, other.objs_.template Get()); + } else { + obj_ = other.objs_.template Get(); + } + } + ); + shm_strong_copy_main(header, alloc, other);*/ + } + + /**==================================== + * Container Flag Operations + * ===================================*/ + + /** Sets this object as destructable */ + void SetDestructable() { + hermes_shm::ForwardIterateTuple::Apply( + objs_, + [](size_t i, auto &obj_) constexpr { + if constexpr(IS_SHM_ARCHIVEABLE(decltype(obj_))) { + obj_.SetDestructable(); + } + } + ); + } + + /** Sets this object as not destructable */ + void UnsetDestructable() { + hermes_shm::ForwardIterateTuple::Apply( + objs_, + [](size_t i, auto &obj_) constexpr { + if constexpr(IS_SHM_ARCHIVEABLE(decltype(obj_))) { + obj_.UnsetDestructable(); + } + } + ); + } + + /** Check if this container is destructable */ + bool IsDestructable() const { return true; } + + /** Check if container has a valid header */ + bool IsValid() const { return header_ != nullptr; } + + /**==================================== + * Header Flag Operations + * ===================================*/ + + /** Check if null */ + bool IsNull() const { + return IsValid(); + } + + /** Get a typed pointer to the object */ + template + POINTER_T GetShmPointer() const { + return GetAllocator()->template + Convert(header_); + } + + /**==================================== + * Query Operations + * ===================================*/ + + /** Get the allocator for this container */ + Allocator* GetAllocator() { + return alloc_; + } + + /** Get the allocator for this container */ + Allocator* GetAllocator() const { + return alloc_; + } + + /** Get the shared-memory allocator id */ + allocator_id_t GetAllocatorId() const { + return GetAllocator()->GetId(); + } + + /** Get the ith constructed container in the tuple */ + template + auto& Get() { + return objs_.template Get(); + } + + /** Get the ith constructed container in the tuple (const) */ + template + auto& Get() const { + return objs_.template Get(); + } +}; + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_STRUCT_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h new file mode 100644 index 000000000..8695151a2 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h @@ -0,0 +1,531 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ +#define HERMES_SHM_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ + +#include "hermes_shm/data_structures/data_structure.h" +#include "hermes_shm/data_structures/internal/shm_archive_or_t.h" + +#include + +namespace hermes_shm::ipc { + +/** forward pointer for list */ +template +class list; + +/** represents an object within a list */ +template +struct list_entry { + public: + OffsetPointer next_ptr_, prior_ptr_; + ShmHeaderOrT data_; + + /** Constructor */ + template + explicit list_entry(Allocator *alloc, Args ...args) + : data_(alloc, std::forward(args)...) {} + + /** Destructor */ + void shm_destroy(Allocator *alloc) { + data_.shm_destroy(alloc); + } + + /** Returns the element stored in the list */ + ShmRef internal_ref(Allocator *alloc) { + return ShmRef(data_.internal_ref(alloc)); + } + + /** Returns the element stored in the list */ + ShmRef internal_ref(Allocator *alloc) const { + return ShmRef(data_.internal_ref(alloc)); + } +}; + +/** + * The list iterator + * */ +template +struct list_iterator_templ { + public: + /**< A shm reference to the containing list object. */ + lipc::ShmRef> list_; + /**< A pointer to the entry in shared memory */ + list_entry *entry_; + /**< The offset of the entry in the shared-memory allocator */ + OffsetPointer entry_ptr_; + + /** Default constructor */ + list_iterator_templ() = default; + + /** End iterator */ + explicit list_iterator_templ(bool) + : entry_(nullptr), entry_ptr_(OffsetPointer::GetNull()) {} + + /** Construct an iterator */ + explicit list_iterator_templ(TypedPointer> list) + : list_(list), entry_(nullptr), entry_ptr_(OffsetPointer::GetNull()) {} + + /** Construct an iterator */ + explicit list_iterator_templ(TypedPointer> list, + list_entry *entry, + OffsetPointer entry_ptr) + : list_(list), entry_(entry), entry_ptr_(entry_ptr) {} + + /** Copy constructor */ + list_iterator_templ(const list_iterator_templ &other) { + list_ = other.list_; + entry_ = other.entry_; + entry_ptr_ = other.entry_ptr_; + } + + /** Assign this iterator from another iterator */ + list_iterator_templ& operator=(const list_iterator_templ &other) { + if (this != &other) { + list_ = other.list_; + entry_ = other.entry_; + entry_ptr_ = other.entry_ptr_; + } + return *this; + } + + /** Get the object the iterator points to */ + ShmRef operator*() { + return entry_->internal_ref(list_->GetAllocator()); + } + + /** Get the object the iterator points to */ + const ShmRef operator*() const { + return entry_->internal_ref(); + } + + /** Get the next iterator (in place) */ + list_iterator_templ& operator++() { + if (is_end()) { return *this; } + entry_ptr_ = entry_->next_ptr_; + entry_ = list_->alloc_->template + Convert>(entry_->next_ptr_); + return *this; + } + + /** Get the prior iterator (in place) */ + list_iterator_templ& operator--() { + if (is_end() || is_begin()) { return *this; } + entry_ptr_ = entry_->prior_ptr_; + entry_ = list_->alloc_->template + Convert>(entry_->prior_ptr_); + return *this; + } + + /** Return the next iterator */ + list_iterator_templ operator++(int) const { + list_iterator_templ next_iter(*this); + ++next_iter; + return next_iter; + } + + /** Return the prior iterator */ + list_iterator_templ operator--(int) const { + list_iterator_templ prior_iter(*this); + --prior_iter; + return prior_iter; + } + + /** Return the iterator at count after this one */ + list_iterator_templ operator+(size_t count) const { + list_iterator_templ pos(*this); + for (size_t i = 0; i < count; ++i) { + ++pos; + } + return pos; + } + + /** Return the iterator at count before this one */ + list_iterator_templ operator-(size_t count) const { + list_iterator_templ pos(*this); + for (size_t i = 0; i < count; ++i) { + --pos; + } + return pos; + } + + /** Get the iterator at count after this one (in-place) */ + void operator+=(size_t count) { + list_iterator_templ pos = (*this) + count; + entry_ = pos.entry_; + entry_ptr_ = pos.entry_ptr_; + } + + /** Get the iterator at count before this one (in-place) */ + void operator-=(size_t count) { + list_iterator_templ pos = (*this) - count; + entry_ = pos.entry_; + entry_ptr_ = pos.entry_ptr_; + } + + /** Determine if two iterators are equal */ + friend bool operator==(const list_iterator_templ &a, + const list_iterator_templ &b) { + return (a.is_end() && b.is_end()) || (a.entry_ == b.entry_); + } + + /** Determine if two iterators are inequal */ + friend bool operator!=(const list_iterator_templ &a, + const list_iterator_templ &b) { + return !(a.is_end() && b.is_end()) && (a.entry_ != b.entry_); + } + + /** Create the end iterator */ + static list_iterator_templ const end() { + const static list_iterator_templ end_iter(true); + return end_iter; + } + + /** Determine whether this iterator is the end iterator */ + bool is_end() const { + return entry_ == nullptr; + } + + /** Determine whether this iterator is the begin iterator */ + bool is_begin() const { + if (entry_) { + return entry_->prior_ptr_.IsNull(); + } else { + return false; + } + } +}; + +/** forward iterator typedef */ +template +using list_iterator = list_iterator_templ; + +/** const forward iterator typedef */ +template +using list_citerator = list_iterator_templ; + + +/** + * MACROS used to simplify the list namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ +#define CLASS_NAME list +#define TYPED_CLASS list +#define TYPED_HEADER ShmHeader> + +/** + * The list shared-memory header + * */ +template +struct ShmHeader> : public ShmBaseHeader { + OffsetPointer head_ptr_, tail_ptr_; + size_t length_; + + /** Default constructor */ + ShmHeader() = default; + + /** Copy constructor */ + ShmHeader(const ShmHeader &other) { + strong_copy(other); + } + + /** Copy assignment operator */ + ShmHeader& operator=(const ShmHeader &other) { + if (this != &other) { + strong_copy(other); + } + return *this; + } + + /** Strong copy operation */ + void strong_copy(const ShmHeader &other) { + head_ptr_ = other.head_ptr_; + tail_ptr_ = other.tail_ptr_; + length_ = other.length_; + } + + /** Move constructor */ + ShmHeader(ShmHeader &&other) { + weak_move(other); + } + + /** Move operator */ + ShmHeader& operator=(ShmHeader &&other) { + if (this != &other) { + weak_move(other); + } + return *this; + } + + /** Move operation */ + void weak_move(ShmHeader &other) { + strong_copy(other); + } +}; + +/** + * Doubly linked list implementation + * */ +template +class list : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) + + public: + //////////////////////////// + /// SHM Overrides + //////////////////////////// + + /** Default constructor */ + list() = default; + + /** Initialize list in shared memory */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header); + header_->length_ = 0; + header_->head_ptr_.SetNull(); + header_->tail_ptr_.SetNull(); + } + + /** Copy from std::list */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, std::list &other) { + shm_init_allocator(alloc); + shm_init_header(header); + for (auto &entry : other) { + emplace_back(entry); + } + } + + /** Destroy all shared memory allocated by the list */ + void shm_destroy_main() { + clear(); + } + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, list &other) { + shm_init_allocator(alloc); + shm_init_header(header); + *header_ = *(other.header_); + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const list &other) { + shm_init_allocator(alloc); + shm_init_header(header); + for (auto iter = other.cbegin(); iter != other.cend(); ++iter) { + emplace_back(**iter); + } + } + + //////////////////////////// + /// List Methods + //////////////////////////// + + /** Construct an element at the back of the list */ + template + void emplace_back(Args&&... args) { + emplace(end(), std::forward(args)...); + } + + /** Construct an element at the beginning of the list */ + template + void emplace_front(Args&&... args) { + emplace(begin(), std::forward(args)...); + } + + /** Construct an element at \a pos position in the list */ + template + void emplace(list_iterator pos, Args&&... args) { + OffsetPointer entry_ptr; + auto entry = _create_entry(entry_ptr, std::forward(args)...); + if (size() == 0) { + entry->prior_ptr_.SetNull(); + entry->next_ptr_.SetNull(); + header_->head_ptr_ = entry_ptr; + header_->tail_ptr_ = entry_ptr; + } else if (pos.is_begin()) { + entry->prior_ptr_.SetNull(); + entry->next_ptr_ = header_->head_ptr_; + auto head = alloc_->template + Convert>(header_->tail_ptr_); + head->prior_ptr_ = entry_ptr; + header_->head_ptr_ = entry_ptr; + } else if (pos.is_end()) { + entry->prior_ptr_ = header_->tail_ptr_; + entry->next_ptr_.SetNull(); + auto tail = alloc_->template + Convert>(header_->tail_ptr_); + tail->next_ptr_ = entry_ptr; + header_->tail_ptr_ = entry_ptr; + } else { + auto next = alloc_->template + Convert>(pos.entry_->next_ptr_); + auto prior = alloc_->template + Convert>(pos.entry_->prior_ptr_); + entry->next_ptr_ = pos.entry_->next_ptr_; + entry->prior_ptr_ = pos.entry_->prior_ptr_; + next->prior_ptr_ = entry_ptr; + prior->next_ptr_ = entry_ptr; + } + ++header_->length_; + } + + /** Erase element with ID */ + void erase(const T &entry) { + auto iter = find(entry); + erase(iter); + } + + /** Erase the element at pos */ + void erase(list_iterator pos) { + erase(pos, pos+1); + } + + /** Erase all elements between first and last */ + void erase(list_iterator first, + list_iterator last) { + if (first.is_end()) { return; } + auto first_prior_ptr = first.entry_->prior_ptr_; + auto pos = first; + while (pos != last) { + auto next = pos + 1; + pos.entry_->shm_destroy(alloc_); + Allocator::DestructObj>(*pos.entry_); + alloc_->Free(pos.entry_ptr_); + --header_->length_; + pos = next; + } + + if (first_prior_ptr.IsNull()) { + header_->head_ptr_ = last.entry_ptr_; + } else { + auto first_prior = alloc_->template + Convert>(first_prior_ptr); + first_prior->next_ptr_ = last.entry_ptr_; + } + + if (last.entry_ptr_.IsNull()) { + header_->tail_ptr_ = first_prior_ptr; + } else { + last.entry_->prior_ptr_ = first_prior_ptr; + } + } + + /** Destroy all elements in the list */ + void clear() { + erase(begin(), end()); + } + + /** Get the object at the front of the list */ + ShmRef front() { + return *begin(); + } + + /** Get the object at the back of the list */ + ShmRef back() { + return *end(); + } + + /** Get the number of elements in the list */ + size_t size() const { + if (!IsNull()) { + return header_->length_; + } + return 0; + } + + /** Find an element in this list */ + list_iterator find(const T &entry) { + for (auto iter = begin(); iter != end(); ++iter) { + lipc::ShmRef ref = *iter; + if (*ref == entry) { + return iter; + } + } + return end(); + } + + /** + * ITERATORS + * */ + + /** Forward iterator begin */ + list_iterator begin() { + if (size() == 0) { return end(); } + auto head = alloc_->template + Convert>(header_->head_ptr_); + return list_iterator(GetShmPointer>>(), + head, header_->head_ptr_); + } + + /** Forward iterator end */ + static list_iterator const end() { + return list_iterator::end(); + } + + /** Constant forward iterator begin */ + list_citerator cbegin() const { + if (size() == 0) { return cend(); } + auto head = alloc_->template + Convert>(header_->head_ptr_); + return list_citerator(GetShmPointer>>(), + head, header_->head_ptr_); + } + + /** Constant forward iterator end */ + static list_citerator const cend() { + return list_citerator::end(); + } + + private: + template + list_entry* _create_entry(OffsetPointer &p, Args&& ...args) { + auto entry = alloc_->template + AllocateConstructObjs>( + 1, p, alloc_, std::forward(args)...); + return entry; + } +}; + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif // HERMES_SHM_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h new file mode 100644 index 000000000..b6dd0f427 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_DATA_STRUCTURES_UNORDERED_MAP_H_ +#define HERMES_SHM_DATA_STRUCTURES_UNORDERED_MAP_H_ + +#include "hermes_shm/thread/thread_manager.h" +#include "hermes_shm/data_structures/thread_unsafe/vector.h" +#include "hermes_shm/data_structures/thread_unsafe/list.h" +#include "hermes_shm/data_structures/pair.h" +#include "hermes_shm/data_structures/data_structure.h" +#include "hermes_shm/types/atomic.h" + +namespace hermes_shm::ipc { + +/** forward pointer for unordered_map */ +template> +class unordered_map; + +/** + * The unordered map iterator (bucket_iter, list_iter) + * */ +template +struct unordered_map_iterator { + public: + using COLLISION_T = lipc::pair; + using BUCKET_T = lipc::list; + + public: + lipc::ShmRef> map_; + vector_iterator bucket_; + list_iterator collision_; + + /** Default constructor */ + unordered_map_iterator() = default; + + /** Construct the iterator */ + explicit unordered_map_iterator(TypedPointer> map) + : map_(map) {} + + /** Copy constructor */ + unordered_map_iterator(const unordered_map_iterator &other) { + shm_strong_copy(other); + } + + /** Assign one iterator into another */ + unordered_map_iterator& + operator=(const unordered_map_iterator &other) { + if (this != &other) { + shm_strong_copy(other); + } + return *this; + } + + /** Copy an iterator */ + void shm_strong_copy(const unordered_map_iterator &other) { + map_ = other.map_; + bucket_ = other.bucket_; + collision_ = other.collision_; + } + + /** Get the pointed object */ + lipc::ShmRef operator*() { + return *collision_; + } + + /** Get the pointed object */ + const lipc::ShmRef operator*() const { + return *collision_; + } + + /** Go to the next object */ + unordered_map_iterator& operator++() { + ++collision_; + make_correct(); + return *this; + } + + /** Return the next iterator */ + unordered_map_iterator operator++(int) const { + unordered_map_iterator next(*this); + ++next; + return next; + } + + /** + * Shifts bucket and collision iterator until there is a valid element. + * Returns true if such an element is found, and false otherwise. + * */ + bool make_correct() { + do { + if (bucket_.is_end()) { + return false; + } + BUCKET_T& bkt = (**bucket_); + list &collisions = bkt; + if (collision_ != collisions.end()) { + return true; + } else { + ++bucket_; + if (bucket_.is_end()) { + return false; + } + BUCKET_T& new_bkt = (**bucket_); + list &new_collisions = new_bkt; + collision_ = collisions.begin(); + } + } while (true); + } + + /** Check if two iterators are equal */ + friend bool operator==(const unordered_map_iterator &a, + const unordered_map_iterator &b) { + if (a.is_end() && b.is_end()) { + return true; + } + return (a.bucket_ == b.bucket_) && (a.collision_ == b.collision_); + } + + /** Check if two iterators are inequal */ + friend bool operator!=(const unordered_map_iterator &a, + const unordered_map_iterator &b) { + if (a.is_end() && b.is_end()) { + return false; + } + return (a.bucket_ != b.bucket_) || (a.collision_ != b.collision_); + } + + /** Determine whether this iterator is the end iterator */ + bool is_end() const { + return bucket_.is_end(); + } + + /** Set this iterator to the end iterator */ + void set_end() { + bucket_.set_end(); + } +}; + +/** + * MACROS to simplify the unordered_map namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ + +#define CLASS_NAME unordered_map +#define TYPED_CLASS unordered_map +#define TYPED_HEADER ShmHeader> + +/** + * The unordered_map shared-memory header + * */ +template +struct ShmHeader : public ShmBaseHeader { + public: + using COLLISION_T = lipc::pair; + using BUCKET_T = lipc::list; + + public: + ShmHeaderOrT> buckets_; + RealNumber max_capacity_; + RealNumber growth_; + lipc::atomic length_; + + /** Default constructor. */ + ShmHeader() = default; + + /** Constructor. Initialize header. */ + explicit ShmHeader(Allocator *alloc, + int num_buckets, + RealNumber max_capacity, + RealNumber growth) : buckets_(alloc, num_buckets) { + max_capacity_ = max_capacity; + growth_ = growth; + length_ = 0; + } + + /** Copy constructor */ + ShmHeader(const ShmHeader &other) = delete; + + /** Move constructor */ + ShmHeader(ShmHeader &&other) = delete; + + /** True move constructor. */ + explicit ShmHeader(Allocator *alloc, + ShmHeader &&other, Allocator *other_alloc) { + (*GetBuckets(alloc)) = std::move(*other.GetBuckets(other_alloc)); + max_capacity_ = other.max_capacity_; + growth_ = other.growth_; + length_ = other.length_.load();/**/ + } + + /** Get a reference to the buckets */ + lipc::ShmRef> GetBuckets(Allocator *alloc) { + return lipc::ShmRef>(buckets_.internal_ref(alloc)); + } +}; + +/** + * The unordered map implementation + * */ +template +class unordered_map : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) + friend unordered_map_iterator; + + public: + using COLLISION_T = lipc::pair; + using BUCKET_T = lipc::list; + + public: + //////////////////////////// + /// SHM Overrides + //////////////////////////// + + /** Default constructor */ + unordered_map() = default; + + /** + * Initialize unordered map + * + * @param alloc the shared-memory allocator + * @param num_buckets the number of buckets to create + * @param max_capacity the maximum number of elements before a growth is + * triggered + * @param growth the multiplier to grow the bucket vector size + * */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, + int num_buckets = 20, + RealNumber max_capacity = RealNumber(4,5), + RealNumber growth = RealNumber(5, 4)) { + shm_init_allocator(alloc); + shm_init_header(header, alloc_, num_buckets, max_capacity, growth); + } + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, unordered_map &other) { + shm_init_allocator(alloc); + shm_init_header(header, + alloc_, + std::move(*other.header_), + other.GetAllocator()); + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const unordered_map &other) { + auto num_buckets = other.get_num_buckets(); + auto max_capacity = other.header_->max_capacity_; + auto growth = other.header_->growth_; + shm_init_allocator(alloc); + shm_init_header(header, alloc_, num_buckets, max_capacity, growth); + for (auto entry : other) { + emplace_templ( + entry->GetKey(), entry->GetVal()); + } + } + + /** Destroy the unordered_map buckets */ + void shm_destroy_main() { + lipc::ShmRef> buckets = GetBuckets(); + buckets->shm_destroy(); + } + + //////////////////////////// + /// Map Operations + //////////////////////////// + + /** + * Construct an object directly in the map. Overrides the object if + * key already exists. + * + * @param key the key to future index the map + * @param args the arguments to construct the object + * @return None + * */ + template + bool emplace(const Key &key, Args&&... args) { + return emplace_templ(key, std::forward(args)...); + } + + /** + * Construct an object directly in the map. Does not modify the key + * if it already exists. + * + * @param key the key to future index the map + * @param args the arguments to construct the object + * @return None + * */ + template + bool try_emplace(const Key &key, Args&&... args) { + return emplace_templ(key, std::forward(args)...); + } + + /** + * Erase an object indexable by \a key key + * */ + void erase(const Key &key) { + if (header_ == nullptr) { shm_init(); } + // Get the bucket the key belongs to + lipc::ShmRef> buckets = GetBuckets(); + size_t bkt_id = Hash{}(key) % buckets->size(); + lipc::ShmRef bkt = (*buckets)[bkt_id]; + + // Find and remove key from collision list + list &collisions = *bkt; + auto iter = find_collision(key, collisions); + if (iter.is_end()) { + return; + } + collisions.erase(iter); + + // Decrement the size of the map + --header_->length_; + } + + /** + * Erase an object at the iterator + * */ + void erase(unordered_map_iterator &iter) { + if (iter == end()) return; + // Acquire the bucket lock for a write (modifying collisions) + lipc::ShmRef bkt = *iter.bucket_; + + // Erase the element from the collision list + list &collisions = bkt; + collisions.erase(iter.collision_); + + // Decrement the size of the map + --header_->length_; + } + + /** + * Erase the entire map + * */ + void clear() { + lipc::ShmRef> buckets = GetBuckets(); + size_t num_buckets = buckets->size(); + buckets->clear(); + buckets->resize(num_buckets); + header_->length_ = 0; + } + + /** + * Locate an entry in the unordered_map + * + * @return the object pointed by key + * @exception UNORDERED_MAP_CANT_FIND the key was not in the map + * */ + ShmRef operator[](const Key &key) { + auto iter = find(key); + if (iter != end()) { + return (*iter)->second_; + } + throw UNORDERED_MAP_CANT_FIND.format(); + } + + /** + * Find an object in the unordered_map + * */ + unordered_map_iterator find(const Key &key) { + unordered_map_iterator iter( + GetShmPointer>>()); + + // Determine the bucket corresponding to the key + lipc::ShmRef> buckets = GetBuckets(); + size_t bkt_id = Hash{}(key) % buckets->size(); + iter.bucket_ = buckets->begin() + bkt_id; + lipc::ShmRef bkt = (*iter.bucket_); + list &collisions = *bkt; + + // Get the specific collision iterator + iter.collision_ = find_collision(key, collisions); + if (iter.collision_.is_end()) { + iter.set_end(); + } + return iter; + } + + /** The number of entries in the map */ + size_t size() const { + if (header_ == nullptr) { + return 0; + } + return header_->length_.load(); + } + + /** The number of buckets in the map */ + size_t get_num_buckets() const { + lipc::ShmRef> buckets = GetBuckets(); + return buckets->size(); + } + + private: + /** + * Find a key in the collision list + * */ + list_iterator + find_collision(const Key &key, list &collisions) { + auto iter = collisions.begin(); + auto iter_end = collisions.end(); + for (; iter != iter_end; ++iter) { + COLLISION_T entry(alloc_, **iter); + if (entry.GetKey() == key) { + return iter; + } + } + return iter_end; + } + + /** + * Construct an object directly in the map + * + * @param key the key to future index the map + * @param args the arguments to construct the object + * @return None + * */ + template + bool emplace_templ(const Key &key, Args&&... args) { + COLLISION_T entry(alloc_, + PiecewiseConstruct(), + make_argpack(key), + make_argpack(std::forward(args)...)); + return insert_templ(entry); + } + + /** + * Insert a serialized (key, value) pair in the map + * + * @param growth whether or not to grow the unordered map on collision + * @param modify_existing whether or not to override an existing entry + * @param entry the (key,value) pair shared-memory serialized + * @return None + * */ + template + bool insert_templ(COLLISION_T &entry) { + if (header_ == nullptr) { shm_init(); } + Key &key = entry.GetKey(); + + // Hash the key to a bucket + lipc::ShmRef> buckets = GetBuckets(); + size_t bkt_id = Hash{}(key) % buckets->size(); + lipc::ShmRef bkt = (*buckets)[bkt_id]; + + // Insert into the map + list &collisions = *bkt; + auto has_key = find_collision(key, collisions); + if (has_key != collisions.end()) { + if constexpr(!modify_existing) { + return false; + } else { + collisions.erase(has_key); + collisions.emplace_back(std::move(entry)); + return true; + } + } + collisions.emplace_back(std::move(entry)); + + // Increment the size of the map + ++header_->length_; + return true; + } + + bool insert_simple(COLLISION_T &&entry, + vector &buckets) { + if (header_ == nullptr) { shm_init(); } + Key &key = entry.GetKey(); + size_t bkt_id = Hash{}(key) % buckets.size(); + lipc::ShmRef bkt = buckets[bkt_id]; + list& collisions = bkt; + collisions.emplace_back(std::move(entry)); + return true; + } + + + public: + //////////////////////////// + /// Iterators + //////////////////////////// + + /** Forward iterator begin */ + inline unordered_map_iterator begin() const { + unordered_map_iterator iter( + GetShmPointer>>()); + lipc::ShmRef> buckets(GetBuckets()); + if (buckets->size() == 0) { + return iter; + } + lipc::ShmRef bkt = (*buckets)[0]; + list &list = *bkt; + iter.bucket_ = buckets->cbegin(); + iter.collision_ = list.begin(); + iter.make_correct(); + return iter; + } + + /** Forward iterator end */ + inline unordered_map_iterator end() const { + unordered_map_iterator iter( + GetShmPointer>>()); + lipc::ShmRef> buckets(GetBuckets()); + iter.bucket_ = buckets->cend(); + return iter; + } + + /** Get the buckets */ + lipc::ShmRef> GetBuckets() { + return header_->GetBuckets(alloc_); + } + + /** Get the buckets (const) */ + lipc::ShmRef> GetBuckets() const { + return header_->GetBuckets(alloc_); + } +}; + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif // HERMES_SHM_DATA_STRUCTURES_UNORDERED_MAP_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h new file mode 100644 index 000000000..1817e4afe --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h @@ -0,0 +1,781 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ +#define HERMES_SHM_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ + +#include "hermes_shm/data_structures/data_structure.h" +#include "hermes_shm/data_structures/internal/shm_archive_or_t.h" + +#include + +namespace hermes_shm::ipc { + +/** forward pointer for vector */ +template +class vector; + +/** + * The vector iterator implementation + * */ +template +struct vector_iterator_templ { + public: + lipc::ShmRef> vec_; + off64_t i_; + + /** Default constructor */ + vector_iterator_templ() = default; + + /** Construct an iterator */ + inline explicit vector_iterator_templ(TypedPointer> vec) + : vec_(vec) {} + + /** Construct end iterator */ + inline explicit vector_iterator_templ(size_t i) + : i_(static_cast(i)) {} + + /** Construct an iterator at \a i offset */ + inline explicit vector_iterator_templ(TypedPointer> vec, size_t i) + : vec_(vec), i_(static_cast(i)) {} + + /** Construct an iterator at \a i offset */ + inline explicit vector_iterator_templ(const lipc::ShmRef> &vec, + size_t i) + : vec_(vec), i_(static_cast(i)) {} + + /** Copy constructor */ + inline vector_iterator_templ(const vector_iterator_templ &other) + : vec_(other.vec_), i_(other.i_) {} + + /** Copy assignment operator */ + inline vector_iterator_templ& + operator=(const vector_iterator_templ &other) { + if (this != &other) { + vec_ = other.vec_; + i_ = other.i_; + } + return *this; + } + + /** Move constructor */ + inline vector_iterator_templ(vector_iterator_templ &&other) { + vec_ = other.vec_; + i_ = other.i_; + } + + /** Move assignment operator */ + inline vector_iterator_templ& + operator=(vector_iterator_templ &&other) { + if (this != &other) { + vec_ = other.vec_; + i_ = other.i_; + } + return *this; + } + + /** Dereference the iterator */ + inline ShmRef operator*() { + return ShmRef(vec_->data_ar()[i_].internal_ref( + vec_->GetAllocator())); + } + + /** Dereference the iterator */ + inline const ShmRef operator*() const { + return ShmRef(vec_->data_ar_const()[i_].internal_ref( + vec_->GetAllocator())); + } + + /** Increment iterator in-place */ + inline vector_iterator_templ& operator++() { + if (is_end()) { return *this; } + if constexpr(FORWARD_ITER) { + ++i_; + if (i_ >= vec_->size()) { + set_end(); + } + } else { + if (i_ == 0) { + set_end(); + } else { + --i_; + } + } + return *this; + } + + /** Decrement iterator in-place */ + inline vector_iterator_templ& operator--() { + if (is_begin() || is_end()) { return *this; } + if constexpr(FORWARD_ITER) { + --i_; + } else { + ++i_; + } + return *this; + } + + /** Create the next iterator */ + inline vector_iterator_templ operator++(int) const { + vector_iterator_templ next_iter(*this); + ++next_iter; + return next_iter; + } + + /** Create the prior iterator */ + inline vector_iterator_templ operator--(int) const { + vector_iterator_templ prior_iter(*this); + --prior_iter; + return prior_iter; + } + + /** Increment iterator by \a count and return */ + inline vector_iterator_templ operator+(size_t count) const { + if (is_end()) { return end(); } + if constexpr(FORWARD_ITER) { + if (i_ + count > vec_->size()) { + return end(); + } + return vector_iterator_templ(vec_, i_ + count); + } else { + if (i_ < count - 1) { + return end(); + } + return vector_iterator_templ(vec_, i_ - count); + } + } + + /** Decrement iterator by \a count and return */ + inline vector_iterator_templ operator-(size_t count) const { + if (is_end()) { return end(); } + if constexpr(FORWARD_ITER) { + if (i_ < count) { + return begin(); + } + return vector_iterator_templ(vec_, i_ - count); + } else { + if (i_ + count > vec_->size() - 1) { + return begin(); + } + return vector_iterator_templ(vec_, i_ + count); + } + } + + /** Increment iterator by \a count in-place */ + inline void operator+=(size_t count) { + if (is_end()) { return end(); } + if constexpr(FORWARD_ITER) { + if (i_ + count > vec_->size()) { + set_end(); + return; + } + i_ += count; + return; + } else { + if (i_ < count - 1) { + set_end(); + return; + } + i_ -= count; + return; + } + } + + /** Decrement iterator by \a count in-place */ + inline void operator-=(size_t count) { + if (is_end()) { return end(); } + if constexpr(FORWARD_ITER) { + if (i_ < count) { + set_begin(); + return; + } + i_ -= count; + return; + } else { + if (i_ + count > vec_->size() - 1) { + set_begin(); + return; + } + i_ += count; + return; + } + } + + /** Check if two iterators are equal */ + inline friend bool operator==(const vector_iterator_templ &a, + const vector_iterator_templ &b) { + return (a.i_ == b.i_); + } + + /** Check if two iterators are inequal */ + inline friend bool operator!=(const vector_iterator_templ &a, + const vector_iterator_templ &b) { + return (a.i_ != b.i_); + } + + /** Create the begin iterator */ + inline vector_iterator_templ const begin() { + if constexpr(FORWARD_ITER) { + return vector_iterator_templ(vec_, 0); + } else { + return vector_iterator_templ(vec_, vec_->size() - 1); + } + } + + /** Create the end iterator */ + inline static vector_iterator_templ const end() { + static vector_iterator_templ end_iter(-1); + return end_iter; + } + + /** Set this iterator to end */ + inline void set_end() { + i_ = -1; + } + + /** Set this iterator to begin */ + inline void set_begin() { + if constexpr(FORWARD_ITER) { + if (vec_->size() > 0) { + i_ = 0; + } else { + set_end(); + } + } else { + i_ = vec_->size() - 1; + } + } + + /** Determine whether this iterator is the begin iterator */ + inline bool is_begin() const { + if constexpr(FORWARD_ITER) { + return (i_ == 0); + } else { + return (i_ == vec_->size() - 1); + } + } + + /** Determine whether this iterator is the end iterator */ + inline bool is_end() const { + return i_ < 0; + } +}; + +/** Forward iterator typedef */ +template +using vector_iterator = vector_iterator_templ; + +/** Backward iterator typedef */ +template +using vector_riterator = vector_iterator_templ; + +/** Constant forward iterator typedef */ +template +using vector_citerator = vector_iterator_templ; + +/** Backward iterator typedef */ +template +using vector_criterator = vector_iterator_templ; + +/** + * MACROS used to simplify the vector namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ +#define CLASS_NAME vector +#define TYPED_CLASS vector +#define TYPED_HEADER ShmHeader> + +/** + * The vector shared-memory header + * */ +template +struct ShmHeader : public ShmBaseHeader { + AtomicPointer vec_ptr_; + size_t max_length_, length_; + + /** Default constructor */ + ShmHeader() = default; + + /** Copy constructor */ + ShmHeader(const ShmHeader &other) { + strong_copy(other); + } + + /** Copy assignment operator */ + ShmHeader& operator=(const ShmHeader &other) { + if (this != &other) { + strong_copy(other); + } + return *this; + } + + /** Strong copy operation */ + void strong_copy(const ShmHeader &other) { + vec_ptr_ = other.vec_ptr_; + max_length_ = other.max_length_; + length_ = other.length_; + } + + /** Move constructor */ + ShmHeader(ShmHeader &&other) { + weak_move(other); + } + + /** Move operator */ + ShmHeader& operator=(ShmHeader &&other) { + if (this != &other) { + weak_move(other); + } + return *this; + } + + /** Move operation */ + void weak_move(ShmHeader &other) { + strong_copy(other); + } +}; + +/** + * The vector class + * */ +template +class vector : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) + + public: + //////////////////////////// + /// SHM Overrides + //////////////////////////// + + /** Default constructor */ + vector() = default; + + /** Construct the vector in shared memory */ + template + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, size_t length, Args&& ...args) { + shm_init_allocator(alloc); + shm_init_header(header); + resize(length, std::forward(args)...); + } + + /** Construct the vector in shared memory */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header); + header_->length_ = 0; + header_->max_length_ = 0; + header_->vec_ptr_.SetNull(); + } + + /** Copy from std::vector */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, std::vector &other) { + shm_init_allocator(alloc); + shm_init_header(header); + reserve(other.size()); + for (auto &entry : other) { + emplace_back(entry); + } + } + + /** Destroy all shared memory allocated by the vector */ + void shm_destroy_main() { + erase(begin(), end()); + if (!header_->vec_ptr_.IsNull()) { + alloc_->Free(header_->vec_ptr_); + } + } + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, vector &other) { + shm_init_allocator(alloc); + shm_init_header(header); + *header_ = *(other.header_); + other.header_->length_ = 0; + } + + /** Copy a vector */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const vector &other) { + shm_init_allocator(alloc); + shm_init_header(header); + reserve(other.size()); + for (auto iter = other.cbegin(); iter != other.cend(); ++iter) { + emplace_back((**iter)); + } + } + + //////////////////////////// + /// Vector Operations + //////////////////////////// + + /** + * Convert to std::vector + * */ + std::vector vec() { + std::vector v; + v.reserve(size()); + for (lipc::ShmRef entry : *this) { + v.emplace_back(*entry); + } + return v; + } + + /** + * Reserve space in the vector to emplace elements. Does not + * change the size of the list. + * + * @param length the maximum size the vector can get before a growth occurs + * @param args the arguments to construct + * */ + template + void reserve(size_t length, Args&& ...args) { + if (IsNull()) { shm_init(); } + if (length == 0) { return; } + grow_vector(data_ar(), length, false, std::forward(args)...); + } + + /** + * Reserve space in the vector to emplace elements. Changes the + * size of the list. + * + * @param length the maximum size the vector can get before a growth occurs + * @param args the arguments used to construct the vector elements + * */ + template + void resize(size_t length, Args&& ...args) { + if (IsNull()) { shm_init(); } + if (length == 0) { return; } + grow_vector(data_ar(), length, true, std::forward(args)...); + header_->length_ = length; + } + + /** Index the vector at position i */ + lipc::ShmRef operator[](const size_t i) { + ShmHeaderOrT *vec = data_ar(); + return lipc::ShmRef(vec[i].internal_ref(alloc_)); + } + + /** Get first element of vector */ + lipc::ShmRef front() { + return (*this)[0]; + } + + /** Get last element of vector */ + lipc::ShmRef back() { + return (*this)[size() - 1]; + } + + /** Index the vector at position i */ + const lipc::ShmRef operator[](const size_t i) const { + ShmHeaderOrT *vec = data_ar_const(); + return lipc::ShmRef(vec[i].internal_ref(alloc_)); + } + + /** Construct an element at the back of the vector */ + template + void emplace_back(Args&& ...args) { + ShmHeaderOrT *vec = data_ar(); + if (header_->length_ == header_->max_length_) { + vec = grow_vector(vec, 0, false); + } + Allocator::ConstructObj>( + *(vec + header_->length_), + alloc_, std::forward(args)...); + ++header_->length_; + } + + /** Construct an element in the front of the vector */ + template + void emplace_front(Args&& ...args) { + emplace(begin(), std::forward(args)...); + } + + /** Construct an element at an arbitrary position in the vector */ + template + void emplace(vector_iterator pos, Args&&... args) { + if (pos.is_end()) { + emplace_back(std::forward(args)...); + return; + } + ShmHeaderOrT *vec = data_ar(); + if (header_->length_ == header_->max_length_) { + vec = grow_vector(vec, 0, false); + } + shift_right(pos); + Allocator::ConstructObj>( + *(vec + pos.i_), + alloc_, std::forward(args)...); + ++header_->length_; + } + + /** Delete the element at \a pos position */ + void erase(vector_iterator pos) { + if (pos.is_end()) return; + shift_left(pos, 1); + header_->length_ -= 1; + } + + /** Delete elements between first and last */ + void erase(vector_iterator first, vector_iterator last) { + size_t last_i; + if (first.is_end()) return; + if (last.is_end()) { + last_i = size(); + } else { + last_i = last.i_; + } + size_t count = last_i - first.i_; + if (count == 0) return; + shift_left(first, count); + header_->length_ -= count; + } + + /** Delete all elements from the vector */ + void clear() { + erase(begin(), end()); + } + + /** Get the size of the vector */ + size_t size() const { + if (header_ == nullptr) { + return 0; + } + return header_->length_; + } + + /** Get the data in the vector */ + void* data() { + if (header_ == nullptr) { + return nullptr; + } + return alloc_->template + Convert(header_->vec_ptr_); + } + + /** Get constant pointer to the data */ + void* data_const() const { + if (header_ == nullptr) { + return nullptr; + } + return alloc_->template + Convert(header_->vec_ptr_); + } + + /** + * Retreives a pointer to the array from the process-independent pointer. + * */ + ShmHeaderOrT* data_ar() { + return alloc_->template + Convert>(header_->vec_ptr_); + } + + /** + * Retreives a pointer to the array from the process-independent pointer. + * */ + ShmHeaderOrT* data_ar_const() const { + return alloc_->template + Convert>(header_->vec_ptr_); + } + + private: + /** + * Grow a vector to a new size. + * + * @param vec the C-style array of elements to grow + * @param max_length the new length of the vector. If 0, the current size + * of the vector will be multiplied by a constant. + * @param args the arguments used to construct the elements of the vector + * */ + template + ShmHeaderOrT* grow_vector(ShmHeaderOrT *vec, size_t max_length, + bool resize, Args&& ...args) { + // Grow vector by 25% + if (max_length == 0) { + max_length = 5 * header_->max_length_ / 4; + if (max_length <= header_->max_length_ + 10) { + max_length += 10; + } + } + if (max_length < header_->max_length_) { + return nullptr; + } + + // Allocate new shared-memory vec + ShmHeaderOrT *new_vec; + if constexpr(std::is_pod() || IS_SHM_ARCHIVEABLE(T)) { + // Use reallocate for well-behaved objects + new_vec = alloc_->template + ReallocateObjs>(header_->vec_ptr_, max_length); + } else { + // Use std::move for unpredictable objects + Pointer new_p; + new_vec = alloc_->template + AllocateObjs>(max_length, new_p); + for (size_t i = 0; i < header_->length_; ++i) { + lipc::ShmRef old = (*this)[i]; + Allocator::ConstructObj>( + *(new_vec + i), + alloc_, std::move(*old)); + } + if (!header_->vec_ptr_.IsNull()) { + alloc_->Free(header_->vec_ptr_); + } + header_->vec_ptr_ = new_p; + } + if (new_vec == nullptr) { + throw OUT_OF_MEMORY.format("vector::emplace_back", + max_length*sizeof(ShmHeaderOrT)); + } + if (resize) { + for (size_t i = header_->length_; i < max_length; ++i) { + Allocator::ConstructObj>( + *(new_vec + i), + alloc_, std::forward(args)...); + } + } + + // Update vector header + header_->max_length_ = max_length; + + return new_vec; + } + + /** + * Shift every element starting at "pos" to the left by count. Any element + * who would be shifted before "pos" will be deleted. + * + * @param pos the starting position + * @param count the amount to shift left by + * */ + void shift_left(const vector_iterator pos, int count = 1) { + ShmHeaderOrT *vec = data_ar(); + for (int i = 0; i < count; ++i) { + auto &vec_i = *(vec + pos.i_ + i); + vec_i.shm_destroy(alloc_); + Allocator::DestructObj>(vec_i); + } + auto dst = vec + pos.i_; + auto src = dst + count; + for (auto i = pos.i_ + count; i < size(); ++i) { + memcpy(dst, src, sizeof(ShmHeaderOrT)); + dst += 1; src += 1; + } + } + + /** + * Shift every element starting at "pos" to the right by count. Increases + * the total number of elements of the vector by "count". Does not modify + * the size parameter of the vector, this is done elsewhere. + * + * @param pos the starting position + * @param count the amount to shift right by + * */ + void shift_right(const vector_iterator pos, int count = 1) { + auto src = data_ar() + size() - 1; + auto dst = src + count; + auto sz = static_cast(size()); + for (auto i = sz - 1; i >= pos.i_; --i) { + memcpy(dst, src, sizeof(ShmHeaderOrT)); + dst -= 1; src -= 1; + } + } + + //////////////////////////// + /// Iterators + //////////////////////////// + + public: + /** Beginning of the forward iterator */ + vector_iterator begin() { + if (size() == 0) { return end(); } + vector_iterator iter(GetShmPointer>>()); + iter.set_begin(); + return iter; + } + + /** End of the forward iterator */ + static vector_iterator const end() { + return vector_iterator::end(); + } + + /** Beginning of the constant forward iterator */ + vector_citerator cbegin() const { + if (size() == 0) { return cend(); } + vector_citerator iter(GetShmPointer>>()); + iter.set_begin(); + return iter; + } + + /** End of the forward iterator */ + static const vector_citerator cend() { + return vector_citerator::end(); + } + + /** Beginning of the reverse iterator */ + vector_riterator rbegin() { + if (size() == 0) { return rend(); } + vector_riterator iter(GetShmPointer>>()); + iter.set_begin(); + return iter; + } + + /** End of the reverse iterator */ + static vector_riterator const rend() { + return vector_riterator::end(); + } + + /** Beginning of the constant reverse iterator */ + vector_criterator crbegin() { + if (size() == 0) { return rend(); } + vector_criterator iter(GetShmPointer>>()); + iter.set_begin(); + return iter; + } + + /** End of the constant reverse iterator */ + static vector_criterator const crend() { + return vector_criterator::end(); + } +}; + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif // HERMES_SHM_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ diff --git a/hermes_shm/include/hermes_shm/introspect/system_info.h b/hermes_shm/include/hermes_shm/introspect/system_info.h new file mode 100644 index 000000000..6d73dbdae --- /dev/null +++ b/hermes_shm/include/hermes_shm/introspect/system_info.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_SYSINFO_INFO_H_ +#define HERMES_SHM_SYSINFO_INFO_H_ + +#include +#include + +namespace hermes_shm { + +struct SystemInfo { + int pid_; + int ncpu_; + int page_size_; + size_t ram_size_; + + SystemInfo() { + pid_ = getpid(); + ncpu_ = get_nprocs_conf(); + page_size_ = getpagesize(); + struct sysinfo info; + sysinfo(&info); + ram_size_ = info.totalram; + } +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_SYSINFO_INFO_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/allocator.h new file mode 100644 index 000000000..5e60747ec --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/allocator/allocator.h @@ -0,0 +1,509 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_H_ +#define HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_H_ + +#include +#include +#include + +namespace hermes_shm::ipc { + +/** + * The allocator type. + * Used to reconstruct allocator from shared memory + * */ +enum class AllocatorType { + kPageAllocator, + kMultiPageAllocator, + kStackAllocator, + kMallocAllocator, +}; + +/** + * The basic shared-memory allocator header. + * Allocators inherit from this. + * */ +struct AllocatorHeader { + int allocator_type_; + allocator_id_t allocator_id_; + size_t custom_header_size_; + + AllocatorHeader() = default; + + void Configure(allocator_id_t allocator_id, + AllocatorType type, + size_t custom_header_size) { + allocator_type_ = static_cast(type); + allocator_id_ = allocator_id; + custom_header_size_ = custom_header_size; + } +}; + +/** + * The allocator base class. + * */ +class Allocator { + protected: + MemoryBackend *backend_; + char *custom_header_; + + public: + /** + * Constructor + * */ + Allocator() : custom_header_(nullptr) {} + + /** + * Destructor + * */ + virtual ~Allocator() = default; + + /** + * Create the shared-memory allocator with \a id unique allocator id over + * the particular slot of a memory backend. + * + * The shm_init function is required, but cannot be marked virtual as + * each allocator has its own arguments to this method. Though each + * allocator must have "id" as its first argument. + * */ + // virtual void shm_init(MemoryBackend *backend, + // allocator_id_t id, Args ...args) = 0; + + /** + * Attach the allocator to the slot and backend passed in the constructor. + * */ + virtual void shm_deserialize(MemoryBackend *backend) = 0; + + /** + * Allocate a region of memory of \a size size + * */ + virtual OffsetPointer AllocateOffset(size_t size) = 0; + + /** + * Allocate a region of memory to a specific pointer type + * */ + template + POINTER_T Allocate(size_t size) { + return POINTER_T(GetId(), AllocateOffset(size).load()); + } + + /** + * Allocate a region of memory of \a size size + * and \a alignment alignment. Assumes that + * alignment is not 0. + * */ + virtual OffsetPointer AlignedAllocateOffset(size_t size, + size_t alignment) = 0; + + /** + * Allocate a region of memory to a specific pointer type + * */ + template + POINTER_T AlignedAllocate(size_t size, size_t alignment) { + return POINTER_T(GetId(), AlignedAllocateOffset(size, alignment).load()); + } + + /** + * Allocate a region of \a size size and \a alignment + * alignment. Will fall back to regular Allocate if + * alignmnet is 0. + * */ + template + inline POINTER_T Allocate(size_t size, size_t alignment) { + if (alignment == 0) { + return Allocate(size); + } else { + return AlignedAllocate(size, alignment); + } + } + + /** + * Reallocate \a pointer to \a new_size new size + * If p is kNullPointer, will internally call Allocate. + * + * @return true if p was modified. + * */ + template + inline bool Reallocate(POINTER_T &p, size_t new_size) { + if (p.IsNull()) { + p = Allocate(new_size); + return true; + } + auto new_p = ReallocateOffsetNoNullCheck(p.ToOffsetPointer(), + new_size); + bool ret = new_p == p.ToOffsetPointer(); + p.off_ = new_p.load(); + return ret; + } + + /** + * Reallocate \a pointer to \a new_size new size. + * Assumes that p is not kNullPointer. + * + * @return true if p was modified. + * */ + virtual OffsetPointer ReallocateOffsetNoNullCheck(OffsetPointer p, + size_t new_size) = 0; + + /** + * Free the memory pointed to by \a ptr Pointer + * */ + template + inline void FreePtr(T *ptr) { + if (ptr == nullptr) { + throw INVALID_FREE.format(); + } + FreeOffsetNoNullCheck(Convert(ptr)); + } + + /** + * Free the memory pointed to by \a p Pointer + * */ + template + inline void Free(POINTER_T &p) { + if (p.IsNull()) { + throw INVALID_FREE.format(); + } + FreeOffsetNoNullCheck(OffsetPointer(p.off_.load())); + } + + /** + * Free the memory pointed to by \a ptr Pointer + * */ + virtual void FreeOffsetNoNullCheck(OffsetPointer p) = 0; + + /** + * Get the allocator identifier + * */ + virtual allocator_id_t GetId() = 0; + + /** + * Get the amount of memory that was allocated, but not yet freed. + * Useful for memory leak checks. + * */ + virtual size_t GetCurrentlyAllocatedSize() = 0; + + + /////////////////////////////////////// + /////////// POINTER ALLOCATORS + /////////////////////////////////////// + + /** + * Allocate a pointer of \a size size and return \a p process-independent + * pointer and a process-specific pointer. + * */ + template + inline T* AllocatePtr(size_t size, POINTER_T &p, size_t alignment = 0) { + p = Allocate(size, alignment); + if (p.IsNull()) { return nullptr; } + return reinterpret_cast(backend_->data_ + p.off_.load()); + } + + /** + * Allocate a pointer of \a size size + * */ + template + inline T* AllocatePtr(size_t size, size_t alignment = 0) { + POINTER_T p; + return AllocatePtr(size, p, alignment); + } + + /** + * Allocate a pointer of \a size size + * */ + template + inline T* ClearAllocatePtr(size_t size, size_t alignment = 0) { + POINTER_T p; + return ClearAllocatePtr(size, p, alignment); + } + + /** + * Allocate a pointer of \a size size and return \a p process-independent + * pointer and a process-specific pointer. + * */ + template + inline T* ClearAllocatePtr(size_t size, POINTER_T &p, size_t alignment = 0) { + p = Allocate(size, alignment); + if (p.IsNull()) { return nullptr; } + auto ptr = reinterpret_cast(backend_->data_ + p.off_.load()); + if (ptr) { + memset(ptr, 0, size); + } + return ptr; + } + + /** + * Reallocate a pointer to a new size + * + * @param p process-independent pointer (input & output) + * @param new_size the new size to allocate + * @param modified whether or not p was modified (output) + * @return A process-specific pointer + * */ + template + inline T* ReallocatePtr(POINTER_T &p, size_t new_size, bool &modified) { + modified = Reallocate(p, new_size); + return Convert(p); + } + + /** + * Reallocate a pointer to a new size + * + * @param p process-independent pointer (input & output) + * @param new_size the new size to allocate + * @return A process-specific pointer + * */ + template + inline T* ReallocatePtr(POINTER_T &p, size_t new_size) { + Reallocate(p, new_size); + return Convert(p); + } + + /** + * Reallocate a pointer to a new size + * + * @param old_ptr process-specific pointer to reallocate + * @param new_size the new size to allocate + * @return A process-specific pointer + * */ + template + inline T* ReallocatePtr(T *old_ptr, size_t new_size) { + OffsetPointer p = Convert(old_ptr); + return ReallocatePtr(p, new_size); + } + + /////////////////////////////////////// + ///////////OBJECT ALLOCATORS + /////////////////////////////////////// + + /** + * Allocate an array of objects (but don't construct). + * + * @return A process-specific pointer + * */ + template + inline T* AllocateObjs(size_t count) { + POINTER_T p; + return AllocateObjs(count, p); + } + + /** + * Allocate an array of objects (but don't construct). + * + * @param count the number of objects to allocate + * @param p process-independent pointer (output) + * @return A process-specific pointer + * */ + template + inline T* AllocateObjs(size_t count, POINTER_T &p) { + return AllocatePtr(count * sizeof(T), p); + } + + /** + * Allocate an array of objects and memset to 0. + * + * @param count the number of objects to allocate + * @param p process-independent pointer (output) + * @return A process-specific pointer + * */ + template + inline T* ClearAllocateObjs(size_t count, POINTER_T &p) { + return ClearAllocatePtr(count * sizeof(T), p); + } + + /** + * Allocate and construct an array of objects + * + * @param count the number of objects to allocate + * @param p process-independent pointer (output) + * @param args parameters to construct object of type T + * @return A process-specific pointer + * */ + template< + typename T, + typename POINTER_T=Pointer, + typename ...Args> + inline T* AllocateConstructObjs(size_t count, POINTER_T &p, Args&& ...args) { + T *ptr = AllocateObjs(count, p); + ConstructObjs(ptr, 0, count, std::forward(args)...); + return ptr; + } + + /** + * Reallocate a pointer of objects to a new size. + * + * @param p process-independent pointer (input & output) + * @param old_count the original number of objects (avoids reconstruction) + * @param new_count the new number of objects + * + * @return A process-specific pointer + * */ + template + inline T* ReallocateObjs(POINTER_T &p, size_t new_count) { + T *ptr = ReallocatePtr(p, new_count*sizeof(T)); + return ptr; + } + + /** + * Reallocate a pointer of objects to a new size and construct the + * new elements in-place. + * + * @param p process-independent pointer (input & output) + * @param old_count the original number of objects (avoids reconstruction) + * @param new_count the new number of objects + * @param args parameters to construct object of type T + * + * @return A process-specific pointer + * */ + template< + typename T, + typename POINTER_T=Pointer, + typename ...Args> + inline T* ReallocateConstructObjs(POINTER_T &p, + size_t old_count, + size_t new_count, + Args&& ...args) { + T *ptr = ReallocatePtr(p, new_count*sizeof(T)); + ConstructObjs(ptr, old_count, new_count, std::forward(args)...); + return ptr; + } + + /** + * Construct each object in an array of objects. + * + * @param ptr the array of objects (potentially archived) + * @param old_count the original size of the ptr + * @param new_count the new size of the ptr + * @param args parameters to construct object of type T + * @return None + * */ + template< + typename T, + typename ...Args> + inline static void ConstructObjs(T *ptr, + size_t old_count, + size_t new_count, Args&& ...args) { + if (ptr == nullptr) { return; } + for (size_t i = old_count; i < new_count; ++i) { + ConstructObj(*(ptr + i), std::forward(args)...); + } + } + + /** + * Construct an object. + * + * @param ptr the object to construct (potentially archived) + * @param args parameters to construct object of type T + * @return None + * */ + template< + typename T, + typename ...Args> + inline static void ConstructObj(T &obj, Args&& ...args) { + new (&obj) T(std::forward(args)...); + } + + /** + * Destruct an array of objects + * + * @param ptr the object to destruct (potentially archived) + * @param count the length of the object array + * @return None + * */ + template + inline static void DestructObjs(T *ptr, size_t count) { + if (ptr == nullptr) { return; } + for (size_t i = 0; i < count; ++i) { + DestructObj((ptr + i)); + } + } + + /** + * Destruct an object + * + * @param ptr the object to destruct (potentially archived) + * @param count the length of the object array + * @return None + * */ + template + inline static void DestructObj(T &obj) { + obj.~T(); + } + + /** + * Get the custom header of the shared-memory allocator + * + * @return Custom header pointer + * */ + template + inline HEADER_T* GetCustomHeader() { + return reinterpret_cast(custom_header_); + } + + /** + * Convert a process-independent pointer into a process-specific pointer + * + * @param p process-independent pointer + * @return a process-specific pointer + * */ + template + inline T* Convert(const POINTER_T &p) { + if (p.IsNull()) { return nullptr; } + return reinterpret_cast(backend_->data_ + p.off_.load()); + } + + /** + * Convert a process-specific pointer into a process-independent pointer + * + * @param ptr process-specific pointer + * @return a process-independent pointer + * */ + template + inline POINTER_T Convert(T *ptr) { + if (ptr == nullptr) { return POINTER_T::GetNull(); } + return POINTER_T(GetId(), + reinterpret_cast(ptr) - + reinterpret_cast(backend_->data_)); + } + + /** + * Determine whether or not this allocator contains a process-specific + * pointer + * + * @param ptr process-specific pointer + * @return True or false + * */ + template + inline bool ContainsPtr(T *ptr) { + return reinterpret_cast(ptr) >= + reinterpret_cast(backend_->data_); + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h b/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h new file mode 100644 index 000000000..59e18ab7a --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ +#define HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ + +#include "allocator.h" +#include "stack_allocator.h" +#include "multi_page_allocator.h" +#include "malloc_allocator.h" + +namespace hermes_shm::ipc { + +class AllocatorFactory { + public: + /** + * Create a new memory allocator + * */ + template + static std::unique_ptr shm_init(MemoryBackend *backend, + allocator_id_t alloc_id, + size_t custom_header_size, + Args&& ...args) { + if constexpr(std::is_same_v) { + // MultiPageAllocator + auto alloc = std::make_unique(); + alloc->shm_init(backend, + alloc_id, + custom_header_size, + std::forward(args)...); + return alloc; + } else if constexpr(std::is_same_v) { + // StackAllocator + auto alloc = std::make_unique(); + alloc->shm_init(backend, + alloc_id, + custom_header_size, + std::forward(args)...); + return alloc; + } else if constexpr(std::is_same_v) { + // Malloc Allocator + auto alloc = std::make_unique(); + alloc->shm_init(backend, + alloc_id, + custom_header_size, + std::forward(args)...); + return alloc; + } else { + // Default + throw std::logic_error("Not a valid allocator"); + } + } + + /** + * Deserialize the allocator managing this backend. + * */ + static std::unique_ptr shm_deserialize(MemoryBackend *backend) { + auto header_ = reinterpret_cast(backend->data_); + switch (static_cast(header_->allocator_type_)) { + // MultiPageAllocator + case AllocatorType::kMultiPageAllocator: { + auto alloc = std::make_unique(); + alloc->shm_deserialize(backend); + return alloc; + } + // Stack Allocator + case AllocatorType::kStackAllocator: { + auto alloc = std::make_unique(); + alloc->shm_deserialize(backend); + return alloc; + } + // Malloc Allocator + case AllocatorType::kMallocAllocator: { + auto alloc = std::make_unique(); + alloc->shm_deserialize(backend); + return alloc; + } + default: return nullptr; + } + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h new file mode 100644 index 000000000..2e8cbb4c0 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ +#define HERMES_SHM_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ + +#include "allocator.h" +#include "hermes_shm/thread/lock.h" + +namespace hermes_shm::ipc { + +struct MallocAllocatorHeader : public AllocatorHeader { + std::atomic total_alloc_size_; + + MallocAllocatorHeader() = default; + + void Configure(allocator_id_t alloc_id, + size_t custom_header_size) { + AllocatorHeader::Configure(alloc_id, AllocatorType::kStackAllocator, + custom_header_size); + total_alloc_size_ = 0; + } +}; + +class MallocAllocator : public Allocator { + private: + MallocAllocatorHeader *header_; + + public: + /** + * Allocator constructor + * */ + MallocAllocator() + : header_(nullptr) {} + + /** + * Get the ID of this allocator from shared memory + * */ + allocator_id_t GetId() override { + return header_->allocator_id_; + } + + /** + * Initialize the allocator in shared memory + * */ + void shm_init(MemoryBackend *backend, + allocator_id_t id, + size_t custom_header_size); + + /** + * Attach an existing allocator from shared memory + * */ + void shm_deserialize(MemoryBackend *backend) override; + + /** + * Allocate a memory of \a size size. The page allocator cannot allocate + * memory larger than the page size. + * */ + OffsetPointer AllocateOffset(size_t size) override; + + /** + * Allocate a memory of \a size size, which is aligned to \a + * alignment. + * */ + OffsetPointer AlignedAllocateOffset(size_t size, size_t alignment) override; + + /** + * Reallocate \a p pointer to \a new_size new size. + * + * @return whether or not the pointer p was changed + * */ + OffsetPointer ReallocateOffsetNoNullCheck(OffsetPointer p, + size_t new_size) override; + + /** + * Free \a ptr pointer. Null check is performed elsewhere. + * */ + void FreeOffsetNoNullCheck(OffsetPointer p) override; + + /** + * Get the current amount of data allocated. Can be used for leak + * checking. + * */ + size_t GetCurrentlyAllocatedSize() override; +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h b/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h new file mode 100644 index 000000000..b81244792 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h @@ -0,0 +1,31 @@ +// +// Created by lukemartinlogan on 12/27/22. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MP_PAGE_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MP_PAGE_H_ + +namespace hermes_shm::ipc { + +struct MpPage { + int flags_; /**< Page flags (e.g., is_allocated?) */ + size_t page_size_; /**< The size of the page allocated */ + uint32_t off_; /**< The offset within the page */ + uint32_t page_idx_; /**< The id of the page in the mp free list */ + + void SetAllocated() { + flags_ = 0x1; + } + + void UnsetAllocated() { + flags_ = 0; + } + + bool IsAllocated() const { + return flags_ & 0x1; + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MP_PAGE_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/multi_page_allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/multi_page_allocator.h new file mode 100644 index 000000000..db7bfda09 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/allocator/multi_page_allocator.h @@ -0,0 +1,204 @@ +// +// Created by lukemartinlogan on 12/25/22. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MULTI_PAGE_ALLOCATOR_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MULTI_PAGE_ALLOCATOR_H_ + +#include "allocator.h" +#include "hermes_shm/thread/lock.h" +#include "mp_page.h" + +namespace hermes_shm::ipc { + +struct MultiPageFreeList { + /// Lock the list + Mutex lock_; + /// Free list for different page sizes + /// Stack allocator + size_t region_off_, region_size_; + /// Number of bytes currently free in this free list + size_t free_size_; + /// Total number of bytes alloc'd from this list + size_t total_alloced_; + /// Total number of bytes freed to this list + size_t total_freed_; + + /** + * The total amount of space allocated by the MultiPageFree list when + * there is \a num_page_caches number of page size free lists + * */ + static size_t GetSizeBytes(size_t num_page_caches) { + return 0; + } + + /** + * Initialize the free list array + * */ + void shm_init(size_t mp_free_list_size, + char *region_start, + size_t region_off, size_t region_size) { + } + + /** Get the free list at index i */ +}; + +struct MultiPageAllocatorHeader : public AllocatorHeader { + /// Number of threads to initially assume + std::atomic concurrency_; + /// Bytes to dedicate to per-thread free list tables + size_t thread_table_size_; + /// Cache every page between these sizes + size_t mp_free_list_size_; + size_t min_page_size_, max_page_size_; + uint32_t min_page_log_, max_page_log_, last_page_idx_; + /// The page sizes to cache + RealNumber growth_rate_; + /// The minimum number of free bytes before a coalesce can be triggered + size_t coalesce_min_size_; + /// The percentage of fragmentation before a coalesce is triggered + RealNumber coalesce_frac_; + + MultiPageAllocatorHeader() = default; + + void Configure(allocator_id_t alloc_id, + size_t custom_header_size, + size_t min_page_size, + size_t max_page_size, + RealNumber growth_rate, + size_t coalesce_min_size, + RealNumber coalesce_frac, + size_t thread_table_size, + uint32_t concurrency) { + } +}; + +class MultiPageAllocator : public Allocator { + private: + MultiPageAllocatorHeader *header_; + + public: + /** + * Allocator constructor + * */ + MultiPageAllocator() + : header_(nullptr) {} + + /** + * Get the ID of this allocator from shared memory + * */ + allocator_id_t GetId() override { + return header_->allocator_id_; + } + + /** + * Initialize the allocator in shared memory + * */ + void shm_init(MemoryBackend *backend, + allocator_id_t alloc_id, + size_t custom_header_size = 0, + size_t min_page_size = 64, + size_t max_page_size = KILOBYTES(32), + RealNumber growth_rate = RealNumber(5, 4), + size_t coalesce_min_size = MEGABYTES(20), + RealNumber coalesce_frac = RealNumber(2, 1), + size_t thread_table_size = MEGABYTES(1), + uint32_t concurrency = 4); + + /** + * Attach an existing allocator from shared memory + * */ + void shm_deserialize(MemoryBackend *backend) override; + + /** + * Allocate a memory of \a size size. The page allocator cannot allocate + * memory larger than the page size. + * */ + OffsetPointer AllocateOffset(size_t size) override; + + /** + * Allocate a memory of \a size size, which is aligned to \a + * alignment. + * */ + OffsetPointer AlignedAllocateOffset(size_t size, size_t alignment) override; + + /** + * Reallocate \a p pointer to \a new_size new size. + * + * @return whether or not the pointer p was changed + * */ + OffsetPointer ReallocateOffsetNoNullCheck( + OffsetPointer p, size_t new_size) override; + + /** + * Free \a ptr pointer. Null check is performed elsewhere. + * */ + void FreeOffsetNoNullCheck(OffsetPointer p) override; + + /** + * Get the current amount of data allocated. Can be used for leak + * checking. + * */ + size_t GetCurrentlyAllocatedSize() override; + + private: + /** Get the index of "x" within the page free list array */ + inline uint32_t IndexLogarithm(size_t x, size_t &round); + + /** Get the pointer to the mp_free_lists_ array */ + void* GetMpFreeListStart(); + + /** Set the page's header */ + void _AllocateHeader(Pointer &p, + size_t page_size, + size_t page_size_idx, + size_t off); + + /** Set the page's header + change allocator stats*/ + void _AllocateHeader(Pointer &p, + MultiPageFreeList &mp_free_list, + size_t page_size, + size_t page_size_idx, + size_t off); + + /** Allocate a page from a thread's mp free list */ + Pointer _Allocate(MultiPageFreeList &free_list, + size_t page_size_idx, size_t page_size); + + /** Allocate a large, cached page */ + bool _AllocateLargeCached(MultiPageFreeList &mp_free_list, + size_t page_size_idx, + size_t page_size, + Pointer &ret); + + /** Allocate a cached page */ + bool _AllocateCached(MultiPageFreeList &mp_free_list, + size_t page_size_idx, + size_t page_size, + Pointer &ret); + + /** Allocate and divide a cached page larger than page_size */ + bool _AllocateBorrowCached(MultiPageFreeList &mp_free_list, + size_t page_size_idx, + size_t page_size, + Pointer &ret); + + /** Allocate a page from the segment */ + bool _AllocateSegment(MultiPageFreeList &mp_free_list, + size_t page_size_idx, + size_t page_size, + Pointer &ret); + + /** Reorganize free space to minimize fragmentation */ + void _Coalesce(MultiPageFreeList &to, tid_t tid); + + /** Create a new thread allocator by borrowing from other allocators */ + void _AddThread(); + + /** Free a page to a free list */ + void _Free(MultiPageFreeList &free_list, Pointer &p); +}; + +} // namespace hermes_shm::ipc + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MULTI_PAGE_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h new file mode 100644 index 000000000..0db83ee02 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ +#define HERMES_SHM_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ + +#include "allocator.h" +#include "hermes_shm/thread/lock.h" + +namespace hermes_shm::ipc { + +struct StackAllocatorHeader : public AllocatorHeader { + std::atomic region_off_; + std::atomic region_size_; + std::atomic total_alloc_; + + StackAllocatorHeader() = default; + + void Configure(allocator_id_t alloc_id, + size_t custom_header_size, + size_t region_off, + size_t region_size) { + AllocatorHeader::Configure(alloc_id, AllocatorType::kStackAllocator, + custom_header_size); + region_off_ = region_off; + region_size_ = region_size; + total_alloc_ = 0; + } +}; + +class StackAllocator : public Allocator { + private: + StackAllocatorHeader *header_; + + public: + /** + * Allocator constructor + * */ + StackAllocator() + : header_(nullptr) {} + + /** + * Get the ID of this allocator from shared memory + * */ + allocator_id_t GetId() override { + return header_->allocator_id_; + } + + /** + * Initialize the allocator in shared memory + * */ + void shm_init(MemoryBackend *backend, + allocator_id_t id, + size_t custom_header_size); + + /** + * Attach an existing allocator from shared memory + * */ + void shm_deserialize(MemoryBackend *backend) override; + + /** + * Allocate a memory of \a size size. The page allocator cannot allocate + * memory larger than the page size. + * */ + OffsetPointer AllocateOffset(size_t size) override; + + /** + * Allocate a memory of \a size size, which is aligned to \a + * alignment. + * */ + OffsetPointer AlignedAllocateOffset(size_t size, size_t alignment) override; + + /** + * Reallocate \a p pointer to \a new_size new size. + * + * @return whether or not the pointer p was changed + * */ + OffsetPointer ReallocateOffsetNoNullCheck( + OffsetPointer p, size_t new_size) override; + + /** + * Free \a ptr pointer. Null check is performed elsewhere. + * */ + void FreeOffsetNoNullCheck(OffsetPointer p) override; + + /** + * Get the current amount of data allocated. Can be used for leak + * checking. + * */ + size_t GetCurrentlyAllocatedSize() override; +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/array_backend.h b/hermes_shm/include/hermes_shm/memory/backend/array_backend.h new file mode 100644 index 000000000..d3158cd4d --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/backend/array_backend.h @@ -0,0 +1,57 @@ +// +// Created by lukemartinlogan on 1/12/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_ARRAY_BACKEND_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_ARRAY_BACKEND_H_ + +#include "memory_backend.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace hermes_shm::ipc { + +class ArrayBackend : public MemoryBackend { + public: + ArrayBackend() = default; + + ~ArrayBackend() override {} + + bool shm_init(size_t size, char *region) { + if (size < sizeof(MemoryBackendHeader)) { + throw SHMEM_CREATE_FAILED.format(); + } + SetInitialized(); + Own(); + header_ = reinterpret_cast(region); + header_->data_size_ = size - sizeof(MemoryBackendHeader); + data_size_ = header_->data_size_; + data_ = region + sizeof(MemoryBackendHeader); + return true; + } + + bool shm_deserialize(std::string url) override { + (void) url; + throw SHMEM_NOT_SUPPORTED.format(); + } + + void shm_detach() override {} + + void shm_destroy() override {} +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_ARRAY_BACKEND_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h b/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h new file mode 100644 index 000000000..28e900a83 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_MEMORY_H +#define HERMES_SHM_MEMORY_H + +#include +#include +#include +#include +#include "hermes_shm/constants/macros.h" +#include + +namespace hermes_shm::ipc { + +struct MemoryBackendHeader { + size_t data_size_; +}; + +enum class MemoryBackendType { + kPosixShmMmap, + kNullBackend, + kArrayBackend, + kPosixMmap, +}; + +#define MEMORY_BACKEND_INITIALIZED 0x1 +#define MEMORY_BACKEND_OWNED 0x2 + +class MemoryBackend { + public: + MemoryBackendHeader *header_; + char *data_; + size_t data_size_; + bitfield32_t flags_; + + public: + MemoryBackend() = default; + + virtual ~MemoryBackend() = default; + + /** Mark data as valid */ + void SetInitialized() { + flags_.SetBits(MEMORY_BACKEND_INITIALIZED); + } + + /** Check if data is valid */ + bool IsInitialized() { + return flags_.OrBits(MEMORY_BACKEND_INITIALIZED); + } + + /** Mark data as invalid */ + void UnsetInitialized() { + flags_.UnsetBits(MEMORY_BACKEND_INITIALIZED); + } + + /** This is the process which destroys the backend */ + void Own() { + flags_.SetBits(MEMORY_BACKEND_OWNED); + } + + /** This is owned */ + bool IsOwned() { + return flags_.OrBits(MEMORY_BACKEND_OWNED); + } + + /** This is not the process which destroys the backend */ + void Disown() { + flags_.UnsetBits(MEMORY_BACKEND_OWNED); + } + + /// Each allocator must define its own shm_init. + // virtual bool shm_init(size_t size, ...) = 0; + virtual bool shm_deserialize(std::string url) = 0; + virtual void shm_detach() = 0; + virtual void shm_destroy() = 0; +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_H diff --git a/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h b/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h new file mode 100644 index 000000000..28ad2fc7b --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ +#define HERMES_SHM_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ + +#include "memory_backend.h" +#include "posix_mmap.h" +#include "posix_shm_mmap.h" +#include "null_backend.h" +#include "array_backend.h" + +namespace hermes_shm::ipc { + +class MemoryBackendFactory { + public: + /** Initialize a new backend */ + template + static std::unique_ptr shm_init( + size_t size, const std::string &url, Args ...args) { + if constexpr(std::is_same_v) { + // PosixShmMmap + auto backend = std::make_unique(); + backend->shm_init(size, url, std::forward(args)...); + return backend; + } else if constexpr(std::is_same_v) { + // PosixMmap + auto backend = std::make_unique(); + backend->shm_init(size, url, std::forward(args)...); + return backend; + } else if constexpr(std::is_same_v) { + // NullBackend + auto backend = std::make_unique(); + backend->shm_init(size, url, std::forward(args)...); + return backend; + } else if constexpr(std::is_same_v) { + // ArrayBackend + auto backend = std::make_unique(); + backend->shm_init(size, url, std::forward(args)...); + return backend; + } else { + throw MEMORY_BACKEND_NOT_FOUND.format(); + } + } + + /** Deserialize an existing backend */ + static std::unique_ptr shm_deserialize( + MemoryBackendType type, const std::string &url) { + switch (type) { + // PosixShmMmap + case MemoryBackendType::kPosixShmMmap: { + auto backend = std::make_unique(); + if (!backend->shm_deserialize(url)) { + throw MEMORY_BACKEND_NOT_FOUND.format(); + } + return backend; + } + + // PosixMmap + case MemoryBackendType::kPosixMmap: { + auto backend = std::make_unique(); + if (!backend->shm_deserialize(url)) { + throw MEMORY_BACKEND_NOT_FOUND.format(); + } + return backend; + } + + // NullBackend + case MemoryBackendType::kNullBackend: { + auto backend = std::make_unique(); + if (!backend->shm_deserialize(url)) { + throw MEMORY_BACKEND_NOT_FOUND.format(); + } + return backend; + } + + // ArrayBackend + case MemoryBackendType::kArrayBackend: { + auto backend = std::make_unique(); + if (!backend->shm_deserialize(url)) { + throw MEMORY_BACKEND_NOT_FOUND.format(); + } + return backend; + } + + // Default + default: return nullptr; + } + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/null_backend.h b/hermes_shm/include/hermes_shm/memory/backend/null_backend.h new file mode 100644 index 000000000..66d30627f --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/backend/null_backend.h @@ -0,0 +1,73 @@ +// +// Created by lukemartinlogan on 1/10/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_NULL_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_NULL_H_ + +#include "memory_backend.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace hermes_shm::ipc { + +class NullBackend : public MemoryBackend { + private: + size_t total_size_; + + public: + NullBackend() = default; + + ~NullBackend() override {} + + bool shm_init(size_t size, const std::string &url) { + (void) url; + SetInitialized(); + Own(); + total_size_ = sizeof(MemoryBackendHeader) + size; + char *ptr = (char*)malloc(sizeof(MemoryBackendHeader)); + header_ = reinterpret_cast(ptr); + header_->data_size_ = size; + data_size_ = size; + data_ = nullptr; + return true; + } + + bool shm_deserialize(std::string url) override { + (void) url; + throw SHMEM_NOT_SUPPORTED.format(); + } + + void shm_detach() override { + _Detach(); + } + + void shm_destroy() override { + _Destroy(); + } + + protected: + void _Detach() { + free(header_); + } + + void _Destroy() { + free(header_); + } +}; + +} // namespace hermes_shm::ipc + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_NULL_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h b/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h new file mode 100644 index 000000000..7ba26b54a --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H +#define HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H + +#include "memory_backend.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace hermes_shm::ipc { + +class PosixMmap : public MemoryBackend { + private: + size_t total_size_; + + public: + /** Constructor */ + PosixMmap() = default; + + /** Destructor */ + ~PosixMmap() override { + if (IsOwned()) { + _Destroy(); + } else { + _Detach(); + } + } + + /** Initialize backend */ + bool shm_init(size_t size) { + SetInitialized(); + Own(); + total_size_ = sizeof(MemoryBackendHeader) + size; + char *ptr = _Map(total_size_); + header_ = reinterpret_cast(ptr); + header_->data_size_ = size; + data_size_ = size; + data_ = reinterpret_cast(header_ + 1); + return true; + } + + /** Deserialize the backend */ + bool shm_deserialize(std::string url) override { + (void) url; + throw SHMEM_NOT_SUPPORTED.format(); + } + + /** Detach the mapped memory */ + void shm_detach() override { + _Detach(); + } + + /** Destroy the mapped memory */ + void shm_destroy() override { + _Destroy(); + } + + protected: + /** Map shared memory */ + template + T* _Map(size_t size) { + T *ptr = reinterpret_cast( + mmap64(nullptr, NextPageSizeMultiple(size), PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); + if (ptr == MAP_FAILED) { + perror("map failed"); + throw SHMEM_CREATE_FAILED.format(); + } + return ptr; + } + + /** Unmap shared memory */ + void _Detach() { + if (!IsInitialized()) { return; } + munmap(reinterpret_cast(header_), total_size_); + UnsetInitialized(); + } + + /** Destroy shared memory */ + void _Destroy() { + if (!IsInitialized()) { return; } + _Detach(); + UnsetInitialized(); + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H diff --git a/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h b/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h new file mode 100644 index 000000000..37a0233be --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H +#define HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H + +#include "memory_backend.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace hermes_shm::ipc { + +class PosixShmMmap : public MemoryBackend { + private: + std::string url_; + int fd_; + + public: + /** Constructor */ + PosixShmMmap() : fd_(-1) {} + + /** Destructor */ + ~PosixShmMmap() override { + if (IsOwned()) { + _Destroy(); + } else { + _Detach(); + } + } + + /** Initialize backend */ + bool shm_init(size_t size, std::string url) { + SetInitialized(); + Own(); + url_ = std::move(url); + shm_unlink(url_.c_str()); + fd_ = shm_open(url_.c_str(), O_CREAT | O_RDWR, 0666); + if (fd_ < 0) { + return false; + } + _Reserve(size); + header_ = _Map(HERMES_SHM_SYSTEM_INFO->page_size_, 0); + header_->data_size_ = size; + data_size_ = size; + data_ = _Map(size, HERMES_SHM_SYSTEM_INFO->page_size_); + return true; + } + + /** Deserialize the backend */ + bool shm_deserialize(std::string url) override { + SetInitialized(); + Disown(); + url_ = std::move(url); + fd_ = shm_open(url_.c_str(), O_RDWR, 0666); + if (fd_ < 0) { + return false; + } + header_ = _Map(HERMES_SHM_SYSTEM_INFO->page_size_, 0); + data_size_ = header_->data_size_; + data_ = _Map(data_size_, HERMES_SHM_SYSTEM_INFO->page_size_); + return true; + } + + /** Detach the mapped memory */ + void shm_detach() override { + _Detach(); + } + + /** Destroy the mapped memory */ + void shm_destroy() override { + _Destroy(); + } + + protected: + /** Reserve shared memory */ + void _Reserve(size_t size) { + int ret = ftruncate64(fd_, static_cast(size)); + if (ret < 0) { + throw SHMEM_RESERVE_FAILED.format(); + } + } + + /** Map shared memory */ + template + T* _Map(size_t size, off64_t off) { + T *ptr = reinterpret_cast( + mmap64(nullptr, size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd_, off)); + if (ptr == MAP_FAILED) { + throw SHMEM_CREATE_FAILED.format(); + } + return ptr; + } + + /** Unmap shared memory */ + void _Detach() { + if (!IsInitialized()) { return; } + munmap(data_, data_size_); + munmap(header_, HERMES_SHM_SYSTEM_INFO->page_size_); + close(fd_); + UnsetInitialized(); + } + + /** Destroy shared memory */ + void _Destroy() { + if (!IsInitialized()) { return; } + _Detach(); + shm_unlink(url_.c_str()); + UnsetInitialized(); + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H diff --git a/hermes_shm/include/hermes_shm/memory/memory.h b/hermes_shm/include/hermes_shm/memory/memory.h new file mode 100644 index 000000000..eac2863f5 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/memory.h @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_MEMORY_MEMORY_H_ +#define HERMES_SHM_MEMORY_MEMORY_H_ + +#include +#include +#include +#include +#include + +namespace hermes_shm::ipc { + +/** + * The identifier for an allocator + * */ +union allocator_id_t { + struct { + uint32_t major_; // Typically some sort of process id + uint32_t minor_; // Typically a process-local id + } bits_; + uint64_t int_; + + /** + * Null allocator ID is -1 (for now) + * */ + allocator_id_t() : int_(0) {} + + /** + * Constructor which sets major & minor + * */ + explicit allocator_id_t(uint32_t major, uint32_t minor) { + bits_.major_ = major; + bits_.minor_ = minor; + } + + /** + * Set this allocator to null + * */ + void SetNull() { + int_ = 0; + } + + /** + * Check if this is the null allocator + * */ + bool IsNull() const { return int_ == 0; } + + /** Equality check */ + bool operator==(const allocator_id_t &other) const { + return other.int_ == int_; + } + + /** Inequality check */ + bool operator!=(const allocator_id_t &other) const { + return other.int_ != int_; + } + + /** Get the null allocator */ + static allocator_id_t GetNull() { + static allocator_id_t alloc(0, 0); + return alloc; + } +}; + +typedef uint32_t slot_id_t; // Uniquely ids a MemoryBackend slot + +/** + * Stores an offset into a memory region. Assumes the developer knows + * which allocator the pointer comes from. + * */ +template +struct OffsetPointerBase { + typedef typename std::conditional, nonatomic>::type atomic_t; + atomic_t off_; /**< Offset within the allocator's slot */ + + /** Default constructor */ + OffsetPointerBase() = default; + + /** Full constructor */ + explicit OffsetPointerBase(size_t off) : off_(off) {} + + /** Full constructor */ + explicit OffsetPointerBase(atomic_t off) : off_(off.load()) {} + + /** Pointer constructor */ + explicit OffsetPointerBase(allocator_id_t alloc_id, size_t off) : off_(off) { + (void) alloc_id; + } + + /** Copy constructor */ + OffsetPointerBase(const OffsetPointerBase &other) + : off_(other.off_.load()) {} + + /** Other copy constructor */ + OffsetPointerBase(const OffsetPointerBase &other) + : off_(other.off_.load()) {} + + /** Move constructor */ + OffsetPointerBase(OffsetPointerBase &&other) noexcept + : off_(other.off_.load()) { + other.SetNull(); + } + + /** Get the offset pointer */ + OffsetPointerBase ToOffsetPointer() { + return OffsetPointerBase(off_.load()); + } + + /** Set to null */ + void SetNull() { + off_ = -1; + } + + /** Check if null */ + bool IsNull() const { + return off_ == -1; + } + + /** Get the null pointer */ + static OffsetPointerBase GetNull() { + const static OffsetPointerBase p(-1); + return p; + } + + /** Atomic load wrapper */ + inline size_t load( + std::memory_order order = std::memory_order_seq_cst) const { + return off_.load(order); + } + + /** Atomic exchange wrapper */ + inline void exchange( + size_t count, std::memory_order order = std::memory_order_seq_cst) { + off_.exchange(count, order); + } + + /** Atomic compare exchange weak wrapper */ + inline bool compare_exchange_weak(size_t& expected, size_t desired, + std::memory_order order = + std::memory_order_seq_cst) { + return off_.compare_exchange_weak(expected, desired, order); + } + + /** Atomic compare exchange strong wrapper */ + inline bool compare_exchange_strong(size_t& expected, size_t desired, + std::memory_order order = + std::memory_order_seq_cst) { + return off_.compare_exchange_weak(expected, desired, order); + } + + /** Atomic add operator */ + inline OffsetPointerBase operator+(size_t count) const { + return OffsetPointerBase(off_ + count); + } + + /** Atomic subtract operator */ + inline OffsetPointerBase operator-(size_t count) const { + return OffsetPointerBase(off_ - count); + } + + /** Atomic add assign operator */ + inline OffsetPointerBase& operator+=(size_t count) { + off_ += count; + return *this; + } + + /** Atomic subtract assign operator */ + inline OffsetPointerBase& operator-=(size_t count) { + off_ -= count; + return *this; + } + + /** Atomic assign operator */ + inline OffsetPointerBase& operator=(size_t count) { + off_ = count; + return *this; + } + + /** Atomic copy assign operator */ + inline OffsetPointerBase& operator=(const OffsetPointerBase &count) { + off_ = count.load(); + return *this; + } + + /** Equality check */ + bool operator==(const OffsetPointerBase &other) const { + return off_ == other.off_; + } + + /** Inequality check */ + bool operator!=(const OffsetPointerBase &other) const { + return off_ != other.off_; + } +}; + +/** Non-atomic offset */ +typedef OffsetPointerBase OffsetPointer; + +/** Atomic offset */ +typedef OffsetPointerBase AtomicOffsetPointer; + +/** Typed offset pointer */ +template +using TypedOffsetPointer = OffsetPointer; + +/** Typed atomic pointer */ +template +using TypedAtomicOffsetPointer = AtomicOffsetPointer; + +/** + * A process-independent pointer, which stores both the allocator's + * information and the offset within the allocator's region + * */ +template +struct PointerBase { + allocator_id_t allocator_id_; /// Allocator the pointer comes from + OffsetPointerBase off_; /// Offset within the allocator's slot + + /** Default constructor */ + PointerBase() = default; + + /** Full constructor */ + explicit PointerBase(allocator_id_t id, size_t off) : + allocator_id_(id), off_(off) {} + + /** Full constructor using offset pointer */ + explicit PointerBase(allocator_id_t id, OffsetPointer off) : + allocator_id_(id), off_(off) {} + + /** Copy constructor */ + PointerBase(const PointerBase &other) + : allocator_id_(other.allocator_id_), off_(other.off_) {} + + /** Other copy constructor */ + PointerBase(const PointerBase &other) + : allocator_id_(other.allocator_id_), off_(other.off_.load()) {} + + /** Move constructor */ + PointerBase(PointerBase &&other) noexcept + : allocator_id_(other.allocator_id_), off_(other.off_) { + other.SetNull(); + } + + /** Get the offset pointer */ + OffsetPointerBase ToOffsetPointer() const { + return OffsetPointerBase(off_.load()); + } + + /** Set to null */ + void SetNull() { + allocator_id_.SetNull(); + } + + /** Check if null */ + bool IsNull() const { + return allocator_id_.IsNull(); + } + + /** Get the null pointer */ + static PointerBase GetNull() { + const static PointerBase p(allocator_id_t::GetNull(), + OffsetPointer::GetNull()); + return p; + } + + /** Copy assignment operator */ + PointerBase& operator=(const PointerBase &other) { + if (this != &other) { + allocator_id_ = other.allocator_id_; + off_ = other.off_; + } + return *this; + } + + /** Move assignment operator */ + PointerBase& operator=(PointerBase &&other) { + if (this != &other) { + allocator_id_ = other.allocator_id_; + off_.exchange(other.off_.load()); + other.SetNull(); + } + return *this; + } + + /** Addition operator */ + PointerBase operator+(size_t size) const { + PointerBase p; + p.allocator_id_ = allocator_id_; + p.off_ = off_ + size; + return p; + } + + /** Subtraction operator */ + PointerBase operator-(size_t size) const { + PointerBase p; + p.allocator_id_ = allocator_id_; + p.off_ = off_ - size; + return p; + } + + /** Addition assignment operator */ + PointerBase& operator+=(size_t size) { + off_ += size; + return *this; + } + + /** Subtraction assignment operator */ + PointerBase& operator-=(size_t size) { + off_ -= size; + return *this; + } + + /** Equality check */ + bool operator==(const PointerBase &other) const { + return (other.allocator_id_ == allocator_id_ && other.off_ == off_); + } + + /** Inequality check */ + bool operator!=(const PointerBase &other) const { + return (other.allocator_id_ != allocator_id_ || other.off_ != off_); + } +}; + +/** Non-atomic pointer */ +typedef PointerBase Pointer; + +/** Atomic pointer */ +typedef PointerBase AtomicPointer; + +/** Typed pointer */ +template +using TypedPointer = Pointer; + +/** Typed atomic pointer */ +template +using TypedAtomicPointer = AtomicPointer; + +/** Round up to the nearest multiple of the alignment */ +static size_t NextAlignmentMultiple(size_t alignment, size_t size) { + auto page_size = HERMES_SHM_SYSTEM_INFO->page_size_; + size_t new_size = size; + size_t page_off = size % alignment; + if (page_off) { + new_size = size + page_size - page_off; + } + return new_size; +} + +/** Round up to the nearest multiple of page size */ +static size_t NextPageSizeMultiple(size_t size) { + auto page_size = HERMES_SHM_SYSTEM_INFO->page_size_; + size_t new_size = NextAlignmentMultiple(page_size, size); + return new_size; +} + +} // namespace hermes_shm::ipc + +namespace std { + +/** Allocator ID hash */ +template <> +struct hash { + std::size_t operator()(const hermes_shm::ipc::allocator_id_t &key) const { + return std::hash{}(key.int_); + } +}; + +} // namespace std + + +#endif // HERMES_SHM_MEMORY_MEMORY_H_ diff --git a/hermes_shm/include/hermes_shm/memory/memory_manager.h b/hermes_shm/include/hermes_shm/memory/memory_manager.h new file mode 100644 index 000000000..584424be8 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/memory_manager.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_MEMORY_MEMORY_MANAGER_H_ +#define HERMES_SHM_MEMORY_MEMORY_MANAGER_H_ + +#include "hermes_shm/memory/allocator/allocator.h" +#include "backend/memory_backend.h" +#include "hermes_shm/memory/allocator/allocator_factory.h" +#include + +namespace lipc = hermes_shm::ipc; + +namespace hermes_shm::ipc { + +class MemoryManager { + private: + allocator_id_t root_allocator_id_; + PosixMmap root_backend_; + StackAllocator root_allocator_; + std::unordered_map> backends_; + std::unordered_map> allocators_; + Allocator *default_allocator_; + + public: + /** The default amount of memory a single allocator manages */ + static const size_t kDefaultBackendSize = GIGABYTES(64); + + /** + * Constructor. Create the root allocator and backend, which is used + * until the user specifies a new default. The root allocator stores + * only private memory. + * */ + MemoryManager() { + root_allocator_id_.bits_.major_ = 0; + root_allocator_id_.bits_.minor_ = -1; + root_backend_.shm_init(HERMES_SHM_SYSTEM_INFO->ram_size_); + root_backend_.Own(); + root_allocator_.shm_init(&root_backend_, root_allocator_id_, 0); + default_allocator_ = &root_allocator_; + } + + /** + * Create a memory backend. Memory backends are divided into slots. + * Each slot corresponds directly with a single allocator. + * There can be multiple slots per-backend, enabling multiple allocation + * policies over a single memory region. + * */ + template + MemoryBackend* CreateBackend(size_t size, + const std::string &url, + Args&& ...args) { + backends_.emplace(url, + MemoryBackendFactory::shm_init(size, url), + std::forward(args)...); + auto backend = backends_[url].get(); + backend->Own(); + return backend; + } + + /** + * Attaches to an existing memory backend located at \a url url. + * */ + MemoryBackend* AttachBackend(MemoryBackendType type, + const std::string &url) { + backends_.emplace(url, MemoryBackendFactory::shm_deserialize(type, url)); + auto backend = backends_[url].get(); + ScanBackends(); + backend->Disown(); + return backend; + } + + /** + * Returns a pointer to a backend that has already been attached. + * */ + MemoryBackend* GetBackend(const std::string &url); + + /** + * Destroys the memory allocated by the entire backend. + * */ + void DestroyBackend(const std::string &url); + + /** + * Scans all attached backends for new memory allocators. + * */ + void ScanBackends(); + + /** + * Registers an allocator. Used internally by ScanBackends, but may + * also be used externally. + * */ + void RegisterAllocator(std::unique_ptr &alloc); + + /** + * Create and register a memory allocator for a particular backend. + * */ + template + Allocator* CreateAllocator(const std::string &url, + allocator_id_t alloc_id, + size_t custom_header_size, + Args&& ...args) { + auto backend = GetBackend(url); + if (alloc_id.IsNull()) { + alloc_id = allocator_id_t(HERMES_SHM_SYSTEM_INFO->pid_, + allocators_.size()); + } + auto alloc = AllocatorFactory::shm_init( + backend, alloc_id, custom_header_size, std::forward(args)...); + RegisterAllocator(alloc); + return GetAllocator(alloc_id); + } + + /** + * Locates an allocator of a particular id + * */ + Allocator* GetAllocator(allocator_id_t alloc_id) { + if (alloc_id.IsNull()) { return nullptr; } + if (alloc_id == root_allocator_.GetId()) { + return &root_allocator_; + } + auto iter = allocators_.find(alloc_id); + if (iter == allocators_.end()) { + ScanBackends(); + } + return reinterpret_cast(allocators_[alloc_id].get()); + } + + /** + * Gets the allocator used for initializing other allocators. + * */ + Allocator* GetRootAllocator() { + return &root_allocator_; + } + + /** + * Gets the allocator used by default when no allocator is + * used to construct an object. + * */ + Allocator* GetDefaultAllocator() { + return default_allocator_; + } + + /** + * Sets the allocator used by default when no allocator is + * used to construct an object. + * */ + void SetDefaultAllocator(Allocator *alloc) { + default_allocator_ = alloc; + } + + /** + * Convert a process-independent pointer into a process-specific pointer. + * */ + template + T* Convert(const POINTER_T &p) { + if (p.IsNull()) { + return nullptr; + } + return GetAllocator(p.allocator_id_)->template + Convert(p); + } + + /** + * Convert a process-specific pointer into a process-independent pointer + * + * @param allocator_id the allocator the pointer belongs to + * @param ptr the pointer to convert + * */ + template + POINTER_T Convert(allocator_id_t allocator_id, T *ptr) { + return GetAllocator(allocator_id)->template + Convert(ptr); + } + + /** + * Convert a process-specific pointer into a process-independent pointer when + * the allocator is unkown. + * + * @param ptr the pointer to convert + * */ + template + POINTER_T Convert(T *ptr) { + for (auto &[alloc_id, alloc] : allocators_) { + if (alloc->ContainsPtr(ptr)) { + return alloc->template + Convert(ptr); + } + } + return Pointer::GetNull(); + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_MEMORY_MANAGER_H_ diff --git a/hermes_shm/include/hermes_shm/thread/lock.h b/hermes_shm/include/hermes_shm/thread/lock.h new file mode 100644 index 000000000..2cb35e4da --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/lock.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_THREAD_LOCK_H_ +#define HERMES_SHM_THREAD_LOCK_H_ + +#include "lock/mutex.h" +#include "lock/rwlock.h" +#include "thread_manager.h" + +#endif // HERMES_SHM_THREAD_LOCK_H_ diff --git a/hermes_shm/include/hermes_shm/thread/lock/mutex.h b/hermes_shm/include/hermes_shm/thread/lock/mutex.h new file mode 100644 index 000000000..c5e20aab5 --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/lock/mutex.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_THREAD_MUTEX_H_ +#define HERMES_SHM_THREAD_MUTEX_H_ + +#include + +namespace hermes_shm { + +struct Mutex { + std::atomic lock_; + + Mutex() : lock_(0) {} + + void Init() { + lock_ = 0; + } + void Lock(); + bool TryLock(); + void Unlock(); +}; + +struct ScopedMutex { + Mutex &lock_; + bool is_locked_; + + explicit ScopedMutex(Mutex &lock); + ~ScopedMutex(); + + void Lock(); + bool TryLock(); + void Unlock(); +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_THREAD_MUTEX_H_ diff --git a/hermes_shm/include/hermes_shm/thread/lock/rwlock.h b/hermes_shm/include/hermes_shm/thread/lock/rwlock.h new file mode 100644 index 000000000..d37330623 --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/lock/rwlock.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_THREAD_RWLOCK_H_ +#define HERMES_SHM_THREAD_RWLOCK_H_ + +#include + +namespace hermes_shm { + +union RwLockPayload { + struct { + uint32_t r_; + uint32_t w_; + } bits_; + uint64_t as_int_; + + RwLockPayload() = default; + + RwLockPayload(const RwLockPayload &other) { + as_int_ = other.as_int_; + } + + RwLockPayload(uint64_t other) { + as_int_ = other; + } + + bool IsWriteLocked() const { + return bits_.w_ > 0; + } + + bool IsReadLocked() const { + return bits_.r_ > 0; + } +}; + +struct RwLock { + std::atomic payload_; + + RwLock() : payload_(0) {} + + void Init() { + payload_ = 0; + } + + RwLock(const RwLock &other) = delete; + + RwLock(RwLock &&other) noexcept + : payload_(other.payload_.load()) {} + + RwLock& operator=(RwLock &&other) { + payload_ = other.payload_.load(); + return (*this); + } + + void ReadLock(); + void ReadUnlock(); + + void WriteLock(); + void WriteUnlock(); + + void assert_r_refcnt(int ref); + void assert_w_refcnt(int ref); +}; + +struct ScopedRwReadLock { + RwLock &lock_; + bool is_locked_; + + explicit ScopedRwReadLock(RwLock &lock); + ~ScopedRwReadLock(); + + void Lock(); + void Unlock(); +}; + +struct ScopedRwWriteLock { + RwLock &lock_; + bool is_locked_; + + explicit ScopedRwWriteLock(RwLock &lock); + ~ScopedRwWriteLock(); + + void Lock(); + void Unlock(); +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_THREAD_RWLOCK_H_ diff --git a/hermes_shm/include/hermes_shm/thread/pthread.h b/hermes_shm/include/hermes_shm/thread/pthread.h new file mode 100644 index 000000000..652de4813 --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/pthread.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_THREAD_PTHREAD_H_ +#define HERMES_SHM_THREAD_PTHREAD_H_ + +#include "thread.h" +#include +#include + +namespace hermes_shm { + +template class Pthread; + +template +struct PthreadParams { + BIND bind_; + Pthread *pthread_; + + PthreadParams(Pthread *pthread, BIND bind) : + bind_(bind), + pthread_(pthread) {} +}; + +template +class Pthread : public Thread { + private: + pthread_t pthread_; + + public: + bool started_; + + public: + Pthread() = default; + explicit Pthread(BIND bind) : started_(false), pthread_(-1) { + PthreadParams params(this, bind); + int ret = pthread_create(&pthread_, nullptr, + DoWork, + ¶ms); + if (ret != 0) { + throw PTHREAD_CREATE_FAILED.format(); + } + while (!started_) {} + } + + void Pause() override {} + + void Resume() override {} + + void Join() override { + void *ret; + pthread_join(pthread_, &ret); + } + + void SetAffinity(int cpu_start, int count) override { + /*cpu_set_t cpus[n_cpu_]; + CPU_ZERO(cpus); + CPU_SET(cpu_id, cpus); + pthread_setaffinity_np_safe(n_cpu_, cpus);*/ + } + + private: + static void* DoWork(void *void_params) { + auto params = (*reinterpret_cast*>(void_params)); + params.pthread_->started_ = true; + params.bind_(); + return nullptr; + } + + inline void pthread_setaffinity_np_safe(int n_cpu, cpu_set_t *cpus) { + int ret = pthread_setaffinity_np(pthread_, n_cpu, cpus); + if (ret != 0) { + throw INVALID_AFFINITY.format(strerror(ret)); + } + } +}; + +class PthreadStatic : public ThreadStatic { + public: + void Yield() override { + pthread_yield(); + } + + tid_t GetTid() override { + return static_cast(pthread_self()); + } +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_THREAD_PTHREAD_H_ diff --git a/hermes_shm/include/hermes_shm/thread/thread.h b/hermes_shm/include/hermes_shm/thread/thread.h new file mode 100644 index 000000000..a6af0cf5e --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/thread.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_THREAD_THREAD_H_ +#define HERMES_SHM_THREAD_THREAD_H_ + +#include +#include +#include +#include + +namespace hermes_shm { + +typedef uint32_t tid_t; + +enum class ThreadType { + kPthread +}; + +class Thread { + public: + virtual void Pause() = 0; + virtual void Resume() = 0; + virtual void Join() = 0; + void SetAffinity(int cpu_id) { SetAffinity(cpu_id, 1); } + virtual void SetAffinity(int cpu_start, int count) = 0; +}; + +class ThreadStatic { + public: + virtual ~ThreadStatic() = default; + virtual void Yield() = 0; + virtual tid_t GetTid() = 0; +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_THREAD_THREAD_H_ diff --git a/hermes_shm/include/hermes_shm/thread/thread_factory.h b/hermes_shm/include/hermes_shm/thread/thread_factory.h new file mode 100644 index 000000000..469001b16 --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/thread_factory.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_THREAD_THREAD_FACTORY_H_ +#define HERMES_SHM_THREAD_THREAD_FACTORY_H_ + +#include "thread.h" +#include "pthread.h" + +namespace hermes_shm { + +template +class ThreadFactory { + private: + ThreadType type_; + BIND bind_; + + public: + explicit ThreadFactory(ThreadType type, BIND bind) + : type_(type), bind_(bind) {} + + std::unique_ptr Get() { + switch (type_) { + case ThreadType::kPthread: return std::make_unique>(bind_); + default: return nullptr; + } + } +}; + +class ThreadStaticFactory { + public: + static std::unique_ptr Get(ThreadType type) { + switch (type) { + case ThreadType::kPthread: return std::make_unique(); + default: return nullptr; + } + } +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_THREAD_THREAD_FACTORY_H_ diff --git a/hermes_shm/include/hermes_shm/thread/thread_manager.h b/hermes_shm/include/hermes_shm/thread/thread_manager.h new file mode 100644 index 000000000..e2e92c87c --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/thread_manager.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_THREAD_THREAD_MANAGER_H_ +#define HERMES_SHM_THREAD_THREAD_MANAGER_H_ + +#include "thread.h" +#include "thread_factory.h" +#include + +namespace hermes_shm { + +class ThreadManager { + public: + ThreadType type_; + std::unique_ptr thread_static_; + + ThreadManager() : type_(ThreadType::kPthread) {} + + void SetThreadType(ThreadType type) { + type_ = type; + } + + ThreadStatic* GetThreadStatic() { + if (!thread_static_) { + thread_static_ = ThreadStaticFactory::Get(type_); + } + return thread_static_.get(); + } +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_THREAD_THREAD_MANAGER_H_ diff --git a/hermes_shm/include/hermes_shm/types/argpack.h b/hermes_shm/include/hermes_shm/types/argpack.h new file mode 100644 index 000000000..821be69cd --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/argpack.h @@ -0,0 +1,226 @@ +// +// Created by lukemartinlogan on 1/28/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ARGPACK_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ARGPACK_H_ + +#include "basic.h" +#include + +namespace hermes_shm { + +/** Type which indicates that a constructor takes ArgPacks as input */ +struct PiecewiseConstruct {}; + +/** Type which ends template recurrence */ +struct EndTemplateRecurrence {}; + +/** Recurrence used to create argument pack */ +template< + size_t idx, + typename T=EndTemplateRecurrence, + typename ...Args> +struct ArgPackRecur { + constexpr static bool is_rval = std::is_rvalue_reference(); + typedef typename std::conditional::type ElementT; + + ElementT arg_; /**< The element stored */ + ArgPackRecur + recur_; /**< Remaining args */ + + /** Default constructor */ + ArgPackRecur() = default; + + /** Constructor. Rvalue reference. */ + explicit ArgPackRecur(T arg, Args&& ...args) + : arg_(std::forward(arg)), recur_(std::forward(args)...) {} + + /** Forward an rvalue reference (only if argpack) */ + template + constexpr decltype(auto) Forward() const { + if constexpr(i == idx) { + if constexpr(is_rval) { + return std::forward(arg_); + } else { + return arg_; + } + } else { + return recur_.template + Forward(); + } + } +}; + +/** Terminator of the ArgPack recurrence */ +template +struct ArgPackRecur { + /** Default constructor */ + ArgPackRecur() = default; + + /** Forward an rvalue reference (only if argpack) */ + template + constexpr void Forward() const { + throw std::logic_error("(Forward) ArgPack index outside of range"); + } +}; + +/** Used to semantically pack arguments */ +template +struct ArgPack { + /** Variable argument pack */ + ArgPackRecur<0, Args...> recur_; + /** Size of the argpack */ + constexpr const static size_t size_ = sizeof...(Args); + + /** General Constructor. */ + ArgPack(Args&& ...args) + : recur_(std::forward(args)...) {} + + /** Get forward reference */ + template + constexpr decltype(auto) Forward() const { + return recur_.template Forward(); + } + + /** Size */ + constexpr static size_t Size() { + return size_; + } +}; + +/** Make an argpack */ +template +ArgPack make_argpack(Args&& ...args) { + return ArgPack(std::forward(args)...); +} + +/** Get the type + reference of the forward for \a pack pack at \a index i */ +#define FORWARD_ARGPACK_FULL_TYPE(pack, i)\ + decltype(pack.template Forward()) + +/** Get type of the forward for \a pack pack at \a index i */ +#define FORWARD_ARGPACK_BASE_TYPE(pack, i)\ + std::remove_reference + +/** Forward the param for \a pack pack at \a index i */ +#define FORWARD_ARGPACK_PARAM(pack, i)\ + std::forward(\ + pack.template Forward()) + +/** Used to pass an argument pack to a function or class method */ +class PassArgPack { + public: + /** Call function with ArgPack */ + template + constexpr static decltype(auto) Call(ArgPackT &&pack, F &&f) { + return _CallRecur<0, ArgPackT, F>( + std::forward(pack), std::forward(f)); + } + + private: + /** Unpacks the ArgPack and passes it to the function */ + template + constexpr static decltype(auto) _CallRecur(ArgPackT &&pack, + F &&f, + CurArgs&& ...args) { + if constexpr(i < ArgPackT::Size()) { + return _CallRecur( + std::forward(pack), + std::forward(f), + std::forward(args)..., + FORWARD_ARGPACK_PARAM(pack, i)); + } else { + return std::__invoke(f, std::forward(args)...); + } + } +}; + +/** Combine multiple argpacks into a single argpack */ +class MergeArgPacks { + public: + /** Call function with ArgPack */ + template + constexpr static decltype(auto) Merge(ArgPacks&& ...packs) { + return _MergePacksRecur<0>(make_argpack(std::forward(packs)...)); + } + + private: + /** Unpacks the C++ parameter pack of ArgPacks */ + template + constexpr static decltype(auto) _MergePacksRecur(ArgPacksT &&packs, + CurArgs&& ...args) { + if constexpr(cur_pack < ArgPacksT::Size()) { + return _MergeRecur< + cur_pack, ArgPacksT, 0>( + // End template parameters + std::forward(packs), + FORWARD_ARGPACK_PARAM(packs, cur_pack), + std::forward(args)... + ); + } else { + return make_argpack(std::forward(args)...); + } + } + + /** Unpacks the C++ parameter pack of ArgPacks */ + template< + size_t cur_pack, typename ArgPacksT, + size_t i, typename ArgPackT, + typename ...CurArgs> + constexpr static decltype(auto) _MergeRecur(ArgPacksT &&packs, + ArgPackT &&pack, + CurArgs&& ...args) { + if constexpr(i < ArgPackT::Size()) { + return _MergeRecur( + std::forward(packs), + std::forward(pack), + std::forward(args)..., FORWARD_ARGPACK_PARAM(pack, i)); + } else { + return _MergePacksRecur( + std::forward(packs), + std::forward(args)...); + } + } +}; + +/** Insert an argpack at the head of each pack in a set of ArgPacks */ +class ProductArgPacks { + public: + /** The product function */ + template + constexpr static decltype(auto) Product(ProductPackT &&prod_pack, + ArgPacks&& ...packs) { + return _ProductPacksRecur<0>( + std::forward(prod_pack), + make_argpack(std::forward(packs)...)); + } + + private: + /** Prepend \a ArgPack prod_pack to every ArgPack in orig_packs */ + template< + size_t cur_pack, + typename ProductPackT, + typename OrigPacksT, + typename ...NewPacks> + constexpr static decltype(auto) _ProductPacksRecur(ProductPackT &&prod_pack, + OrigPacksT &&orig_packs, + NewPacks&& ...packs) { + if constexpr(cur_pack < OrigPacksT::Size()) { + return _ProductPacksRecur( + std::forward(prod_pack), + std::forward(orig_packs), + std::forward(packs)..., + std::forward(prod_pack), + FORWARD_ARGPACK_PARAM(orig_packs, cur_pack)); + } else { + return make_argpack(std::forward(packs)...); + } + } +}; + +} // namespace hermes_shm + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ARGPACK_H_ diff --git a/hermes_shm/include/hermes_shm/types/atomic.h b/hermes_shm/include/hermes_shm/types/atomic.h new file mode 100644 index 000000000..c02ac0b41 --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/atomic.h @@ -0,0 +1,244 @@ +// +// Created by lukemartinlogan on 1/13/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ATOMIC_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ATOMIC_H_ + +#include + +namespace hermes_shm::ipc { + +/** Provides the API of an atomic, without being atomic */ +template +struct nonatomic { + T x; + + /** Constructor */ + inline nonatomic() = default; + + /** Full constructor */ + inline nonatomic(T def) : x(def) {} + + /** Atomic fetch_add wrapper*/ + inline T fetch_add( + T count, std::memory_order order = std::memory_order_seq_cst) { + (void) order; + x += count; + return x; + } + + /** Atomic fetch_sub wrapper*/ + inline T fetch_sub( + T count, std::memory_order order = std::memory_order_seq_cst) { + (void) order; + x -= count; + return x; + } + + /** Atomic load wrapper */ + inline T load( + std::memory_order order = std::memory_order_seq_cst) const { + (void) order; + return x; + } + + /** Atomic exchange wrapper */ + inline void exchange( + T count, std::memory_order order = std::memory_order_seq_cst) { + (void) order; + x = count; + } + + /** Atomic compare exchange weak wrapper */ + inline bool compare_exchange_weak(T& expected, T desired, + std::memory_order order = + std::memory_order_seq_cst) { + (void) expected; (void) order; + x = desired; + return true; + } + + /** Atomic compare exchange strong wrapper */ + inline bool compare_exchange_strong(T& expected, T desired, + std::memory_order order = + std::memory_order_seq_cst) { + (void) expected; (void) order; + x = desired; + return true; + } + + /** Atomic pre-increment operator */ + inline nonatomic& operator++() { + ++x; + return *this; + } + + /** Atomic post-increment operator */ + inline nonatomic operator++(int) { + return atomic(x+1); + } + + /** Atomic pre-decrement operator */ + inline nonatomic& operator--() { + --x; + return *this; + } + + /** Atomic post-decrement operator */ + inline nonatomic operator--(int) { + return atomic(x-1); + } + + /** Atomic add operator */ + inline nonatomic operator+(T count) const { + return nonatomic(x + count); + } + + /** Atomic subtract operator */ + inline nonatomic operator-(T count) const { + return nonatomic(x - count); + } + + /** Atomic add assign operator */ + inline nonatomic& operator+=(T count) { + x += count; + return *this; + } + + /** Atomic subtract assign operator */ + inline nonatomic& operator-=(T count) { + x -= count; + return *this; + } + + /** Atomic assign operator */ + inline nonatomic& operator=(T count) { + x = count; + return *this; + } + + /** Equality check */ + inline bool operator==(const nonatomic &other) const { + return (other.x == x); + } + + /** Inequality check */ + inline bool operator!=(const nonatomic &other) const { + return (other.x != x); + } +}; + +/** A wrapper around std::atomic */ +template +struct atomic { + std::atomic x; + + /** Constructor */ + inline atomic() = default; + + /** Full constructor */ + inline atomic(T def) : x(def) {} + + /** Atomic fetch_add wrapper*/ + inline T fetch_add( + T count, std::memory_order order = std::memory_order_seq_cst) { + return x.fetch_add(count, order); + } + + /** Atomic fetch_sub wrapper*/ + inline T fetch_sub( + T count, std::memory_order order = std::memory_order_seq_cst) { + return x.fetch_sub(count, order); + } + + /** Atomic load wrapper */ + inline T load( + std::memory_order order = std::memory_order_seq_cst) const { + return x.load(order); + } + + /** Atomic exchange wrapper */ + inline void exchange( + T count, std::memory_order order = std::memory_order_seq_cst) { + x.exchange(count, order); + } + + /** Atomic compare exchange weak wrapper */ + inline bool compare_exchange_weak(T& expected, T desired, + std::memory_order order = + std::memory_order_seq_cst) { + return x.compare_exchange_weak(expected, desired, order); + } + + /** Atomic compare exchange strong wrapper */ + inline bool compare_exchange_strong(T& expected, T desired, + std::memory_order order = + std::memory_order_seq_cst) { + return x.compare_exchange_strong(expected, desired, order); + } + + /** Atomic pre-increment operator */ + inline atomic& operator++() { + ++x; + return *this; + } + + /** Atomic post-increment operator */ + inline atomic operator++(int) { + return atomic(x+1); + } + + /** Atomic pre-decrement operator */ + inline atomic& operator--() { + --x; + return *this; + } + + /** Atomic post-decrement operator */ + inline atomic operator--(int) { + return atomic(x-1); + } + + /** Atomic add operator */ + inline atomic operator+(T count) const { + return x + count; + } + + /** Atomic subtract operator */ + inline atomic operator-(T count) const { + return x - count; + } + + /** Atomic add assign operator */ + inline atomic& operator+=(T count) { + x += count; + return *this; + } + + /** Atomic subtract assign operator */ + inline atomic& operator-=(T count) { + x -= count; + return *this; + } + + /** Atomic assign operator */ + inline atomic& operator=(T count) { + x.exchange(count); + return *this; + } + + /** Equality check */ + inline bool operator==(const atomic &other) const { + return (other.x == x); + } + + /** Inequality check */ + inline bool operator!=(const atomic &other) const { + return (other.x != x); + } +}; + +} + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ATOMIC_H_ diff --git a/hermes_shm/include/hermes_shm/types/basic.h b/hermes_shm/include/hermes_shm/types/basic.h new file mode 100644 index 000000000..e1a8f0d89 --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/basic.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_BASICS_H +#define HERMES_SHM_BASICS_H + +#define MODULE_KEY_SIZE 32 + +#include +using std::size_t; + +#include +#include +#include +#include +#include + +namespace hermes_shm { + +/** + * decimal + (numerator/65536) + * */ +struct RealNumber { + uint64_t decimal_; + uint32_t numerator_; + static const uint32_t precision = 65536; + + RealNumber() = default; + + /** + * Converts numerator / denomintor -> + * decimal + (numerator / 65536); + * + * For example, + * 4/5 = (4 * 65536 / 5) / 65536 + * */ + explicit RealNumber(uint64_t numerator, uint64_t denominator) { + decimal_ = numerator / denominator; + uint64_t rem = numerator % denominator; + numerator_ = rem * precision / denominator; + } + + /** + * (d1 + n1/p) * d2 = + * d1 * d2 + d2 * n1 / p + * */ + RealNumber operator*(size_t other) const { + RealNumber res; + res.decimal_ = other * decimal_; + uint64_t frac = other * numerator_; + res.decimal_ += frac / precision; + res.numerator_ = frac % precision; + return res; + } + + /** + * (d1 + n1/p) * (d2 + n2/p) = + * (d1 * d2) + (d1 * n2)/p + (d2 * n1) / p + (n1 * n2 / p) / p = + * (d1 * d2) + [(d1 * n2) + (d2 * n1) + (n1 * n2)/p] / p + * */ + RealNumber operator*(const RealNumber &other) const { + RealNumber res; + // d1 * d2 + res.decimal_ = other.decimal_ * decimal_; + uint64_t frac = + (decimal_ * other.numerator_) + // d1 * n2 + (other.decimal_ * numerator_) + // d2 * n1 + (numerator_ * other.numerator_) / precision; // n1 * n2 / p + res.decimal_ += frac / precision; + res.numerator_ = frac % precision; + return res; + } + + RealNumber operator*=(size_t other) { + (*this) = (*this) * other; + return *this; + } + + RealNumber operator*=(const RealNumber &other) { + (*this) = (*this) * other; + return *this; + } + + size_t as_int() const { + return decimal_ + numerator_ / precision; + } +}; + +struct id { + char key_[MODULE_KEY_SIZE]; + id() = default; + ~id() = default; + explicit id(const std::string &key_str) { + snprintf(key_, MODULE_KEY_SIZE, "%s", key_str.c_str()); + } + explicit id(const char* key_str) { + snprintf(key_, MODULE_KEY_SIZE, "%s", key_str); + } + bool operator==(const id &other) const { + return strncmp(key_, other.key_, MODULE_KEY_SIZE) == 0; + } + void copy(const std::string &str) { + memcpy(key_, str.c_str(), str.size()); + key_[str.size()] = 0; + } + const char& operator[](int i) { + return key_[i]; + } +}; + +typedef int32_t off_t; + +} // namespace hermes_shm + +namespace std { +template<> +struct hash { + size_t operator()(const hermes_shm::id &id) const { + size_t sum = 0; + int len = strnlen(id.key_, MODULE_KEY_SIZE); + for (int i = 0; i < len; ++i) { + if (id.key_[i] == 0) { break; } + sum += id.key_[i] << (i % 8); + } + return sum; + } +}; +} // namespace std + +#endif // HERMES_SHM_BASICS_H diff --git a/hermes_shm/include/hermes_shm/types/bitfield.h b/hermes_shm/include/hermes_shm/types/bitfield.h new file mode 100644 index 000000000..073f4482a --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/bitfield.h @@ -0,0 +1,67 @@ +// +// Created by lukemartinlogan on 1/1/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_BITFIELD_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_BITFIELD_H_ + +#include + +namespace hermes_shm { + +#define BIT_OPT(T, n) (((T)1) << n) + +/** + * A generic bitfield template + * */ +template +struct bitfield { + T bits_; + + bitfield() : bits_(0) {} + + inline void SetBits(T mask) { + bits_ |= mask; + } + + inline void UnsetBits(T mask) { + bits_ &= ~mask; + } + + inline bool OrBits(T mask) const { + return bits_ & mask; + } + + inline void CopyBits(bitfield field, T mask) { + bits_ &= (field.bits_ & mask); + } + + inline void Clear() { + bits_ = 0; + } +} __attribute__((packed)); +typedef bitfield bitfield8_t; +typedef bitfield bitfield16_t; +typedef bitfield bitfield32_t; + +#define INHERIT_BITFIELD_OPS(BITFIELD_VAR, MASK_T)\ + inline void SetBits(MASK_T mask) {\ + BITFIELD_VAR.SetBits(mask);\ + }\ + inline void UnsetBits(MASK_T mask) {\ + BITFIELD_VAR.UnsetBits(mask);\ + }\ + inline bool OrBits(MASK_T mask) const {\ + return BITFIELD_VAR.OrBits(mask);\ + }\ + inline void Clear() {\ + BITFIELD_VAR.Clear();\ + }\ + template\ + inline void CopyBits(BITFIELD_T field, MASK_T mask) {\ + BITFIELD_VAR.CopyBits(field, mask);\ + } + +} // namespace hermes_shm + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_BITFIELD_H_ diff --git a/hermes_shm/include/hermes_shm/types/charbuf.h b/hermes_shm/include/hermes_shm/types/charbuf.h new file mode 100644 index 000000000..24d60019e --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/charbuf.h @@ -0,0 +1,196 @@ +// +// Created by lukemartinlogan on 1/31/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_CHARBUF_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_CHARBUF_H_ + +#include "basic.h" +#include "hermes_shm/memory/memory_manager.h" +#include + +namespace hermes_shm { + +/** An uninterpreted array of bytes */ +struct charbuf { + lipc::Allocator *alloc_; /**< The allocator used to allocate data */ + char *data_; /**< The pointer to data */ + size_t size_; /**< The size of data */ + bool destructable_; /**< Whether or not this container owns data */ + + /** Default constructor */ + charbuf() : alloc_(nullptr), data_(nullptr), size_(0), destructable_(false) {} + + /** Destructor */ + ~charbuf() { Free(); } + + /** Size-based constructor */ + explicit charbuf(size_t size) { + Allocate(HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(), size); + } + + /** String-based constructor */ + explicit charbuf(const std::string &data) { + Allocate(HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(), data.size()); + memcpy(data_, data.data(), data.size()); + } + + /** Pointer-based constructor */ + explicit charbuf(char *data, size_t size) + : alloc_(nullptr), data_(data), size_(size), destructable_(false) {} + + /** + * Pointer-based constructor + * This should only be used when Blob itself is const. + * */ + explicit charbuf(const char *data, size_t size) + : alloc_(nullptr), data_(const_cast(data)), + size_(size), destructable_(false) {} + + + /** Copy constructor */ + charbuf(const charbuf &other) { + if (!Allocate(HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(), + other.size())) { + return; + } + memcpy(data_, other.data(), size()); + } + + /** Copy assignment operator */ + charbuf& operator=(const charbuf &other) { + if (this != &other) { + Free(); + if (!Allocate(HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(), + other.size())) { + return *this; + } + memcpy(data_, other.data(), size()); + } + return *this; + } + + /** Move constructor */ + charbuf(charbuf &&other) { + alloc_ = other.alloc_; + data_ = other.data_; + size_ = other.size_; + destructable_ = other.destructable_; + other.size_ = 0; + other.destructable_ = false; + } + + /** Move assignment operator */ + charbuf& operator=(charbuf &other) { + if (this != &other) { + Free(); + alloc_ = other.alloc_; + data_ = other.data_; + size_ = other.size_; + destructable_ = other.destructable_; + other.size_ = 0; + other.destructable_ = false; + } + return *this; + } + + /** Destroy and resize */ + void resize(size_t new_size) { + if (new_size <= size()) { + size_ = new_size; + return; + } + if (alloc_ == nullptr) { + alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + } + if (destructable_) { + data_ = alloc_->ReallocatePtr(data_, new_size); + } else { + data_ = alloc_->AllocatePtr(new_size); + } + destructable_ = true; + size_ = new_size; + } + + /** Reference data */ + char* data() { + return data_; + } + + /** Reference data */ + char* data() const { + return data_; + } + + /** Reference size */ + size_t size() const { + return size_; + } + + /** + * Comparison operators + * */ + + int _strncmp(const char *a, size_t len_a, + const char *b, size_t len_b) const { + if (len_a != len_b) { + return int((int64_t)len_a - (int64_t)len_b); + } + int sum = 0; + for (size_t i = 0; i < len_a; ++i) { + sum += a[i] - b[i]; + } + return sum; + } + +#define HERMES_SHM_STR_CMP_OPERATOR(op) \ + bool operator op(const char *other) const { \ + return _strncmp(data(), size(), other, strlen(other)) op 0; \ + } \ + bool operator op(const std::string &other) const { \ + return _strncmp(data(), size(), other.data(), other.size()) op 0; \ + } \ + bool operator op(const charbuf &other) const { \ + return _strncmp(data(), size(), other.data(), other.size()) op 0; \ + } + + HERMES_SHM_STR_CMP_OPERATOR(==) + HERMES_SHM_STR_CMP_OPERATOR(!=) + HERMES_SHM_STR_CMP_OPERATOR(<) + HERMES_SHM_STR_CMP_OPERATOR(>) + HERMES_SHM_STR_CMP_OPERATOR(<=) + HERMES_SHM_STR_CMP_OPERATOR(>=) + +#undef HERMES_SHM_STR_CMP_OPERATOR + + private: + /** Allocate charbuf */ + bool Allocate(lipc::Allocator *alloc, size_t size) { + lipc::OffsetPointer p; + if (size == 0) { + alloc_ = nullptr; + data_ = nullptr; + size_ = 0; + destructable_ = false; + return false; + } + alloc_ = alloc; + data_ = alloc->AllocatePtr(size, p); + size_ = size; + destructable_ = true; + return true; + } + + /** Explicitly free the charbuf */ + void Free() { + if (destructable_ && data_ && size_) { + alloc_->FreePtr(data_); + } + } +}; + +typedef charbuf string; + +} // namespace hermes_shm + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_CHARBUF_H_ diff --git a/hermes_shm/include/hermes_shm/types/messages.h b/hermes_shm/include/hermes_shm/types/messages.h new file mode 100644 index 000000000..4b09541c0 --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/messages.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_MESSAGES_H +#define HERMES_SHM_MESSAGES_H + +namespace hermes_shm { + +enum { + HERMES_SHM_ADMIN_REGISTER_QP +}; + +struct admin_request { + int op_; + admin_request() {} + explicit admin_request(int op) : op_(op) {} +}; + +struct admin_reply { + int code_; + admin_reply() {} + explicit admin_reply(int code) : code_(code) {} +}; + +struct setup_reply : public admin_reply { + uint32_t region_id_; + uint32_t region_size_; + uint32_t request_region_size_; + uint32_t request_unit_; + uint32_t queue_region_size_; + uint32_t queue_depth_; + uint32_t num_queues_; + uint32_t namespace_region_id_; + uint32_t namespace_region_size_; + uint32_t namespace_max_entries_; +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_MESSAGES_H diff --git a/hermes_shm/include/hermes_shm/types/tuple_base.h b/hermes_shm/include/hermes_shm/types/tuple_base.h new file mode 100644 index 000000000..81696ce93 --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/tuple_base.h @@ -0,0 +1,239 @@ +// +// Created by lukemartinlogan on 1/26/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_TupleBase_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_TupleBase_H_ + +#include +#include "basic.h" +#include "argpack.h" + +namespace hermes_shm { + +/** The null container wrapper */ +template +using NullWrap = T; + +/** Recurrence used to create argument pack */ +template< + template typename Wrap, + size_t idx, + typename T=EndTemplateRecurrence, + typename ...Args> +struct TupleBaseRecur { + Wrap arg_; /**< The element stored */ + TupleBaseRecur + recur_; /**< Remaining args */ + + /** Default constructor */ + TupleBaseRecur() = default; + + /** Constructor. Const reference. */ + explicit TupleBaseRecur(const T &arg, Args&& ...args) + : arg_(std::forward(arg)), recur_(std::forward(args)...) {} + + /** Constructor. Lvalue reference. */ + explicit TupleBaseRecur(T& arg, Args&& ...args) + : arg_(std::forward(arg)), recur_(std::forward(args)...) {} + + /** Constructor. Rvalue reference. */ + explicit TupleBaseRecur(T&& arg, Args&& ...args) + : arg_(std::forward(arg)), recur_(std::forward(args)...) {} + + /** Move constructor */ + TupleBaseRecur(TupleBaseRecur &&other) noexcept + : arg_(std::move(other.arg_)), recur_(std::move(other.recur_)) {} + + /** Move assignment operator */ + TupleBaseRecur& operator=(TupleBaseRecur &&other) { + if (this != &other) { + arg_ = std::move(other.arg_); + recur_ = std::move(other.recur_); + } + return *this; + } + + /** Copy constructor */ + TupleBaseRecur(const TupleBaseRecur &other) + : arg_(other.arg_), recur_(other.recur_) {} + + /** Copy assignment operator */ + TupleBaseRecur& operator=(const TupleBaseRecur &other) { + if (this != &other) { + arg_ = other.arg_; + recur_ = other.recur_; + } + return *this; + } + + /** Solidification constructor */ + template + explicit TupleBaseRecur(ArgPack &&other) + : arg_(other.template Forward()), + recur_(std::forward>(other)) {} + + /** Get reference to internal variable (only if tuple) */ + template + constexpr auto& Get() { + if constexpr(i == idx) { + return arg_; + } else { + return recur_.template + Get(); + } + } + + /** Get reference to internal variable (only if tuple, const) */ + template + constexpr auto& Get() const { + if constexpr(i == idx) { + return arg_; + } else { + return recur_.template + Get(); + } + } +}; + +/** Terminator of the TupleBase recurrence */ +template< + template typename Wrap, + size_t idx> +struct TupleBaseRecur { + /** Default constructor */ + TupleBaseRecur() = default; + + /** Solidification constructor */ + template + explicit TupleBaseRecur(ArgPack &&other) {} + + /** Getter */ + template + void Get() { + throw std::logic_error("(Get) TupleBase index outside of range"); + } + + /** Getter */ + template + void Get() const { + throw std::logic_error("(Get) TupleBase index outside of range"); + } +}; + +/** Used to semantically pack arguments */ +template< + bool is_argpack, + template typename Wrap, + typename ...Args> +struct TupleBase { + /** Variable argument pack */ + TupleBaseRecur recur_; + + /** Default constructor */ + TupleBase() = default; + + /** General Constructor. */ + template + explicit TupleBase(Args&& ...args) + : recur_(std::forward(args)...) {} + + /** Move constructor */ + TupleBase(TupleBase &&other) noexcept + : recur_(std::move(other.recur_)) {} + + /** Move assignment operator */ + TupleBase& operator=(TupleBase &&other) noexcept { + if (this != &other) { + recur_ = std::move(other.recur_); + } + return *this; + } + + /** Copy constructor */ + TupleBase(const TupleBase &other) + : recur_(other.recur_) {} + + /** Copy assignment operator */ + TupleBase& operator=(const TupleBase &other) { + if (this != &other) { + recur_ = other.recur_; + } + return *this; + } + + /** Solidification constructor */ + template + explicit TupleBase(ArgPack &&other) + : recur_(std::forward>(other)) {} + + /** Getter */ + template + constexpr auto& Get() { + return recur_.template Get(); + } + + /** Getter (const) */ + template + constexpr auto& Get() const { + return recur_.template Get(); + } + + /** Size */ + constexpr static size_t Size() { + return sizeof...(Args); + } +}; + +/** Tuple definition */ +template +using tuple = TupleBase; + +/** Tuple Wrapper Definition */ +template typename Wrap, typename ...Containers> +using tuple_wrap = TupleBase; + +/** Used to emulate constexpr to lambda */ +template +struct MakeConstexpr { + constexpr static T val_ = Val; + constexpr static T Get() { + return val_; + } +}; + +/** Apply a function over an entire TupleBase / tuple */ +template +class IterateTuple { + public: + /** Apply a function to every element of a tuple */ + template + constexpr static void Apply(TupleT &pack, F &&f) { + _Apply<0, TupleT, F>(pack, std::forward(f)); + } + + private: + /** Apply the function recursively */ + template + constexpr static void _Apply(TupleT &pack, F &&f) { + if constexpr(i < TupleT::Size()) { + if constexpr(reverse) { + _Apply(pack, std::forward(f)); + f(MakeConstexpr(), pack.template Get()); + } else { + f(MakeConstexpr(), pack.template Get()); + _Apply(pack, std::forward(f)); + } + } + } +}; + +/** Forward iterate over tuple and apply function */ +using ForwardIterateTuple = IterateTuple; + +/** Reverse iterate over tuple and apply function */ +using ReverseIterateTuple = IterateTuple; + +} // namespace hermes_shm + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_TupleBase_H_ diff --git a/hermes_shm/include/hermes_shm/util/auto_trace.h b/hermes_shm/include/hermes_shm/util/auto_trace.h new file mode 100644 index 000000000..4fa65171e --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/auto_trace.h @@ -0,0 +1,44 @@ +// +// Created by lukemartinlogan on 1/11/23. +// + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_UTIL_AUTO_TRACE_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_UTIL_AUTO_TRACE_H_ + +#include "formatter.h" +#include "timer.h" + +namespace hermes_shm { + +#define AUTO_TRACE() AutoTrace(__PRETTY_FUNCTION__); + +/** An in-memory log of trace times */ +class AutoTraceLog { + public: + std::stringstream ss_; + void emplace_back(const std::string &fname, Timer timer) { + ss_ << fname << "," << timer.GetUsec() << "," << std::endl; + } +}; + +/** Trace function execution times */ +class AutoTrace { + private: + HighResMonotonicTimer timer_; + std::string fname_; + static AutoTraceLog log_; + + public: + AutoTrace(const std::string &fname) : fname_(fname) { + timer_.Resume(); + } + + ~AutoTrace() { + timer_.Pause(); + log_.emplace_back(fname_, timer_); + } +}; + +} // namespace hermes_shm + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_UTIL_AUTO_TRACE_H_ diff --git a/hermes_shm/include/hermes_shm/util/debug.h b/hermes_shm/include/hermes_shm/util/debug.h new file mode 100644 index 000000000..b43469fda --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/debug.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_DEBUG_H +#define HERMES_SHM_DEBUG_H + +#if defined(HERMES_SHM_DEBUG) && defined(__cplusplus) +#define AUTO_TRACE(...) \ + hermes_shm::AutoTrace auto_tracer(false, __PRETTY_FUNCTION__, __VA_ARGS__); +#define TRACEPOINT(...) \ + hermes_shm::AutoTrace(true, __PRETTY_FUNCTION__, __VA_ARGS__); +#elif defined(KERNEL_BUILD) && defined(DEBUG) +#define AUTO_TRACE(...) pr_info(__VA_ARGS__); +#define TRACEPOINT(...) pr_info(__VA_ARGS__); +#else +#define AUTO_TRACE(...) +#define TRACEPOINT(...) +#endif + +#ifdef __cplusplus + +#include "stdio.h" +#include "hermes_shm/util/timer.h" +#include "hermes_shm/util/formatter.h" +#include +#include + +namespace hermes_shm { + +class AutoTrace { + private: + std::string base_text_; + bool tracepoint_; + hermes_shm::HighResCpuTimer t_cpu_; + hermes_shm::HighResMonotonicTimer t_total_; + + public: + template + AutoTrace(bool tracepoint, Args&& ...args) : tracepoint_(tracepoint) { + // TODO(llogan): Redo with good argpack + std::stringstream ss; + base_text_ = ss.str(); + t_cpu_.Resume(); + t_total_.Resume(); + if (!tracepoint) { + printf("%s\n", (base_text_ + "start").c_str()); + } else { + printf("%d;%s\n", gettid(), (base_text_).c_str()); + } + } + + ~AutoTrace() { + if (!tracepoint_) { + t_cpu_.Pause(); + t_total_.Pause(); + base_text_ += "cpu-time-us;" + + std::to_string(t_cpu_.GetUsec()) + ";total-time-us;" + + std::to_string(t_total_.GetUsec()) + ";"; + printf("%s\n", (base_text_ + "end").c_str()); + } + } +}; + +} // namespace hermes_shm + +#endif + +#endif // HERMES_SHM_DEBUG_H diff --git a/hermes_shm/include/hermes_shm/util/error.h b/hermes_shm/include/hermes_shm/util/error.h new file mode 100644 index 000000000..2c65ab2aa --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/error.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_ERROR_H +#define HERMES_SHM_ERROR_H + +// #ifdef __cplusplus + +#include +#include +#include +#include +#include + +#define HERMES_SHM_ERROR_TYPE std::shared_ptr +#define HERMES_SHM_ERROR_HANDLE_START() try { +#define HERMES_SHM_ERROR_HANDLE_END() \ + } catch(HERMES_SHM_ERROR_TYPE &err) { err->print(); exit(-1024); } +#define HERMES_SHM_ERROR_HANDLE_TRY try +#define HERMES_SHM_ERROR_PTR err +#define HERMES_SHM_ERROR_HANDLE_CATCH catch(HERMES_SHM_ERROR_TYPE &HERMES_SHM_ERROR_PTR) +#define HERMES_SHM_ERROR_IS(err, check) (err->get_code() == check.get_code()) + +namespace hermes_shm { + +class Error { + private: + std::string fmt_; + std::string msg_; + public: + Error() : fmt_() {} + explicit Error(std::string fmt) : fmt_(std::move(fmt)) {} + ~Error() = default; + + template + std::shared_ptr format(Args&& ...args) const { + std::shared_ptr err = std::make_shared(fmt_); + err->msg_ = Formatter::format(fmt_, std::forward(args)...); + return err; + } + + void print() { + std::cout << msg_ << std::endl; + } +}; + +} // namespace hermes_shm + +// #endif + +#endif // HERMES_SHM_ERROR_H diff --git a/hermes_shm/include/hermes_shm/util/errors.h b/hermes_shm/include/hermes_shm/util/errors.h new file mode 100644 index 000000000..18fc46c9d --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/errors.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_ERRORS_H +#define HERMES_SHM_ERRORS_H + +#ifdef __cplusplus + +#include + +namespace hermes_shm { + const Error FILE_NOT_FOUND("File not found at {}"); + const Error INVALID_STORAGE_TYPE("{} is not a valid storage method"); + const Error INVALID_SERIALIZER_TYPE("{} is not a valid serializer type"); + const Error INVALID_TRANSPORT_TYPE("{} is not a valid transport type"); + const Error INVALID_AFFINITY("Could not set CPU affinity of thread: {}"); + const Error MMAP_FAILED("Could not mmap file: {}"); + const Error LAZY_ERROR("Error in function {}"); + const Error PTHREAD_CREATE_FAILED("Failed to create a pthread"); + const Error NOT_IMPLEMENTED("{} not implemented"); + + const Error DLSYM_MODULE_NOT_FOUND("Module {} was not loaded; error {}"); + const Error DLSYM_MODULE_NO_CONSTRUCTOR("Module {} has no constructor"); + + const Error UNIX_SOCKET_FAILED("Failed to create socket: {}"); + const Error UNIX_BIND_FAILED("Failed to bind socket: {}"); + const Error UNIX_CONNECT_FAILED("Failed to connect over socket: {}"); + const Error UNIX_SENDMSG_FAILED("Failed to send message over socket: {}"); + const Error UNIX_RECVMSG_FAILED("Failed to receive message over socket: {}"); + const Error UNIX_SETSOCKOPT_FAILED("Failed to set socket options: {}"); + const Error UNIX_GETSOCKOPT_FAILED("Failed to acquire user credentials: {}"); + const Error UNIX_LISTEN_FAILED("Failed to listen for connections: {}"); + const Error UNIX_ACCEPT_FAILED("Failed accept connections: {}"); + + const Error ARRAY_OUT_OF_BOUNDS("Exceeded the bounds of array in {}"); + + const Error SHMEM_CREATE_FAILED("Failed to allocate SHMEM"); + const Error SHMEM_RESERVE_FAILED("Failed to reserve SHMEM"); + const Error SHMEM_NOT_SUPPORTED("Attempting to deserialize a non-shm backend"); + const Error MEMORY_BACKEND_NOT_FOUND("Failed to find the memory backend"); + const Error NOT_ENOUGH_CONCURRENT_SPACE("{}: Failed to divide memory slot {} among {} devices"); + const Error ALIGNED_ALLOC_NOT_SUPPORTED("Allocator does not support aligned allocations"); + const Error PAGE_SIZE_UNSUPPORTED("Allocator does not support size: {}"); + const Error OUT_OF_MEMORY("{}: could not allocate memory of size {}"); + const Error INVALID_FREE("{}: could not free memory of size {}"); + const Error DOUBLE_FREE("Freeing the same memory twice!"); + + const Error UNORDERED_MAP_CANT_FIND("Could not find key in unordered_map"); +} // namespace hermes_shm + +#endif + +#endif // HERMES_SHM_ERRORS_H diff --git a/hermes_shm/include/hermes_shm/util/formatter.h b/hermes_shm/include/hermes_shm/util/formatter.h new file mode 100644 index 000000000..3733fa6bd --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/formatter.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_ERROR_SERIALIZER_H +#define HERMES_SHM_ERROR_SERIALIZER_H + +#include +#include +#include +#include +#include +#include +#include + +#define NUMBER_SERIAL(type) \ + return std::to_string(num_.type); + +namespace hermes_shm { + +class Formattable { + public: + virtual std::string ToString() = 0; +}; + +class SizeType : public Formattable { + public: + double num_; + size_t unit_; + + static const size_t + BYTES = 1, + KB = (1ul << 10), + MB = (1ul << 20), + GB = (1ul << 30), + TB = (1ul << 40); + + std::string unit_to_str(size_t unit) { + switch (unit) { + case BYTES: return "BYTES"; + case KB: return "KB"; + case MB: return "MB"; + case GB: return "GB"; + case TB: return "TB"; + } + return ""; + } + + SizeType() : num_(0), unit_(0) {} + SizeType(const SizeType &old_obj) { + num_ = old_obj.num_; + unit_ = old_obj.unit_; + } + + SizeType(int8_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(int16_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(int32_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(int64_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(uint8_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(uint16_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(uint32_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(uint64_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(float bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(double bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + + std::string ToString() { + return std::to_string(num_) + unit_to_str(unit_); + } +}; + +class Formatter { + public: + template + static std::string format(std::string fmt, Args&& ...args) { + // make_argpack(std::forward(args)...); + return fmt; + } +}; + +} // namespace hermes_shm + +#endif //HERMES_SHM_ERROR_SERIALIZER_H diff --git a/hermes_shm/include/hermes_shm/util/partitioner.h b/hermes_shm/include/hermes_shm/util/partitioner.h new file mode 100644 index 000000000..3485a4b3c --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/partitioner.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_PARTITIONER_H +#define HERMES_SHM_PARTITIONER_H + +// Reference: https://stackoverflow.com/questions/63372288/getting-list-of-pids-from-proc-in-linux + +#include +#include +#include +#include +#include + +namespace hermes_shm { + +class ProcessAffiner { + private: + int n_cpu_; + cpu_set_t *cpus_; + + public: + ProcessAffiner() { + n_cpu_ = get_nprocs_conf(); + cpus_ = new cpu_set_t[n_cpu_]; + CPU_ZERO(cpus_); + } + + ~ProcessAffiner() { + delete cpus_; + } + + inline bool isdigit(char digit) { + return ('0' <= digit && digit <= '9'); + } + + inline int GetNumCPU() { + return n_cpu_; + } + + inline void SetCpu(int cpu) { + CPU_SET(cpu, cpus_); + } + + inline void SetCpus(int off, int len) { + for (int i = 0; i < len; ++i) { + SetCpu(off + i); + } + } + + inline void ClearCpu(int cpu) { + CPU_CLR(cpu, cpus_); + } + + inline void ClearCpus(int off, int len) { + for (int i = 0; i < len; ++i) { + ClearCpu(off + i); + } + } + + inline void Clear() { + CPU_ZERO(cpus_); + } + + int AffineAll(void) { + DIR *procdir; + struct dirent *entry; + int count = 0; + + // Open /proc directory. + procdir = opendir("/proc"); + if (!procdir) { + perror("opendir failed"); + return 0; + } + + // Iterate through all files and folders of /proc. + while ((entry = readdir(procdir))) { + // Skip anything that is not a PID folder. + if (!is_pid_folder(entry)) + continue; + // Get the PID of the running process + int proc_pid = atoi(entry->d_name); + // Set the affinity of all running process to this mask + count += Affine(proc_pid); + } + closedir(procdir); + return count; + } + int Affine(std::vector &&pids) { + return Affine(pids); + } + int Affine(std::vector &pids) { + // Set the affinity of all running process to this mask + int count = 0; + for (pid_t &pid : pids) { + count += Affine(pid); + } + return count; + } + int Affine(int pid) { + return SetAffinitySafe(pid, n_cpu_, cpus_); + } + + void PrintAffinity(int pid) { + PrintAffinity("", pid); + } + void PrintAffinity(std::string prefix, int pid) { + std::vector cpus(n_cpu_); + sched_getaffinity(pid, n_cpu_, cpus.data()); + PrintAffinity(prefix, pid, cpus.data()); + } + + void PrintAffinity(std::string prefix, int pid, cpu_set_t *cpus) { + std::string affinity = ""; + for (int i = 0; i < n_cpu_; ++i) { + if (CPU_ISSET(i, cpus)) { + affinity += std::to_string(i) + ", "; + } + } + printf("%s: CPU affinity[pid=%d]: %s\n", prefix.c_str(), + pid, affinity.c_str()); + } + + private: + int SetAffinitySafe(int pid, int n_cpu, cpu_set_t *cpus) { + int ret = sched_setaffinity(pid, n_cpu, cpus); + if (ret == -1) { + return 0; + } + return 1; + } + + // Helper function to check if a struct dirent from /proc is a PID folder. + int is_pid_folder(const struct dirent *entry) { + const char *p; + for (p = entry->d_name; *p; p++) { + if (!isdigit(*p)) + return false; + } + return true; + } +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_PARTITIONER_H diff --git a/hermes_shm/include/hermes_shm/util/path_parser.h b/hermes_shm/include/hermes_shm/util/path_parser.h new file mode 100644 index 000000000..0e5df9fd6 --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/path_parser.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_PATH_PARSER_H +#define HERMES_SHM_PATH_PARSER_H + +#include +#include +#include +#include + +namespace scs { + +std::string path_parser(std::string path) { + std::smatch env_names; + std::regex expr("\\$\\{[^\\}]+\\}"); + if (!std::regex_search(path, env_names, expr)) { + return path; + } + for (auto &env_name_re : env_names) { + std::string to_replace = std::string(env_name_re); + std::string env_name = to_replace.substr(2, to_replace.size()-3); + std::string env_val = env_name; + try { + char *ret = getenv(env_name.c_str()); + if (ret) { + env_val = ret; + } else { + continue; + } + } catch(...) { + } + std::regex replace_expr("\\$\\{" + env_name + "\\}"); + path = std::regex_replace(path, replace_expr, env_val); + } + return path; +} + +} // namespace scs + +#endif // HERMES_SHM_PATH_PARSER_H diff --git a/hermes_shm/include/hermes_shm/util/singleton.h b/hermes_shm/include/hermes_shm/util/singleton.h new file mode 100644 index 000000000..8c5e32e54 --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/singleton.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef SCS_SINGLETON_H +#define SCS_SINGLETON_H + +#include +#include "hermes_shm/thread/lock/mutex.h" + +namespace scs { + +template +class Singleton { + private: + static T obj_; + public: + Singleton() = default; + static T* GetInstance() { + return &obj_; + } +}; + +} // namespace scs + +#endif // SCS_SINGLETON_H diff --git a/hermes_shm/include/hermes_shm/util/timer.h b/hermes_shm/include/hermes_shm/util/timer.h new file mode 100644 index 000000000..810aea91b --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/timer.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_TIMER_H +#define HERMES_SHM_TIMER_H + +#include +#include +#include + +namespace hermes_shm { + +template +class TimerBase { + private: + std::chrono::time_point start_, end_; + double time_ns_; + + public: + TimerBase() : time_ns_(0) {} + + void Resume() { + start_ = T::now(); + } + double Pause() { + time_ns_ += GetNsecFromStart(); + return time_ns_; + } + double Pause(double &dt) { + dt = GetNsecFromStart(); + time_ns_ += dt; + return time_ns_; + } + void Reset() { + time_ns_ = 0; + } + + double GetNsecFromStart() { + end_ = T::now(); + double elapsed = std::chrono::duration_cast( + end_ - start_).count(); + return elapsed; + } + double GetUsecFromStart() { + end_ = T::now(); + return std::chrono::duration_cast( + end_ - start_).count(); + } + double GetMsecFromStart() { + end_ = T::now(); + return std::chrono::duration_cast( + end_ - start_).count(); + } + double GetSecFromStart() { + end_ = T::now(); + return std::chrono::duration_cast( + end_ - start_).count(); + } + + double GetNsec() const { + return time_ns_; + } + double GetUsec() const { + return time_ns_/1000; + } + double GetMsec() const { + return time_ns_/1000000; + } + double GetSec() const { + return time_ns_/1000000000; + } + + double GetUsFromEpoch() const { + std::chrono::time_point point = + std::chrono::system_clock::now(); + return std::chrono::duration_cast( + point.time_since_epoch()).count(); + } +}; + +typedef TimerBase HighResCpuTimer; +typedef TimerBase HighResMonotonicTimer; +typedef HighResMonotonicTimer Timer; + +} // namespace hermes_shm + +#endif // HERMES_SHM_TIMER_H diff --git a/hermes_shm/src/CMakeLists.txt b/hermes_shm/src/CMakeLists.txt new file mode 100644 index 000000000..fa5030a67 --- /dev/null +++ b/hermes_shm/src/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +##################Build HermesShm main packages +add_library(hermes_shm_data_structures + ${CMAKE_CURRENT_SOURCE_DIR}/thread/mutex.cc + ${CMAKE_CURRENT_SOURCE_DIR}/thread/rwlock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/memory/malloc_allocator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/memory/stack_allocator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/memory/multi_page_allocator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/memory/memory_manager.cc + ${CMAKE_CURRENT_SOURCE_DIR}/data_structure_singleton.cc) +target_link_libraries(hermes_shm_data_structures + yaml-cpp pthread -lrt -ldl) + +##################Install HermesShm +install(TARGETS + hermes_shm_data_structures + EXPORT + ${HERMES_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR}) + +##################COVERAGE +if(HERMES_ENABLE_COVERAGE) + set_coverage_flags(hermes_shm_data_structures) +endif() + +#----------------------------------------------------------------------------- +# Export all exported targets to the build tree for use by parent project +#----------------------------------------------------------------------------- +set(HERMES_EXPORTED_LIBS + hermes_shm_data_structures + ${HERMES_EXPORTED_LIBS}) +if(NOT HERMES_EXTERNALLY_CONFIGURED) + EXPORT ( + TARGETS + ${HERMES_EXPORTED_LIBS} + FILE + ${HERMES_EXPORTED_TARGETS}.cmake + ) +endif() \ No newline at end of file diff --git a/hermes_shm/src/data_structure_singleton.cc b/hermes_shm/src/data_structure_singleton.cc new file mode 100644 index 000000000..89f6b5fcb --- /dev/null +++ b/hermes_shm/src/data_structure_singleton.cc @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +#include +template<> hermes_shm::SystemInfo scs::Singleton::obj_ = hermes_shm::SystemInfo(); +#include +template<> hermes_shm::ipc::MemoryManager scs::Singleton::obj_ = hermes_shm::ipc::MemoryManager(); +#include +template<> hermes_shm::ThreadManager scs::Singleton::obj_ = hermes_shm::ThreadManager(); diff --git a/hermes_shm/src/memory/malloc_allocator.cc b/hermes_shm/src/memory/malloc_allocator.cc new file mode 100644 index 000000000..4473d6c81 --- /dev/null +++ b/hermes_shm/src/memory/malloc_allocator.cc @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include + +namespace hermes_shm::ipc { + +struct MallocPage { + size_t page_size_; +}; + +void MallocAllocator::shm_init(MemoryBackend *backend, + allocator_id_t id, + size_t custom_header_size) { + backend_ = backend; + header_ = reinterpret_cast( + malloc(sizeof(MallocAllocatorHeader) + custom_header_size)); + custom_header_ = reinterpret_cast(header_ + 1); + header_->Configure(id, custom_header_size); +} + +void MallocAllocator::shm_deserialize(MemoryBackend *backend) { + throw NOT_IMPLEMENTED.format("MallocAllocator::shm_deserialize"); +} + +size_t MallocAllocator::GetCurrentlyAllocatedSize() { + return header_->total_alloc_size_; +} + +OffsetPointer MallocAllocator::AllocateOffset(size_t size) { + auto page = reinterpret_cast( + malloc(sizeof(MallocPage) + size)); + page->page_size_ = size; + header_->total_alloc_size_ += size; + return OffsetPointer(size_t(page + 1)); +} + +OffsetPointer MallocAllocator::AlignedAllocateOffset(size_t size, + size_t alignment) { + auto page = reinterpret_cast( + aligned_alloc(alignment, sizeof(MallocPage) + size)); + page->page_size_ = size; + header_->total_alloc_size_ += size; + return OffsetPointer(size_t(page + 1)); +} + +OffsetPointer MallocAllocator::ReallocateOffsetNoNullCheck(OffsetPointer p, + size_t new_size) { + // Get the input page + auto page = reinterpret_cast( + p.off_.load() - sizeof(MallocPage)); + header_->total_alloc_size_ += new_size - page->page_size_; + + // Reallocate the input page + auto new_page = reinterpret_cast( + realloc(page, sizeof(MallocPage) + new_size)); + new_page->page_size_ = new_size; + + // Create the pointer + return OffsetPointer(size_t(new_page + 1)); +} + +void MallocAllocator::FreeOffsetNoNullCheck(OffsetPointer p) { + auto page = reinterpret_cast( + p.off_.load() - sizeof(MallocPage)); + header_->total_alloc_size_ -= page->page_size_; + free(page); +} + +} // namespace hermes_shm::ipc diff --git a/hermes_shm/src/memory/memory_intercept.cc b/hermes_shm/src/memory/memory_intercept.cc new file mode 100644 index 000000000..cb13475c0 --- /dev/null +++ b/hermes_shm/src/memory/memory_intercept.cc @@ -0,0 +1,85 @@ +// +// Created by lukemartinlogan on 12/21/22. +// + +#include +#include +#include "hermes_shm/memory/memory_manager.h" + +using hermes_shm::ipc::Pointer; +using hermes_shm::ipc::Allocator; + +/** Allocate SIZE bytes of memory. */ +void* malloc(size_t size) { + auto alloc = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + return alloc->AllocatePtr(size); +} + +/** Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ +void* calloc(size_t nmemb, size_t size) { + auto alloc = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + return alloc->ClearAllocatePtr(nmemb * size); +} + +/** + * Re-allocate the previously allocated block in ptr, making the new + * block SIZE bytes long. + * */ +void* realloc(void *ptr, size_t size) { + Pointer p = HERMES_SHM_MEMORY_MANAGER->Convert(ptr); + auto alloc = HERMES_SHM_MEMORY_MANAGER->GetAllocator(p.allocator_id_); + return alloc->AllocatePtr(size); +} + +/** + * Re-allocate the previously allocated block in PTR, making the new + * block large enough for NMEMB elements of SIZE bytes each. + * */ +void* reallocarray(void *ptr, size_t nmemb, size_t size) { + return realloc(ptr, nmemb * size); +} + +/** Free a block allocated by `malloc', `realloc' or `calloc'. */ +void free(void *ptr) { + Pointer p = HERMES_SHM_MEMORY_MANAGER->Convert(ptr); + auto alloc = HERMES_SHM_MEMORY_MANAGER->GetAllocator(p.allocator_id_); + alloc->Free(p); +} + +/** Allocate SIZE bytes allocated to ALIGNMENT bytes. */ +void* memalign(size_t alignment, size_t size) { + // TODO(llogan): need to add an aligned allocator + return malloc(size); +} + +/** Allocate SIZE bytes on a page boundary. */ +void* valloc(size_t size) { + return memalign(HERMES_SHM_SYSTEM_INFO->page_size_, size); +} + +/** + * Equivalent to valloc(minimum-page-that-holds(n)), + * that is, round up size to nearest pagesize. + * */ +void* pvalloc(size_t size) { + size_t new_size = hermes_shm::ipc::NextPageSizeMultiple(size); + return valloc(new_size); +} + +/** + * Allocates size bytes and places the address of the + * allocated memory in *memptr. The address of the allocated memory + * will be a multiple of alignment, which must be a power of two and a multiple + * of sizeof(void *). Returns NULL if size is 0. */ +int posix_memalign(void **memptr, size_t alignment, size_t size) { + (*memptr) = memalign(alignment, size); + return 0; +} + +/** + * Aligned to an alignment with a size that is a multiple of the + * alignment + * */ +void *aligned_alloc(size_t alignment, size_t size) { + return memalign(alignment, hermes_shm::ipc::NextAlignmentMultiple(alignment, size)); +} diff --git a/hermes_shm/src/memory/memory_intercept.h b/hermes_shm/src/memory/memory_intercept.h new file mode 100644 index 000000000..51ec48a09 --- /dev/null +++ b/hermes_shm/src/memory/memory_intercept.h @@ -0,0 +1,10 @@ +// +// Created by lukemartinlogan on 12/21/22. +// + +#ifndef HERMES_SHM_SRC_MEMORY_MEMORY_INTERCEPT_H_ +#define HERMES_SHM_SRC_MEMORY_MEMORY_INTERCEPT_H_ + + + +#endif //HERMES_SHM_SRC_MEMORY_MEMORY_INTERCEPT_H_ diff --git a/hermes_shm/src/memory/memory_manager.cc b/hermes_shm/src/memory/memory_manager.cc new file mode 100644 index 000000000..2fdbaa41e --- /dev/null +++ b/hermes_shm/src/memory/memory_manager.cc @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include +#include "hermes_shm/memory/backend/memory_backend_factory.h" +#include "hermes_shm/memory/allocator/allocator_factory.h" +#include +#include + +namespace hermes_shm::ipc { + +MemoryBackend* MemoryManager::GetBackend(const std::string &url) { + return backends_[url].get(); +} + +void MemoryManager::DestroyBackend(const std::string &url) { + auto backend = GetBackend(url); + backend->shm_destroy(); + backends_.erase(url); +} + +void MemoryManager::ScanBackends() { + for (auto &[url, backend] : backends_) { + auto alloc = AllocatorFactory::shm_deserialize(backend.get()); + RegisterAllocator(alloc); + } +} + +void MemoryManager::RegisterAllocator(std::unique_ptr &alloc) { + if (default_allocator_ == nullptr || + default_allocator_ == &root_allocator_) { + default_allocator_ = alloc.get(); + } + allocators_.emplace(alloc->GetId(), std::move(alloc)); +} + +} // namespace hermes_shm::ipc diff --git a/hermes_shm/src/memory/multi_page_allocator.cc b/hermes_shm/src/memory/multi_page_allocator.cc new file mode 100644 index 000000000..eeb0f2396 --- /dev/null +++ b/hermes_shm/src/memory/multi_page_allocator.cc @@ -0,0 +1,104 @@ +// +// Created by lukemartinlogan on 12/25/22. +// + +#include "hermes_shm/memory/allocator/multi_page_allocator.h" + +namespace hermes_shm::ipc { + +/** + * base^y = x; solve for y (round up) + * */ +uint32_t CountLogarithm(RealNumber base, size_t x, size_t &round) { + uint32_t y = 1; + RealNumber compound(base); + while (compound.as_int() < x) { + compound *= base; + RealNumber compound_exp = compound * compound; + y += 1; + if (compound_exp.as_int() <= x) { + y *= 2; + compound = compound_exp; + } + } + round = compound.as_int(); + return y; +} + +/** + * The index of the free list to allocate pages from + * */ +inline uint32_t MultiPageAllocator::IndexLogarithm(size_t x, size_t &round) { + if (x <= header_->min_page_size_) { + round = header_->min_page_size_; + return 0; + } else if (x > header_->max_page_size_){ + round = x; + return header_->last_page_idx_; + } + size_t log = CountLogarithm(header_->growth_rate_, x, round); + return log - header_->min_page_log_; +} + +/** + * Initialize the allocator in shared memory + * */ +void MultiPageAllocator::shm_init(MemoryBackend *backend, + allocator_id_t alloc_id, + size_t custom_header_size, + size_t min_page_size, + size_t max_page_size, + RealNumber growth_rate, + size_t coalesce_min_size, + RealNumber coalesce_frac, + size_t thread_table_size, + uint32_t concurrency) { +} + +/** + * Attach an existing allocator from shared memory + * */ +void MultiPageAllocator::shm_deserialize(MemoryBackend *backend) { +} + +/** + * Allocate a memory of \a size size. + * */ +OffsetPointer MultiPageAllocator::AllocateOffset(size_t size) { + return OffsetPointer(); +} + +/** + * Allocate a memory of \a size size, which is aligned to \a + * alignment. + * */ +OffsetPointer MultiPageAllocator::AlignedAllocateOffset(size_t size, + size_t alignment) { + return OffsetPointer(); +} + +/** + * Reallocate \a p pointer to \a new_size new size. + * + * @return whether or not the pointer p was changed + * */ +OffsetPointer MultiPageAllocator::ReallocateOffsetNoNullCheck(OffsetPointer p, + size_t new_size) { + return OffsetPointer(); +} + +/** + * Free \a ptr pointer. Null check is performed elsewhere. + * */ +void MultiPageAllocator::FreeOffsetNoNullCheck(OffsetPointer p) { +} + +/** + * Get the current amount of data allocated. Can be used for leak + * checking. + * */ +size_t MultiPageAllocator::GetCurrentlyAllocatedSize() { + return 0; +} + +} // namespace hermes_shm::ipc \ No newline at end of file diff --git a/hermes_shm/src/memory/stack_allocator.cc b/hermes_shm/src/memory/stack_allocator.cc new file mode 100644 index 000000000..36362c174 --- /dev/null +++ b/hermes_shm/src/memory/stack_allocator.cc @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include +#include + +namespace hermes_shm::ipc { + +void StackAllocator::shm_init(MemoryBackend *backend, + allocator_id_t id, + size_t custom_header_size) { + backend_ = backend; + header_ = reinterpret_cast(backend_->data_); + custom_header_ = reinterpret_cast(header_ + 1); + size_t region_off = (custom_header_ - backend_->data_) + custom_header_size; + size_t region_size = backend_->data_size_ - region_off; + header_->Configure(id, custom_header_size, region_off, region_size); +} + +void StackAllocator::shm_deserialize(MemoryBackend *backend) { + backend_ = backend; + header_ = reinterpret_cast(backend_->data_); + custom_header_ = reinterpret_cast(header_ + 1); +} + +size_t StackAllocator::GetCurrentlyAllocatedSize() { + return header_->total_alloc_; +} + +OffsetPointer StackAllocator::AllocateOffset(size_t size) { + size += sizeof(MpPage); + OffsetPointer p(header_->region_off_.fetch_add(size)); + auto hdr = Convert(p); + hdr->SetAllocated(); + hdr->page_size_ = size; + header_->region_size_.fetch_sub(hdr->page_size_); + header_->total_alloc_.fetch_add(hdr->page_size_); + return p + sizeof(MpPage); +} + +OffsetPointer StackAllocator::AlignedAllocateOffset(size_t size, + size_t alignment) { + throw ALIGNED_ALLOC_NOT_SUPPORTED.format(); +} + +OffsetPointer StackAllocator::ReallocateOffsetNoNullCheck(OffsetPointer p, + size_t new_size) { + OffsetPointer new_p; + void *src = Convert(p); + auto hdr = Convert(p - sizeof(MpPage)); + size_t old_size = hdr->page_size_ - sizeof(MpPage); + void *dst = AllocatePtr(new_size, new_p); + memcpy(dst, src, old_size); + Free(p); + return new_p; +} + +void StackAllocator::FreeOffsetNoNullCheck(OffsetPointer p) { + auto hdr = Convert(p - sizeof(MpPage)); + if (!hdr->IsAllocated()) { + throw DOUBLE_FREE.format(); + } + hdr->UnsetAllocated(); + header_->total_alloc_.fetch_sub(hdr->page_size_); +} + +} // namespace hermes_shm::ipc diff --git a/hermes_shm/src/thread/mutex.cc b/hermes_shm/src/thread/mutex.cc new file mode 100644 index 000000000..af620fd25 --- /dev/null +++ b/hermes_shm/src/thread/mutex.cc @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "hermes_shm/thread/lock.h" +#include "hermes_shm/thread/thread_manager.h" + +namespace hermes_shm { + +/** + * Acquire the mutex + * */ +void Mutex::Lock() { + auto thread_info = HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + while (!TryLock()) { + thread_info->Yield(); + } +} + +/** + * Attempt to acquire the mutex + * */ +bool Mutex::TryLock() { + if (lock_.load() != 0) return false; + uint32_t tkt = lock_.fetch_add(1); + if (tkt != 0) { + lock_.fetch_sub(1); + return false; + } + return true; +} + +/** + * Release the mutex + * */ +void Mutex::Unlock() { + lock_.fetch_sub(1); +} + +/** + * SCOPED MUTEX + * */ + +/** + * Constructor + * */ +ScopedMutex::ScopedMutex(Mutex &lock) +: lock_(lock), is_locked_(false) { +} + +/** + * Release the mutex + * */ +ScopedMutex::~ScopedMutex() { + Unlock(); +} + +/** + * Acquire the mutex + * */ +void ScopedMutex::Lock() { + if (!is_locked_) { + lock_.Lock(); + is_locked_ = true; + } +} + +/** + * Attempt to acquire the mutex + * */ +bool ScopedMutex::TryLock() { + if (!is_locked_) { + is_locked_ = lock_.TryLock(); + } + return is_locked_; +} + +/** + * Acquire the mutex + * */ +void ScopedMutex::Unlock() { + if (is_locked_) { + lock_.Unlock(); + is_locked_ = false; + } +} + +} // namespace hermes_shm diff --git a/hermes_shm/src/thread/rwlock.cc b/hermes_shm/src/thread/rwlock.cc new file mode 100644 index 000000000..2b202d035 --- /dev/null +++ b/hermes_shm/src/thread/rwlock.cc @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "hermes_shm/thread/lock/rwlock.h" +#include "hermes_shm/thread/thread_manager.h" + +namespace hermes_shm { + +/** + * Acquire the read lock + * */ +void RwLock::ReadLock() { + bool ret = false; + RwLockPayload expected, desired; + auto thread_info = HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + do { + expected.as_int_ = payload_.load(); + if (expected.IsWriteLocked()) { + thread_info->Yield(); + continue; + } + desired = expected; + desired.bits_.r_ += 1; + ret = payload_.compare_exchange_weak( + expected.as_int_, + desired.as_int_); + } while (!ret); +} + +/** + * Release the read lock + * */ +void RwLock::ReadUnlock() { + bool ret; + RwLockPayload expected, desired; + do { + expected.as_int_ = payload_.load(); + desired = expected; + desired.bits_.r_ -= 1; + ret = payload_.compare_exchange_weak( + expected.as_int_, + desired.as_int_); + } while (!ret); +} + +/** + * Acquire the write lock + * */ +void RwLock::WriteLock() { + bool ret = false; + RwLockPayload expected, desired; + auto thread_info = HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + do { + expected.as_int_ = payload_.load(); + if (expected.IsReadLocked()) { + thread_info->Yield(); + continue; + } + if (expected.IsWriteLocked()) { + thread_info->Yield(); + continue; + } + desired = expected; + desired.bits_.w_ += 1; + ret = payload_.compare_exchange_weak( + expected.as_int_, + desired.as_int_); + } while (!ret); +} + +/** + * Release the write lock + * */ +void RwLock::WriteUnlock() { + bool ret; + RwLockPayload expected, desired; + do { + expected.as_int_ = payload_.load(); + desired = expected; + desired.bits_.w_ -= 1; + ret = payload_.compare_exchange_weak( + expected.as_int_, + desired.as_int_); + } while (!ret); +} + +/** + * Verify the reference count for reads (for debugging) + * */ +void RwLock::assert_r_refcnt(int ref) { + if (RwLockPayload(payload_).bits_.r_ != ref) { + throw 1; + } +} + +/** + * Verify the reference count for writes (for debugging) + * */ +void RwLock::assert_w_refcnt(int ref) { + if (RwLockPayload(payload_).bits_.w_ > 1) { + throw 1; + } +} + +/** + * SCOPED R/W READ LOCK + * */ + +/** + * Constructor + * */ +ScopedRwReadLock::ScopedRwReadLock(RwLock &lock) +: lock_(lock), is_locked_(false) { + Lock(); +} + +/** + * Release the read lock + * */ +ScopedRwReadLock::~ScopedRwReadLock() { + Unlock(); +} + +/** + * Acquire the read lock + * */ +void ScopedRwReadLock::Lock() { + if (!is_locked_) { + lock_.ReadLock(); + is_locked_ = true; + } +} + +/** + * Release the read lock + * */ +void ScopedRwReadLock::Unlock() { + if (is_locked_) { + lock_.ReadUnlock(); + is_locked_ = false; + } +} + +/** + * SCOPED R/W WRITE LOCK + * */ + +/** + * Constructor + * */ +ScopedRwWriteLock::ScopedRwWriteLock(RwLock &lock) +: lock_(lock), is_locked_(false) { + Lock(); +} + +/** + * Release the write lock + * */ +ScopedRwWriteLock::~ScopedRwWriteLock() { + Unlock(); +} + +/** + * Acquire the write lock + * */ +void ScopedRwWriteLock::Lock() { + if (!is_locked_) { + lock_.WriteLock(); + is_locked_ = true; + } +} + +/** + * Release the write lock + * */ +void ScopedRwWriteLock::Unlock() { + if (is_locked_) { + lock_.WriteUnlock(); + is_locked_ = false; + } +} + +} // namespace hermes_shm diff --git a/hermes_shm/test/CMakeLists.txt b/hermes_shm/test/CMakeLists.txt new file mode 100644 index 000000000..81aad4158 --- /dev/null +++ b/hermes_shm/test/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_subdirectory(unit) \ No newline at end of file diff --git a/hermes_shm/test/unit/CMakeLists.txt b/hermes_shm/test/unit/CMakeLists.txt new file mode 100644 index 000000000..d14daaa58 --- /dev/null +++ b/hermes_shm/test/unit/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +set(TEST_MAIN ${CMAKE_CURRENT_SOURCE_DIR}) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +add_subdirectory(data_structures) +add_subdirectory(allocators) +add_subdirectory(types) \ No newline at end of file diff --git a/hermes_shm/test/unit/allocators/CMakeLists.txt b/hermes_shm/test/unit/allocators/CMakeLists.txt new file mode 100644 index 000000000..b6328e0c2 --- /dev/null +++ b/hermes_shm/test/unit/allocators/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(test_allocator_exec + ${TEST_MAIN}/main.cc + test_init.cc + allocator.cc + allocator_thread.cc) +add_dependencies(test_allocator_exec hermes_shm_data_structures) +target_link_libraries(test_allocator_exec + hermes_shm_data_structures Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) + +# PAGE ALLOCATOR TESTS +add_test(NAME test_page_allocator COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_allocator_exec "StackAllocator") +add_test(NAME test_page_allocator_4t COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_allocator_exec "StackAllocatorMultithreaded") diff --git a/hermes_shm/test/unit/allocators/allocator.cc b/hermes_shm/test/unit/allocators/allocator.cc new file mode 100644 index 000000000..941736340 --- /dev/null +++ b/hermes_shm/test/unit/allocators/allocator.cc @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "test_init.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" +#include "hermes_shm/memory/allocator/multi_page_allocator.h" + +void PageAllocationTest(Allocator *alloc) { + int count = 1024; + size_t page_size = KILOBYTES(4); + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + + // Allocate pages + std::vector ps(count); + void *ptrs[count]; + for (int i = 0; i < count; ++i) { + ptrs[i] = alloc->AllocatePtr(page_size, ps[i]); + memset(ptrs[i], i, page_size); + REQUIRE(ps[i].off_.load() != 0); + REQUIRE(!ps[i].IsNull()); + REQUIRE(ptrs[i] != nullptr); + } + + // Convert process pointers into independent pointers + for (int i = 0; i < count; ++i) { + Pointer p = mem_mngr->Convert(ptrs[i]); + REQUIRE(p == ps[i]); + REQUIRE(VerifyBuffer((char*)ptrs[i], page_size, i)); + } + + // Check the custom header + auto hdr = alloc->GetCustomHeader(); + REQUIRE(hdr->checksum_ == HEADER_CHECKSUM); + + // Free pages + for (int i = 0; i < count; ++i) { + alloc->Free(ps[i]); + } + + // Reallocate pages + for (int i = 0; i < count; ++i) { + ptrs[i] = alloc->AllocatePtr(page_size, ps[i]); + REQUIRE(ps[i].off_.load() != 0); + REQUIRE(!ps[i].IsNull()); + } + + // Free again + for (int i = 0; i < count; ++i) { + alloc->Free(ps[i]); + } +} + +void MultiPageAllocationTest(Allocator *alloc) { + size_t alloc_sizes[] = { + 64, 128, 256, + KILOBYTES(1), KILOBYTES(4), KILOBYTES(64), + MEGABYTES(1), MEGABYTES(16), MEGABYTES(32) + }; + + // Allocate and free pages between 64 bytes and 1MB + { + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + for (size_t r = 0; r < 10; ++r) { + for (size_t i = 0; i < 1000; ++i) { + Pointer ps[4]; + for (size_t j = 0; j < 4; ++j) { + ps[j] = alloc->Allocate(alloc_sizes[i % 9]); + } + for (size_t j = 0; j < 4; ++j) { + alloc->Free(ps[j]); + } + } + } + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + } + + // Aligned allocate 4KB pages + { + for (size_t i = 0; i < 1024; ++i) { + Pointer p = alloc->AlignedAllocate(KILOBYTES(4), KILOBYTES(4)); + memset(alloc->Convert(p), 0, KILOBYTES(4)); + alloc->Free(p); + } + } + + // Reallocate a 4KB page to 16KB + { + Pointer p = alloc->Allocate(KILOBYTES(4)); + alloc->Reallocate(p, KILOBYTES(16)); + memset(alloc->Convert(p), 0, KILOBYTES(16)); + alloc->Free(p); + } +} + +TEST_CASE("StackAllocator") { + auto alloc = Pretest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + PageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + Posttest(); +} + +TEST_CASE("MultiPageAllocator") { + auto alloc = Pretest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + PageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + MultiPageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + + Posttest(); +} + +TEST_CASE("MallocAllocator") { + auto alloc = Pretest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + PageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + MultiPageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + + Posttest(); +} \ No newline at end of file diff --git a/hermes_shm/test/unit/allocators/allocator_thread.cc b/hermes_shm/test/unit/allocators/allocator_thread.cc new file mode 100644 index 000000000..8900e42d0 --- /dev/null +++ b/hermes_shm/test/unit/allocators/allocator_thread.cc @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "test_init.h" + +void MultiThreadedPageAllocationTest(Allocator *alloc) { + int nthreads = 8; + HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + + omp_set_dynamic(0); +#pragma omp parallel shared(alloc) num_threads(nthreads) + { +#pragma omp barrier + PageAllocationTest(alloc); +#pragma omp barrier + } +} + +TEST_CASE("StackAllocatorMultithreaded") { + auto alloc = Pretest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + MultiThreadedPageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + Posttest(); +} + +TEST_CASE("MultiPageAllocatorMultithreaded") { + auto alloc = Pretest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + MultiThreadedPageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + Posttest(); +} diff --git a/hermes_shm/test/unit/allocators/test_init.cc b/hermes_shm/test/unit/allocators/test_init.cc new file mode 100644 index 000000000..54fac303e --- /dev/null +++ b/hermes_shm/test/unit/allocators/test_init.cc @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "test_init.h" + +void Posttest() { + std::string shm_url = "test_allocators"; + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + mem_mngr->DestroyBackend(shm_url); +} + +void MainPretest() {} + +void MainPosttest() {} diff --git a/hermes_shm/test/unit/allocators/test_init.h b/hermes_shm/test/unit/allocators/test_init.h new file mode 100644 index 000000000..b0c862950 --- /dev/null +++ b/hermes_shm/test/unit/allocators/test_init.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ +#define HERMES_SHM_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ + +#include "basic_test.h" +#include "omp.h" +#include "hermes_shm/memory/memory_manager.h" + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::MemoryManager; +using hermes_shm::ipc::Pointer; + +#define HEADER_CHECKSUM 8482942 + +struct SimpleAllocatorHeader { + int checksum_; +}; + +template +Allocator* Pretest() { + std::string shm_url = "test_allocators"; + allocator_id_t alloc_id(0, 1); + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + mem_mngr->CreateBackend( + MemoryManager::kDefaultBackendSize, shm_url); + mem_mngr->CreateAllocator( + shm_url, alloc_id, sizeof(SimpleAllocatorHeader)); + auto alloc = mem_mngr->GetAllocator(alloc_id); + auto hdr = alloc->GetCustomHeader(); + hdr->checksum_ = HEADER_CHECKSUM; + return alloc; +} + +void Posttest(); +void PageAllocationTest(Allocator *alloc); + +#endif // HERMES_SHM_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ diff --git a/hermes_shm/test/unit/basic_test.h b/hermes_shm/test/unit/basic_test.h new file mode 100644 index 000000000..e9b934b7f --- /dev/null +++ b/hermes_shm/test/unit/basic_test.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#ifndef HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ +#define HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ + +#define CATCH_CONFIG_RUNNER +#include + +namespace cl = Catch::Clara; +cl::Parser define_options(); + +#include +#include + +static bool VerifyBuffer(char *ptr, size_t size, char nonce) { + for (size_t i = 0; i < size; ++i) { + if (ptr[i] != nonce) { + std::cout << (int)ptr[i] << std::endl; + return false; + } + } + return true; +} + +/** var = TYPE(val) */ +#define SET_VAR_TO_INT_OR_STRING(TYPE, VAR, VAL)\ + if constexpr(std::is_same_v) {\ + VAR = lipc::string(std::to_string(VAL));\ + } else if constexpr(std::is_same_v) {\ + VAR = std::string(std::to_string(VAL));\ + } else {\ + VAR = VAL;\ + } + +/** TYPE VAR = TYPE(VAL) */ +#define CREATE_SET_VAR_TO_INT_OR_STRING(TYPE, VAR, VAL)\ + TYPE VAR;\ + SET_VAR_TO_INT_OR_STRING(TYPE, VAR, VAL); + +/** RET = int(TYPE(VAR)); */ +#define GET_INT_FROM_VAR(TYPE, RET, VAR)\ + if constexpr(std::is_same_v) {\ + RET = atoi((VAR).str().c_str());\ + } else if constexpr(std::is_same_v) {\ + RET = atoi((VAR).c_str());\ + } else {\ + RET = VAR;\ + } + +/** int RET = int(TYPE(VAR)); */ +#define CREATE_GET_INT_FROM_VAR(TYPE, RET, VAR)\ + int RET;\ + GET_INT_FROM_VAR(TYPE, RET, VAR) + +void MainPretest(); +void MainPosttest(); + +#endif // HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ diff --git a/hermes_shm/test/unit/data_structures/CMakeLists.txt b/hermes_shm/test/unit/data_structures/CMakeLists.txt new file mode 100644 index 000000000..0db1dd7ff --- /dev/null +++ b/hermes_shm/test/unit/data_structures/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +include_directories(${CMAKE_SOURCE_DIR}/test/unit) +add_subdirectory(backend) +add_subdirectory(containers) +add_subdirectory(containers_mpi) +add_subdirectory(lock) \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/backend/CMakeLists.txt b/hermes_shm/test/unit/data_structures/backend/CMakeLists.txt new file mode 100644 index 000000000..fb2b751eb --- /dev/null +++ b/hermes_shm/test/unit/data_structures/backend/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(test_memory_exec + ${TEST_MAIN}/main_mpi.cc + test_init.cc + backend.cc + memory_slots.cc + memory_manager.cc) +add_dependencies(test_memory_exec hermes_shm_data_structures) +target_link_libraries(test_memory_exec + hermes_shm_data_structures Catch2::Catch2 MPI::MPI_CXX) + +# TESTS +add_test(NAME test_memory_slots COMMAND + mpirun -n 2 ${CMAKE_CURRENT_BINARY_DIR}/test_memory_exec "MemorySlot") +add_test(NAME test_reserve COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_memory_exec "BackendReserve") +add_test(NAME test_memory_manager COMMAND + mpirun -n 2 ${CMAKE_CURRENT_BINARY_DIR}/test_memory_exec "MemoryManager") \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/backend/backend.cc b/hermes_shm/test/unit/data_structures/backend/backend.cc new file mode 100644 index 000000000..b23d7e31b --- /dev/null +++ b/hermes_shm/test/unit/data_structures/backend/backend.cc @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#include "basic_test.h" + +#include "hermes_shm/memory/backend/posix_shm_mmap.h" + +using hermes_shm::ipc::PosixShmMmap; + +TEST_CASE("BackendReserve") { + PosixShmMmap b1; + + // Reserve + Map 8GB of memory + b1.shm_init(GIGABYTES(8), "shmem_test"); + + // Set 2GB of SHMEM + memset(b1.data_, 0, GIGABYTES(2)); + + // Destroy SHMEM + b1.shm_destroy(); +} diff --git a/hermes_shm/test/unit/data_structures/backend/memory_manager.cc b/hermes_shm/test/unit/data_structures/backend/memory_manager.cc new file mode 100644 index 000000000..39cdfb4ce --- /dev/null +++ b/hermes_shm/test/unit/data_structures/backend/memory_manager.cc @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "basic_test.h" + +#include +#include "hermes_shm/memory/memory_manager.h" + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::MemoryManager; + +struct SimpleHeader { + hermes_shm::ipc::Pointer p_; +}; + +TEST_CASE("MemoryManager") { + int rank; + char nonce = 8; + size_t page_size = KILOBYTES(4); + std::string shm_url = "test_mem_backend"; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + allocator_id_t alloc_id(0, 1); + + HERMES_SHM_ERROR_HANDLE_START() + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + + if (rank == 0) { + std::cout << "Creating SHMEM (rank 0): " << shm_url << std::endl; + mem_mngr->CreateBackend( + MemoryManager::kDefaultBackendSize, shm_url); + mem_mngr->CreateAllocator( + shm_url, alloc_id, 0); + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank != 0) { + std::cout << "Attaching SHMEM (rank 1): " << shm_url << std::endl; + mem_mngr->AttachBackend(MemoryBackendType::kPosixShmMmap, shm_url); + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank == 0) { + std::cout << "Allocating pages (rank 0)" << std::endl; + lipc::Allocator *alloc = mem_mngr->GetAllocator(alloc_id); + char *page = alloc->AllocatePtr(page_size); + memset(page, nonce, page_size); + auto header = alloc->GetCustomHeader(); + lipc::Pointer p1 = mem_mngr->Convert(alloc_id, page); + lipc::Pointer p2 = mem_mngr->Convert(page); + header->p_ = p1; + REQUIRE(p1 == p2); + REQUIRE(VerifyBuffer(page, page_size, nonce)); + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank != 0) { + std::cout << "Finding and checking pages (rank 1)" << std::endl; + lipc::Allocator *alloc = mem_mngr->GetAllocator(alloc_id); + SimpleHeader *header = alloc->GetCustomHeader(); + char *page = alloc->Convert(header->p_); + REQUIRE(VerifyBuffer(page, page_size, nonce)); + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank == 0) { + mem_mngr->DestroyBackend(shm_url); + } + + HERMES_SHM_ERROR_HANDLE_END() +} diff --git a/hermes_shm/test/unit/data_structures/backend/memory_slots.cc b/hermes_shm/test/unit/data_structures/backend/memory_slots.cc new file mode 100644 index 000000000..9e574c900 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/backend/memory_slots.cc @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#include "basic_test.h" + +#include +#include +#include "hermes_shm/memory/backend/posix_shm_mmap.h" + +using hermes_shm::ipc::PosixShmMmap; + +TEST_CASE("MemorySlot") { + int rank; + char nonce = 8; + std::string shm_url = "test_mem_backend"; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + HERMES_SHM_ERROR_HANDLE_START() + + PosixShmMmap backend; + if (rank == 0) { + std::cout << "HERE?" << std::endl; + SECTION("Creating SHMEM (rank 0)") { + backend.shm_init(MEGABYTES(1), shm_url); + memset(backend.data_, nonce, backend.data_size_); + } + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank != 0) { + SECTION("Attaching SHMEM (rank 1)") { + backend.shm_deserialize(shm_url); + char *ptr = backend.data_; + REQUIRE(VerifyBuffer(ptr, backend.data_size_, nonce)); + } + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank == 0) { + SECTION("Destroying shmem (rank 1)") { + backend.shm_destroy(); + } + } + + HERMES_SHM_ERROR_HANDLE_END() +} diff --git a/hermes_shm/test/unit/data_structures/backend/test_init.cc b/hermes_shm/test/unit/data_structures/backend/test_init.cc new file mode 100644 index 000000000..cb402e14b --- /dev/null +++ b/hermes_shm/test/unit/data_structures/backend/test_init.cc @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "basic_test.h" + +void MainPretest() {} + +void MainPosttest() {} diff --git a/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt b/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt new file mode 100644 index 000000000..f14f20020 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(test_data_structure_exec + ${TEST_MAIN}/main.cc + test_init.cc + string.cc + pair.cc + tuple.cc + list.cc + vector.cc + manual_ptr.cc + unordered_map.cc +) + +add_dependencies(test_data_structure_exec hermes_shm_data_structures) +target_link_libraries(test_data_structure_exec + hermes_shm_data_structures Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) + +# STRING TESTS +add_test(NAME test_string COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "String") + +# VECTOR TESTS +add_test(NAME test_vector_of_int COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "VectorOfInt") +add_test(NAME test_vector_of_string COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "VectorOfString") +add_test(NAME test_vector_of_list_of_string COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "VectorOfListOfString") + +# LIST TESTS +add_test(NAME test_list_of_int COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "ListOfInt") +add_test(NAME test_list_of_string COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "ListOfString") + +# MANUAL PTR TESTS +add_test(NAME test_manual_ptr_of_string COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "ManualPtrOfString") + +# UNIQUE PTR TESTS +add_test(NAME test_unique_ptr_of_string COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "UniquePtrOfString") + +# UNORDERED_MAP TESTS +add_test(NAME test_unordered_map_of_int_int COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "UnorderedMapOfIntInt") +add_test(NAME test_unordered_map_of_int_str COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "UnorderedMapOfIntString") +add_test(NAME test_unordered_map_of_str_int COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "UnorderedMapOfStringInt") +add_test(NAME test_unordered_map_of_str_str COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "UnorderedMapOfStringString") diff --git a/hermes_shm/test/unit/data_structures/containers/list.cc b/hermes_shm/test/unit/data_structures/containers/list.cc new file mode 100644 index 000000000..f766ae673 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/list.cc @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#include "basic_test.h" +#include "test_init.h" +#include "list.h" +#include "hermes_shm/data_structures/thread_unsafe/list.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" + +using hermes_shm::ipc::list; + +template +void ListTest() { + Allocator *alloc = alloc_g; + list lp(alloc); + ListTestSuite> test(lp, alloc); + + test.EmplaceTest(30); + test.ForwardIteratorTest(); + test.ConstForwardIteratorTest(); + test.CopyConstructorTest(); + test.CopyAssignmentTest(); + test.MoveConstructorTest(); + test.MoveAssignmentTest(); + test.EmplaceFrontTest(); + test.ModifyEntryCopyIntoTest(); + test.ModifyEntryMoveIntoTest(); + test.EraseTest(); +} + +TEST_CASE("ListOfInt") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + ListTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("ListOfString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + ListTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("ListOfStdString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + ListTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/containers/list.h b/hermes_shm/test/unit/data_structures/containers/list.h new file mode 100644 index 000000000..af7743059 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/list.h @@ -0,0 +1,184 @@ +// +// Created by lukemartinlogan on 1/10/23. +// + +#ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ +#define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ + +#include "basic_test.h" +#include "test_init.h" +#include + +template +class ListTestSuite { + public: + Container &obj_; + Allocator *alloc_; + + /// Constructor + ListTestSuite(Container &obj, Allocator *alloc) + : obj_(obj), alloc_(alloc) {} + + /// Emplace elements + void EmplaceTest(int count = 30) { + for (int i = 0; i < count; ++i) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, var, i); + obj_.emplace_back(var); + } + REQUIRE(obj_.size() == count); + } + + /// Forward iterator + void ForwardIteratorTest(int count = 30) { + int fcur = 0; + for (auto num : obj_) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, fcur_conv, fcur); + REQUIRE(*num == fcur_conv); + ++fcur; + } + } + + /// Constant Forward iterator + void ConstForwardIteratorTest(int count = 30) { + const Container &obj = obj_; + int fcur = 0; + for (auto iter = obj.cbegin(); iter != obj.cend(); ++iter) { + lipc::ShmRef num = *iter; + CREATE_SET_VAR_TO_INT_OR_STRING(T, fcur_conv, fcur); + REQUIRE(*num == fcur_conv); + ++fcur; + } + } + + /// Copy constructor + void CopyConstructorTest() { + int count = obj_.size(); + Container cpy(obj_); + VerifyCopy(obj_, cpy, count); + } + + /// Copy assignment + void CopyAssignmentTest() { + int count = obj_.size(); + Container cpy; + cpy = obj_; + VerifyCopy(obj_, cpy, count); + } + + /// Move constructor + void MoveConstructorTest() { + int count = obj_.size(); + Container cpy(std::move(obj_)); + VerifyMove(obj_, cpy, count); + obj_ = std::move(cpy); + VerifyMove(cpy, obj_, count); + } + + /// Move assignment + void MoveAssignmentTest() { + int count = obj_.size(); + Container cpy; + cpy = std::move(obj_); + VerifyMove(obj_, cpy, count); + obj_ = std::move(cpy); + VerifyMove(cpy, obj_, count); + } + + /// Emplace and erase front + void EmplaceFrontTest() { + CREATE_SET_VAR_TO_INT_OR_STRING(T, i0, 100); + int old_size = obj_.size(); + obj_.emplace_front(i0); + REQUIRE(*obj_.front() == i0); + REQUIRE(obj_.size() == old_size + 1); + obj_.erase(obj_.begin(), obj_.begin() + 1); + } + + /// Copy an object into the container + void ModifyEntryCopyIntoTest() { + // Modify the fourth list entry + { + CREATE_SET_VAR_TO_INT_OR_STRING(T, i4, 25); + auto iter = obj_.begin() + 4; + (**iter) = i4; + } + + // Verify the modification took place + { + CREATE_SET_VAR_TO_INT_OR_STRING(T, i4, 25); + auto iter = obj_.begin() + 4; + REQUIRE((**iter) == i4); + } + } + + /// Move an object into the container + void ModifyEntryMoveIntoTest() { + // Modify the fourth list entry + { + CREATE_SET_VAR_TO_INT_OR_STRING(T, i4, 25); + auto iter = obj_.begin() + 4; + (**iter) = std::move(i4); + } + + // Verify the modification took place + { + CREATE_SET_VAR_TO_INT_OR_STRING(T, i4, 25); + auto iter = obj_.begin() + 4; + REQUIRE((**iter) == i4); + } + } + + /// Verify erase + void EraseTest() { + obj_.clear(); + REQUIRE(obj_.size() == 0); + } + + private: + /// Verify copy construct/assign worked + void VerifyCopy(Container &obj, + Container &cpy, + int count) { + REQUIRE(obj_.size() == count); + REQUIRE(cpy.size() == count); + + // Verify obj + { + int fcur = 0; + for (auto num : obj_) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, fcur_conv, fcur); + REQUIRE(*num == fcur_conv); + ++fcur; + } + } + + // Verify copy + { + int fcur = 0; + for (auto num : cpy) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, fcur_conv, fcur); + REQUIRE(*num == fcur_conv); + ++fcur; + } + } + } + + /// Verify move worked + void VerifyMove(Container &orig_obj, + Container &new_obj, + int count) { + // Verify move into cpy worked + { + int fcur = 0; + REQUIRE(orig_obj.size() == 0); + REQUIRE(new_obj.size() == count); + for (auto num : new_obj) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, fcur_conv, fcur); + REQUIRE(*num == fcur_conv); + ++fcur; + } + } + } +}; + +#endif //HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ diff --git a/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc b/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc new file mode 100644 index 000000000..a3759d364 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "hermes_shm/data_structures/smart_ptr/manual_ptr.h" +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" +#include "smart_ptr.h" + +using hermes_shm::ipc::string; +using hermes_shm::ipc::mptr; +using hermes_shm::ipc::mptr; +using hermes_shm::ipc::make_mptr; +using hermes_shm::ipc::TypedPointer; + +template +void ManualPtrTest() { + Allocator *alloc = alloc_g; + lipc::SmartPtrTestSuite> test; + CREATE_SET_VAR_TO_INT_OR_STRING(T, num, 25); + test.ptr_ = make_mptr(num); + test.DereferenceTest(num); + test.MoveConstructorTest(num); + test.MoveAssignmentTest(num); + test.CopyConstructorTest(num); + test.CopyAssignmentTest(num); + test.SerializeationConstructorTest(num); + test.SerializeationOperatorTest(num); + test.ptr_.shm_destroy(); +} + +TEST_CASE("ManualPtrOfString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + ManualPtrTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} diff --git a/hermes_shm/test/unit/data_structures/containers/pair.cc b/hermes_shm/test/unit/data_structures/containers/pair.cc new file mode 100644 index 000000000..591b8db7b --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/pair.cc @@ -0,0 +1,56 @@ +// +// Created by lukemartinlogan on 1/15/23. +// + +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/pair.h" +#include "hermes_shm/data_structures/string.h" + +template +void PairTest() { + Allocator *alloc = alloc_g; + + // Construct test + { + CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); + CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); + lipc::pair data(alloc, first, second); + REQUIRE(*data.first_ == first); + REQUIRE(*data.second_ == second); + } + + // Copy test + { + CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); + CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); + lipc::pair data(alloc, first, second); + lipc::pair cpy(data); + REQUIRE(*cpy.first_ == first); + REQUIRE(*cpy.second_ == second); + } + + // Move test + { + CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); + CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); + lipc::pair data(alloc, first, second); + lipc::pair cpy(std::move(data)); + REQUIRE(*cpy.first_ == first); + REQUIRE(*cpy.second_ == second); + } +} + +TEST_CASE("PairOfIntInt") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + PairTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("PairOfIntString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + PairTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/containers/slist.cc b/hermes_shm/test/unit/data_structures/containers/slist.cc new file mode 100644 index 000000000..d101ef18f --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/slist.cc @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#include "basic_test.h" +#include "test_init.h" +#include "list.h" +#include "hermes_shm/data_structures/thread_unsafe/slist.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" + +using hermes_shm::ipc::slist; + +template +void SListTest() { + Allocator *alloc = alloc_g; + slist lp(alloc); + ListTestSuite> test(lp, alloc); + + test.EmplaceTest(30); + test.ForwardIteratorTest(); + test.CopyConstructorTest(); + test.CopyAssignmentTest(); + test.MoveConstructorTest(); + test.MoveAssignmentTest(); + test.EmplaceFrontTest(); + test.ModifyEntryCopyIntoTest(); + test.ModifyEntryMoveIntoTest(); + test.EraseTest(); +} + +TEST_CASE("SListOfInt") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + SListTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("SListOfString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + SListTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("SListOfStdString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + SListTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/containers/smart_ptr.h b/hermes_shm/test/unit/data_structures/containers/smart_ptr.h new file mode 100644 index 000000000..3e45ddacf --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/smart_ptr.h @@ -0,0 +1,76 @@ +// +// Created by lukemartinlogan on 1/20/23. +// + +#ifndef HERMES_SHM_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ +#define HERMES_SHM_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ + +#include "basic_test.h" +#include "test_init.h" + +namespace hermes_shm::ipc { + +template +class SmartPtrTestSuite { + public: + PointerT ptr_; + + public: + // Test dereference + void DereferenceTest(T &num) { + REQUIRE(ptr_.get_ref() == num); + REQUIRE(ptr_.get_ref_const() == num); + REQUIRE(*ptr_ == num); + } + + // Test move constructor + void MoveConstructorTest(T &num) { + PointerT ptr2(std::move(ptr_)); + REQUIRE(ptr_.IsNull()); + REQUIRE(std::hash{}(ptr2) == std::hash{}(num)); + ptr_ = std::move(ptr2); + } + + // Test move assignment operator + void MoveAssignmentTest(T &num) { + PointerT ptr2 = std::move(ptr_); + REQUIRE(ptr_.IsNull()); + REQUIRE(std::hash{}(ptr2) == std::hash{}(num)); + ptr_ = std::move(ptr2); + } + + // Test copy constructor + void CopyConstructorTest(T &num) { + PointerT ptr2(ptr_); + REQUIRE(*ptr_ == num); + REQUIRE(*ptr2 == num); + } + + // Test copy assignment + void CopyAssignmentTest(T &num) { + PointerT ptr2 = ptr_; + REQUIRE(*ptr_ == num); + REQUIRE(*ptr2 == num); + } + + // Test serialization + deserialization (constructor) + void SerializeationConstructorTest(T &num) { + TypedPointer ar; + ptr_ >> ar; + PointerT from_ar(ar); + REQUIRE(*from_ar == num); + } + + // Test serialization + deserialization (operator) + void SerializeationOperatorTest(T &num) { + TypedPointer ar; + ptr_ >> ar; + PointerT from_ar; + from_ar << ar; + REQUIRE(*from_ar == num); + } +}; + +} // namespace hermes_shm::ipc + +#endif //HERMES_SHM_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ diff --git a/hermes_shm/test/unit/data_structures/containers/string.cc b/hermes_shm/test/unit/data_structures/containers/string.cc new file mode 100644 index 000000000..d3dabe686 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/string.cc @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" + +using hermes_shm::ipc::string; + +void TestString() { + Allocator *alloc = alloc_g; + + auto text1 = string("hello1"); + REQUIRE(text1 == "hello1"); + REQUIRE(text1 != "h"); + REQUIRE(text1 != "asdfklaf"); + + auto text2 = string("hello2"); + REQUIRE(text2 == "hello2"); + + string text3 = text1 + text2; + REQUIRE(text3 == "hello1hello2"); + + string text4(6); + memcpy(text4.data_mutable(), "hello4", strlen("hello4")); + + string text5 = text4; + REQUIRE(text5 == "hello4"); + REQUIRE(text5.header_ != text4.header_); + + string text6 = std::move(text5); + REQUIRE(text6 == "hello4"); +} + +TEST_CASE("String") { + Allocator *alloc = alloc_g; + REQUIRE(IS_SHM_ARCHIVEABLE(string)); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + TestString(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} diff --git a/hermes_shm/test/unit/data_structures/containers/test_init.cc b/hermes_shm/test/unit/data_structures/containers/test_init.cc new file mode 100644 index 000000000..4e2b0b5a8 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/test_init.cc @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "basic_test.h" +#include "test_init.h" +#include + +#include "hermes_shm/memory/allocator/stack_allocator.h" + +Allocator *alloc_g = nullptr; + +void Posttest() { + std::string shm_url = "test_allocators"; + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + mem_mngr->DestroyBackend(shm_url); + alloc_g = nullptr; +} + +void MainPretest() { + Pretest(); +} + +void MainPosttest() { + Posttest(); +} diff --git a/hermes_shm/test/unit/data_structures/containers/test_init.h b/hermes_shm/test/unit/data_structures/containers/test_init.h new file mode 100644 index 000000000..1dd6b3370 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/test_init.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ +#define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ + +#include "hermes_shm/data_structures/data_structure.h" + +using hermes_shm::ipc::PosixShmMmap; +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::Pointer; + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::MemoryManager; +using hermes_shm::ipc::Pointer; + +extern Allocator *alloc_g; + +template +void Pretest() { + std::string shm_url = "test_allocators"; + allocator_id_t alloc_id(0, 1); + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + mem_mngr->CreateBackend( + MemoryManager::kDefaultBackendSize, shm_url); + mem_mngr->CreateAllocator(shm_url, alloc_id, 0); + alloc_g = mem_mngr->GetAllocator(alloc_id); +} + +void Posttest(); + +#endif // HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ diff --git a/hermes_shm/test/unit/data_structures/containers/tuple.cc b/hermes_shm/test/unit/data_structures/containers/tuple.cc new file mode 100644 index 000000000..1a32436b1 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/tuple.cc @@ -0,0 +1,75 @@ +// +// Created by lukemartinlogan on 1/15/23. +// + +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/struct.h" +#include "hermes_shm/data_structures/string.h" + +template +void TupleTest() { + Allocator *alloc = alloc_g; + + // Construct test + { + CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); + CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); + lipc::ShmHeader> hdr; + lipc::ShmStruct + data(hdr, alloc, + hermes_shm::make_argpack(first), + hermes_shm::make_argpack(second)); + REQUIRE(data.template Get<0>() == first); + REQUIRE(data.template Get<1>() == second); + } + + // Copy test + /*{ + CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); + CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); + lipc::tuple data(alloc, first, second); + lipc::tuple cpy(data); + REQUIRE(cpy.template Get<0>() == first); + REQUIRE(cpy.template Get<1>() == second); + } + + // Move test + { + CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); + CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); + lipc::tuple data(alloc, first, second); + lipc::tuple cpy(std::move(data)); + REQUIRE(cpy.template Get<0>() == first); + REQUIRE(cpy.template Get<1>() == second); + }*/ +} + +#include + +int y() { + return 0; +} + + +class Y { + public: + Y() = default; + Y(int x) {} + Y(int x, int w) {} +}; + +TEST_CASE("TupleOfIntInt") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + + TupleTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("TupleOfIntString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + // TupleTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/containers/unordered_map.cc b/hermes_shm/test/unit/data_structures/containers/unordered_map.cc new file mode 100644 index 000000000..34bf137eb --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/unordered_map.cc @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/thread_unsafe/unordered_map.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::MemoryManager; +using hermes_shm::ipc::Pointer; +using hermes_shm::ipc::unordered_map; +using hermes_shm::ipc::string; + +#define GET_INT_FROM_KEY(VAR) CREATE_GET_INT_FROM_VAR(Key, key_ret, VAR) +#define GET_INT_FROM_VAL(VAR) CREATE_GET_INT_FROM_VAR(Val, val_ret, VAR) + +#define CREATE_KV_PAIR(KEY_NAME, KEY, VAL_NAME, VAL)\ + CREATE_SET_VAR_TO_INT_OR_STRING(Key, KEY_NAME, KEY); \ + CREATE_SET_VAR_TO_INT_OR_STRING(Val, VAL_NAME, VAL); + +template +void UnorderedMapOpTest() { + Allocator *alloc = alloc_g; + unordered_map map(alloc); + + // Insert 20 entries into the map (no growth trigger) + { + for (int i = 0; i < 20; ++i) { + CREATE_KV_PAIR(key, i, val, i); + map.emplace(key, val); + } + } + + // Check if the 20 entries are indexable + { + for (int i = 0; i < 20; ++i) { + CREATE_KV_PAIR(key, i, val, i); + REQUIRE(*(map[key]) == val); + } + } + + // Check if 20 entries are findable + { + for (int i = 0; i < 20; ++i) { + CREATE_KV_PAIR(key, i, val, i); + auto iter = map.find(key); + REQUIRE((*iter)->GetVal() == val); + } + } + + // Iterate over the map + { + // auto prep = map.iter_prep(); + // prep.Lock(); + int i = 0; + for (auto entry : map) { + GET_INT_FROM_KEY(entry->GetKey()); + GET_INT_FROM_VAL(entry->GetVal()); + REQUIRE((0 <= key_ret && key_ret < 20)); + REQUIRE((0 <= val_ret && val_ret < 20)); + ++i; + } + REQUIRE(i == 20); + } + + // Re-emplace elements + { + for (int i = 0; i < 20; ++i) { + CREATE_KV_PAIR(key, i, val, i + 100); + map.emplace(key, val); + REQUIRE(*(map[key]) == val); + } + } + + // Modify the fourth map entry (move assignment) + { + CREATE_KV_PAIR(key, 4, val, 25); + auto iter = map.find(key); + (*iter)->GetVal() = std::move(val); + REQUIRE((*iter)->GetVal() == val); + } + + // Verify the modification took place + { + CREATE_KV_PAIR(key, 4, val, 25); + REQUIRE(*(map[key]) == val); + } + + // Modify the fourth map entry (copy assignment) + { + CREATE_KV_PAIR(key, 4, val, 50); + auto iter = map.find(key); + (*iter)->GetVal() = val; + REQUIRE((*iter)->GetVal() == val); + } + + // Verify the modification took place + { + CREATE_KV_PAIR(key, 4, val, 50); + REQUIRE(*(map[key]) == val); + } + + // Modify the fourth map entry (copy assignment) + { + CREATE_KV_PAIR(key, 4, val, 100); + auto x = map[key]; + (*x) = val; + } + + // Verify the modification took place + { + CREATE_KV_PAIR(key, 4, val, 100); + REQUIRE(*map[key] == val); + } + + // Remove 15 entries from the map + { + for (int i = 0; i < 15; ++i) { + CREATE_KV_PAIR(key, i, val, i); + map.erase(key); + } + REQUIRE(map.size() == 5); + for (int i = 0; i < 15; ++i) { + CREATE_KV_PAIR(key, i, val, i); + REQUIRE(map.find(key) == map.end()); + } + } + + // Attempt to replace an existing key + { + for (int i = 15; i < 20; ++i) { + CREATE_KV_PAIR(key, i, val, 100); + REQUIRE(map.try_emplace(key, val) == false); + } + for (int i = 15; i < 20; ++i) { + CREATE_KV_PAIR(key, i, val, 100); + REQUIRE(*map[key] != val); + } + } + + // Erase the entire map + { + map.clear(); + REQUIRE(map.size() == 0); + } + + // Add 100 entries to the map (should force a growth) + { + for (int i = 0; i < 100; ++i) { + CREATE_KV_PAIR(key, i, val, i); + map.emplace(key, val); + REQUIRE(map.find(key) != map.end()); + } + for (int i = 0; i < 100; ++i) { + CREATE_KV_PAIR(key, i, val, i); + REQUIRE(map.find(key) != map.end()); + } + } + + // Copy the unordered_map + { + unordered_map cpy(map); + for (int i = 0; i < 100; ++i) { + CREATE_KV_PAIR(key, i, val, i); + REQUIRE(map.find(key) != map.end()); + REQUIRE(cpy.find(key) != cpy.end()); + } + } + + // Move the unordered_map + { + unordered_map cpy = std::move(map); + for (int i = 0; i < 100; ++i) { + CREATE_KV_PAIR(key, i, val, i); + REQUIRE(cpy.find(key) != cpy.end()); + } + map = std::move(cpy); + } + + // Emplace a move entry into the map + +} + +TEST_CASE("UnorderedMapOfIntInt") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + UnorderedMapOpTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("UnorderedMapOfIntString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + UnorderedMapOpTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + + +TEST_CASE("UnorderedMapOfStringInt") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + UnorderedMapOpTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("UnorderedMapOfStringString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + UnorderedMapOpTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} diff --git a/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc b/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc new file mode 100644 index 000000000..3ec56b297 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#include "omp.h" +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/thread_safe/unordered_map.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" +#include "hermes_shm/util/errors.h" +#include + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::MemoryManager; +using hermes_shm::ipc::Pointer; +using hermes_shm::ipc::unordered_map; +using hermes_shm::ipc::string; + +void UnorderedMapParallelInsert() { + Allocator *alloc = alloc_g; + unordered_map map(alloc); + + int entries_per_thread = 50; + int nthreads = 4; + int total_entries = nthreads * entries_per_thread; + HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + + omp_set_dynamic(0); +#pragma omp parallel shared(alloc, map) num_threads(nthreads) + { + int rank = omp_get_thread_num(); + int off = rank*entries_per_thread; +#pragma omp barrier + // Insert entries into the map (no growth trigger) + { + for (int i = 0; i < entries_per_thread; ++i) { + int key = off + i; + int val = 2 * key; + auto t1 = string(std::to_string(key)); + auto t2 = string(std::to_string(val)); + + { + std::stringstream ss; + ss << "Emplace start: " << t1.str() << std::endl; + std::cout << ss.str(); + } + map.emplace(t1, t2); + { + std::stringstream ss; + ss << "Emplace end: " << t1.str() << std::endl; + std::cout << ss.str(); + } + } + } +#pragma omp barrier + } + REQUIRE(map.size() == total_entries); + + // Verify the map has all entries + for (int i = 0; i < total_entries; ++i) { + auto key = string(std::to_string(i)); + auto val = string(std::to_string(2*i)); + REQUIRE(*(map[key]) == val); + } +} + +TEST_CASE("UnorderedMapParallelInsert") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + UnorderedMapParallelInsert(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} diff --git a/hermes_shm/test/unit/data_structures/containers/vector.cc b/hermes_shm/test/unit/data_structures/containers/vector.cc new file mode 100644 index 000000000..9eabe42a0 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/vector.cc @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/thread_unsafe/vector.h" +#include "hermes_shm/data_structures/thread_unsafe/list.h" +#include "hermes_shm/data_structures/string.h" +#include "vector.h" + +using hermes_shm::ipc::vector; +using hermes_shm::ipc::list; +using hermes_shm::ipc::string; + +template +void VectorTest() { + Allocator *alloc = alloc_g; + vector vec(alloc); + VectorTestSuite> test(vec, alloc); + + test.EmplaceTest(15); + test.IndexTest(); + test.ForwardIteratorTest(); + test.ConstForwardIteratorTest(); + test.CopyConstructorTest(); + test.CopyAssignmentTest(); + test.MoveConstructorTest(); + test.MoveAssignmentTest(); + test.EmplaceFrontTest(); + test.ModifyEntryCopyIntoTest(); + test.ModifyEntryMoveIntoTest(); + test.EraseTest(); +} + +void VectorOfListOfStringTest() { + Allocator *alloc = alloc_g; + vector> vec(alloc); + + vec.resize(10); + for (auto bkt : vec) { + (*bkt).emplace_back("hello"); + } + vec.clear(); +} + +TEST_CASE("VectorOfInt") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + VectorTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("VectorOfString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + VectorTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("VectorOfStdString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + VectorTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("VectorOfListOfString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + VectorOfListOfStringTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + diff --git a/hermes_shm/test/unit/data_structures/containers/vector.h b/hermes_shm/test/unit/data_structures/containers/vector.h new file mode 100644 index 000000000..52f125938 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/vector.h @@ -0,0 +1,29 @@ +// +// Created by lukemartinlogan on 1/10/23. +// + +#ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ +#define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ + +#include "list.h" + +template +class VectorTestSuite : public ListTestSuite { + public: + using ListTestSuite::obj_; + + public: + /// Constructor + VectorTestSuite(Container &obj, Allocator *alloc) + : ListTestSuite(obj, alloc) {} + + /// Test vector index operator + void IndexTest() { + for (int i = 0; i < obj_.size(); ++i) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, var, i); + REQUIRE(*obj_[i] == var); + } + } +}; + +#endif //HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/CMakeLists.txt b/hermes_shm/test/unit/data_structures/containers_mpi/CMakeLists.txt new file mode 100644 index 000000000..32e29ea53 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers_mpi/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(test_data_structure_mpi_exec + ${TEST_MAIN}/main_mpi.cc + test_init.cc + list_vec_mpi.cc +) + +add_dependencies(test_data_structure_mpi_exec hermes_shm_data_structures) +target_link_libraries(test_data_structure_mpi_exec + hermes_shm_data_structures Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) + +# VECTOR TESTS +add_test(NAME test_vector_of_int_mpi COMMAND + mpirun -n 4 ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_mpi_exec "VectorOfIntMpi") +add_test(NAME test_vector_of_string_mpi COMMAND + mpirun -n 1 ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_mpi_exec "VectorOfStringMpi") + +# LIST TESTS +add_test(NAME test_list_of_int_mpi COMMAND + mpirun -n 4 ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_mpi_exec "ListOfIntMpi") +add_test(NAME test_list_of_string_mpi COMMAND + mpirun -n 2 ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_mpi_exec "ListOfStringMpi") + +message("mpirun -n 1 ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_mpi_exec ListOfStringMpi") \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc b/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc new file mode 100644 index 000000000..be92791fe --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc @@ -0,0 +1,102 @@ +// +// Created by lukemartinlogan on 1/30/23. +// + +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/data_structures/thread_unsafe/list.h" +#include "hermes_shm/data_structures/thread_unsafe/vector.h" +#include "hermes_shm/util/error.h" + +template +void ListVecTest(size_t count) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + Allocator *alloc = alloc_g; + Pointer *header = alloc->GetCustomHeader(); + ContainerT obj; + + try { + if (rank == 0) { + obj.shm_init(alloc); + obj >> (*header); + } + MPI_Barrier(MPI_COMM_WORLD); + obj.shm_deserialize(*header); + MPI_Barrier(MPI_COMM_WORLD); + + // Write 100 objects from rank 0 + { + if (rank == 0) { + for (int i = 0; i < count; ++i) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, var, i); + obj.emplace_back(var); + } + } + MPI_Barrier(MPI_COMM_WORLD); + } + + // Read 100 objects from every rank + { + REQUIRE(obj.size() == count); + int i = 0; + for (lipc::ShmRef var : obj) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, orig, i); + REQUIRE(*var == orig); + ++i; + } + MPI_Barrier(MPI_COMM_WORLD); + } + + // Modify an object in rank 0 + { + if (rank == 0) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, update, count); + lipc::ShmRef first = *obj.begin(); + (*first) = update; + } + MPI_Barrier(MPI_COMM_WORLD); + } + + // Check if modification received + { + CREATE_SET_VAR_TO_INT_OR_STRING(T, update, count); + lipc::ShmRef first = *obj.begin(); + REQUIRE((*first) == update); + MPI_Barrier(MPI_COMM_WORLD); + MPI_Barrier(MPI_COMM_WORLD); + } + + } catch(HERMES_SHM_ERROR_TYPE &HERMES_SHM_ERROR_PTR) { + std::cout << "HERE0" << std::endl; + err->print(); + } catch(hermes_shm::Error &err) { + std::cout << "HERE1" << std::endl; + err.print(); + } catch(int err) { + std::cout << "HERE2" << std::endl; + } catch(std::runtime_error &err) { + std::cout << "HERE3" << std::endl; + } catch(std::logic_error &err) { + std::cout << "HERE4" << std::endl; + } catch(...) { + std::cout << "HERE5" << std::endl; + } +} + +TEST_CASE("ListOfIntMpi") { + ListVecTest>(100); +} + +TEST_CASE("ListOfStringMpi") { + ListVecTest>(100); +} + +TEST_CASE("VectorOfIntMpi") { + ListVecTest>(100); +} + +TEST_CASE("VectorOfStringMpi") { + ListVecTest>(100); +} \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc new file mode 100644 index 000000000..92cc361af --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "basic_test.h" +#include "test_init.h" + +#include "hermes_shm/memory/allocator/stack_allocator.h" + +Allocator *alloc_g = nullptr; + +template +void PretestRank0() { + std::string shm_url = "test_allocators"; + allocator_id_t alloc_id(0, 1); + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + mem_mngr->CreateBackend( + MemoryManager::kDefaultBackendSize, shm_url); + mem_mngr->CreateAllocator(shm_url, alloc_id, sizeof(Pointer)); + alloc_g = mem_mngr->GetAllocator(alloc_id); +} + +void PretestRankN() { + std::string shm_url = "test_allocators"; + allocator_id_t alloc_id(0, 1); + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + mem_mngr->AttachBackend(MemoryBackendType::kPosixShmMmap, shm_url); + alloc_g = mem_mngr->GetAllocator(alloc_id); +} + +void MainPretest() { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) { + PretestRank0(); + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank != 0) { + PretestRankN(); + } +} + +void MainPosttest() { +} diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h new file mode 100644 index 000000000..6419e28e7 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ +#define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ + +#include "hermes_shm/data_structures/data_structure.h" +#include + +using hermes_shm::ipc::PosixShmMmap; +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::Pointer; + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::MemoryManager; +using hermes_shm::ipc::Pointer; + +extern Allocator *alloc_g; + +void Posttest(); + +#endif // HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ diff --git a/hermes_shm/test/unit/data_structures/lock/CMakeLists.txt b/hermes_shm/test/unit/data_structures/lock/CMakeLists.txt new file mode 100644 index 000000000..8962fb4fc --- /dev/null +++ b/hermes_shm/test/unit/data_structures/lock/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(test_lock_exec + ${TEST_MAIN}/main.cc + test_init.cc + lock.cc) +add_dependencies(test_lock_exec hermes_shm_data_structures) +target_link_libraries(test_lock_exec + hermes_shm_data_structures Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) + +add_test(NAME test_mutex COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_lock_exec "Mutex") + +add_test(NAME test_rw_lock COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_lock_exec "RwLock") + diff --git a/hermes_shm/test/unit/data_structures/lock/lock.cc b/hermes_shm/test/unit/data_structures/lock/lock.cc new file mode 100644 index 000000000..f9e8e23ea --- /dev/null +++ b/hermes_shm/test/unit/data_structures/lock/lock.cc @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "basic_test.h" +#include "omp.h" +#include "hermes_shm/thread/lock.h" + +using hermes_shm::Mutex; +using hermes_shm::RwLock; + +void MutexTest() { + int nthreads = 8; + int loop_count = 10000; + int count = 0; + Mutex lock; + + HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + + omp_set_dynamic(0); +#pragma omp parallel shared(lock) num_threads(nthreads) + { + // Support parallel write +#pragma omp barrier + for (int i = 0; i < loop_count; ++i) { + lock.Lock(); + count += 1; + lock.Unlock(); + } +#pragma omp barrier + REQUIRE(count == loop_count * nthreads); +#pragma omp barrier + } +} + +void barrier_for_reads(std::vector &tid_start, int left) { + int count; + do { + count = 0; + for (int i = 0; i < left; ++i) { + count += tid_start[i]; + } + } while (count < left); +} + +void RwLockTest() { + int nthreads = 8; + int left = nthreads / 2; + std::vector tid_start(left, 0); + int loop_count = 100000; + int count = 0; + RwLock lock; + + HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + + omp_set_dynamic(0); +#pragma omp parallel \ + shared(lock, nthreads, left, loop_count, count, tid_start) \ + num_threads(nthreads) + { + int tid = omp_get_thread_num(); + + // Support parallel write +#pragma omp barrier + for (int i = 0; i < loop_count; ++i) { + lock.WriteLock(); + count += 1; + lock.WriteUnlock(); + } +#pragma omp barrier + REQUIRE(count == loop_count * nthreads); +#pragma omp barrier + + // Support for parallel read and write +#pragma omp barrier + + int cur_count = count; + if (tid < left) { + lock.ReadLock(); + tid_start[tid] = 1; + barrier_for_reads(tid_start, left); + for (int i = 0; i < loop_count; ++i) { + REQUIRE(count == cur_count); + } + lock.ReadUnlock(); + } else { + barrier_for_reads(tid_start, left); + lock.WriteLock(); + for (int i = 0; i < loop_count; ++i) { + count += 1; + } + lock.WriteUnlock(); + } + } +} + +TEST_CASE("Mutex") { + MutexTest(); +} + +TEST_CASE("RwLock") { + RwLockTest(); +} diff --git a/hermes_shm/test/unit/data_structures/lock/test_init.cc b/hermes_shm/test/unit/data_structures/lock/test_init.cc new file mode 100644 index 000000000..cb402e14b --- /dev/null +++ b/hermes_shm/test/unit/data_structures/lock/test_init.cc @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "basic_test.h" + +void MainPretest() {} + +void MainPosttest() {} diff --git a/hermes_shm/test/unit/main.cc b/hermes_shm/test/unit/main.cc new file mode 100644 index 000000000..a0ea64a53 --- /dev/null +++ b/hermes_shm/test/unit/main.cc @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "basic_test.h" +#include + +int main(int argc, char **argv) { + int rc; + Catch::Session session; + auto cli = session.cli(); + session.cli(cli); + rc = session.applyCommandLine(argc, argv); + if (rc != 0) return rc; + MainPretest(); + rc = session.run(); + MainPosttest(); + if (rc != 0) return rc; + return rc; +} diff --git a/hermes_shm/test/unit/main_mpi.cc b/hermes_shm/test/unit/main_mpi.cc new file mode 100644 index 000000000..944123734 --- /dev/null +++ b/hermes_shm/test/unit/main_mpi.cc @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "basic_test.h" +#include + +int main(int argc, char **argv) { + int rc; + MPI_Init(&argc, &argv); + Catch::Session session; + auto cli = session.cli(); + session.cli(cli); + rc = session.applyCommandLine(argc, argv); + if (rc != 0) return rc; + MainPretest(); + rc = session.run(); + MainPosttest(); + if (rc != 0) return rc; + MPI_Finalize(); + return rc; +} diff --git a/hermes_shm/test/unit/types/CMakeLists.txt b/hermes_shm/test/unit/types/CMakeLists.txt new file mode 100644 index 000000000..7f5c06b15 --- /dev/null +++ b/hermes_shm/test/unit/types/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(test_types + ${TEST_MAIN}/main.cc + test_init.cc + test_argpack.cc) +target_link_libraries(test_types + Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) + +#add_test(NAME test_connect COMMAND +# bash ${CMAKE_CURRENT_SOURCE_DIR}/test_connect.sh +# ${CMAKE_BINARY_DIR}/labstor_runtime +# ${CMAKE_CURRENT_BINARY_DIR}/test_connect_exec +# ${CMAKE_SOURCE_DIR}/config/config.yaml) \ No newline at end of file diff --git a/hermes_shm/test/unit/types/test_argpack.cc b/hermes_shm/test/unit/types/test_argpack.cc new file mode 100644 index 000000000..cac27bb4e --- /dev/null +++ b/hermes_shm/test/unit/types/test_argpack.cc @@ -0,0 +1,172 @@ +// +// Created by lukemartinlogan on 1/26/23. +// + +#include "basic_test.h" +#include +#include + +void test_argpack0_pass() { + std::cout << "HERE0" << std::endl; +} + +void test_argpack0() { + hermes_shm::PassArgPack::Call(hermes_shm::ArgPack<>(), test_argpack0_pass); +} + +template +void test_argpack3_pass(T1 x, T2 y, T3 z) { + REQUIRE(x == 0); + REQUIRE(y == 1); + REQUIRE(z == 0); + std::cout << "HERE3" << std::endl; +} + +void test_product1(int b, int c) { + REQUIRE(b == 1); + REQUIRE(c == 2); +} + +void test_product2(double d, double e) { + REQUIRE(d == 3); + REQUIRE(e == 4); +} + +template +void test_product(int a, Pack1 &&pack1, int a2, Pack2 &&pack2) { + REQUIRE(a == 0); + REQUIRE(a2 == 0); + hermes_shm::PassArgPack::Call( + std::forward(pack1), + test_product1); + hermes_shm::PassArgPack::Call( + std::forward(pack2), + test_product2); +} + +template +void verify_tuple3(hermes_shm::tuple &x) { + REQUIRE(x.Size() == 3); + REQUIRE(x.template Get<0>() == 0); + REQUIRE(x.template Get<1>() == 1); + REQUIRE(x.template Get<2>() == 0); +#ifdef TEST_COMPILER_ERROR + std::cout << x.Get<3>() << std::endl; +#endif +} + +template +void test_argpack3() { + // Pass an argpack to a function + { + hermes_shm::PassArgPack::Call( + hermes_shm::make_argpack(T1(0), T2(1), T3(0)), + test_argpack3_pass); + } + + // Pass an argpack containing references to a function + { + T2 y = 1; + hermes_shm::PassArgPack::Call( + hermes_shm::make_argpack(0, y, 0), + test_argpack3_pass); + } + + // Create a 3-tuple + { + hermes_shm::tuple x(0, 1, 0); + verify_tuple3(x); + } + + // Copy a tuple + { + hermes_shm::tuple y(0, 1, 0); + hermes_shm::tuple x(y); + verify_tuple3(x); + } + + // Copy assign tuple + { + hermes_shm::tuple y(0, 1, 0); + hermes_shm::tuple x; + x = y; + verify_tuple3(x); + } + + // Move tuple + { + hermes_shm::tuple y(0, 1, 0); + hermes_shm::tuple x(std::move(y)); + verify_tuple3(x); + } + + // Move assign tuple + { + hermes_shm::tuple y(0, 1, 0); + hermes_shm::tuple x; + x = std::move(y); + verify_tuple3(x); + } + + // Iterate over a tuple + { + hermes_shm::tuple x(0, 1, 0); + hermes_shm::ForwardIterateTuple::Apply( + x, + [](auto i, auto &arg) constexpr { + std::cout << "lambda: " << i.Get() << std::endl; + }); + } + + // Merge two argpacks into a single pack + { + size_t y = hermes_shm::MergeArgPacks::Merge( + hermes_shm::make_argpack(T1(0)), + hermes_shm::make_argpack(T2(1), T2(0))).Size(); + REQUIRE(y == 3); + } + + // Pass a merged argpack to a function + { + hermes_shm::PassArgPack::Call( + hermes_shm::MergeArgPacks::Merge( + hermes_shm::make_argpack(0), + hermes_shm::make_argpack(1, 0)), + test_argpack3_pass); + } + + // Construct tuple from argpack + { + hermes_shm::tuple x( + hermes_shm::make_argpack(10, 11, 12)); + REQUIRE(x.Get<0>() == 10); + REQUIRE(x.Get<1>() == 11); + REQUIRE(x.Get<2>() == 12); + } + + // Product an argpack + { + auto&& pack = hermes_shm::ProductArgPacks::Product( + 0, + hermes_shm::make_argpack(1, 2), + hermes_shm::make_argpack(3, 4)); + REQUIRE(pack.Size() == 4); + } + + // Product an argpack + { + hermes_shm::PassArgPack::Call( + hermes_shm::ProductArgPacks::Product( + 0, + hermes_shm::make_argpack(1, 2), + hermes_shm::make_argpack(3.0, 4.0)), + test_product< + hermes_shm::ArgPack, + hermes_shm::ArgPack>); + } +} + +TEST_CASE("TestArgpack") { + test_argpack0(); + test_argpack3(); +} \ No newline at end of file diff --git a/hermes_shm/test/unit/types/test_init.cc b/hermes_shm/test/unit/types/test_init.cc new file mode 100644 index 000000000..cb402e14b --- /dev/null +++ b/hermes_shm/test/unit/types/test_init.cc @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of HermesShm + * + * HermesShm 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 Lesser 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 + * . + */ + + +#include "basic_test.h" + +void MainPretest() {} + +void MainPosttest() {} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3d6956b52..5dd7f8d42 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -71,26 +71,26 @@ set(HERMES_BUILD_INCLUDE_DEPENDENCIES ) add_library(hermes ${HERMES_SRCS}) - target_include_directories(hermes PUBLIC "$" $ ) - target_include_directories(hermes SYSTEM PUBLIC ${HERMES_EXT_INCLUDE_DEPENDENCIES} ) - -add_dependencies(hermes hermes_adapter_io_clients) +add_dependencies(hermes + hermes_adapter_io_clients + hermes_shm_data_structures) target_link_libraries(hermes + PUBLIC hermes_shm_data_structures PUBLIC hermes_adapter_io_clients PUBLIC ${GLPK_LIBRARIES} PUBLIC ${CMAKE_HERMES_COMMUNICATION_TYPE_LIB} PUBLIC ${CMAKE_HERMES_RPC_TYPE_LIB} PUBLIC glog::glog PUBLIC yaml-cpp - PUBLIC labstor_client labstor_data_structures + PUBLIC labstor_client hermes_shm_data_structures PUBLIC "$<$:${GOTCHA_MODULE_LIBS}>" ) diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 005042499..5f2e47b35 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -120,7 +120,7 @@ void Hermes::LoadClientConfig(std::string config_path) { void Hermes::InitSharedMemory() { // Create shared-memory allocator - auto mem_mngr = LABSTOR_MEMORY_MANAGER; + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; mem_mngr->CreateBackend( lipc::MemoryManager::kDefaultBackendSize, server_config_.shmem_name_); @@ -134,7 +134,7 @@ void Hermes::InitSharedMemory() { void Hermes::LoadSharedMemory() { // Load shared-memory allocator - auto mem_mngr = LABSTOR_MEMORY_MANAGER; + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; mem_mngr->AttachBackend(lipc::MemoryBackendType::kPosixShmMmap, server_config_.shmem_name_); main_alloc_ = mem_mngr->GetAllocator(main_alloc_id); diff --git a/src/data_structures.h b/src/data_structures.h index fcbf55faf..ae4bbc660 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -13,21 +13,21 @@ #ifndef HERMES_SRC_DATA_STRUCTURES_H_ #define HERMES_SRC_DATA_STRUCTURES_H_ -#include -#include -#include -#include -#include -#include -#include - -namespace lipc = labstor::ipc; - -using labstor::RwLock; -using labstor::Mutex; -using labstor::bitfield32_t; -using labstor::ScopedRwReadLock; -using labstor::ScopedRwWriteLock; +#include +#include +#include +#include +#include +#include +#include + +namespace lipc = hermes_shm::ipc; + +using hermes_shm::RwLock; +using hermes_shm::Mutex; +using hermes_shm::bitfield32_t; +using hermes_shm::ScopedRwReadLock; +using hermes_shm::ScopedRwWriteLock; #include #include diff --git a/src/dpe/random.cc b/src/dpe/random.cc index 92ad83960..a60824268 100644 --- a/src/dpe/random.cc +++ b/src/dpe/random.cc @@ -22,6 +22,7 @@ Status Random::Placement(const std::vector &blob_sizes, const lipc::vector &targets, const api::Context &ctx, std::vector &output) { + throw std::logic_error("Not currently implemented"); } } // namespace hermes diff --git a/src/dpe/round_robin.cc b/src/dpe/round_robin.cc index 12b64ea04..eb1f81410 100644 --- a/src/dpe/round_robin.cc +++ b/src/dpe/round_robin.cc @@ -19,7 +19,7 @@ Status RoundRobin::Placement(const std::vector &blob_sizes, const lipc::vector &targets, const api::Context &ctx, std::vector &output) { + throw std::logic_error("Not currently implemented"); } - } // namespace hermes diff --git a/src/hermes_types.h b/src/hermes_types.h index 4bb64cf90..c4bfdf72e 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -208,7 +208,7 @@ struct TraitId { namespace hermes::api { /** A blob is an uniterpreted array of bytes */ -typedef labstor::charbuf Blob; +typedef hermes_shm::charbuf Blob; /** Supported data placement policies */ enum class PlacementPolicy { diff --git a/src/rpc_thallium_serialization.h b/src/rpc_thallium_serialization.h index 96eca8b8c..f3fb4dae6 100644 --- a/src/rpc_thallium_serialization.h +++ b/src/rpc_thallium_serialization.h @@ -21,7 +21,6 @@ #include "hermes_types.h" #include "metadata_types.h" #include "data_structures.h" -#include namespace hermes { diff --git a/test/basic_test.h b/test/basic_test.h index 02b546b05..68824078a 100644 --- a/test/basic_test.h +++ b/test/basic_test.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef LABSTOR_TEST_UNIT_BASIC_TEST_H_ -#define LABSTOR_TEST_UNIT_BASIC_TEST_H_ +#ifndef HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ +#define HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ #define CATCH_CONFIG_RUNNER #include @@ -35,4 +35,4 @@ static bool VerifyBuffer(char *ptr, size_t size, char nonce) { void MainPretest(); void MainPosttest(); -#endif // LABSTOR_TEST_UNIT_BASIC_TEST_H_ +#endif // HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ From c6913c68c79836d5e35ed4a5d7ded5ddb0fe2fbf Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 09:16:40 -0600 Subject: [PATCH 136/511] Removed most labstor instances --- CMake/FindLabStor.cmake | 43 ------------------- .../include/hermes_shm/constants/constants.h | 33 -------------- .../hermes_shm/constants/singleton_macros.h | 12 ------ hermes_shm/src/memory/memory_manager.cc | 1 - hermes_shm/test/unit/types/CMakeLists.txt | 8 +--- 5 files changed, 1 insertion(+), 96 deletions(-) delete mode 100644 CMake/FindLabStor.cmake delete mode 100644 hermes_shm/include/hermes_shm/constants/constants.h delete mode 100644 hermes_shm/include/hermes_shm/constants/singleton_macros.h diff --git a/CMake/FindLabStor.cmake b/CMake/FindLabStor.cmake deleted file mode 100644 index aa23f5165..000000000 --- a/CMake/FindLabStor.cmake +++ /dev/null @@ -1,43 +0,0 @@ -# Find hermes_shm header and library. -# - -# This module defines the following uncached variables: -# LabStor_FOUND, if false, do not try to use hermes_shm. -# LabStor_INCLUDE_DIRS, where to find hermes_shm.h. -# LabStor_LIBRARIES, the libraries to link against to use the hermes_shm library -# LabStor_LIBRARY_DIRS, the directory where the hermes_shm library is found. - -find_path( - LabStor_INCLUDE_DIR - hermes_shm/hermes_shm.h -) - -if( LabStor_INCLUDE_DIR ) - get_filename_component(LabStor_DIR ${LabStor_INCLUDE_DIR} PATH) - - find_library( - LabStor_LIBRARY - NAMES hermes_shm_data_structures - ) - - if( LabStor_LIBRARY ) - set(LabStor_LIBRARY_DIR "") - get_filename_component(LabStor_LIBRARY_DIRS ${LabStor_LIBRARY} PATH) - # Set uncached variables as per standard. - set(LabStor_FOUND ON) - set(LabStor_INCLUDE_DIRS ${LabStor_INCLUDE_DIR}) - set(LabStor_LIBRARIES ${LabStor_LIBRARY}) - endif(LabStor_LIBRARY) -else(LabStor_INCLUDE_DIR) - message(STATUS "Findlabstor: Could not find hermes_shm.h") -endif(LabStor_INCLUDE_DIR) - -if(LabStor_FOUND) - if(NOT LabStor_FIND_QUIETLY) - message(STATUS "Findlabstor: Found both hermes_shm.h and liblabstor.a") - endif(NOT LabStor_FIND_QUIETLY) -else(LabStor_FOUND) - if(LabStor_FIND_REQUIRED) - message(STATUS "Findlabstor: Could not find hermes_shm.h and/or liblabstor.a") - endif(LabStor_FIND_REQUIRED) -endif(LabStor_FOUND) diff --git a/hermes_shm/include/hermes_shm/constants/constants.h b/hermes_shm/include/hermes_shm/constants/constants.h deleted file mode 100644 index 7328f1199..000000000 --- a/hermes_shm/include/hermes_shm/constants/constants.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - -#ifndef HERMES_SHM_CONSTANTS_CONSTANTS_H_ -#define HERMES_SHM_CONSTANTS_CONSTANTS_H_ - -#include - -const char kLabStorRuntimeUrl[] = "labstor_runtime_url"; - -#endif // HERMES_SHM_CONSTANTS_CONSTANTS_H_ diff --git a/hermes_shm/include/hermes_shm/constants/singleton_macros.h b/hermes_shm/include/hermes_shm/constants/singleton_macros.h deleted file mode 100644 index 517ccb37d..000000000 --- a/hermes_shm/include/hermes_shm/constants/singleton_macros.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_CONSTANTS_SINGLETON_MACROS_H_H -#define HERMES_SHM_INCLUDE_HERMES_SHM_CONSTANTS_SINGLETON_MACROS_H_H - -#include - -#define HERMES_SHM_IPC_MANAGER scs::Singleton::GetInstance() -#define HERMES_SHM_IPC_MANAGER_T hermes_shm::IpcManager* - -#define HERMES_SHM_CONFIGURATION_MANAGER scs::Singleton::GetInstance() -#define HERMES_SHM_CONFIGURATION_MANAGER_T hermes_shm::ConfigurationManager* - -#endif // include_labstor_constants_singleton_macros_h diff --git a/hermes_shm/src/memory/memory_manager.cc b/hermes_shm/src/memory/memory_manager.cc index 2fdbaa41e..1fe868d54 100644 --- a/hermes_shm/src/memory/memory_manager.cc +++ b/hermes_shm/src/memory/memory_manager.cc @@ -28,7 +28,6 @@ #include "hermes_shm/memory/backend/memory_backend_factory.h" #include "hermes_shm/memory/allocator/allocator_factory.h" #include -#include namespace hermes_shm::ipc { diff --git a/hermes_shm/test/unit/types/CMakeLists.txt b/hermes_shm/test/unit/types/CMakeLists.txt index 7f5c06b15..1437ed150 100644 --- a/hermes_shm/test/unit/types/CMakeLists.txt +++ b/hermes_shm/test/unit/types/CMakeLists.txt @@ -8,10 +8,4 @@ add_executable(test_types test_init.cc test_argpack.cc) target_link_libraries(test_types - Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) - -#add_test(NAME test_connect COMMAND -# bash ${CMAKE_CURRENT_SOURCE_DIR}/test_connect.sh -# ${CMAKE_BINARY_DIR}/labstor_runtime -# ${CMAKE_CURRENT_BINARY_DIR}/test_connect_exec -# ${CMAKE_SOURCE_DIR}/config/config.yaml) \ No newline at end of file + Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) \ No newline at end of file From 20f1be63ef1a480fd43f463f98a13a8598e45e8c Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 09:19:17 -0600 Subject: [PATCH 137/511] Remove unused data structures --- adapter/adapter_constants.h | 14 +- adapter/adapter_types.h | 14 +- adapter/mpiio/mpiio_fs_api.h | 14 +- adapter/mpiio/mpiio_io_client.cc | 16 +- adapter/mpiio/mpiio_io_client.h | 14 +- .../data_structure_singleton_macros.h | 12 + .../include/hermes_shm/constants/macros.h | 35 +- .../data_structures/data_structure.h | 36 +- .../data_structures/internal/shm_archive.h | 36 +- .../internal/shm_archive_or_t.h | 36 +- .../data_structures/internal/shm_container.h | 36 +- .../internal/shm_container_extend_macro.h | 12 + .../internal/shm_container_macro.h | 12 + .../internal/shm_deserialize.h | 14 +- .../data_structures/internal/shm_macros.h | 36 +- .../internal/shm_null_container.h | 14 +- .../data_structures/internal/shm_ref.h | 14 +- .../data_structures/internal/shm_smart_ptr.h | 36 +- .../template/shm_container_base_example.h | 14 +- .../template/shm_container_base_template.h | 14 +- .../template/shm_container_extend_example.h | 14 +- .../template/shm_container_extend_template.h | 14 +- .../include/hermes_shm/data_structures/pair.h | 14 +- .../data_structures/smart_ptr/manual_ptr.h | 36 +- .../hermes_shm/data_structures/string.h | 36 +- .../hermes_shm/data_structures/struct.h | 455 ------------------ .../data_structures/thread_unsafe/list.h | 36 +- .../thread_unsafe/unordered_map.h | 36 +- .../data_structures/thread_unsafe/vector.h | 36 +- .../hermes_shm/introspect/system_info.h | 35 +- .../hermes_shm/memory/allocator/allocator.h | 35 +- .../memory/allocator/allocator_factory.h | 36 +- .../memory/allocator/malloc_allocator.h | 36 +- .../hermes_shm/memory/allocator/mp_page.h | 14 +- .../memory/allocator/multi_page_allocator.h | 14 +- .../memory/allocator/stack_allocator.h | 36 +- .../hermes_shm/memory/backend/array_backend.h | 14 +- .../memory/backend/memory_backend.h | 35 +- .../memory/backend/memory_backend_factory.h | 36 +- .../hermes_shm/memory/backend/null_backend.h | 14 +- .../hermes_shm/memory/backend/posix_mmap.h | 35 +- .../memory/backend/posix_shm_mmap.h | 35 +- hermes_shm/include/hermes_shm/memory/memory.h | 36 +- .../hermes_shm/memory/memory_manager.h | 35 +- hermes_shm/include/hermes_shm/thread/lock.h | 36 +- .../include/hermes_shm/thread/lock/mutex.h | 36 +- .../include/hermes_shm/thread/lock/rwlock.h | 36 +- .../include/hermes_shm/thread/pthread.h | 35 +- hermes_shm/include/hermes_shm/thread/thread.h | 35 +- .../hermes_shm/thread/thread_factory.h | 35 +- .../hermes_shm/thread/thread_manager.h | 36 +- hermes_shm/include/hermes_shm/types/argpack.h | 14 +- hermes_shm/include/hermes_shm/types/atomic.h | 14 +- hermes_shm/include/hermes_shm/types/basic.h | 35 +- .../include/hermes_shm/types/bitfield.h | 14 +- hermes_shm/include/hermes_shm/types/charbuf.h | 14 +- .../include/hermes_shm/types/messages.h | 35 +- .../include/hermes_shm/types/tuple_base.h | 14 +- .../include/hermes_shm/util/auto_trace.h | 14 +- hermes_shm/include/hermes_shm/util/debug.h | 35 +- hermes_shm/include/hermes_shm/util/error.h | 35 +- hermes_shm/include/hermes_shm/util/errors.h | 35 +- .../include/hermes_shm/util/formatter.h | 35 +- .../include/hermes_shm/util/partitioner.h | 35 +- .../include/hermes_shm/util/path_parser.h | 35 +- .../include/hermes_shm/util/singleton.h | 35 +- hermes_shm/include/hermes_shm/util/timer.h | 35 +- hermes_shm/src/data_structure_singleton.cc | 12 + hermes_shm/src/memory/malloc_allocator.cc | 36 +- hermes_shm/src/memory/memory_intercept.cc | 14 +- hermes_shm/src/memory/memory_intercept.h | 14 +- hermes_shm/src/memory/memory_manager.cc | 36 +- hermes_shm/src/memory/multi_page_allocator.cc | 16 +- hermes_shm/src/memory/stack_allocator.cc | 36 +- hermes_shm/src/thread/mutex.cc | 36 +- hermes_shm/src/thread/rwlock.cc | 36 +- hermes_shm/test/unit/allocators/allocator.cc | 38 +- .../test/unit/allocators/allocator_thread.cc | 36 +- hermes_shm/test/unit/allocators/test_init.cc | 36 +- hermes_shm/test/unit/allocators/test_init.h | 36 +- hermes_shm/test/unit/basic_test.h | 35 +- .../unit/data_structures/backend/backend.cc | 35 +- .../data_structures/backend/memory_manager.cc | 36 +- .../data_structures/backend/memory_slots.cc | 35 +- .../unit/data_structures/backend/test_init.cc | 36 +- .../data_structures/containers/CMakeLists.txt | 1 - .../unit/data_structures/containers/list.cc | 37 +- .../unit/data_structures/containers/list.h | 14 +- .../data_structures/containers/manual_ptr.cc | 36 +- .../unit/data_structures/containers/pair.cc | 16 +- .../unit/data_structures/containers/slist.cc | 37 +- .../data_structures/containers/smart_ptr.h | 14 +- .../unit/data_structures/containers/string.cc | 35 +- .../data_structures/containers/test_init.cc | 36 +- .../data_structures/containers/test_init.h | 36 +- .../unit/data_structures/containers/tuple.cc | 75 --- .../containers/unordered_map.cc | 35 +- .../containers/unordered_map_thread.cc | 35 +- .../unit/data_structures/containers/vector.cc | 36 +- .../unit/data_structures/containers/vector.h | 14 +- .../containers_mpi/list_vec_mpi.cc | 16 +- .../containers_mpi/test_init.cc | 36 +- .../containers_mpi/test_init.h | 36 +- .../test/unit/data_structures/lock/lock.cc | 36 +- .../unit/data_structures/lock/test_init.cc | 36 +- hermes_shm/test/unit/main.cc | 36 +- hermes_shm/test/unit/main_mpi.cc | 36 +- hermes_shm/test/unit/types/test_argpack.cc | 16 +- hermes_shm/test/unit/types/test_init.cc | 36 +- src/api/hermes_singleton.cc | 2 +- src/config_client_default.h | 14 +- src/config_server_default.h | 14 +- 112 files changed, 1209 insertions(+), 2356 deletions(-) delete mode 100644 hermes_shm/include/hermes_shm/data_structures/struct.h delete mode 100644 hermes_shm/test/unit/data_structures/containers/tuple.cc diff --git a/adapter/adapter_constants.h b/adapter/adapter_constants.h index c6a78a033..54da8118e 100644 --- a/adapter/adapter_constants.h +++ b/adapter/adapter_constants.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 2/4/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_ADAPTER_ADAPTER_CONSTANTS_H_ #define HERMES_ADAPTER_ADAPTER_CONSTANTS_H_ diff --git a/adapter/adapter_types.h b/adapter/adapter_types.h index ae3f6eb4a..bea038c3a 100644 --- a/adapter/adapter_types.h +++ b/adapter/adapter_types.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 2/4/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_ADAPTER_ADAPTER_TYPES_H_ #define HERMES_ADAPTER_ADAPTER_TYPES_H_ diff --git a/adapter/mpiio/mpiio_fs_api.h b/adapter/mpiio/mpiio_fs_api.h index f547309ec..14da4dc4f 100644 --- a/adapter/mpiio/mpiio_fs_api.h +++ b/adapter/mpiio/mpiio_fs_api.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 2/4/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_ADAPTER_MPIIO_MPIIO_FS_API_H_ #define HERMES_ADAPTER_MPIIO_MPIIO_FS_API_H_ diff --git a/adapter/mpiio/mpiio_io_client.cc b/adapter/mpiio/mpiio_io_client.cc index c82a52e01..ff8b625e8 100644 --- a/adapter/mpiio/mpiio_io_client.cc +++ b/adapter/mpiio/mpiio_io_client.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 2/4/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "mpiio_io_client.h" @@ -166,4 +174,4 @@ void MpiioIoClient::UpdateIoStatus(size_t count, IoStatus &status) { status.mpi_status_ptr_->count_lo = count; } -} // namespace hermes::adapter::fs \ No newline at end of file +} // namespace hermes::adapter::fs diff --git a/adapter/mpiio/mpiio_io_client.h b/adapter/mpiio/mpiio_io_client.h index 637023851..9c0d06b2f 100644 --- a/adapter/mpiio/mpiio_io_client.h +++ b/adapter/mpiio/mpiio_io_client.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 2/4/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_ADAPTER_MPIIO_MPIIO_IO_CLIENT_H_ #define HERMES_ADAPTER_MPIIO_MPIIO_IO_CLIENT_H_ diff --git a/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h b/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h index 0390fefa1..3f1519c23 100644 --- a/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h +++ b/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_CONSTANTS_DATA_STRUCTURE_SINGLETON_MACROS_H_H #define HERMES_SHM_INCLUDE_HERMES_SHM_CONSTANTS_DATA_STRUCTURE_SINGLETON_MACROS_H_H diff --git a/hermes_shm/include/hermes_shm/constants/macros.h b/hermes_shm/include/hermes_shm/constants/macros.h index 31c39002e..884527725 100644 --- a/hermes_shm/include/hermes_shm/constants/macros.h +++ b/hermes_shm/include/hermes_shm/constants/macros.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_MACROS_H #define HERMES_SHM_MACROS_H diff --git a/hermes_shm/include/hermes_shm/data_structures/data_structure.h b/hermes_shm/include/hermes_shm/data_structures/data_structure.h index cc200ae83..ce21574c3 100644 --- a/hermes_shm/include/hermes_shm/data_structures/data_structure.h +++ b/hermes_shm/include/hermes_shm/data_structures/data_structure.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_DATA_STRUCTURES_DATA_STRUCTURE_H_ #define HERMES_SHM_DATA_STRUCTURES_DATA_STRUCTURE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h index 01473c036..447c3516d 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_DATA_STRUCTURES_SHM_ARCHIVE_H_ #define HERMES_SHM_DATA_STRUCTURES_SHM_ARCHIVE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h index bc3d9f5b3..52b4e9ae4 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_DATA_STRUCTURES_SHM_AR_H_ #define HERMES_SHM_DATA_STRUCTURES_SHM_AR_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h index 6fffc637a..113c0ca3f 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_SHM_CONTAINER_H_ #define HERMES_SHM_SHM_CONTAINER_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h index fa6376515..791bcce3c 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ #define HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ #define SHM_CONTAINER_EXTEND_TEMPLATE(CLASS_NAME,TYPED_CLASS,TYPED_HEADER)\ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h index fa354b1e9..fa330ddf7 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ #define HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ #define SHM_CONTAINER_TEMPLATE(CLASS_NAME,TYPED_CLASS,TYPED_HEADER)\ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h index c193984fa..e674177d9 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/24/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h index e62738172..24555abf4 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_MEMORY_SHM_MACROS_H_ #define HERMES_SHM_MEMORY_SHM_MACROS_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h index f03aed0ba..dba9ce461 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/27/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h index 896a54329..2bbf3a9fd 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/15/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h index 1f03cc9e5..55d186e0b 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ #define HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h index fa752bf21..2f6eeeb4e 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/24/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h index f942eafed..b55829c51 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + public: /**==================================== * Variables & Types @@ -340,4 +352,4 @@ lipc::Allocator* GetAllocator() const { /** Get the shared-memory allocator id */ lipc::allocator_id_t GetAllocatorId() const { return alloc_->GetId(); -} \ No newline at end of file +} diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h index 4a3311630..1346b8aeb 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/24/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /** * Let's say we want a data structure diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h index 68925e847..1112c9716 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + public: /**==================================== * Variables & Types @@ -235,4 +247,4 @@ Allocator* GetAllocator() const { /** Get the shared-memory allocator id */ allocator_id_t GetAllocatorId() const { return GetAllocator()->GetId(); -} \ No newline at end of file +} diff --git a/hermes_shm/include/hermes_shm/data_structures/pair.h b/hermes_shm/include/hermes_shm/data_structures/pair.h index a75d7a743..6a999adc7 100644 --- a/hermes_shm/include/hermes_shm/data_structures/pair.h +++ b/hermes_shm/include/hermes_shm/data_structures/pair.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/15/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_PAIR_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_PAIR_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h b/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h index a86cbb50e..892bbfe9f 100644 --- a/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h +++ b/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_DATA_STRUCTURES_PTR_H_ #define HERMES_SHM_DATA_STRUCTURES_PTR_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/string.h b/hermes_shm/include/hermes_shm/data_structures/string.h index 61131057f..e5d968eb9 100644 --- a/hermes_shm/include/hermes_shm/data_structures/string.h +++ b/hermes_shm/include/hermes_shm/data_structures/string.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_DATA_STRUCTURES_LOCKLESS_STRING_H_ #define HERMES_SHM_DATA_STRUCTURES_LOCKLESS_STRING_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/struct.h b/hermes_shm/include/hermes_shm/data_structures/struct.h deleted file mode 100644 index 5fb314896..000000000 --- a/hermes_shm/include/hermes_shm/data_structures/struct.h +++ /dev/null @@ -1,455 +0,0 @@ -// -// Created by lukemartinlogan on 1/26/23. -// - -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_STRUCT_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_STRUCT_H_ - -#include "hermes_shm/data_structures/internal/shm_container.h" -#include "hermes_shm/data_structures/internal/shm_archive_or_t.h" -#include "hermes_shm/data_structures/internal/shm_null_container.h" -#include "hermes_shm/types/tuple_base.h" - -#define CLASS_NAME ShmStruct -#define TYPED_CLASS ShmStruct -#define TYPED_HEADER ShmHeader> - -namespace hermes_shm::ipc { - -/** Tuple forward declaration */ -template -class ShmStruct; - -/** Tuple SHM header */ -template -struct ShmHeader> { - /**< All object headers */ - hermes_shm::tuple_wrap hdrs_; - - /** Default initialize headers */ - ShmHeader() = default; - - /** Piecewise initialize all headers */ - template - explicit ShmHeader(Allocator *alloc, Args&& ...args) { - ForwardIterateTuple::Apply( - hdrs_, - [alloc, args=make_argpack(std::forward(args)...)] - (auto i, auto &obj_hdr) constexpr { - obj_hdr.PiecewiseInit(alloc, args.template Forward()); - }); - } - - /** Get the internal reference to the ith object */ - template - decltype(auto) internal_ref(Allocator *alloc) { - return hdrs_.template Get().internal_ref(alloc); - } - - /** Destructor */ - void shm_destroy(Allocator *alloc) { - hermes_shm::ForwardIterateTuple::Apply( - hdrs_, - [alloc](size_t i, auto &obj_hdr) constexpr { - obj_hdr.shm_destroy(alloc); - } - ); - } -}; - -/** A tuple of objects to store in shared memory */ -template -class ShmStruct : public ShmContainer { - public: - /**==================================== - * Variables & Types - *===================================*/ - - typedef TYPED_HEADER header_t; /**< Index to header type */ - header_t *header_; /**< The shared-memory header */ - Allocator *alloc_; /**< Allocator used for the header */ - hermes_shm::tuple - objs_; /**< Constructed objects */ - - public: - /**==================================== - * Shm Overrides - * ===================================*/ - - /** Default constructor */ - CLASS_NAME() = delete; - - /** Default shm constructor */ - template - void shm_init_main(TYPED_HEADER *header, - Allocator *alloc) { - shm_init_header(header, alloc); - } - - /** Piecewise shm constructor */ - template - void shm_init_main(TYPED_HEADER *header, - Allocator *alloc, - Args&& ...args) { - shm_init_header(header, alloc, - std::forward(args)...); - } - - /** Move constructor */ - void shm_weak_move_main(TYPED_HEADER *header, - Allocator *alloc, CLASS_NAME &other) { - shm_init_header(header, alloc, std::move(other)); - } - - /** Copy constructor */ - void shm_strong_copy_main(TYPED_HEADER *header, - Allocator *alloc, const CLASS_NAME &other) { - shm_init_header(header, alloc, other); - } - - /** Destroy the shared-memory data. */ - void shm_destroy_main() {} - - /** Store into shared memory */ - void shm_serialize_main() const {} - - /** Load from shared memory */ - void shm_deserialize_main() {} - - /**==================================== - * Constructors - * ===================================*/ - - /** Constructor. Allocate header with default allocator. */ - template - explicit CLASS_NAME(Args&& ...args) { - shm_init(std::forward(args)...); - } - - /** Constructor. Allocate header with default allocator. */ - template - void shm_init(Args&& ...args) { - shm_destroy(false); - shm_init_main(typed_nullptr(), - typed_nullptr(), - std::forward(args)...); - } - - /** Constructor. Initialize an already-allocated header. */ - template - void shm_init(TYPED_HEADER &header, - lipc::Allocator *alloc, Args&& ...args) { - shm_destroy(false); - shm_init_main(&header, alloc, std::forward(args)...); - } - - /** Initialize the allocator */ - void shm_init_allocator(Allocator *alloc) { - if (alloc == nullptr) { - alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); - } else { - alloc_ = alloc; - } - } - - /** Default initialize a data structure's header. */ - void shm_init_header(TYPED_HEADER *header, - Allocator *alloc) { - if (IsValid()) { return; } - shm_init_allocator(alloc); - if (header != nullptr) { - header_ = header; - Allocator::ConstructObj(*header_); - } else { - throw std::runtime_error("Header must be non-null during init of struct"); - } - } - - /** Piecewise initialize a data structure's header. */ - template - void shm_init_header(TYPED_HEADER *header, - Allocator *alloc, - Args&& ...args) { - if (IsValid()) { return; } - shm_init_allocator(alloc); - if (header == nullptr) { - throw std::runtime_error("Header must be non-null during init of struct"); - } - header_ = header; - Allocator::ConstructObj( - *header_, - alloc_, std::forward(args)...); - // TODO(llogan): pass headers to each container? - } - - /**==================================== - * Serialization - * ===================================*/ - - /** Serialize into a Pointer */ - void shm_serialize(TypedPointer &ar) const { - ar = GetAllocator()->template - Convert(header_); - shm_serialize_main(); - } - - /** Serialize into an AtomicPointer */ - void shm_serialize(TypedAtomicPointer &ar) const { - ar = GetAllocator()->template - Convert(header_); - shm_serialize_main(); - } - - /** Override << operators */ - SHM_SERIALIZE_OPS((TYPED_CLASS)) - - /**==================================== - * Deserialization - * ===================================*/ - - /** Deserialize object from a raw pointer */ - bool shm_deserialize(const TypedPointer &ar) { - return shm_deserialize( - HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_), - ar.ToOffsetPointer() - ); - } - - /** Deserialize object from allocator + offset */ - bool shm_deserialize(Allocator *alloc, OffsetPointer header_ptr) { - if (header_ptr.IsNull()) { return false; } - return shm_deserialize(alloc, - alloc->Convert< - TYPED_HEADER, - OffsetPointer>(header_ptr)); - } - - /** Deserialize object from another object (weak copy) */ - bool shm_deserialize(const CLASS_NAME &other) { - if (other.IsNull()) { return false; } - return shm_deserialize(other.GetAllocator(), other.header_); - } - - /** Deserialize object from allocator + header */ - bool shm_deserialize(Allocator *alloc, - TYPED_HEADER *header) { - /*alloc_ = alloc; - header_ = header; - hermes_shm::ForwardIterateTuple::Apply( - objs_, - [this, alloc](size_t i, auto &obj_) constexpr { - if constexpr(IS_SHM_ARCHIVEABLE(decltype(obj_))) { - obj_->shm_deserialize(alloc, this->header_->template Get()); - } - } - ); - shm_deserialize_main(); - return true;*/ - } - - /** Constructor. Deserialize the object from the reference. */ - template - void shm_init(lipc::ShmRef &obj) { - shm_deserialize(obj->GetAllocator(), obj->header_); - } - - /** Override >> operators */ - SHM_DESERIALIZE_OPS ((TYPED_CLASS)) - - /**==================================== - * Destructors - * ===================================*/ - - /** Destructor */ - ~CLASS_NAME() { - shm_destroy(true); - } - - /** Shm Destructor */ - void shm_destroy(bool destroy_header = true) { - /*hermes_shm::ReverseIterateTuple::Apply( - objs_, - [destroy_header](size_t i, auto &obj_) constexpr { - if constexpr(IS_SHM_ARCHIVEABLE(decltype(obj_))) { - obj_.shm_destroy(destroy_header); - } - } - );*/ - } - - /**==================================== - * Move Operations - * ===================================*/ - - /** Move constructor */ - CLASS_NAME(CLASS_NAME &&other) noexcept { - shm_weak_move( - typed_nullptr(), - typed_nullptr(), - other); - } - - /** Move assignment operator */ - CLASS_NAME& operator=(CLASS_NAME &&other) noexcept { - shm_weak_move( - typed_nullptr(), - typed_nullptr(), - other); - return *this; - } - - /** Move shm_init constructor */ - void shm_init_main(TYPED_HEADER *header, - lipc::Allocator *alloc, - CLASS_NAME &&other) noexcept { - shm_weak_move(header, alloc, other); - } - - /** Move operation */ - void shm_weak_move(TYPED_HEADER *header, - lipc::Allocator *alloc, - CLASS_NAME &other) { - /*hermes_shm::ForwardIterateTuple::Apply( - objs_, - [header, alloc, other](size_t i, auto &obj_) constexpr { - if constexpr(IS_SHM_ARCHIVEABLE(decltype(obj_))) { - obj_.shm_weak_move(header, alloc, other.objs_.template Get()); - } else { - obj_ = std::move(other.objs_.template Get()); - } - } - );*/ - } - - /**==================================== - * Copy Operations - * ===================================*/ - - /** Copy constructor */ - CLASS_NAME(const CLASS_NAME &other) noexcept { - shm_init(other); - } - - /** Copy assignment constructor */ - CLASS_NAME &operator=(const CLASS_NAME &other) { - if (this != &other) { - shm_strong_copy( - typed_nullptr(), - typed_nullptr(), - other); - } - return *this; - } - - /** Copy shm_init constructor */ - void shm_init_main(TYPED_HEADER *header, - lipc::Allocator *alloc, - const CLASS_NAME &other) { - shm_strong_copy(header, alloc, other); - } - - /** Strong Copy operation */ - void shm_strong_copy(TYPED_HEADER *header, lipc::Allocator *alloc, - const CLASS_NAME &other) { - /*hermes_shm::ForwardIterateTuple::Apply( - objs_, - [header, alloc, other](size_t i, auto &obj_) constexpr { - if constexpr(IS_SHM_ARCHIVEABLE(decltype(obj_))) { - obj_.shm_strong_copy(header, alloc, other.objs_.template Get()); - } else { - obj_ = other.objs_.template Get(); - } - } - ); - shm_strong_copy_main(header, alloc, other);*/ - } - - /**==================================== - * Container Flag Operations - * ===================================*/ - - /** Sets this object as destructable */ - void SetDestructable() { - hermes_shm::ForwardIterateTuple::Apply( - objs_, - [](size_t i, auto &obj_) constexpr { - if constexpr(IS_SHM_ARCHIVEABLE(decltype(obj_))) { - obj_.SetDestructable(); - } - } - ); - } - - /** Sets this object as not destructable */ - void UnsetDestructable() { - hermes_shm::ForwardIterateTuple::Apply( - objs_, - [](size_t i, auto &obj_) constexpr { - if constexpr(IS_SHM_ARCHIVEABLE(decltype(obj_))) { - obj_.UnsetDestructable(); - } - } - ); - } - - /** Check if this container is destructable */ - bool IsDestructable() const { return true; } - - /** Check if container has a valid header */ - bool IsValid() const { return header_ != nullptr; } - - /**==================================== - * Header Flag Operations - * ===================================*/ - - /** Check if null */ - bool IsNull() const { - return IsValid(); - } - - /** Get a typed pointer to the object */ - template - POINTER_T GetShmPointer() const { - return GetAllocator()->template - Convert(header_); - } - - /**==================================== - * Query Operations - * ===================================*/ - - /** Get the allocator for this container */ - Allocator* GetAllocator() { - return alloc_; - } - - /** Get the allocator for this container */ - Allocator* GetAllocator() const { - return alloc_; - } - - /** Get the shared-memory allocator id */ - allocator_id_t GetAllocatorId() const { - return GetAllocator()->GetId(); - } - - /** Get the ith constructed container in the tuple */ - template - auto& Get() { - return objs_.template Get(); - } - - /** Get the ith constructed container in the tuple (const) */ - template - auto& Get() const { - return objs_.template Get(); - } -}; - -} // namespace hermes_shm::ipc - -#undef CLASS_NAME -#undef TYPED_CLASS -#undef TYPED_HEADER - -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_STRUCT_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h index 8695151a2..297fbff72 100644 --- a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ #define HERMES_SHM_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h index b6dd0f427..b309921a2 100644 --- a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_DATA_STRUCTURES_UNORDERED_MAP_H_ #define HERMES_SHM_DATA_STRUCTURES_UNORDERED_MAP_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h index 1817e4afe..6dbb05181 100644 --- a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ #define HERMES_SHM_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ diff --git a/hermes_shm/include/hermes_shm/introspect/system_info.h b/hermes_shm/include/hermes_shm/introspect/system_info.h index 6d73dbdae..6e1d86a14 100644 --- a/hermes_shm/include/hermes_shm/introspect/system_info.h +++ b/hermes_shm/include/hermes_shm/introspect/system_info.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_SYSINFO_INFO_H_ #define HERMES_SHM_SYSINFO_INFO_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/allocator.h index 5e60747ec..8adb8de1b 100644 --- a/hermes_shm/include/hermes_shm/memory/allocator/allocator.h +++ b/hermes_shm/include/hermes_shm/memory/allocator/allocator.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_H_ #define HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h b/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h index 59e18ab7a..f14da3ca4 100644 --- a/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h +++ b/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ #define HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h index 2e8cbb4c0..1413025a2 100644 --- a/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h +++ b/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ #define HERMES_SHM_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h b/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h index b81244792..eed6f96c0 100644 --- a/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h +++ b/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/27/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MP_PAGE_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MP_PAGE_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/multi_page_allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/multi_page_allocator.h index db7bfda09..b85cf2b9e 100644 --- a/hermes_shm/include/hermes_shm/memory/allocator/multi_page_allocator.h +++ b/hermes_shm/include/hermes_shm/memory/allocator/multi_page_allocator.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/25/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MULTI_PAGE_ALLOCATOR_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MULTI_PAGE_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h index 0db83ee02..2f4717623 100644 --- a/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h +++ b/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ #define HERMES_SHM_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/array_backend.h b/hermes_shm/include/hermes_shm/memory/backend/array_backend.h index d3158cd4d..3e14b9831 100644 --- a/hermes_shm/include/hermes_shm/memory/backend/array_backend.h +++ b/hermes_shm/include/hermes_shm/memory/backend/array_backend.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/12/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_ARRAY_BACKEND_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_ARRAY_BACKEND_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h b/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h index 28e900a83..b96f59872 100644 --- a/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h +++ b/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_MEMORY_H #define HERMES_SHM_MEMORY_H diff --git a/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h b/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h index 28ad2fc7b..0332502c1 100644 --- a/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h +++ b/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ #define HERMES_SHM_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/null_backend.h b/hermes_shm/include/hermes_shm/memory/backend/null_backend.h index 66d30627f..33b17329c 100644 --- a/hermes_shm/include/hermes_shm/memory/backend/null_backend.h +++ b/hermes_shm/include/hermes_shm/memory/backend/null_backend.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/10/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_NULL_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_NULL_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h b/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h index 7ba26b54a..6840cdbc4 100644 --- a/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h +++ b/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H #define HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H diff --git a/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h b/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h index 37a0233be..43f16e10c 100644 --- a/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h +++ b/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H #define HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H diff --git a/hermes_shm/include/hermes_shm/memory/memory.h b/hermes_shm/include/hermes_shm/memory/memory.h index eac2863f5..35e6ba87d 100644 --- a/hermes_shm/include/hermes_shm/memory/memory.h +++ b/hermes_shm/include/hermes_shm/memory/memory.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_MEMORY_MEMORY_H_ #define HERMES_SHM_MEMORY_MEMORY_H_ diff --git a/hermes_shm/include/hermes_shm/memory/memory_manager.h b/hermes_shm/include/hermes_shm/memory/memory_manager.h index 584424be8..29990d85c 100644 --- a/hermes_shm/include/hermes_shm/memory/memory_manager.h +++ b/hermes_shm/include/hermes_shm/memory/memory_manager.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_MEMORY_MEMORY_MANAGER_H_ #define HERMES_SHM_MEMORY_MEMORY_MANAGER_H_ diff --git a/hermes_shm/include/hermes_shm/thread/lock.h b/hermes_shm/include/hermes_shm/thread/lock.h index 2cb35e4da..61cdfb36f 100644 --- a/hermes_shm/include/hermes_shm/thread/lock.h +++ b/hermes_shm/include/hermes_shm/thread/lock.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_THREAD_LOCK_H_ #define HERMES_SHM_THREAD_LOCK_H_ diff --git a/hermes_shm/include/hermes_shm/thread/lock/mutex.h b/hermes_shm/include/hermes_shm/thread/lock/mutex.h index c5e20aab5..4902d5052 100644 --- a/hermes_shm/include/hermes_shm/thread/lock/mutex.h +++ b/hermes_shm/include/hermes_shm/thread/lock/mutex.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_THREAD_MUTEX_H_ #define HERMES_SHM_THREAD_MUTEX_H_ diff --git a/hermes_shm/include/hermes_shm/thread/lock/rwlock.h b/hermes_shm/include/hermes_shm/thread/lock/rwlock.h index d37330623..c7bee4e49 100644 --- a/hermes_shm/include/hermes_shm/thread/lock/rwlock.h +++ b/hermes_shm/include/hermes_shm/thread/lock/rwlock.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_THREAD_RWLOCK_H_ #define HERMES_SHM_THREAD_RWLOCK_H_ diff --git a/hermes_shm/include/hermes_shm/thread/pthread.h b/hermes_shm/include/hermes_shm/thread/pthread.h index 652de4813..65d894359 100644 --- a/hermes_shm/include/hermes_shm/thread/pthread.h +++ b/hermes_shm/include/hermes_shm/thread/pthread.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_THREAD_PTHREAD_H_ #define HERMES_SHM_THREAD_PTHREAD_H_ diff --git a/hermes_shm/include/hermes_shm/thread/thread.h b/hermes_shm/include/hermes_shm/thread/thread.h index a6af0cf5e..cdf12cfda 100644 --- a/hermes_shm/include/hermes_shm/thread/thread.h +++ b/hermes_shm/include/hermes_shm/thread/thread.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_THREAD_THREAD_H_ #define HERMES_SHM_THREAD_THREAD_H_ diff --git a/hermes_shm/include/hermes_shm/thread/thread_factory.h b/hermes_shm/include/hermes_shm/thread/thread_factory.h index 469001b16..c10356c99 100644 --- a/hermes_shm/include/hermes_shm/thread/thread_factory.h +++ b/hermes_shm/include/hermes_shm/thread/thread_factory.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_THREAD_THREAD_FACTORY_H_ #define HERMES_SHM_THREAD_THREAD_FACTORY_H_ diff --git a/hermes_shm/include/hermes_shm/thread/thread_manager.h b/hermes_shm/include/hermes_shm/thread/thread_manager.h index e2e92c87c..93bdd9660 100644 --- a/hermes_shm/include/hermes_shm/thread/thread_manager.h +++ b/hermes_shm/include/hermes_shm/thread/thread_manager.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_THREAD_THREAD_MANAGER_H_ #define HERMES_SHM_THREAD_THREAD_MANAGER_H_ diff --git a/hermes_shm/include/hermes_shm/types/argpack.h b/hermes_shm/include/hermes_shm/types/argpack.h index 821be69cd..9205b73ed 100644 --- a/hermes_shm/include/hermes_shm/types/argpack.h +++ b/hermes_shm/include/hermes_shm/types/argpack.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/28/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ARGPACK_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ARGPACK_H_ diff --git a/hermes_shm/include/hermes_shm/types/atomic.h b/hermes_shm/include/hermes_shm/types/atomic.h index c02ac0b41..f39b00eb7 100644 --- a/hermes_shm/include/hermes_shm/types/atomic.h +++ b/hermes_shm/include/hermes_shm/types/atomic.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/13/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ATOMIC_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ATOMIC_H_ diff --git a/hermes_shm/include/hermes_shm/types/basic.h b/hermes_shm/include/hermes_shm/types/basic.h index e1a8f0d89..bd02abe18 100644 --- a/hermes_shm/include/hermes_shm/types/basic.h +++ b/hermes_shm/include/hermes_shm/types/basic.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_BASICS_H #define HERMES_SHM_BASICS_H diff --git a/hermes_shm/include/hermes_shm/types/bitfield.h b/hermes_shm/include/hermes_shm/types/bitfield.h index 073f4482a..b0a5346a7 100644 --- a/hermes_shm/include/hermes_shm/types/bitfield.h +++ b/hermes_shm/include/hermes_shm/types/bitfield.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/1/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_BITFIELD_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_BITFIELD_H_ diff --git a/hermes_shm/include/hermes_shm/types/charbuf.h b/hermes_shm/include/hermes_shm/types/charbuf.h index 24d60019e..741ab6537 100644 --- a/hermes_shm/include/hermes_shm/types/charbuf.h +++ b/hermes_shm/include/hermes_shm/types/charbuf.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/31/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_CHARBUF_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_CHARBUF_H_ diff --git a/hermes_shm/include/hermes_shm/types/messages.h b/hermes_shm/include/hermes_shm/types/messages.h index 4b09541c0..11b87e230 100644 --- a/hermes_shm/include/hermes_shm/types/messages.h +++ b/hermes_shm/include/hermes_shm/types/messages.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_MESSAGES_H #define HERMES_SHM_MESSAGES_H diff --git a/hermes_shm/include/hermes_shm/types/tuple_base.h b/hermes_shm/include/hermes_shm/types/tuple_base.h index 81696ce93..c24aeca93 100644 --- a/hermes_shm/include/hermes_shm/types/tuple_base.h +++ b/hermes_shm/include/hermes_shm/types/tuple_base.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/26/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_TupleBase_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_TupleBase_H_ diff --git a/hermes_shm/include/hermes_shm/util/auto_trace.h b/hermes_shm/include/hermes_shm/util/auto_trace.h index 4fa65171e..614bc3085 100644 --- a/hermes_shm/include/hermes_shm/util/auto_trace.h +++ b/hermes_shm/include/hermes_shm/util/auto_trace.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/11/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_INCLUDE_HERMES_SHM_UTIL_AUTO_TRACE_H_ #define HERMES_SHM_INCLUDE_HERMES_SHM_UTIL_AUTO_TRACE_H_ diff --git a/hermes_shm/include/hermes_shm/util/debug.h b/hermes_shm/include/hermes_shm/util/debug.h index b43469fda..68bf7e504 100644 --- a/hermes_shm/include/hermes_shm/util/debug.h +++ b/hermes_shm/include/hermes_shm/util/debug.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_DEBUG_H #define HERMES_SHM_DEBUG_H diff --git a/hermes_shm/include/hermes_shm/util/error.h b/hermes_shm/include/hermes_shm/util/error.h index 2c65ab2aa..027bbfbff 100644 --- a/hermes_shm/include/hermes_shm/util/error.h +++ b/hermes_shm/include/hermes_shm/util/error.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_ERROR_H #define HERMES_SHM_ERROR_H diff --git a/hermes_shm/include/hermes_shm/util/errors.h b/hermes_shm/include/hermes_shm/util/errors.h index 18fc46c9d..9ae0e6f8f 100644 --- a/hermes_shm/include/hermes_shm/util/errors.h +++ b/hermes_shm/include/hermes_shm/util/errors.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_ERRORS_H #define HERMES_SHM_ERRORS_H diff --git a/hermes_shm/include/hermes_shm/util/formatter.h b/hermes_shm/include/hermes_shm/util/formatter.h index 3733fa6bd..a5b9c7d8d 100644 --- a/hermes_shm/include/hermes_shm/util/formatter.h +++ b/hermes_shm/include/hermes_shm/util/formatter.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_ERROR_SERIALIZER_H #define HERMES_SHM_ERROR_SERIALIZER_H diff --git a/hermes_shm/include/hermes_shm/util/partitioner.h b/hermes_shm/include/hermes_shm/util/partitioner.h index 3485a4b3c..e1122cd06 100644 --- a/hermes_shm/include/hermes_shm/util/partitioner.h +++ b/hermes_shm/include/hermes_shm/util/partitioner.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_PARTITIONER_H #define HERMES_SHM_PARTITIONER_H diff --git a/hermes_shm/include/hermes_shm/util/path_parser.h b/hermes_shm/include/hermes_shm/util/path_parser.h index 0e5df9fd6..eaff1531f 100644 --- a/hermes_shm/include/hermes_shm/util/path_parser.h +++ b/hermes_shm/include/hermes_shm/util/path_parser.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_PATH_PARSER_H #define HERMES_SHM_PATH_PARSER_H diff --git a/hermes_shm/include/hermes_shm/util/singleton.h b/hermes_shm/include/hermes_shm/util/singleton.h index 8c5e32e54..bbfb063fe 100644 --- a/hermes_shm/include/hermes_shm/util/singleton.h +++ b/hermes_shm/include/hermes_shm/util/singleton.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef SCS_SINGLETON_H #define SCS_SINGLETON_H diff --git a/hermes_shm/include/hermes_shm/util/timer.h b/hermes_shm/include/hermes_shm/util/timer.h index 810aea91b..3561c5d18 100644 --- a/hermes_shm/include/hermes_shm/util/timer.h +++ b/hermes_shm/include/hermes_shm/util/timer.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_TIMER_H #define HERMES_SHM_TIMER_H diff --git a/hermes_shm/src/data_structure_singleton.cc b/hermes_shm/src/data_structure_singleton.cc index 89f6b5fcb..309f96b0c 100644 --- a/hermes_shm/src/data_structure_singleton.cc +++ b/hermes_shm/src/data_structure_singleton.cc @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include #include #include diff --git a/hermes_shm/src/memory/malloc_allocator.cc b/hermes_shm/src/memory/malloc_allocator.cc index 4473d6c81..313e5c5d2 100644 --- a/hermes_shm/src/memory/malloc_allocator.cc +++ b/hermes_shm/src/memory/malloc_allocator.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include diff --git a/hermes_shm/src/memory/memory_intercept.cc b/hermes_shm/src/memory/memory_intercept.cc index cb13475c0..c8109e4fc 100644 --- a/hermes_shm/src/memory/memory_intercept.cc +++ b/hermes_shm/src/memory/memory_intercept.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/21/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include diff --git a/hermes_shm/src/memory/memory_intercept.h b/hermes_shm/src/memory/memory_intercept.h index 51ec48a09..6c86ac713 100644 --- a/hermes_shm/src/memory/memory_intercept.h +++ b/hermes_shm/src/memory/memory_intercept.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/21/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_SRC_MEMORY_MEMORY_INTERCEPT_H_ #define HERMES_SHM_SRC_MEMORY_MEMORY_INTERCEPT_H_ diff --git a/hermes_shm/src/memory/memory_manager.cc b/hermes_shm/src/memory/memory_manager.cc index 1fe868d54..2ce79e735 100644 --- a/hermes_shm/src/memory/memory_manager.cc +++ b/hermes_shm/src/memory/memory_manager.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "hermes_shm/memory/backend/memory_backend_factory.h" diff --git a/hermes_shm/src/memory/multi_page_allocator.cc b/hermes_shm/src/memory/multi_page_allocator.cc index eeb0f2396..2d04be254 100644 --- a/hermes_shm/src/memory/multi_page_allocator.cc +++ b/hermes_shm/src/memory/multi_page_allocator.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 12/25/22. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "hermes_shm/memory/allocator/multi_page_allocator.h" @@ -101,4 +109,4 @@ size_t MultiPageAllocator::GetCurrentlyAllocatedSize() { return 0; } -} // namespace hermes_shm::ipc \ No newline at end of file +} // namespace hermes_shm::ipc diff --git a/hermes_shm/src/memory/stack_allocator.cc b/hermes_shm/src/memory/stack_allocator.cc index 36362c174..622323187 100644 --- a/hermes_shm/src/memory/stack_allocator.cc +++ b/hermes_shm/src/memory/stack_allocator.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include diff --git a/hermes_shm/src/thread/mutex.cc b/hermes_shm/src/thread/mutex.cc index af620fd25..4f0ef3b60 100644 --- a/hermes_shm/src/thread/mutex.cc +++ b/hermes_shm/src/thread/mutex.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "hermes_shm/thread/lock.h" #include "hermes_shm/thread/thread_manager.h" diff --git a/hermes_shm/src/thread/rwlock.cc b/hermes_shm/src/thread/rwlock.cc index 2b202d035..5554d7c4a 100644 --- a/hermes_shm/src/thread/rwlock.cc +++ b/hermes_shm/src/thread/rwlock.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "hermes_shm/thread/lock/rwlock.h" #include "hermes_shm/thread/thread_manager.h" diff --git a/hermes_shm/test/unit/allocators/allocator.cc b/hermes_shm/test/unit/allocators/allocator.cc index 941736340..a1c65a2d3 100644 --- a/hermes_shm/test/unit/allocators/allocator.cc +++ b/hermes_shm/test/unit/allocators/allocator.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "test_init.h" #include "hermes_shm/memory/allocator/stack_allocator.h" @@ -147,4 +133,4 @@ TEST_CASE("MallocAllocator") { REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); Posttest(); -} \ No newline at end of file +} diff --git a/hermes_shm/test/unit/allocators/allocator_thread.cc b/hermes_shm/test/unit/allocators/allocator_thread.cc index 8900e42d0..d2e7e6cb5 100644 --- a/hermes_shm/test/unit/allocators/allocator_thread.cc +++ b/hermes_shm/test/unit/allocators/allocator_thread.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "test_init.h" diff --git a/hermes_shm/test/unit/allocators/test_init.cc b/hermes_shm/test/unit/allocators/test_init.cc index 54fac303e..4b0042a82 100644 --- a/hermes_shm/test/unit/allocators/test_init.cc +++ b/hermes_shm/test/unit/allocators/test_init.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "test_init.h" diff --git a/hermes_shm/test/unit/allocators/test_init.h b/hermes_shm/test/unit/allocators/test_init.h index b0c862950..53e532efd 100644 --- a/hermes_shm/test/unit/allocators/test_init.h +++ b/hermes_shm/test/unit/allocators/test_init.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ #define HERMES_SHM_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ diff --git a/hermes_shm/test/unit/basic_test.h b/hermes_shm/test/unit/basic_test.h index e9b934b7f..e249ed22d 100644 --- a/hermes_shm/test/unit/basic_test.h +++ b/hermes_shm/test/unit/basic_test.h @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ #define HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ diff --git a/hermes_shm/test/unit/data_structures/backend/backend.cc b/hermes_shm/test/unit/data_structures/backend/backend.cc index b23d7e31b..fa7b8a53a 100644 --- a/hermes_shm/test/unit/data_structures/backend/backend.cc +++ b/hermes_shm/test/unit/data_structures/backend/backend.cc @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" diff --git a/hermes_shm/test/unit/data_structures/backend/memory_manager.cc b/hermes_shm/test/unit/data_structures/backend/memory_manager.cc index 39cdfb4ce..63f9e1f00 100644 --- a/hermes_shm/test/unit/data_structures/backend/memory_manager.cc +++ b/hermes_shm/test/unit/data_structures/backend/memory_manager.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" diff --git a/hermes_shm/test/unit/data_structures/backend/memory_slots.cc b/hermes_shm/test/unit/data_structures/backend/memory_slots.cc index 9e574c900..f5df1a526 100644 --- a/hermes_shm/test/unit/data_structures/backend/memory_slots.cc +++ b/hermes_shm/test/unit/data_structures/backend/memory_slots.cc @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" diff --git a/hermes_shm/test/unit/data_structures/backend/test_init.cc b/hermes_shm/test/unit/data_structures/backend/test_init.cc index cb402e14b..7590f5764 100644 --- a/hermes_shm/test/unit/data_structures/backend/test_init.cc +++ b/hermes_shm/test/unit/data_structures/backend/test_init.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" diff --git a/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt b/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt index f14f20020..6b6cda3a6 100644 --- a/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt +++ b/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt @@ -8,7 +8,6 @@ add_executable(test_data_structure_exec test_init.cc string.cc pair.cc - tuple.cc list.cc vector.cc manual_ptr.cc diff --git a/hermes_shm/test/unit/data_structures/containers/list.cc b/hermes_shm/test/unit/data_structures/containers/list.cc index f766ae673..365138a44 100644 --- a/hermes_shm/test/unit/data_structures/containers/list.cc +++ b/hermes_shm/test/unit/data_structures/containers/list.cc @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include "test_init.h" @@ -70,4 +57,4 @@ TEST_CASE("ListOfStdString") { REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); ListTest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); -} \ No newline at end of file +} diff --git a/hermes_shm/test/unit/data_structures/containers/list.h b/hermes_shm/test/unit/data_structures/containers/list.h index af7743059..82df721a4 100644 --- a/hermes_shm/test/unit/data_structures/containers/list.h +++ b/hermes_shm/test/unit/data_structures/containers/list.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/10/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ #define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ diff --git a/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc b/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc index a3759d364..8ce61ef1f 100644 --- a/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc +++ b/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "hermes_shm/data_structures/smart_ptr/manual_ptr.h" #include "basic_test.h" diff --git a/hermes_shm/test/unit/data_structures/containers/pair.cc b/hermes_shm/test/unit/data_structures/containers/pair.cc index 591b8db7b..19a6fd29c 100644 --- a/hermes_shm/test/unit/data_structures/containers/pair.cc +++ b/hermes_shm/test/unit/data_structures/containers/pair.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/15/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include "test_init.h" @@ -53,4 +61,4 @@ TEST_CASE("PairOfIntString") { REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); PairTest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); -} \ No newline at end of file +} diff --git a/hermes_shm/test/unit/data_structures/containers/slist.cc b/hermes_shm/test/unit/data_structures/containers/slist.cc index d101ef18f..a2135bafc 100644 --- a/hermes_shm/test/unit/data_structures/containers/slist.cc +++ b/hermes_shm/test/unit/data_structures/containers/slist.cc @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include "test_init.h" @@ -69,4 +56,4 @@ TEST_CASE("SListOfStdString") { REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); SListTest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); -} \ No newline at end of file +} diff --git a/hermes_shm/test/unit/data_structures/containers/smart_ptr.h b/hermes_shm/test/unit/data_structures/containers/smart_ptr.h index 3e45ddacf..3f56ed4a8 100644 --- a/hermes_shm/test/unit/data_structures/containers/smart_ptr.h +++ b/hermes_shm/test/unit/data_structures/containers/smart_ptr.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/20/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ #define HERMES_SHM_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ diff --git a/hermes_shm/test/unit/data_structures/containers/string.cc b/hermes_shm/test/unit/data_structures/containers/string.cc index d3dabe686..104c198ea 100644 --- a/hermes_shm/test/unit/data_structures/containers/string.cc +++ b/hermes_shm/test/unit/data_structures/containers/string.cc @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include "test_init.h" diff --git a/hermes_shm/test/unit/data_structures/containers/test_init.cc b/hermes_shm/test/unit/data_structures/containers/test_init.cc index 4e2b0b5a8..567cf42da 100644 --- a/hermes_shm/test/unit/data_structures/containers/test_init.cc +++ b/hermes_shm/test/unit/data_structures/containers/test_init.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include "test_init.h" diff --git a/hermes_shm/test/unit/data_structures/containers/test_init.h b/hermes_shm/test/unit/data_structures/containers/test_init.h index 1dd6b3370..041560218 100644 --- a/hermes_shm/test/unit/data_structures/containers/test_init.h +++ b/hermes_shm/test/unit/data_structures/containers/test_init.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ #define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ diff --git a/hermes_shm/test/unit/data_structures/containers/tuple.cc b/hermes_shm/test/unit/data_structures/containers/tuple.cc deleted file mode 100644 index 1a32436b1..000000000 --- a/hermes_shm/test/unit/data_structures/containers/tuple.cc +++ /dev/null @@ -1,75 +0,0 @@ -// -// Created by lukemartinlogan on 1/15/23. -// - -#include "basic_test.h" -#include "test_init.h" -#include "hermes_shm/data_structures/struct.h" -#include "hermes_shm/data_structures/string.h" - -template -void TupleTest() { - Allocator *alloc = alloc_g; - - // Construct test - { - CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); - CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); - lipc::ShmHeader> hdr; - lipc::ShmStruct - data(hdr, alloc, - hermes_shm::make_argpack(first), - hermes_shm::make_argpack(second)); - REQUIRE(data.template Get<0>() == first); - REQUIRE(data.template Get<1>() == second); - } - - // Copy test - /*{ - CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); - CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); - lipc::tuple data(alloc, first, second); - lipc::tuple cpy(data); - REQUIRE(cpy.template Get<0>() == first); - REQUIRE(cpy.template Get<1>() == second); - } - - // Move test - { - CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); - CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); - lipc::tuple data(alloc, first, second); - lipc::tuple cpy(std::move(data)); - REQUIRE(cpy.template Get<0>() == first); - REQUIRE(cpy.template Get<1>() == second); - }*/ -} - -#include - -int y() { - return 0; -} - - -class Y { - public: - Y() = default; - Y(int x) {} - Y(int x, int w) {} -}; - -TEST_CASE("TupleOfIntInt") { - Allocator *alloc = alloc_g; - REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); - - TupleTest(); - REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); -} - -TEST_CASE("TupleOfIntString") { - Allocator *alloc = alloc_g; - REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); - // TupleTest(); - REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); -} \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/containers/unordered_map.cc b/hermes_shm/test/unit/data_structures/containers/unordered_map.cc index 34bf137eb..afef50f08 100644 --- a/hermes_shm/test/unit/data_structures/containers/unordered_map.cc +++ b/hermes_shm/test/unit/data_structures/containers/unordered_map.cc @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include "test_init.h" diff --git a/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc b/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc index 3ec56b297..88e6bce50 100644 --- a/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc +++ b/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "omp.h" #include "basic_test.h" diff --git a/hermes_shm/test/unit/data_structures/containers/vector.cc b/hermes_shm/test/unit/data_structures/containers/vector.cc index 9eabe42a0..13a5caf22 100644 --- a/hermes_shm/test/unit/data_structures/containers/vector.cc +++ b/hermes_shm/test/unit/data_structures/containers/vector.cc @@ -1,27 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include "test_init.h" @@ -92,4 +79,3 @@ TEST_CASE("VectorOfListOfString") { VectorOfListOfStringTest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); } - diff --git a/hermes_shm/test/unit/data_structures/containers/vector.h b/hermes_shm/test/unit/data_structures/containers/vector.h index 52f125938..9a1158164 100644 --- a/hermes_shm/test/unit/data_structures/containers/vector.h +++ b/hermes_shm/test/unit/data_structures/containers/vector.h @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/10/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ #define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc b/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc index be92791fe..22be9bc47 100644 --- a/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc +++ b/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/30/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include "test_init.h" @@ -99,4 +107,4 @@ TEST_CASE("VectorOfIntMpi") { TEST_CASE("VectorOfStringMpi") { ListVecTest>(100); -} \ No newline at end of file +} diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc index 92cc361af..e23fcf7d4 100644 --- a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc +++ b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include "test_init.h" diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h index 6419e28e7..77a20a365 100644 --- a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h +++ b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ #define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ diff --git a/hermes_shm/test/unit/data_structures/lock/lock.cc b/hermes_shm/test/unit/data_structures/lock/lock.cc index f9e8e23ea..db6b9204a 100644 --- a/hermes_shm/test/unit/data_structures/lock/lock.cc +++ b/hermes_shm/test/unit/data_structures/lock/lock.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include "omp.h" diff --git a/hermes_shm/test/unit/data_structures/lock/test_init.cc b/hermes_shm/test/unit/data_structures/lock/test_init.cc index cb402e14b..7590f5764 100644 --- a/hermes_shm/test/unit/data_structures/lock/test_init.cc +++ b/hermes_shm/test/unit/data_structures/lock/test_init.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" diff --git a/hermes_shm/test/unit/main.cc b/hermes_shm/test/unit/main.cc index a0ea64a53..da1e76728 100644 --- a/hermes_shm/test/unit/main.cc +++ b/hermes_shm/test/unit/main.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include diff --git a/hermes_shm/test/unit/main_mpi.cc b/hermes_shm/test/unit/main_mpi.cc index 944123734..c34f81eca 100644 --- a/hermes_shm/test/unit/main_mpi.cc +++ b/hermes_shm/test/unit/main_mpi.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include diff --git a/hermes_shm/test/unit/types/test_argpack.cc b/hermes_shm/test/unit/types/test_argpack.cc index cac27bb4e..5a38f72fd 100644 --- a/hermes_shm/test/unit/types/test_argpack.cc +++ b/hermes_shm/test/unit/types/test_argpack.cc @@ -1,6 +1,14 @@ -// -// Created by lukemartinlogan on 1/26/23. -// +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" #include @@ -169,4 +177,4 @@ void test_argpack3() { TEST_CASE("TestArgpack") { test_argpack0(); test_argpack3(); -} \ No newline at end of file +} diff --git a/hermes_shm/test/unit/types/test_init.cc b/hermes_shm/test/unit/types/test_init.cc index cb402e14b..7590f5764 100644 --- a/hermes_shm/test/unit/types/test_init.cc +++ b/hermes_shm/test/unit/types/test_init.cc @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2022 SCS Lab , - * Luke Logan , - * Jaime Cernuda Garcia - * Jay Lofstead , - * Anthony Kougkas , - * Xian-He Sun - * - * This file is part of HermesShm - * - * HermesShm 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 Lesser 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 - * . - */ - +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "basic_test.h" diff --git a/src/api/hermes_singleton.cc b/src/api/hermes_singleton.cc index 481517830..1326ed620 100644 --- a/src/api/hermes_singleton.cc +++ b/src/api/hermes_singleton.cc @@ -20,4 +20,4 @@ void Finalize() { HERMES->Finalize(); } -void __attribute__((destructor)) Finalize(); \ No newline at end of file +void __attribute__((destructor)) Finalize(); diff --git a/src/config_client_default.h b/src/config_client_default.h index 5ac8b8081..0e0873c5b 100644 --- a/src/config_client_default.h +++ b/src/config_client_default.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ #define HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ const char* kClientDefaultConfigStr = @@ -10,4 +22,4 @@ const char* kClientDefaultConfigStr = " - path: \"/\"\n" " page_size: 1MB\n" " mode: kDefault\n"; -#endif // HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ \ No newline at end of file +#endif // HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ diff --git a/src/config_server_default.h b/src/config_server_default.h index d19b4a203..9aad5ae0f 100644 --- a/src/config_server_default.h +++ b/src/config_server_default.h @@ -1,3 +1,15 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ #define HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ const char* kServerDefaultConfigStr = @@ -133,4 +145,4 @@ const char* kServerDefaultConfigStr = "\n" "# The interval in milliseconds at which to update the global system view.\n" "system_view_state_update_interval_ms: 1000\n"; -#endif // HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ \ No newline at end of file +#endif // HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ From 9fb284190bfee5189cd13da8b930f0a2470fa85a Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 09:19:38 -0600 Subject: [PATCH 138/511] Remove slist --- .../unit/data_structures/containers/slist.cc | 59 ------------------- 1 file changed, 59 deletions(-) delete mode 100644 hermes_shm/test/unit/data_structures/containers/slist.cc diff --git a/hermes_shm/test/unit/data_structures/containers/slist.cc b/hermes_shm/test/unit/data_structures/containers/slist.cc deleted file mode 100644 index a2135bafc..000000000 --- a/hermes_shm/test/unit/data_structures/containers/slist.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "basic_test.h" -#include "test_init.h" -#include "list.h" -#include "hermes_shm/data_structures/thread_unsafe/slist.h" -#include "hermes_shm/data_structures/string.h" -#include "hermes_shm/memory/allocator/stack_allocator.h" - -using hermes_shm::ipc::slist; - -template -void SListTest() { - Allocator *alloc = alloc_g; - slist lp(alloc); - ListTestSuite> test(lp, alloc); - - test.EmplaceTest(30); - test.ForwardIteratorTest(); - test.CopyConstructorTest(); - test.CopyAssignmentTest(); - test.MoveConstructorTest(); - test.MoveAssignmentTest(); - test.EmplaceFrontTest(); - test.ModifyEntryCopyIntoTest(); - test.ModifyEntryMoveIntoTest(); - test.EraseTest(); -} - -TEST_CASE("SListOfInt") { - Allocator *alloc = alloc_g; - REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); - SListTest(); - REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); -} - -TEST_CASE("SListOfString") { - Allocator *alloc = alloc_g; - REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); - SListTest(); - REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); -} - -TEST_CASE("SListOfStdString") { - Allocator *alloc = alloc_g; - REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); - SListTest(); - REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); -} From 732b3377ec6ad802c6548748e93b436ad8e50e5b Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 09:20:53 -0600 Subject: [PATCH 139/511] Disable data structure unit tests --- hermes_shm/CMakeLists.txt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/hermes_shm/CMakeLists.txt b/hermes_shm/CMakeLists.txt index 2fe0d0424..31484fb5f 100644 --- a/hermes_shm/CMakeLists.txt +++ b/hermes_shm/CMakeLists.txt @@ -7,9 +7,10 @@ include_directories(${CMAKE_SOURCE_DIR}/include) ###################OPTIONS option(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" ON) -option(BUILD_MPI_TESTS "Build tests which depend on MPI" ON) -option(BUILD_OpenMP_TESTS "Build tests which depend on OpenMP" ON) -option(BUILD_Boost_TESTS "Build tests which depend on libboost" ON) +option(BUILD_TESTS "Wether or not to build unit tests" OFF) +option(BUILD_MPI_TESTS "Build tests which depend on MPI" OFF) +option(BUILD_OpenMP_TESTS "Build tests which depend on OpenMP" OFF) +option(BUILD_Boost_TESTS "Build tests which depend on libboost" OFF) ##################CMAKE MODULES set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake) @@ -56,5 +57,7 @@ add_subdirectory(src) ##################MODULES & TESTS set(TEST_MAIN ${CMAKE_SOURCE_DIR}/test/unit) -enable_testing() -add_subdirectory(test) \ No newline at end of file +if (BUILD_TESTS) + enable_testing() + add_subdirectory(test) +endif() \ No newline at end of file From 39b5a4a2a32e38e54c561dbbca8763f8e9a39eea Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 09:32:18 -0600 Subject: [PATCH 140/511] Fix lint issues --- adapter/adapter_types.h | 4 ++-- adapter/mpiio/mpiio_api.cc | 2 +- adapter/mpiio/mpiio_fs_api.h | 3 ++- adapter/mpiio/mpiio_io_client.cc | 6 ++++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/adapter/adapter_types.h b/adapter/adapter_types.h index bea038c3a..9694be15d 100644 --- a/adapter/adapter_types.h +++ b/adapter/adapter_types.h @@ -46,7 +46,7 @@ struct AdapterObjectConfig { class AdapterModeConv { public: static std::string str(AdapterMode mode) { - switch(mode) { + switch (mode) { case AdapterMode::kDefault: { return "AdapterMode::kDefault"; } @@ -77,6 +77,6 @@ class AdapterModeConv { }; -} // namespace hermes +} // namespace hermes::adapter #endif // HERMES_ADAPTER_ADAPTER_TYPES_H_ diff --git a/adapter/mpiio/mpiio_api.cc b/adapter/mpiio/mpiio_api.cc index e1eb6c305..32e65b3c6 100644 --- a/adapter/mpiio/mpiio_api.cc +++ b/adapter/mpiio/mpiio_api.cc @@ -229,7 +229,7 @@ int HERMES_DECL(MPI_File_write_at_all)(MPI_File fh, MPI_Offset offset, auto fs_api = HERMES_MPIIO_FS; if (fs_api->IsMpiFpTracked(&fh)) { File f; f.hermes_mpi_fh_ = fh; - return fs_api->WriteAll(f, stat_exists, buf, + return fs_api->WriteAll(f, stat_exists, buf, offset, count, datatype, status); } return real_api->MPI_File_write_at_all(fh, offset, buf, count, datatype, diff --git a/adapter/mpiio/mpiio_fs_api.h b/adapter/mpiio/mpiio_fs_api.h index 14da4dc4f..90655f12d 100644 --- a/adapter/mpiio/mpiio_fs_api.h +++ b/adapter/mpiio/mpiio_fs_api.h @@ -134,7 +134,8 @@ class MpiioFs : public Filesystem { } int WriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, - MPI_Datatype datatype, MPI_Status *status, FsIoOptions opts) { + MPI_Datatype datatype, + MPI_Status *status, FsIoOptions opts) { opts.mpi_type_ = datatype; int total; MPI_Scan(&count, &total, 1, MPI_INT, MPI_SUM, stat.comm_); diff --git a/adapter/mpiio/mpiio_io_client.cc b/adapter/mpiio/mpiio_io_client.cc index ff8b625e8..61fb66d42 100644 --- a/adapter/mpiio/mpiio_io_client.cc +++ b/adapter/mpiio/mpiio_io_client.cc @@ -96,7 +96,8 @@ void MpiioIoClient::WriteBlob(const lipc::charbuf &bkt_name, MPI_File fh; int write_count = 0; status.mpi_ret_ = real_api->MPI_File_open(MPI_COMM_SELF, filename.c_str(), - MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); + MPI_MODE_RDONLY, + MPI_INFO_NULL, &fh); if (status.mpi_ret_ != MPI_SUCCESS) { return; } @@ -139,7 +140,8 @@ void MpiioIoClient::ReadBlob(const lipc::charbuf &bkt_name, MPI_File fh; int read_count = 0; status.mpi_ret_ = real_api->MPI_File_open(MPI_COMM_SELF, filename.c_str(), - MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); + MPI_MODE_RDONLY, MPI_INFO_NULL, + &fh); if (status.mpi_ret_ != MPI_SUCCESS) { return; } From fc4401ff6878c96126ba9f87d3bd322122ceec85 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 09:42:42 -0600 Subject: [PATCH 141/511] Add /tmp to included --- adapter/filesystem/filesystem.cc | 1 + adapter/test/data/hermes_client.yaml | 2 +- config/hermes_client_default.yaml | 2 +- src/api/bucket.cc | 2 ++ src/config_client_default.h | 16 ++-------------- src/config_server_default.h | 14 +------------- 6 files changed, 8 insertions(+), 29 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 43f557eb1..89b7a7e68 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -252,6 +252,7 @@ off_t Filesystem::Tell(File &f, AdapterStat &stat) { int Filesystem::Sync(File &f, AdapterStat &stat) { IoClientContext opts; opts.type_ = type_; + opts.adapter_mode_ = stat.adapter_mode_; stat.bkt_id_->Flush(opts); return 0; } diff --git a/adapter/test/data/hermes_client.yaml b/adapter/test/data/hermes_client.yaml index 19e887cab..79342f086 100644 --- a/adapter/test/data/hermes_client.yaml +++ b/adapter/test/data/hermes_client.yaml @@ -1,5 +1,5 @@ stop_daemon: false -path_inclusions: ["/home"] +path_inclusions: ["/home", "/tmp"] path_exclusions: ["/"] file_page_size: 1024KB base_adapter_mode: kDefault \ No newline at end of file diff --git a/config/hermes_client_default.yaml b/config/hermes_client_default.yaml index ee3c489d9..1e377b233 100644 --- a/config/hermes_client_default.yaml +++ b/config/hermes_client_default.yaml @@ -1,5 +1,5 @@ stop_daemon: false -path_inclusions: ["/home"] +path_inclusions: ["/home", "/tmp"] path_exclusions: ["/"] file_page_size: 1024KB base_adapter_mode: kDefault diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 126aa2164..55784c74c 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -282,6 +282,7 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, void Bucket::FlushBlob(BlobId blob_id, const IoClientContext &opts) { LOG(INFO) << "Flushing blob" << std::endl; + if (opts.adapter_mode_ == AdapterMode::kScratch) { return; } Blob full_blob; IoStatus status; // Read blob from Hermes @@ -304,6 +305,7 @@ void Bucket::FlushBlob(BlobId blob_id, * */ void Bucket::Flush(const IoClientContext &opts) { std::vector blob_ids = GetContainedBlobIds(); + if (opts.adapter_mode_ == AdapterMode::kScratch) { return; } LOG(INFO) << "Flushing " << blob_ids.size() << " blobs" << std::endl; for (BlobId &blob_id : blob_ids) { FlushBlob(blob_id, opts); diff --git a/src/config_client_default.h b/src/config_client_default.h index 0e0873c5b..ee5238c7e 100644 --- a/src/config_client_default.h +++ b/src/config_client_default.h @@ -1,20 +1,8 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - #ifndef HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ #define HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ const char* kClientDefaultConfigStr = "stop_daemon: false\n" -"path_inclusions: [\"/home\"]\n" +"path_inclusions: [\"/home\", \"/tmp\"]\n" "path_exclusions: [\"/\"]\n" "file_page_size: 1024KB\n" "base_adapter_mode: kDefault\n" @@ -22,4 +10,4 @@ const char* kClientDefaultConfigStr = " - path: \"/\"\n" " page_size: 1MB\n" " mode: kDefault\n"; -#endif // HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ +#endif // HERMES_SRC_CONFIG_CLIENT_DEFAULT_H_ \ No newline at end of file diff --git a/src/config_server_default.h b/src/config_server_default.h index 9aad5ae0f..d19b4a203 100644 --- a/src/config_server_default.h +++ b/src/config_server_default.h @@ -1,15 +1,3 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - #ifndef HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ #define HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ const char* kServerDefaultConfigStr = @@ -145,4 +133,4 @@ const char* kServerDefaultConfigStr = "\n" "# The interval in milliseconds at which to update the global system view.\n" "system_view_state_update_interval_ms: 1000\n"; -#endif // HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ +#endif // HERMES_SRC_CONFIG_SERVER_DEFAULT_H_ \ No newline at end of file From 3a58133e23cd2cdd49c1f0fd15d2ac70f263b3ad Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 10:13:53 -0600 Subject: [PATCH 142/511] Improve MPI-IO logging --- adapter/mpiio/mpiio_api.cc | 48 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/adapter/mpiio/mpiio_api.cc b/adapter/mpiio/mpiio_api.cc index 32e65b3c6..bf0b46933 100644 --- a/adapter/mpiio/mpiio_api.cc +++ b/adapter/mpiio/mpiio_api.cc @@ -44,6 +44,7 @@ extern "C" { */ int HERMES_DECL(MPI_Init)(int *argc, char ***argv) { LOG(INFO) << "MPI Init intercepted." << std::endl; + TRANSPARENT_HERMES auto real_api = HERMES_MPIIO_API; return real_api->MPI_Init(argc, argv); } @@ -55,11 +56,13 @@ int HERMES_DECL(MPI_Finalize)(void) { } int HERMES_DECL(MPI_Wait)(MPI_Request *req, MPI_Status *status) { + LOG(INFO) << "In MPI_Wait." << std::endl; auto fs_api = HERMES_MPIIO_FS; return fs_api->Wait(req, status); } int HERMES_DECL(MPI_Waitall)(int count, MPI_Request *req, MPI_Status *status) { + LOG(INFO) << "In MPI_Waitall." << std::endl; auto fs_api = HERMES_MPIIO_FS; return fs_api->WaitAll(count, req, status); } @@ -71,9 +74,10 @@ int HERMES_DECL(MPI_File_open)(MPI_Comm comm, const char *filename, int amode, MPI_Info info, MPI_File *fh) { auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "Intercept MPI_File_open for filename: " << filename + << " and mode: " << amode << std::endl; if (fs_api->IsPathTracked(filename)) { - LOG(INFO) << "Intercept MPI_File_open for filename: " << filename - << " and mode: " << amode << " is tracked." << std::endl; + LOG(INFO) << "Intercept MPI_File_open: " << std::endl; AdapterStat stat; stat.comm_ = comm; stat.amode_ = amode; @@ -89,7 +93,9 @@ int HERMES_DECL(MPI_File_close)(MPI_File *fh) { bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_seek." << std::endl; if (fs_api->IsMpiFpTracked(fh)) { + LOG(INFO) << "Intercept MPI_File_seek." << std::endl; File f; f.hermes_mpi_fh_ = *fh; return fs_api->Close(f, stat_exists); } @@ -100,7 +106,9 @@ int HERMES_DECL(MPI_File_seek)(MPI_File fh, MPI_Offset offset, int whence) { bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_seek." << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_seek." << std::endl; File f; f.hermes_mpi_fh_ = fh; return fs_api->Seek(f, stat_exists, offset, whence); } @@ -112,6 +120,7 @@ int HERMES_DECL(MPI_File_seek_shared)(MPI_File fh, MPI_Offset offset, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_seek_shared." << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { LOG(INFO) << "Intercept MPI_File_seek_shared offset:" << offset << " whence:" << whence << "." << std::endl; @@ -125,7 +134,9 @@ int HERMES_DECL(MPI_File_get_position)(MPI_File fh, MPI_Offset *offset) { bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_get_position." << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_get_position." << std::endl; File f; f.hermes_mpi_fh_ = fh; (*offset) = static_cast(fs_api->Tell(f, stat_exists)); return MPI_SUCCESS; @@ -138,6 +149,7 @@ int HERMES_DECL(MPI_File_read_all)(MPI_File fh, void *buf, int count, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_read_all." << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { LOG(INFO) << "Intercept MPI_File_read_all." << std::endl; File f; f.hermes_mpi_fh_ = fh; @@ -151,7 +163,9 @@ int HERMES_DECL(MPI_File_read_at_all)(MPI_File fh, MPI_Offset offset, void *buf, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_read_at_all." << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_read_at_all." << std::endl; File f; f.hermes_mpi_fh_ = fh; return fs_api->ReadAll(f, stat_exists, buf, offset, count, datatype, status); @@ -165,7 +179,9 @@ int HERMES_DECL(MPI_File_read_at)(MPI_File fh, MPI_Offset offset, void *buf, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_read_at." << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_read_at." << std::endl; File f; f.hermes_mpi_fh_ = fh; return fs_api->Read(f, stat_exists, buf, offset, count, datatype, status); } @@ -176,7 +192,9 @@ int HERMES_DECL(MPI_File_read)(MPI_File fh, void *buf, int count, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_read." << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_read." << std::endl; File f; f.hermes_mpi_fh_ = fh; int ret = fs_api->Read(f, stat_exists, buf, count, datatype, status); if (stat_exists) return ret; @@ -189,7 +207,9 @@ int HERMES_DECL(MPI_File_read_ordered)(MPI_File fh, void *buf, int count, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_read_ordered." << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_read_ordered." << std::endl; File f; f.hermes_mpi_fh_ = fh; return fs_api->ReadOrdered(f, stat_exists, buf, count, datatype, status); } @@ -201,6 +221,7 @@ int HERMES_DECL(MPI_File_read_shared)(MPI_File fh, void *buf, int count, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_read_shared." << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { LOG(INFO) << "Intercept MPI_File_read_shared." << std::endl; File f; f.hermes_mpi_fh_ = fh; @@ -213,6 +234,7 @@ int HERMES_DECL(MPI_File_write_all)(MPI_File fh, const void *buf, int count, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_write_all." << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { LOG(INFO) << "Intercept MPI_File_write_all." << std::endl; File f; f.hermes_mpi_fh_ = fh; @@ -227,7 +249,9 @@ int HERMES_DECL(MPI_File_write_at_all)(MPI_File fh, MPI_Offset offset, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_write_at_all" << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_write_at_all" << std::endl; File f; f.hermes_mpi_fh_ = fh; return fs_api->WriteAll(f, stat_exists, buf, offset, count, datatype, status); @@ -243,6 +267,7 @@ int HERMES_DECL(MPI_File_write_at)(MPI_File fh, MPI_Offset offset, auto fs_api = HERMES_MPIIO_FS; LOG(INFO) << "In MPI_File_write_at" << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_write_at" << std::endl; File f; f.hermes_mpi_fh_ = fh; return fs_api->Write(f, stat_exists, buf, offset, count, datatype, status); } @@ -255,6 +280,7 @@ int HERMES_DECL(MPI_File_write)(MPI_File fh, const void *buf, int count, auto fs_api = HERMES_MPIIO_FS; LOG(INFO) << "In MPI_File_write" << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_write" << std::endl; File f; f.hermes_mpi_fh_ = fh; return fs_api->Write(f, stat_exists, buf, count, datatype, status); } @@ -266,7 +292,9 @@ int HERMES_DECL(MPI_File_write_ordered)(MPI_File fh, const void *buf, int count, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_write_shared" << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_write_ordered" << std::endl; File f; f.hermes_mpi_fh_ = fh; return fs_api->WriteOrdered(f, stat_exists, buf, count, datatype, status); } @@ -278,8 +306,10 @@ int HERMES_DECL(MPI_File_write_shared)(MPI_File fh, const void *buf, int count, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_write_shared" << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { // NOTE(llogan): originally WriteOrdered + LOG(INFO) << "Intercept MPI_File_write_shared" << std::endl; File f; f.hermes_mpi_fh_ = fh; return fs_api->WriteOrdered(f, stat_exists, buf, count, datatype, status); } @@ -295,7 +325,9 @@ int HERMES_DECL(MPI_File_iread_at)(MPI_File fh, MPI_Offset offset, void *buf, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_iread_at" << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_iread_at" << std::endl; File f; f.hermes_mpi_fh_ = fh; fs_api->ARead(f, stat_exists, buf, offset, count, datatype, request); return MPI_SUCCESS; @@ -307,7 +339,9 @@ int HERMES_DECL(MPI_File_iread)(MPI_File fh, void *buf, int count, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_iread" << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_iread" << std::endl; File f; f.hermes_mpi_fh_ = fh; fs_api->ARead(f, stat_exists, buf, count, datatype, request); } @@ -319,7 +353,9 @@ int HERMES_DECL(MPI_File_iread_shared)(MPI_File fh, void *buf, int count, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_iread_shared" << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_iread_shared" << std::endl; File f; f.hermes_mpi_fh_ = fh; fs_api->ARead(f, stat_exists, buf, count, datatype, request); return MPI_SUCCESS; @@ -333,7 +369,9 @@ int HERMES_DECL(MPI_File_iwrite_at)(MPI_File fh, MPI_Offset offset, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_iwrite_at" << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_iwrite_at" << std::endl; File f; f.hermes_mpi_fh_ = fh; fs_api->AWrite(f, stat_exists, buf, offset, count, datatype, request); return MPI_SUCCESS; @@ -347,7 +385,9 @@ int HERMES_DECL(MPI_File_iwrite)(MPI_File fh, const void *buf, int count, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_iwrite" << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_iwrite" << std::endl; File f; f.hermes_mpi_fh_ = fh; fs_api->AWrite(f, stat_exists, buf, count, datatype, request); return MPI_SUCCESS; @@ -360,7 +400,9 @@ int HERMES_DECL(MPI_File_iwrite_shared)(MPI_File fh, const void *buf, int count, bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_iwrite_shared" << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_iwrite_shared" << std::endl; File f; f.hermes_mpi_fh_ = fh; fs_api->AWriteOrdered(f, stat_exists, buf, count, datatype, request); return MPI_SUCCESS; @@ -375,7 +417,9 @@ int HERMES_DECL(MPI_File_sync)(MPI_File fh) { bool stat_exists; auto real_api = HERMES_MPIIO_API; auto fs_api = HERMES_MPIIO_FS; + LOG(INFO) << "In MPI_File_iwrite_shared" << std::endl; if (fs_api->IsMpiFpTracked(&fh)) { + LOG(INFO) << "Intercept MPI_File_sync" << std::endl; File f; f.hermes_mpi_fh_ = fh; fs_api->Sync(f, stat_exists); return 0; From ac6c93d6fe7ae76edcfbaf0c488aef511537fc01 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 11:05:11 -0600 Subject: [PATCH 143/511] lipc -> hipc --- adapter/filesystem/filesystem.cc | 4 +- adapter/io_client/io_client.h | 6 +- adapter/mapper/abstract_mapper.h | 4 +- adapter/mpiio/mpiio_io_client.cc | 6 +- adapter/mpiio/mpiio_io_client.h | 6 +- adapter/posix/posix_io_client.cc | 6 +- adapter/posix/posix_io_client.h | 6 +- adapter/stdio/stdio_io_client.cc | 6 +- adapter/stdio/stdio_io_client.h | 6 +- .../data_structures/internal/shm_archive.h | 8 +- .../data_structures/internal/shm_container.h | 2 +- .../internal/shm_container_extend_macro.h | 10 +- .../internal/shm_container_macro.h | 64 +++++------ .../data_structures/internal/shm_macros.h | 6 +- .../data_structures/internal/shm_smart_ptr.h | 8 +- .../template/shm_container_base_example.h | 72 ++++++------- .../template/shm_container_base_template.h | 64 +++++------ .../template/shm_container_extend_example.h | 10 +- .../template/shm_container_extend_template.h | 10 +- .../include/hermes_shm/data_structures/pair.h | 20 ++-- .../data_structures/thread_unsafe/list.h | 4 +- .../thread_unsafe/unordered_map.h | 56 +++++----- .../data_structures/thread_unsafe/vector.h | 20 ++-- .../hermes_shm/memory/memory_manager.h | 2 +- hermes_shm/include/hermes_shm/types/charbuf.h | 6 +- hermes_shm/test/unit/allocators/allocator.cc | 6 +- .../test/unit/allocators/allocator_thread.cc | 4 +- hermes_shm/test/unit/basic_test.h | 6 +- .../data_structures/backend/memory_manager.cc | 12 +-- .../unit/data_structures/containers/list.cc | 2 +- .../unit/data_structures/containers/list.h | 2 +- .../data_structures/containers/manual_ptr.cc | 4 +- .../unit/data_structures/containers/pair.cc | 12 +-- .../data_structures/containers/test_init.cc | 2 +- .../unit/data_structures/containers/vector.cc | 2 +- .../containers_mpi/list_vec_mpi.cc | 14 +-- .../containers_mpi/test_init.cc | 2 +- src/api/bucket.cc | 20 ++-- src/api/hermes.cc | 8 +- src/api/hermes.h | 4 +- src/api/vbucket.cc | 4 +- src/borg_io_clients/borg_posix_client.h | 2 +- src/buffer_organizer.cc | 20 ++-- src/buffer_organizer.h | 12 +-- src/buffer_pool.cc | 10 +- src/buffer_pool.h | 12 +-- src/config_server.cc | 8 +- src/config_server.h | 26 ++--- src/constants.h | 2 +- src/data_placement_engine.cc | 2 +- src/data_placement_engine.h | 2 +- src/data_structures.h | 2 +- src/dpe/minimize_io_time.cc | 6 +- src/dpe/minimize_io_time.h | 6 +- src/dpe/random.cc | 2 +- src/dpe/random.h | 2 +- src/dpe/round_robin.cc | 2 +- src/dpe/round_robin.h | 2 +- src/metadata_manager.cc | 102 +++++++++--------- src/metadata_manager.h | 86 +++++++-------- src/metadata_types.h | 62 +++++------ 61 files changed, 442 insertions(+), 442 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 89b7a7e68..59439215a 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -79,7 +79,7 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, for (const auto &p : mapping) { const Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); - lipc::charbuf blob_name(p.CreateBlobName(kPageSize)); + hipc::charbuf blob_name(p.CreateBlobName(kPageSize)); BlobId blob_id; opts.type_ = type_; opts.backend_off_ = p.page_ * kPageSize; @@ -122,7 +122,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, for (const auto &p : mapping) { Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); - lipc::charbuf blob_name(p.CreateBlobName(kPageSize)); + hipc::charbuf blob_name(p.CreateBlobName(kPageSize)); BlobId blob_id; opts.backend_off_ = p.page_ * kPageSize; opts.backend_size_ = kPageSize; diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index e509a77d3..e401dd673 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -157,7 +157,7 @@ class IoClient { virtual ~IoClient() = default; /** Get initial statistics from the backend */ - virtual void InitBucketState(const lipc::charbuf &bkt_name, + virtual void InitBucketState(const hipc::charbuf &bkt_name, const IoClientContext &opts, GlobalIoClientState &stat) = 0; @@ -174,13 +174,13 @@ class IoClient { GlobalIoClientState &stat) = 0; /** Write blob to backend */ - virtual void WriteBlob(const lipc::charbuf &bkt_name, + virtual void WriteBlob(const hipc::charbuf &bkt_name, const Blob &full_blob, const IoClientContext &opts, IoStatus &status) = 0; /** Read blob from the backend */ - virtual void ReadBlob(const lipc::charbuf &bkt_name, + virtual void ReadBlob(const hipc::charbuf &bkt_name, Blob &full_blob, const IoClientContext &opts, IoStatus &status) = 0; diff --git a/adapter/mapper/abstract_mapper.h b/adapter/mapper/abstract_mapper.h index 5a08f8e47..72d4f7a47 100644 --- a/adapter/mapper/abstract_mapper.h +++ b/adapter/mapper/abstract_mapper.h @@ -36,8 +36,8 @@ struct BlobPlacement { int time_; /**< The order of the blob in a list of blobs */ /** create a BLOB name from index. */ - lipc::charbuf CreateBlobName(size_t page_size) const { - lipc::charbuf buf(sizeof(page_) + sizeof(page_size)); + hipc::charbuf CreateBlobName(size_t page_size) const { + hipc::charbuf buf(sizeof(page_) + sizeof(page_size)); size_t off = 0; memcpy(buf.data_mutable() + off, &page_, sizeof(page_)); off += sizeof(page_); diff --git a/adapter/mpiio/mpiio_io_client.cc b/adapter/mpiio/mpiio_io_client.cc index 61fb66d42..a41681e41 100644 --- a/adapter/mpiio/mpiio_io_client.cc +++ b/adapter/mpiio/mpiio_io_client.cc @@ -66,7 +66,7 @@ void MpiioIoClient::HermesClose(IoClientObject &f, } /** Get initial statistics from the backend */ -void MpiioIoClient::InitBucketState(const lipc::charbuf &bkt_name, +void MpiioIoClient::InitBucketState(const hipc::charbuf &bkt_name, const IoClientContext &opts, GlobalIoClientState &stat) { } @@ -83,7 +83,7 @@ size_t MpiioIoClient::IoSizeFromCount(int count, } /** Write blob to backend */ -void MpiioIoClient::WriteBlob(const lipc::charbuf &bkt_name, +void MpiioIoClient::WriteBlob(const hipc::charbuf &bkt_name, const Blob &full_blob, const IoClientContext &opts, IoStatus &status) { @@ -127,7 +127,7 @@ void MpiioIoClient::WriteBlob(const lipc::charbuf &bkt_name, } /** Read blob from the backend */ -void MpiioIoClient::ReadBlob(const lipc::charbuf &bkt_name, +void MpiioIoClient::ReadBlob(const hipc::charbuf &bkt_name, Blob &full_blob, const IoClientContext &opts, IoStatus &status) { diff --git a/adapter/mpiio/mpiio_io_client.h b/adapter/mpiio/mpiio_io_client.h index 9c0d06b2f..5bde45ae8 100644 --- a/adapter/mpiio/mpiio_io_client.h +++ b/adapter/mpiio/mpiio_io_client.h @@ -70,7 +70,7 @@ class MpiioIoClient : public hermes::adapter::fs::FilesystemIoClient { FilesystemIoClientObject &fs_mdm) override; /** Get initial statistics from the backend */ - void InitBucketState(const lipc::charbuf &bkt_name, + void InitBucketState(const hipc::charbuf &bkt_name, const IoClientContext &opts, GlobalIoClientState &stat) override; @@ -80,13 +80,13 @@ class MpiioIoClient : public hermes::adapter::fs::FilesystemIoClient { IoClientContext &opts); /** Write blob to backend */ - void WriteBlob(const lipc::charbuf &bkt_name, + void WriteBlob(const hipc::charbuf &bkt_name, const Blob &full_blob, const IoClientContext &opts, IoStatus &status) override; /** Read blob from the backend */ - void ReadBlob(const lipc::charbuf &bkt_name, + void ReadBlob(const hipc::charbuf &bkt_name, Blob &full_blob, const IoClientContext &opts, IoStatus &status) override; diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 731f07bb8..6cfabce7b 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -68,7 +68,7 @@ void PosixIoClient::HermesClose(IoClientObject &f, } /** Get initial statistics from the backend */ -void PosixIoClient::InitBucketState(const lipc::charbuf &bkt_name, +void PosixIoClient::InitBucketState(const hipc::charbuf &bkt_name, const IoClientContext &opts, GlobalIoClientState &stat) { stat.true_size_ = 0; @@ -82,7 +82,7 @@ void PosixIoClient::InitBucketState(const lipc::charbuf &bkt_name, } /** Write blob to backend */ -void PosixIoClient::WriteBlob(const lipc::charbuf &bkt_name, +void PosixIoClient::WriteBlob(const hipc::charbuf &bkt_name, const Blob &full_blob, const IoClientContext &opts, IoStatus &status) { @@ -105,7 +105,7 @@ void PosixIoClient::WriteBlob(const lipc::charbuf &bkt_name, } /** Read blob from the backend */ -void PosixIoClient::ReadBlob(const lipc::charbuf &bkt_name, +void PosixIoClient::ReadBlob(const hipc::charbuf &bkt_name, Blob &full_blob, const IoClientContext &opts, IoStatus &status) { diff --git a/adapter/posix/posix_io_client.h b/adapter/posix/posix_io_client.h index fe9738a21..489a33b11 100644 --- a/adapter/posix/posix_io_client.h +++ b/adapter/posix/posix_io_client.h @@ -71,18 +71,18 @@ class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { FilesystemIoClientObject &fs_mdm) override; /** Get initial statistics from the backend */ - void InitBucketState(const lipc::charbuf &bkt_name, + void InitBucketState(const hipc::charbuf &bkt_name, const IoClientContext &opts, GlobalIoClientState &stat) override; /** Write blob to backend */ - void WriteBlob(const lipc::charbuf &bkt_name, + void WriteBlob(const hipc::charbuf &bkt_name, const Blob &full_blob, const IoClientContext &opts, IoStatus &status) override; /** Read blob from the backend */ - void ReadBlob(const lipc::charbuf &bkt_name, + void ReadBlob(const hipc::charbuf &bkt_name, Blob &full_blob, const IoClientContext &opts, IoStatus &status) override; diff --git a/adapter/stdio/stdio_io_client.cc b/adapter/stdio/stdio_io_client.cc index dcec01cd4..ef3c973d3 100644 --- a/adapter/stdio/stdio_io_client.cc +++ b/adapter/stdio/stdio_io_client.cc @@ -64,14 +64,14 @@ void StdioIoClient::HermesClose(IoClientObject &f, } /** Get initial statistics from the backend */ -void StdioIoClient::InitBucketState(const lipc::charbuf &bkt_name, +void StdioIoClient::InitBucketState(const hipc::charbuf &bkt_name, const IoClientContext &opts, GlobalIoClientState &stat) { // TODO(llogan) } /** Write blob to backend */ -void StdioIoClient::WriteBlob(const lipc::charbuf &bkt_name, +void StdioIoClient::WriteBlob(const hipc::charbuf &bkt_name, const Blob &full_blob, const IoClientContext &opts, IoStatus &status) { @@ -94,7 +94,7 @@ void StdioIoClient::WriteBlob(const lipc::charbuf &bkt_name, } /** Read blob from the backend */ -void StdioIoClient::ReadBlob(const lipc::charbuf &bkt_name, +void StdioIoClient::ReadBlob(const hipc::charbuf &bkt_name, Blob &full_blob, const IoClientContext &opts, IoStatus &status) { diff --git a/adapter/stdio/stdio_io_client.h b/adapter/stdio/stdio_io_client.h index 81a52901b..48d471c05 100644 --- a/adapter/stdio/stdio_io_client.h +++ b/adapter/stdio/stdio_io_client.h @@ -70,18 +70,18 @@ class StdioIoClient : public hermes::adapter::fs::FilesystemIoClient { FilesystemIoClientObject &fs_mdm) override; /** Get initial statistics from the backend */ - void InitBucketState(const lipc::charbuf &bkt_name, + void InitBucketState(const hipc::charbuf &bkt_name, const IoClientContext &opts, GlobalIoClientState &stat) override; /** Write blob to backend */ - void WriteBlob(const lipc::charbuf &bkt_name, + void WriteBlob(const hipc::charbuf &bkt_name, const Blob &full_blob, const IoClientContext &opts, IoStatus &status) override; /** Read blob from the backend */ - void ReadBlob(const lipc::charbuf &bkt_name, + void ReadBlob(const hipc::charbuf &bkt_name, Blob &full_blob, const IoClientContext &opts, IoStatus &status) override; diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h index 447c3516d..d0f12ca10 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h @@ -75,10 +75,10 @@ class ShmArchiveable : public ShmPredictable { * Enables a specific TypedPointer type to be serialized * */ #define SHM_SERIALIZE_OPS(TYPED_CLASS)\ - void operator>>(lipc::TypedPointer &ar) const {\ + void operator>>(hipc::TypedPointer &ar) const {\ shm_serialize(ar);\ }\ - void operator>>(lipc::TypedAtomicPointer &ar) const {\ + void operator>>(hipc::TypedAtomicPointer &ar) const {\ shm_serialize(ar);\ } @@ -86,11 +86,11 @@ class ShmArchiveable : public ShmPredictable { * Enables a specific TypedPointer type to be deserialized * */ #define SHM_DESERIALIZE_OPS(TYPED_CLASS)\ - void operator<<(const lipc::TypedPointer &ar) {\ + void operator<<(const hipc::TypedPointer &ar) {\ shm_deserialize(ar);\ }\ void operator<<(\ - const lipc::TypedAtomicPointer &ar) {\ + const hipc::TypedAtomicPointer &ar) {\ shm_deserialize(ar);\ } diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h index 113c0ca3f..3df01401f 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h @@ -21,7 +21,7 @@ #include "shm_ref.h" #include "shm_deserialize.h" -namespace lipc = hermes_shm::ipc; +namespace hipc = hermes_shm::ipc; namespace hermes_shm::ipc { diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h index 791bcce3c..8cf120288 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h @@ -82,7 +82,7 @@ bool shm_deserialize(Allocator *alloc,\ \ /** Constructor. Deserialize the object from the reference. */\ template\ -void shm_init(lipc::ShmRef &obj) {\ +void shm_init(hipc::ShmRef &obj) {\ shm_deserialize(obj->GetAllocator(), obj->header_);\ }\ \ @@ -130,14 +130,14 @@ return *this;\ \ /** Move shm_init constructor */\ void shm_init_main(TYPE_UNWRAP(TYPED_HEADER) *header,\ - lipc::Allocator *alloc,\ + hipc::Allocator *alloc,\ TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ shm_weak_move(header, alloc, other);\ }\ \ /** Move operation */\ void shm_weak_move(TYPE_UNWRAP(TYPED_HEADER) *header,\ - lipc::Allocator *alloc,\ + hipc::Allocator *alloc,\ TYPE_UNWRAP(CLASS_NAME) &other) {\ obj_.shm_weak_move(header, alloc, other);\ }\ @@ -164,13 +164,13 @@ TYPE_UNWRAP(CLASS_NAME) &operator=(const TYPE_UNWRAP(CLASS_NAME) &other) {\ \ /** Copy shm_init constructor */\ void shm_init_main(TYPE_UNWRAP(TYPED_HEADER) *header,\ - lipc::Allocator *alloc,\ + hipc::Allocator *alloc,\ const TYPE_UNWRAP(CLASS_NAME) &other) {\ shm_strong_copy(header, alloc, other);\ }\ \ /** Strong Copy operation */\ -void shm_strong_copy(TYPE_UNWRAP(TYPED_HEADER) *header, lipc::Allocator *alloc,\ +void shm_strong_copy(TYPE_UNWRAP(TYPED_HEADER) *header, hipc::Allocator *alloc,\ const TYPE_UNWRAP(CLASS_NAME) &other) {\ if (other.IsNull()) { return; }\ shm_destroy(false);\ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h index fa330ddf7..20b285082 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h @@ -20,7 +20,7 @@ public:\ \ typedef TYPE_UNWRAP(TYPED_HEADER) header_t; /** Header type query */\ header_t *header_; /**< Header of the shared-memory data structure */\ -lipc::Allocator *alloc_; /**< lipc::Allocator used for this data structure */\ +hipc::Allocator *alloc_; /**< hipc::Allocator used for this data structure */\ hermes_shm::bitfield32_t flags_; /**< Flags used data structure status */\ \ public:\ @@ -38,16 +38,16 @@ shm_init(std::forward(args)...);\ template\ void shm_init(Args&& ...args) {\ shm_destroy(false);\ - shm_init_main(lipc::typed_nullptr(),\ - lipc::typed_nullptr(),\ + shm_init_main(hipc::typed_nullptr(),\ + hipc::typed_nullptr(),\ std::forward(args)...);\ }\ \ /** Constructor. Allocate header with specific allocator. */\ template\ -void shm_init(lipc::Allocator *alloc, Args&& ...args) {\ +void shm_init(hipc::Allocator *alloc, Args&& ...args) {\ shm_destroy(false);\ - shm_init_main(lipc::typed_nullptr(),\ + shm_init_main(hipc::typed_nullptr(),\ alloc,\ std::forward(args)...);\ }\ @@ -55,13 +55,13 @@ void shm_init(lipc::Allocator *alloc, Args&& ...args) {\ /** Constructor. Initialize an already-allocated header. */\ template\ void shm_init(TYPE_UNWRAP(TYPED_HEADER) &header,\ - lipc::Allocator *alloc, Args&& ...args) {\ + hipc::Allocator *alloc, Args&& ...args) {\ shm_destroy(false);\ shm_init_main(&header, alloc, std::forward(args)...);\ }\ \ /** Initialize the data structure's allocator */\ -inline void shm_init_allocator(lipc::Allocator *alloc) {\ +inline void shm_init_allocator(hipc::Allocator *alloc) {\ if (IsValid()) { return; }\ if (alloc == nullptr) {\ alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator();\ @@ -81,7 +81,7 @@ void shm_init_header(TYPE_UNWRAP(TYPED_HEADER) *header,\ if (IsValid()) {\ header_->SetBits(SHM_CONTAINER_DATA_VALID);\ } else if (header == nullptr) {\ - lipc::Pointer p;\ + hipc::Pointer p;\ header_ = alloc_->template\ AllocateConstructObjs(\ 1, p, std::forward(args)...);\ @@ -92,9 +92,9 @@ void shm_init_header(TYPE_UNWRAP(TYPED_HEADER) *header,\ SHM_CONTAINER_VALID |\ SHM_CONTAINER_DESTRUCTABLE);\ } else {\ - lipc::Pointer header_ptr;\ + hipc::Pointer header_ptr;\ header_ = header;\ - lipc::Allocator::ConstructObj(\ + hipc::Allocator::ConstructObj(\ *header_, std::forward(args)...);\ header_->SetBits(\ SHM_CONTAINER_DATA_VALID);\ @@ -109,16 +109,16 @@ void shm_init_header(TYPE_UNWRAP(TYPED_HEADER) *header,\ * ===================================*/\ \ /** Serialize into a Pointer */\ -void shm_serialize(lipc::TypedPointer &ar) const {\ +void shm_serialize(hipc::TypedPointer &ar) const {\ ar = alloc_->template\ - Convert(header_);\ + Convert(header_);\ shm_serialize_main();\ }\ \ /** Serialize into an AtomicPointer */\ -void shm_serialize(lipc::TypedAtomicPointer &ar) const {\ +void shm_serialize(hipc::TypedAtomicPointer &ar) const {\ ar = alloc_->template\ - Convert(header_);\ + Convert(header_);\ shm_serialize_main();\ }\ \ @@ -130,7 +130,7 @@ SHM_SERIALIZE_OPS((TYPE_UNWRAP(TYPED_CLASS)))\ * ===================================*/\ \ /** Deserialize object from a raw pointer */\ -bool shm_deserialize(const lipc::TypedPointer &ar) {\ +bool shm_deserialize(const hipc::TypedPointer &ar) {\ return shm_deserialize(\ HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_),\ ar.ToOffsetPointer()\ @@ -138,12 +138,12 @@ bool shm_deserialize(const lipc::TypedPointer &ar) {\ }\ \ /** Deserialize object from allocator + offset */\ -bool shm_deserialize(lipc::Allocator *alloc, lipc::OffsetPointer header_ptr) {\ +bool shm_deserialize(hipc::Allocator *alloc, hipc::OffsetPointer header_ptr) {\ if (header_ptr.IsNull()) { return false; }\ return shm_deserialize(alloc,\ alloc->Convert<\ TYPE_UNWRAP(TYPED_HEADER),\ - lipc::OffsetPointer>(header_ptr));\ + hipc::OffsetPointer>(header_ptr));\ }\ \ /** Deserialize object from another object (weak copy) */\ @@ -153,7 +153,7 @@ bool shm_deserialize(const TYPE_UNWRAP(CLASS_NAME) &other) {\ }\ \ /** Deserialize object from allocator + header */\ -bool shm_deserialize(lipc::Allocator *alloc,\ +bool shm_deserialize(hipc::Allocator *alloc,\ TYPE_UNWRAP(TYPED_HEADER) *header) {\ flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE);\ alloc_ = alloc;\ @@ -165,7 +165,7 @@ bool shm_deserialize(lipc::Allocator *alloc,\ \ /** Constructor. Deserialize the object from the reference. */\ template\ -void shm_init(lipc::ShmRef &obj) {\ +void shm_init(hipc::ShmRef &obj) {\ shm_deserialize(obj->GetAllocator(), obj->header_);\ }\ \ @@ -204,8 +204,8 @@ void shm_destroy(bool destroy_header = true) {\ /** Move constructor */\ TYPE_UNWRAP(CLASS_NAME)(TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ shm_weak_move(\ - lipc::typed_nullptr(),\ - lipc::typed_nullptr(),\ + hipc::typed_nullptr(),\ + hipc::typed_nullptr(),\ other);\ }\ \ @@ -213,8 +213,8 @@ shm_weak_move(\ TYPE_UNWRAP(CLASS_NAME)& operator=(TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ if (this != &other) {\ shm_weak_move(\ - lipc::typed_nullptr(),\ - lipc::typed_nullptr(),\ + hipc::typed_nullptr(),\ + hipc::typed_nullptr(),\ other);\ }\ return *this;\ @@ -222,14 +222,14 @@ return *this;\ \ /** Move shm_init constructor */\ void shm_init_main(TYPE_UNWRAP(TYPED_HEADER) *header,\ - lipc::Allocator *alloc,\ + hipc::Allocator *alloc,\ TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ shm_weak_move(header, alloc, other);\ }\ \ /** Move operation */\ void shm_weak_move(TYPE_UNWRAP(TYPED_HEADER) *header,\ - lipc::Allocator *alloc,\ + hipc::Allocator *alloc,\ TYPE_UNWRAP(CLASS_NAME) &other) {\ if (other.IsNull()) { return; }\ if (IsValid() && other.GetAllocator() != GetAllocator()) {\ @@ -259,8 +259,8 @@ TYPE_UNWRAP(CLASS_NAME)(const TYPE_UNWRAP(CLASS_NAME) &other) noexcept {\ TYPE_UNWRAP(CLASS_NAME)& operator=(const TYPE_UNWRAP(CLASS_NAME) &other) {\ if (this != &other) {\ shm_strong_copy(\ - lipc::typed_nullptr(),\ - lipc::typed_nullptr(),\ + hipc::typed_nullptr(),\ + hipc::typed_nullptr(),\ other);\ }\ return *this;\ @@ -268,14 +268,14 @@ TYPE_UNWRAP(CLASS_NAME)& operator=(const TYPE_UNWRAP(CLASS_NAME) &other) {\ \ /** Copy shm_init constructor */\ void shm_init_main(TYPE_UNWRAP(TYPED_HEADER) *header,\ - lipc::Allocator *alloc,\ + hipc::Allocator *alloc,\ const TYPE_UNWRAP(CLASS_NAME) &other) {\ shm_strong_copy(header, alloc, other);\ }\ \ /** Strong Copy operation */\ void shm_strong_copy(TYPE_UNWRAP(TYPED_HEADER) *header,\ - lipc::Allocator *alloc,\ + hipc::Allocator *alloc,\ const TYPE_UNWRAP(CLASS_NAME) &other) {\ if (other.IsNull()) { return; }\ shm_destroy(false);\ @@ -343,17 +343,17 @@ POINTER_T GetShmPointer() const {\ * ===================================*/\ \ /** Get the allocator for this container */\ -lipc::Allocator* GetAllocator() {\ +hipc::Allocator* GetAllocator() {\ return alloc_;\ }\ \ /** Get the allocator for this container */\ -lipc::Allocator* GetAllocator() const {\ +hipc::Allocator* GetAllocator() const {\ return alloc_;\ }\ \ /** Get the shared-memory allocator id */\ -lipc::allocator_id_t GetAllocatorId() const {\ +hipc::allocator_id_t GetAllocatorId() const {\ return alloc_->GetId();\ }\ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h index 24555abf4..179785009 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h @@ -37,7 +37,7 @@ /** * SHM_T_OR_PTR_T: Returns T if SHM_ARCHIVEABLE, and T* otherwise. Used - * internally by lipc::ShmRef. + * internally by hipc::ShmRef. * * @param T: The type being stored in the shmem data structure * */ @@ -46,12 +46,12 @@ /** * ShmHeaderOrT: Returns TypedPointer if SHM_ARCHIVEABLE, and T - * otherwise. Used to construct an lipc::ShmRef. + * otherwise. Used to construct an hipc::ShmRef. * * @param T The type being stored in the shmem data structure * */ #define SHM_ARCHIVE_OR_T(T) \ - SHM_X_OR_Y(T, lipc::TypedPointer, T) + SHM_X_OR_Y(T, hipc::TypedPointer, T) /** * SHM_T_OR_SHM_STRUCT_T: Used by unique_ptr and manual_ptr to internally diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h index 55d186e0b..4db23e2ae 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h @@ -132,10 +132,10 @@ class ShmSmartPtr : public ShmSmartPointer { * A macro for defining shared memory serializations * */ #define SHM_SERIALIZE_WRAPPER(AR_TYPE)\ - void shm_serialize(lipc::TypedPointer &type) const {\ + void shm_serialize(hipc::TypedPointer &type) const {\ obj_.shm_serialize(type);\ }\ - void shm_serialize(lipc::TypedAtomicPointer &type) const {\ + void shm_serialize(hipc::TypedAtomicPointer &type) const {\ obj_.shm_serialize(type);\ }\ SHM_SERIALIZE_OPS(AR_TYPE) @@ -144,10 +144,10 @@ class ShmSmartPtr : public ShmSmartPointer { * A macro for defining shared memory deserializations * */ #define SHM_DESERIALIZE_WRAPPER(AR_TYPE)\ - void shm_deserialize(const lipc::TypedPointer &type) {\ + void shm_deserialize(const hipc::TypedPointer &type) {\ obj_.shm_deserialize(type);\ }\ - void shm_deserialize(const lipc::TypedAtomicPointer &type) {\ + void shm_deserialize(const hipc::TypedAtomicPointer &type) {\ obj_.shm_deserialize(type);\ }\ SHM_DESERIALIZE_OPS(AR_TYPE) diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h index 2f6eeeb4e..bb5b8c96b 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h @@ -27,7 +27,7 @@ template class ShmHeader; template<> - class ShmHeader : public lipc::ShmBaseHeader { + class ShmHeader : public hipc::ShmBaseHeader { }; class ShmContainerExample { @@ -38,7 +38,7 @@ class ShmContainerExample { typedef TYPED_HEADER header_t; /** Header type query */ header_t *header_; /**< Header of the shared-memory data structure */ - lipc::Allocator *alloc_; /**< lipc::Allocator used for this data structure */ + hipc::Allocator *alloc_; /**< hipc::Allocator used for this data structure */ hermes_shm::bitfield32_t flags_; /**< Flags used data structure status */ public: @@ -51,21 +51,21 @@ class ShmContainerExample { /** Default shm constructor */ void shm_init_main(TYPED_HEADER *header, - lipc::Allocator *alloc) { + hipc::Allocator *alloc) { shm_init_allocator(alloc); shm_init_header(header); } /** Move constructor */ void shm_weak_move_main(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, CLASS_NAME &other) { shm_init_main(header, alloc); } /** Copy constructor */ void shm_strong_copy_main(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, const CLASS_NAME &other) { shm_init_main(header, alloc); } @@ -93,16 +93,16 @@ class ShmContainerExample { template void shm_init(Args&& ...args) { shm_destroy(false); - shm_init_main(lipc::typed_nullptr(), - lipc::typed_nullptr(), + shm_init_main(hipc::typed_nullptr(), + hipc::typed_nullptr(), std::forward(args)...); } /** Constructor. Allocate header with specific allocator. */ template - void shm_init(lipc::Allocator *alloc, Args&& ...args) { + void shm_init(hipc::Allocator *alloc, Args&& ...args) { shm_destroy(false); - shm_init_main(lipc::typed_nullptr(), + shm_init_main(hipc::typed_nullptr(), alloc, std::forward(args)...); } @@ -110,13 +110,13 @@ class ShmContainerExample { /** Constructor. Initialize an already-allocated header. */ template void shm_init(TYPED_HEADER &header, - lipc::Allocator *alloc, Args&& ...args) { + hipc::Allocator *alloc, Args&& ...args) { shm_destroy(false); shm_init_main(&header, alloc, std::forward(args)...); } /** Initialize the data structure's allocator */ - inline void shm_init_allocator(lipc::Allocator *alloc) { + inline void shm_init_allocator(hipc::Allocator *alloc) { if (IsValid()) { return; } if (alloc == nullptr) { alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); @@ -136,7 +136,7 @@ class ShmContainerExample { if (IsValid()) { header_->SetBits(SHM_CONTAINER_DATA_VALID); } else if (header == nullptr) { - lipc::Pointer p; + hipc::Pointer p; header_ = alloc_->template AllocateConstructObjs( 1, p, std::forward(args)...); @@ -147,9 +147,9 @@ class ShmContainerExample { SHM_CONTAINER_VALID | SHM_CONTAINER_DESTRUCTABLE); } else { - lipc::Pointer header_ptr; + hipc::Pointer header_ptr; header_ = header; - lipc::Allocator::ConstructObj( + hipc::Allocator::ConstructObj( *header_, std::forward(args)...); header_->SetBits( SHM_CONTAINER_DATA_VALID); @@ -164,16 +164,16 @@ class ShmContainerExample { * ===================================*/ /** Serialize into a Pointer */ - void shm_serialize(lipc::TypedPointer &ar) const { + void shm_serialize(hipc::TypedPointer &ar) const { ar = alloc_->template - Convert(header_); + Convert(header_); shm_serialize_main(); } /** Serialize into an AtomicPointer */ - void shm_serialize(lipc::TypedAtomicPointer &ar) const { + void shm_serialize(hipc::TypedAtomicPointer &ar) const { ar = alloc_->template - Convert(header_); + Convert(header_); shm_serialize_main(); } @@ -185,7 +185,7 @@ class ShmContainerExample { * ===================================*/ /** Deserialize object from a raw pointer */ - bool shm_deserialize(const lipc::TypedPointer &ar) { + bool shm_deserialize(const hipc::TypedPointer &ar) { return shm_deserialize( HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_), ar.ToOffsetPointer() @@ -193,12 +193,12 @@ class ShmContainerExample { } /** Deserialize object from allocator + offset */ - bool shm_deserialize(lipc::Allocator *alloc, lipc::OffsetPointer header_ptr) { + bool shm_deserialize(hipc::Allocator *alloc, hipc::OffsetPointer header_ptr) { if (header_ptr.IsNull()) { return false; } return shm_deserialize(alloc, alloc->Convert< TYPED_HEADER, - lipc::OffsetPointer>(header_ptr)); + hipc::OffsetPointer>(header_ptr)); } /** Deserialize object from another object (weak copy) */ @@ -208,7 +208,7 @@ class ShmContainerExample { } /** Deserialize object from allocator + header */ - bool shm_deserialize(lipc::Allocator *alloc, + bool shm_deserialize(hipc::Allocator *alloc, TYPED_HEADER *header) { flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE); alloc_ = alloc; @@ -220,7 +220,7 @@ class ShmContainerExample { /** Constructor. Deserialize the object from the reference. */ template - void shm_init(lipc::ShmRef &obj) { + void shm_init(hipc::ShmRef &obj) { shm_deserialize(obj->GetAllocator(), obj->header_); } @@ -259,8 +259,8 @@ class ShmContainerExample { /** Move constructor */ CLASS_NAME(CLASS_NAME &&other) noexcept { shm_weak_move( - lipc::typed_nullptr(), - lipc::typed_nullptr(), + hipc::typed_nullptr(), + hipc::typed_nullptr(), other); } @@ -268,8 +268,8 @@ class ShmContainerExample { CLASS_NAME& operator=(CLASS_NAME &&other) noexcept { if (this != &other) { shm_weak_move( - lipc::typed_nullptr(), - lipc::typed_nullptr(), + hipc::typed_nullptr(), + hipc::typed_nullptr(), other); } return *this; @@ -277,14 +277,14 @@ class ShmContainerExample { /** Move shm_init constructor */ void shm_init_main(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, CLASS_NAME &&other) noexcept { shm_weak_move(header, alloc, other); } /** Move operation */ void shm_weak_move(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, CLASS_NAME &other) { if (other.IsNull()) { return; } if (IsValid() && other.GetAllocator() != GetAllocator()) { @@ -314,8 +314,8 @@ class ShmContainerExample { CLASS_NAME& operator=(const CLASS_NAME &other) { if (this != &other) { shm_strong_copy( - lipc::typed_nullptr(), - lipc::typed_nullptr(), + hipc::typed_nullptr(), + hipc::typed_nullptr(), other); } return *this; @@ -323,14 +323,14 @@ class ShmContainerExample { /** Copy shm_init constructor */ void shm_init_main(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, const CLASS_NAME &other) { shm_strong_copy(header, alloc, other); } /** Strong Copy operation */ void shm_strong_copy(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, const CLASS_NAME &other) { if (other.IsNull()) { return; } shm_destroy(false); @@ -398,17 +398,17 @@ class ShmContainerExample { * ===================================*/ /** Get the allocator for this container */ - lipc::Allocator* GetAllocator() { + hipc::Allocator* GetAllocator() { return alloc_; } /** Get the allocator for this container */ - lipc::Allocator* GetAllocator() const { + hipc::Allocator* GetAllocator() const { return alloc_; } /** Get the shared-memory allocator id */ - lipc::allocator_id_t GetAllocatorId() const { + hipc::allocator_id_t GetAllocatorId() const { return alloc_->GetId(); } }; diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h index b55829c51..e6aff6dd9 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h @@ -17,7 +17,7 @@ typedef TYPED_HEADER header_t; /** Header type query */ header_t *header_; /**< Header of the shared-memory data structure */ -lipc::Allocator *alloc_; /**< lipc::Allocator used for this data structure */ +hipc::Allocator *alloc_; /**< hipc::Allocator used for this data structure */ hermes_shm::bitfield32_t flags_; /**< Flags used data structure status */ public: @@ -35,16 +35,16 @@ shm_init(std::forward(args)...); template void shm_init(Args&& ...args) { shm_destroy(false); - shm_init_main(lipc::typed_nullptr(), - lipc::typed_nullptr(), + shm_init_main(hipc::typed_nullptr(), + hipc::typed_nullptr(), std::forward(args)...); } /** Constructor. Allocate header with specific allocator. */ template -void shm_init(lipc::Allocator *alloc, Args&& ...args) { +void shm_init(hipc::Allocator *alloc, Args&& ...args) { shm_destroy(false); - shm_init_main(lipc::typed_nullptr(), + shm_init_main(hipc::typed_nullptr(), alloc, std::forward(args)...); } @@ -52,13 +52,13 @@ void shm_init(lipc::Allocator *alloc, Args&& ...args) { /** Constructor. Initialize an already-allocated header. */ template void shm_init(TYPED_HEADER &header, - lipc::Allocator *alloc, Args&& ...args) { + hipc::Allocator *alloc, Args&& ...args) { shm_destroy(false); shm_init_main(&header, alloc, std::forward(args)...); } /** Initialize the data structure's allocator */ -inline void shm_init_allocator(lipc::Allocator *alloc) { +inline void shm_init_allocator(hipc::Allocator *alloc) { if (IsValid()) { return; } if (alloc == nullptr) { alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); @@ -78,7 +78,7 @@ void shm_init_header(TYPED_HEADER *header, if (IsValid()) { header_->SetBits(SHM_CONTAINER_DATA_VALID); } else if (header == nullptr) { - lipc::Pointer p; + hipc::Pointer p; header_ = alloc_->template AllocateConstructObjs( 1, p, std::forward(args)...); @@ -89,9 +89,9 @@ void shm_init_header(TYPED_HEADER *header, SHM_CONTAINER_VALID | SHM_CONTAINER_DESTRUCTABLE); } else { - lipc::Pointer header_ptr; + hipc::Pointer header_ptr; header_ = header; - lipc::Allocator::ConstructObj( + hipc::Allocator::ConstructObj( *header_, std::forward(args)...); header_->SetBits( SHM_CONTAINER_DATA_VALID); @@ -106,16 +106,16 @@ void shm_init_header(TYPED_HEADER *header, * ===================================*/ /** Serialize into a Pointer */ -void shm_serialize(lipc::TypedPointer &ar) const { +void shm_serialize(hipc::TypedPointer &ar) const { ar = alloc_->template - Convert(header_); + Convert(header_); shm_serialize_main(); } /** Serialize into an AtomicPointer */ -void shm_serialize(lipc::TypedAtomicPointer &ar) const { +void shm_serialize(hipc::TypedAtomicPointer &ar) const { ar = alloc_->template - Convert(header_); + Convert(header_); shm_serialize_main(); } @@ -127,7 +127,7 @@ SHM_SERIALIZE_OPS((TYPED_CLASS)) * ===================================*/ /** Deserialize object from a raw pointer */ -bool shm_deserialize(const lipc::TypedPointer &ar) { +bool shm_deserialize(const hipc::TypedPointer &ar) { return shm_deserialize( HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_), ar.ToOffsetPointer() @@ -135,12 +135,12 @@ bool shm_deserialize(const lipc::TypedPointer &ar) { } /** Deserialize object from allocator + offset */ -bool shm_deserialize(lipc::Allocator *alloc, lipc::OffsetPointer header_ptr) { +bool shm_deserialize(hipc::Allocator *alloc, hipc::OffsetPointer header_ptr) { if (header_ptr.IsNull()) { return false; } return shm_deserialize(alloc, alloc->Convert< TYPED_HEADER, - lipc::OffsetPointer>(header_ptr)); + hipc::OffsetPointer>(header_ptr)); } /** Deserialize object from another object (weak copy) */ @@ -150,7 +150,7 @@ bool shm_deserialize(const CLASS_NAME &other) { } /** Deserialize object from allocator + header */ -bool shm_deserialize(lipc::Allocator *alloc, +bool shm_deserialize(hipc::Allocator *alloc, TYPED_HEADER *header) { flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE); alloc_ = alloc; @@ -162,7 +162,7 @@ bool shm_deserialize(lipc::Allocator *alloc, /** Constructor. Deserialize the object from the reference. */ template -void shm_init(lipc::ShmRef &obj) { +void shm_init(hipc::ShmRef &obj) { shm_deserialize(obj->GetAllocator(), obj->header_); } @@ -201,8 +201,8 @@ void shm_destroy(bool destroy_header = true) { /** Move constructor */ CLASS_NAME(CLASS_NAME &&other) noexcept { shm_weak_move( - lipc::typed_nullptr(), - lipc::typed_nullptr(), + hipc::typed_nullptr(), + hipc::typed_nullptr(), other); } @@ -210,8 +210,8 @@ shm_weak_move( CLASS_NAME& operator=(CLASS_NAME &&other) noexcept { if (this != &other) { shm_weak_move( - lipc::typed_nullptr(), - lipc::typed_nullptr(), + hipc::typed_nullptr(), + hipc::typed_nullptr(), other); } return *this; @@ -219,14 +219,14 @@ return *this; /** Move shm_init constructor */ void shm_init_main(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, CLASS_NAME &&other) noexcept { shm_weak_move(header, alloc, other); } /** Move operation */ void shm_weak_move(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, CLASS_NAME &other) { if (other.IsNull()) { return; } if (IsValid() && other.GetAllocator() != GetAllocator()) { @@ -256,8 +256,8 @@ CLASS_NAME(const CLASS_NAME &other) noexcept { CLASS_NAME& operator=(const CLASS_NAME &other) { if (this != &other) { shm_strong_copy( - lipc::typed_nullptr(), - lipc::typed_nullptr(), + hipc::typed_nullptr(), + hipc::typed_nullptr(), other); } return *this; @@ -265,14 +265,14 @@ CLASS_NAME& operator=(const CLASS_NAME &other) { /** Copy shm_init constructor */ void shm_init_main(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, const CLASS_NAME &other) { shm_strong_copy(header, alloc, other); } /** Strong Copy operation */ void shm_strong_copy(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, const CLASS_NAME &other) { if (other.IsNull()) { return; } shm_destroy(false); @@ -340,16 +340,16 @@ POINTER_T GetShmPointer() const { * ===================================*/ /** Get the allocator for this container */ -lipc::Allocator* GetAllocator() { +hipc::Allocator* GetAllocator() { return alloc_; } /** Get the allocator for this container */ -lipc::Allocator* GetAllocator() const { +hipc::Allocator* GetAllocator() const { return alloc_; } /** Get the shared-memory allocator id */ -lipc::allocator_id_t GetAllocatorId() const { +hipc::allocator_id_t GetAllocatorId() const { return alloc_->GetId(); } diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h index 1346b8aeb..9f98382ff 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h @@ -136,7 +136,7 @@ class ShmContainerExtendExample : public ShmContainer { /** Constructor. Deserialize the object from the reference. */ template - void shm_init(lipc::ShmRef &obj) { + void shm_init(hipc::ShmRef &obj) { shm_deserialize(obj->GetAllocator(), obj->header_); } @@ -184,14 +184,14 @@ class ShmContainerExtendExample : public ShmContainer { /** Move shm_init constructor */ void shm_init_main(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, CLASS_NAME &&other) noexcept { shm_weak_move(header, alloc, other); } /** Move operation */ void shm_weak_move(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, CLASS_NAME &other) { obj_.shm_weak_move(header, alloc, other); } @@ -218,13 +218,13 @@ class ShmContainerExtendExample : public ShmContainer { /** Copy shm_init constructor */ void shm_init_main(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, const CLASS_NAME &other) { shm_strong_copy(header, alloc, other); } /** Strong Copy operation */ - void shm_strong_copy(TYPED_HEADER *header, lipc::Allocator *alloc, + void shm_strong_copy(TYPED_HEADER *header, hipc::Allocator *alloc, const CLASS_NAME &other) { if (other.IsNull()) { return; } shm_destroy(false); diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h index 1112c9716..9a08e22e7 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h @@ -79,7 +79,7 @@ bool shm_deserialize(Allocator *alloc, /** Constructor. Deserialize the object from the reference. */ template -void shm_init(lipc::ShmRef &obj) { +void shm_init(hipc::ShmRef &obj) { shm_deserialize(obj->GetAllocator(), obj->header_); } @@ -127,14 +127,14 @@ return *this; /** Move shm_init constructor */ void shm_init_main(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, CLASS_NAME &&other) noexcept { shm_weak_move(header, alloc, other); } /** Move operation */ void shm_weak_move(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, CLASS_NAME &other) { obj_.shm_weak_move(header, alloc, other); } @@ -161,13 +161,13 @@ CLASS_NAME &operator=(const CLASS_NAME &other) { /** Copy shm_init constructor */ void shm_init_main(TYPED_HEADER *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, const CLASS_NAME &other) { shm_strong_copy(header, alloc, other); } /** Strong Copy operation */ -void shm_strong_copy(TYPED_HEADER *header, lipc::Allocator *alloc, +void shm_strong_copy(TYPED_HEADER *header, hipc::Allocator *alloc, const CLASS_NAME &other) { if (other.IsNull()) { return; } shm_destroy(false); diff --git a/hermes_shm/include/hermes_shm/data_structures/pair.h b/hermes_shm/include/hermes_shm/data_structures/pair.h index 6a999adc7..035854acf 100644 --- a/hermes_shm/include/hermes_shm/data_structures/pair.h +++ b/hermes_shm/include/hermes_shm/data_structures/pair.h @@ -83,8 +83,8 @@ class pair : public ShmContainer { SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) public: - lipc::ShmRef first_; - lipc::ShmRef second_; + hipc::ShmRef first_; + hipc::ShmRef second_; public: /** Default constructor */ @@ -105,8 +105,8 @@ class pair : public ShmContainer { alloc_, std::forward(first), std::forward(second)); - first_ = lipc::ShmRef(header_->first_.internal_ref(alloc_)); - second_ = lipc::ShmRef(header_->second_.internal_ref(alloc_)); + first_ = hipc::ShmRef(header_->first_.internal_ref(alloc_)); + second_ = hipc::ShmRef(header_->second_.internal_ref(alloc_)); } /** Construct pair by copying parameters */ @@ -116,8 +116,8 @@ class pair : public ShmContainer { shm_init_allocator(alloc); shm_init_header(header, alloc_, first, second); - first_ = lipc::ShmRef(header_->first_.internal_ref(alloc_)); - second_ = lipc::ShmRef(header_->second_.internal_ref(alloc_)); + first_ = hipc::ShmRef(header_->first_.internal_ref(alloc_)); + second_ = hipc::ShmRef(header_->second_.internal_ref(alloc_)); } /** Construct pair piecewise */ @@ -133,8 +133,8 @@ class pair : public ShmContainer { std::forward(hint), std::forward(first), std::forward(second)); - first_ = lipc::ShmRef(header_->first_.internal_ref(alloc_)); - second_ = lipc::ShmRef(header_->second_.internal_ref(alloc_)); + first_ = hipc::ShmRef(header_->first_.internal_ref(alloc_)); + second_ = hipc::ShmRef(header_->second_.internal_ref(alloc_)); } /** Move constructor */ @@ -165,8 +165,8 @@ class pair : public ShmContainer { /** Load from shared memory */ void shm_deserialize_main() { - first_ = lipc::ShmRef(header_->first_.internal_ref(alloc_)); - second_ = lipc::ShmRef(header_->second_.internal_ref(alloc_)); + first_ = hipc::ShmRef(header_->first_.internal_ref(alloc_)); + second_ = hipc::ShmRef(header_->second_.internal_ref(alloc_)); } /** Get the first object */ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h index 297fbff72..e80ce4b3e 100644 --- a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h @@ -59,7 +59,7 @@ template struct list_iterator_templ { public: /**< A shm reference to the containing list object. */ - lipc::ShmRef> list_; + hipc::ShmRef> list_; /**< A pointer to the entry in shared memory */ list_entry *entry_; /**< The offset of the entry in the shared-memory allocator */ @@ -458,7 +458,7 @@ class list : public ShmContainer { /** Find an element in this list */ list_iterator find(const T &entry) { for (auto iter = begin(); iter != end(); ++iter) { - lipc::ShmRef ref = *iter; + hipc::ShmRef ref = *iter; if (*ref == entry) { return iter; } diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h index b309921a2..80ee70487 100644 --- a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h @@ -32,11 +32,11 @@ class unordered_map; template struct unordered_map_iterator { public: - using COLLISION_T = lipc::pair; - using BUCKET_T = lipc::list; + using COLLISION_T = hipc::pair; + using BUCKET_T = hipc::list; public: - lipc::ShmRef> map_; + hipc::ShmRef> map_; vector_iterator bucket_; list_iterator collision_; @@ -69,12 +69,12 @@ struct unordered_map_iterator { } /** Get the pointed object */ - lipc::ShmRef operator*() { + hipc::ShmRef operator*() { return *collision_; } /** Get the pointed object */ - const lipc::ShmRef operator*() const { + const hipc::ShmRef operator*() const { return *collision_; } @@ -161,14 +161,14 @@ struct unordered_map_iterator { template struct ShmHeader : public ShmBaseHeader { public: - using COLLISION_T = lipc::pair; - using BUCKET_T = lipc::list; + using COLLISION_T = hipc::pair; + using BUCKET_T = hipc::list; public: ShmHeaderOrT> buckets_; RealNumber max_capacity_; RealNumber growth_; - lipc::atomic length_; + hipc::atomic length_; /** Default constructor. */ ShmHeader() = default; @@ -199,8 +199,8 @@ struct ShmHeader : public ShmBaseHeader { } /** Get a reference to the buckets */ - lipc::ShmRef> GetBuckets(Allocator *alloc) { - return lipc::ShmRef>(buckets_.internal_ref(alloc)); + hipc::ShmRef> GetBuckets(Allocator *alloc) { + return hipc::ShmRef>(buckets_.internal_ref(alloc)); } }; @@ -214,8 +214,8 @@ class unordered_map : public ShmContainer { friend unordered_map_iterator; public: - using COLLISION_T = lipc::pair; - using BUCKET_T = lipc::list; + using COLLISION_T = hipc::pair; + using BUCKET_T = hipc::list; public: //////////////////////////// @@ -275,7 +275,7 @@ class unordered_map : public ShmContainer { /** Destroy the unordered_map buckets */ void shm_destroy_main() { - lipc::ShmRef> buckets = GetBuckets(); + hipc::ShmRef> buckets = GetBuckets(); buckets->shm_destroy(); } @@ -315,9 +315,9 @@ class unordered_map : public ShmContainer { void erase(const Key &key) { if (header_ == nullptr) { shm_init(); } // Get the bucket the key belongs to - lipc::ShmRef> buckets = GetBuckets(); + hipc::ShmRef> buckets = GetBuckets(); size_t bkt_id = Hash{}(key) % buckets->size(); - lipc::ShmRef bkt = (*buckets)[bkt_id]; + hipc::ShmRef bkt = (*buckets)[bkt_id]; // Find and remove key from collision list list &collisions = *bkt; @@ -337,7 +337,7 @@ class unordered_map : public ShmContainer { void erase(unordered_map_iterator &iter) { if (iter == end()) return; // Acquire the bucket lock for a write (modifying collisions) - lipc::ShmRef bkt = *iter.bucket_; + hipc::ShmRef bkt = *iter.bucket_; // Erase the element from the collision list list &collisions = bkt; @@ -351,7 +351,7 @@ class unordered_map : public ShmContainer { * Erase the entire map * */ void clear() { - lipc::ShmRef> buckets = GetBuckets(); + hipc::ShmRef> buckets = GetBuckets(); size_t num_buckets = buckets->size(); buckets->clear(); buckets->resize(num_buckets); @@ -380,10 +380,10 @@ class unordered_map : public ShmContainer { GetShmPointer>>()); // Determine the bucket corresponding to the key - lipc::ShmRef> buckets = GetBuckets(); + hipc::ShmRef> buckets = GetBuckets(); size_t bkt_id = Hash{}(key) % buckets->size(); iter.bucket_ = buckets->begin() + bkt_id; - lipc::ShmRef bkt = (*iter.bucket_); + hipc::ShmRef bkt = (*iter.bucket_); list &collisions = *bkt; // Get the specific collision iterator @@ -404,7 +404,7 @@ class unordered_map : public ShmContainer { /** The number of buckets in the map */ size_t get_num_buckets() const { - lipc::ShmRef> buckets = GetBuckets(); + hipc::ShmRef> buckets = GetBuckets(); return buckets->size(); } @@ -455,9 +455,9 @@ class unordered_map : public ShmContainer { Key &key = entry.GetKey(); // Hash the key to a bucket - lipc::ShmRef> buckets = GetBuckets(); + hipc::ShmRef> buckets = GetBuckets(); size_t bkt_id = Hash{}(key) % buckets->size(); - lipc::ShmRef bkt = (*buckets)[bkt_id]; + hipc::ShmRef bkt = (*buckets)[bkt_id]; // Insert into the map list &collisions = *bkt; @@ -483,7 +483,7 @@ class unordered_map : public ShmContainer { if (header_ == nullptr) { shm_init(); } Key &key = entry.GetKey(); size_t bkt_id = Hash{}(key) % buckets.size(); - lipc::ShmRef bkt = buckets[bkt_id]; + hipc::ShmRef bkt = buckets[bkt_id]; list& collisions = bkt; collisions.emplace_back(std::move(entry)); return true; @@ -499,11 +499,11 @@ class unordered_map : public ShmContainer { inline unordered_map_iterator begin() const { unordered_map_iterator iter( GetShmPointer>>()); - lipc::ShmRef> buckets(GetBuckets()); + hipc::ShmRef> buckets(GetBuckets()); if (buckets->size() == 0) { return iter; } - lipc::ShmRef bkt = (*buckets)[0]; + hipc::ShmRef bkt = (*buckets)[0]; list &list = *bkt; iter.bucket_ = buckets->cbegin(); iter.collision_ = list.begin(); @@ -515,18 +515,18 @@ class unordered_map : public ShmContainer { inline unordered_map_iterator end() const { unordered_map_iterator iter( GetShmPointer>>()); - lipc::ShmRef> buckets(GetBuckets()); + hipc::ShmRef> buckets(GetBuckets()); iter.bucket_ = buckets->cend(); return iter; } /** Get the buckets */ - lipc::ShmRef> GetBuckets() { + hipc::ShmRef> GetBuckets() { return header_->GetBuckets(alloc_); } /** Get the buckets (const) */ - lipc::ShmRef> GetBuckets() const { + hipc::ShmRef> GetBuckets() const { return header_->GetBuckets(alloc_); } }; diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h index 6dbb05181..38996df27 100644 --- a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h @@ -30,7 +30,7 @@ class vector; template struct vector_iterator_templ { public: - lipc::ShmRef> vec_; + hipc::ShmRef> vec_; off64_t i_; /** Default constructor */ @@ -49,7 +49,7 @@ struct vector_iterator_templ { : vec_(vec), i_(static_cast(i)) {} /** Construct an iterator at \a i offset */ - inline explicit vector_iterator_templ(const lipc::ShmRef> &vec, + inline explicit vector_iterator_templ(const hipc::ShmRef> &vec, size_t i) : vec_(vec), i_(static_cast(i)) {} @@ -434,7 +434,7 @@ class vector : public ShmContainer { std::vector vec() { std::vector v; v.reserve(size()); - for (lipc::ShmRef entry : *this) { + for (hipc::ShmRef entry : *this) { v.emplace_back(*entry); } return v; @@ -470,25 +470,25 @@ class vector : public ShmContainer { } /** Index the vector at position i */ - lipc::ShmRef operator[](const size_t i) { + hipc::ShmRef operator[](const size_t i) { ShmHeaderOrT *vec = data_ar(); - return lipc::ShmRef(vec[i].internal_ref(alloc_)); + return hipc::ShmRef(vec[i].internal_ref(alloc_)); } /** Get first element of vector */ - lipc::ShmRef front() { + hipc::ShmRef front() { return (*this)[0]; } /** Get last element of vector */ - lipc::ShmRef back() { + hipc::ShmRef back() { return (*this)[size() - 1]; } /** Index the vector at position i */ - const lipc::ShmRef operator[](const size_t i) const { + const hipc::ShmRef operator[](const size_t i) const { ShmHeaderOrT *vec = data_ar_const(); - return lipc::ShmRef(vec[i].internal_ref(alloc_)); + return hipc::ShmRef(vec[i].internal_ref(alloc_)); } /** Construct an element at the back of the vector */ @@ -632,7 +632,7 @@ class vector : public ShmContainer { new_vec = alloc_->template AllocateObjs>(max_length, new_p); for (size_t i = 0; i < header_->length_; ++i) { - lipc::ShmRef old = (*this)[i]; + hipc::ShmRef old = (*this)[i]; Allocator::ConstructObj>( *(new_vec + i), alloc_, std::move(*old)); diff --git a/hermes_shm/include/hermes_shm/memory/memory_manager.h b/hermes_shm/include/hermes_shm/memory/memory_manager.h index 29990d85c..6e912f57b 100644 --- a/hermes_shm/include/hermes_shm/memory/memory_manager.h +++ b/hermes_shm/include/hermes_shm/memory/memory_manager.h @@ -18,7 +18,7 @@ #include "hermes_shm/memory/allocator/allocator_factory.h" #include -namespace lipc = hermes_shm::ipc; +namespace hipc = hermes_shm::ipc; namespace hermes_shm::ipc { diff --git a/hermes_shm/include/hermes_shm/types/charbuf.h b/hermes_shm/include/hermes_shm/types/charbuf.h index 741ab6537..155a5b1aa 100644 --- a/hermes_shm/include/hermes_shm/types/charbuf.h +++ b/hermes_shm/include/hermes_shm/types/charbuf.h @@ -21,7 +21,7 @@ namespace hermes_shm { /** An uninterpreted array of bytes */ struct charbuf { - lipc::Allocator *alloc_; /**< The allocator used to allocate data */ + hipc::Allocator *alloc_; /**< The allocator used to allocate data */ char *data_; /**< The pointer to data */ size_t size_; /**< The size of data */ bool destructable_; /**< Whether or not this container owns data */ @@ -173,8 +173,8 @@ struct charbuf { private: /** Allocate charbuf */ - bool Allocate(lipc::Allocator *alloc, size_t size) { - lipc::OffsetPointer p; + bool Allocate(hipc::Allocator *alloc, size_t size) { + hipc::OffsetPointer p; if (size == 0) { alloc_ = nullptr; data_ = nullptr; diff --git a/hermes_shm/test/unit/allocators/allocator.cc b/hermes_shm/test/unit/allocators/allocator.cc index a1c65a2d3..9cf4c3271 100644 --- a/hermes_shm/test/unit/allocators/allocator.cc +++ b/hermes_shm/test/unit/allocators/allocator.cc @@ -102,7 +102,7 @@ void MultiPageAllocationTest(Allocator *alloc) { } TEST_CASE("StackAllocator") { - auto alloc = Pretest(); + auto alloc = Pretest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); PageAllocationTest(alloc); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); @@ -110,7 +110,7 @@ TEST_CASE("StackAllocator") { } TEST_CASE("MultiPageAllocator") { - auto alloc = Pretest(); + auto alloc = Pretest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); PageAllocationTest(alloc); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); @@ -123,7 +123,7 @@ TEST_CASE("MultiPageAllocator") { } TEST_CASE("MallocAllocator") { - auto alloc = Pretest(); + auto alloc = Pretest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); PageAllocationTest(alloc); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); diff --git a/hermes_shm/test/unit/allocators/allocator_thread.cc b/hermes_shm/test/unit/allocators/allocator_thread.cc index d2e7e6cb5..b76762f63 100644 --- a/hermes_shm/test/unit/allocators/allocator_thread.cc +++ b/hermes_shm/test/unit/allocators/allocator_thread.cc @@ -26,7 +26,7 @@ void MultiThreadedPageAllocationTest(Allocator *alloc) { } TEST_CASE("StackAllocatorMultithreaded") { - auto alloc = Pretest(); + auto alloc = Pretest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); MultiThreadedPageAllocationTest(alloc); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); @@ -34,7 +34,7 @@ TEST_CASE("StackAllocatorMultithreaded") { } TEST_CASE("MultiPageAllocatorMultithreaded") { - auto alloc = Pretest(); + auto alloc = Pretest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); MultiThreadedPageAllocationTest(alloc); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); diff --git a/hermes_shm/test/unit/basic_test.h b/hermes_shm/test/unit/basic_test.h index e249ed22d..e669ed34e 100644 --- a/hermes_shm/test/unit/basic_test.h +++ b/hermes_shm/test/unit/basic_test.h @@ -34,8 +34,8 @@ static bool VerifyBuffer(char *ptr, size_t size, char nonce) { /** var = TYPE(val) */ #define SET_VAR_TO_INT_OR_STRING(TYPE, VAR, VAL)\ - if constexpr(std::is_same_v) {\ - VAR = lipc::string(std::to_string(VAL));\ + if constexpr(std::is_same_v) {\ + VAR = hipc::string(std::to_string(VAL));\ } else if constexpr(std::is_same_v) {\ VAR = std::string(std::to_string(VAL));\ } else {\ @@ -49,7 +49,7 @@ static bool VerifyBuffer(char *ptr, size_t size, char nonce) { /** RET = int(TYPE(VAR)); */ #define GET_INT_FROM_VAR(TYPE, RET, VAR)\ - if constexpr(std::is_same_v) {\ + if constexpr(std::is_same_v) {\ RET = atoi((VAR).str().c_str());\ } else if constexpr(std::is_same_v) {\ RET = atoi((VAR).c_str());\ diff --git a/hermes_shm/test/unit/data_structures/backend/memory_manager.cc b/hermes_shm/test/unit/data_structures/backend/memory_manager.cc index 63f9e1f00..e6d6a6742 100644 --- a/hermes_shm/test/unit/data_structures/backend/memory_manager.cc +++ b/hermes_shm/test/unit/data_structures/backend/memory_manager.cc @@ -38,9 +38,9 @@ TEST_CASE("MemoryManager") { if (rank == 0) { std::cout << "Creating SHMEM (rank 0): " << shm_url << std::endl; - mem_mngr->CreateBackend( + mem_mngr->CreateBackend( MemoryManager::kDefaultBackendSize, shm_url); - mem_mngr->CreateAllocator( + mem_mngr->CreateAllocator( shm_url, alloc_id, 0); } MPI_Barrier(MPI_COMM_WORLD); @@ -51,12 +51,12 @@ TEST_CASE("MemoryManager") { MPI_Barrier(MPI_COMM_WORLD); if (rank == 0) { std::cout << "Allocating pages (rank 0)" << std::endl; - lipc::Allocator *alloc = mem_mngr->GetAllocator(alloc_id); + hipc::Allocator *alloc = mem_mngr->GetAllocator(alloc_id); char *page = alloc->AllocatePtr(page_size); memset(page, nonce, page_size); auto header = alloc->GetCustomHeader(); - lipc::Pointer p1 = mem_mngr->Convert(alloc_id, page); - lipc::Pointer p2 = mem_mngr->Convert(page); + hipc::Pointer p1 = mem_mngr->Convert(alloc_id, page); + hipc::Pointer p2 = mem_mngr->Convert(page); header->p_ = p1; REQUIRE(p1 == p2); REQUIRE(VerifyBuffer(page, page_size, nonce)); @@ -64,7 +64,7 @@ TEST_CASE("MemoryManager") { MPI_Barrier(MPI_COMM_WORLD); if (rank != 0) { std::cout << "Finding and checking pages (rank 1)" << std::endl; - lipc::Allocator *alloc = mem_mngr->GetAllocator(alloc_id); + hipc::Allocator *alloc = mem_mngr->GetAllocator(alloc_id); SimpleHeader *header = alloc->GetCustomHeader(); char *page = alloc->Convert(header->p_); REQUIRE(VerifyBuffer(page, page_size, nonce)); diff --git a/hermes_shm/test/unit/data_structures/containers/list.cc b/hermes_shm/test/unit/data_structures/containers/list.cc index 365138a44..e13939ed9 100644 --- a/hermes_shm/test/unit/data_structures/containers/list.cc +++ b/hermes_shm/test/unit/data_structures/containers/list.cc @@ -48,7 +48,7 @@ TEST_CASE("ListOfInt") { TEST_CASE("ListOfString") { Allocator *alloc = alloc_g; REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); - ListTest(); + ListTest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); } diff --git a/hermes_shm/test/unit/data_structures/containers/list.h b/hermes_shm/test/unit/data_structures/containers/list.h index 82df721a4..b5819eabb 100644 --- a/hermes_shm/test/unit/data_structures/containers/list.h +++ b/hermes_shm/test/unit/data_structures/containers/list.h @@ -51,7 +51,7 @@ class ListTestSuite { const Container &obj = obj_; int fcur = 0; for (auto iter = obj.cbegin(); iter != obj.cend(); ++iter) { - lipc::ShmRef num = *iter; + hipc::ShmRef num = *iter; CREATE_SET_VAR_TO_INT_OR_STRING(T, fcur_conv, fcur); REQUIRE(*num == fcur_conv); ++fcur; diff --git a/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc b/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc index 8ce61ef1f..49f1a2d2a 100644 --- a/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc +++ b/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc @@ -26,7 +26,7 @@ using hermes_shm::ipc::TypedPointer; template void ManualPtrTest() { Allocator *alloc = alloc_g; - lipc::SmartPtrTestSuite> test; + hipc::SmartPtrTestSuite> test; CREATE_SET_VAR_TO_INT_OR_STRING(T, num, 25); test.ptr_ = make_mptr(num); test.DereferenceTest(num); @@ -42,6 +42,6 @@ void ManualPtrTest() { TEST_CASE("ManualPtrOfString") { Allocator *alloc = alloc_g; REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); - ManualPtrTest(); + ManualPtrTest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); } diff --git a/hermes_shm/test/unit/data_structures/containers/pair.cc b/hermes_shm/test/unit/data_structures/containers/pair.cc index 19a6fd29c..aa047f447 100644 --- a/hermes_shm/test/unit/data_structures/containers/pair.cc +++ b/hermes_shm/test/unit/data_structures/containers/pair.cc @@ -23,7 +23,7 @@ void PairTest() { { CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); - lipc::pair data(alloc, first, second); + hipc::pair data(alloc, first, second); REQUIRE(*data.first_ == first); REQUIRE(*data.second_ == second); } @@ -32,8 +32,8 @@ void PairTest() { { CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); - lipc::pair data(alloc, first, second); - lipc::pair cpy(data); + hipc::pair data(alloc, first, second); + hipc::pair cpy(data); REQUIRE(*cpy.first_ == first); REQUIRE(*cpy.second_ == second); } @@ -42,8 +42,8 @@ void PairTest() { { CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); - lipc::pair data(alloc, first, second); - lipc::pair cpy(std::move(data)); + hipc::pair data(alloc, first, second); + hipc::pair cpy(std::move(data)); REQUIRE(*cpy.first_ == first); REQUIRE(*cpy.second_ == second); } @@ -59,6 +59,6 @@ TEST_CASE("PairOfIntInt") { TEST_CASE("PairOfIntString") { Allocator *alloc = alloc_g; REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); - PairTest(); + PairTest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); } diff --git a/hermes_shm/test/unit/data_structures/containers/test_init.cc b/hermes_shm/test/unit/data_structures/containers/test_init.cc index 567cf42da..df4498908 100644 --- a/hermes_shm/test/unit/data_structures/containers/test_init.cc +++ b/hermes_shm/test/unit/data_structures/containers/test_init.cc @@ -26,7 +26,7 @@ void Posttest() { } void MainPretest() { - Pretest(); + Pretest(); } void MainPosttest() { diff --git a/hermes_shm/test/unit/data_structures/containers/vector.cc b/hermes_shm/test/unit/data_structures/containers/vector.cc index 13a5caf22..66adca8ce 100644 --- a/hermes_shm/test/unit/data_structures/containers/vector.cc +++ b/hermes_shm/test/unit/data_structures/containers/vector.cc @@ -62,7 +62,7 @@ TEST_CASE("VectorOfInt") { TEST_CASE("VectorOfString") { Allocator *alloc = alloc_g; REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); - VectorTest(); + VectorTest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); } diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc b/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc index 22be9bc47..73a2bc64e 100644 --- a/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc +++ b/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc @@ -49,7 +49,7 @@ void ListVecTest(size_t count) { { REQUIRE(obj.size() == count); int i = 0; - for (lipc::ShmRef var : obj) { + for (hipc::ShmRef var : obj) { CREATE_SET_VAR_TO_INT_OR_STRING(T, orig, i); REQUIRE(*var == orig); ++i; @@ -61,7 +61,7 @@ void ListVecTest(size_t count) { { if (rank == 0) { CREATE_SET_VAR_TO_INT_OR_STRING(T, update, count); - lipc::ShmRef first = *obj.begin(); + hipc::ShmRef first = *obj.begin(); (*first) = update; } MPI_Barrier(MPI_COMM_WORLD); @@ -70,7 +70,7 @@ void ListVecTest(size_t count) { // Check if modification received { CREATE_SET_VAR_TO_INT_OR_STRING(T, update, count); - lipc::ShmRef first = *obj.begin(); + hipc::ShmRef first = *obj.begin(); REQUIRE((*first) == update); MPI_Barrier(MPI_COMM_WORLD); MPI_Barrier(MPI_COMM_WORLD); @@ -94,17 +94,17 @@ void ListVecTest(size_t count) { } TEST_CASE("ListOfIntMpi") { - ListVecTest>(100); + ListVecTest>(100); } TEST_CASE("ListOfStringMpi") { - ListVecTest>(100); + ListVecTest>(100); } TEST_CASE("VectorOfIntMpi") { - ListVecTest>(100); + ListVecTest>(100); } TEST_CASE("VectorOfStringMpi") { - ListVecTest>(100); + ListVecTest>(100); } diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc index e23fcf7d4..b74bb31f3 100644 --- a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc +++ b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc @@ -40,7 +40,7 @@ void MainPretest() { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (rank == 0) { - PretestRank0(); + PretestRank0(); } MPI_Barrier(MPI_COMM_WORLD); if (rank != 0) { diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 55784c74c..ebf37e4a8 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -28,7 +28,7 @@ Bucket::Bucket(const std::string &bkt_name, Context &ctx, const IoClientContext &opts) : mdm_(&HERMES->mdm_), bpm_(&HERMES->bpm_), name_(bkt_name) { - lipc::string lname(bkt_name); + hipc::string lname(bkt_name); id_ = mdm_->LocalGetOrCreateBucket(lname, opts); } @@ -57,7 +57,7 @@ void Bucket::UnlockBucket(MdLockType lock_type) { * Rename this bucket * */ void Bucket::Rename(std::string new_bkt_name) { - lipc::string lname(new_bkt_name); + hipc::string lname(new_bkt_name); mdm_->LocalRenameBucket(id_, lname); } @@ -76,7 +76,7 @@ void Bucket::Destroy() { * */ Status Bucket::GetBlobId(const std::string &blob_name, BlobId &blob_id) { - lipc::string lblob_name(blob_name); + hipc::string lblob_name(blob_name); blob_id = mdm_->LocalGetBlobId(GetId(), lblob_name); return Status(); } @@ -89,7 +89,7 @@ Status Bucket::GetBlobId(const std::string &blob_name, * @return The Status of the operation * */ Status Bucket::GetBlobName(const BlobId &blob_id, std::string &blob_name) { - lipc::string lblob_name(blob_name); + hipc::string lblob_name(blob_name); blob_name = mdm_->LocalGetBlobName(blob_id); return Status(); } @@ -117,7 +117,7 @@ Status Bucket::TryCreateBlob(const std::string &blob_name, Context &ctx, const IoClientContext &opts) { std::pair ret = mdm_->LocalBucketTryCreateBlob( - id_, lipc::charbuf(blob_name)); + id_, hipc::charbuf(blob_name)); blob_id = ret.first; if (ret.second) { mdm_->LocalBucketRegisterBlobId(id_, @@ -146,7 +146,7 @@ Status Bucket::Put(std::string blob_name, for (auto &schema : schemas) { // TODO(llogan): rpcify auto buffers = bpm_->LocalAllocateAndSetBuffers(schema, blob); - auto put_ret = mdm_->LocalBucketPutBlob(id_, lipc::string(blob_name), + auto put_ret = mdm_->LocalBucketPutBlob(id_, hipc::string(blob_name), blob.size(), buffers); blob_id = std::get<0>(put_ret); bool did_create = std::get<1>(put_ret); @@ -201,7 +201,7 @@ Status Bucket::PartialPutOrCreate(const std::string &blob_name, auto io_client = IoClientFactory::Get(opts.type_); full_blob.resize(opts.backend_size_); if (io_client) { - io_client->ReadBlob(lipc::charbuf(name_), + io_client->ReadBlob(hipc::charbuf(name_), full_blob, opts, status); } } @@ -259,7 +259,7 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, auto io_client = IoClientFactory::Get(opts.type_); full_blob.resize(opts.backend_size_); if (io_client) { - io_client->ReadBlob(lipc::charbuf(name_), full_blob, opts, status); + io_client->ReadBlob(hipc::charbuf(name_), full_blob, opts, status); if (opts.adapter_mode_ != AdapterMode::kBypass) { Put(blob_name, full_blob, blob_id, ctx); } @@ -293,7 +293,7 @@ void Bucket::FlushBlob(BlobId blob_id, auto io_client = IoClientFactory::Get(opts.type_); if (io_client) { IoClientContext decode_opts = io_client->DecodeBlobName(opts, blob_name); - io_client->WriteBlob(lipc::charbuf(name_), + io_client->WriteBlob(hipc::charbuf(name_), full_blob, decode_opts, status); @@ -334,7 +334,7 @@ bool Bucket::ContainsBlob(BlobId blob_id) { void Bucket::RenameBlob(BlobId blob_id, std::string new_blob_name, Context &ctx) { - lipc::string lnew_blob_name(new_blob_name); + hipc::string lnew_blob_name(new_blob_name); mdm_->LocalRenameBlob(id_, blob_id, lnew_blob_name); } diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 5f2e47b35..81489a31a 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -121,11 +121,11 @@ void Hermes::LoadClientConfig(std::string config_path) { void Hermes::InitSharedMemory() { // Create shared-memory allocator auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; - mem_mngr->CreateBackend( - lipc::MemoryManager::kDefaultBackendSize, + mem_mngr->CreateBackend( + hipc::MemoryManager::kDefaultBackendSize, server_config_.shmem_name_); main_alloc_ = - mem_mngr->CreateAllocator( + mem_mngr->CreateAllocator( server_config_.shmem_name_, main_alloc_id, sizeof(HermesShmHeader)); @@ -135,7 +135,7 @@ void Hermes::InitSharedMemory() { void Hermes::LoadSharedMemory() { // Load shared-memory allocator auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; - mem_mngr->AttachBackend(lipc::MemoryBackendType::kPosixShmMmap, + mem_mngr->AttachBackend(hipc::MemoryBackendType::kPosixShmMmap, server_config_.shmem_name_); main_alloc_ = mem_mngr->GetAllocator(main_alloc_id); header_ = main_alloc_->GetCustomHeader(); diff --git a/src/api/hermes.h b/src/api/hermes.h index d378323ac..bc1891879 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -40,7 +40,7 @@ class VBucket; * The Hermes shared-memory header * */ struct HermesShmHeader { - lipc::Pointer ram_tier_; + hipc::Pointer ram_tier_; MetadataManagerShmHeader mdm_; BufferPoolShmHeader bpm_; }; @@ -59,7 +59,7 @@ class Hermes { BufferOrganizer borg_; COMM_TYPE comm_; RPC_TYPE rpc_; - lipc::Allocator *main_alloc_; + hipc::Allocator *main_alloc_; bool is_being_initialized_; bool is_initialized_; bool is_terminated_; diff --git a/src/api/vbucket.cc b/src/api/vbucket.cc index 61c673252..eaef59737 100644 --- a/src/api/vbucket.cc +++ b/src/api/vbucket.cc @@ -25,7 +25,7 @@ VBucket::VBucket(const std::string &name, Context &ctx, const IoClientContext &opts) : mdm_(&HERMES->mdm_), ctx_(ctx) { - lipc::string lname(name); + hipc::string lname(name); // TODO(llogan): rpcify id_ = mdm_->LocalGetOrCreateVBucket(lname, opts); } @@ -36,7 +36,7 @@ VBucket::VBucket(const std::string &name, * @param name the name of the new vbucket * */ void VBucket::Rename(std::string name) { - lipc::string lname(name); + hipc::string lname(name); mdm_->LocalRenameVBucket(id_, lname); } diff --git a/src/borg_io_clients/borg_posix_client.h b/src/borg_io_clients/borg_posix_client.h index 365810fea..82aaac9fd 100644 --- a/src/borg_io_clients/borg_posix_client.h +++ b/src/borg_io_clients/borg_posix_client.h @@ -26,7 +26,7 @@ class PosixIoClient : public BorgIoClient { public: bool Init(DeviceInfo &dev_info) override { auto api = HERMES_POSIX_API; - lipc::string text = (*dev_info.mount_dir_) + + hipc::string text = (*dev_info.mount_dir_) + "/" + "slab_" + (*dev_info.dev_name_); (*dev_info.mount_point_) = std::move(text); int fd = api->open((*dev_info.mount_point_).c_str(), diff --git a/src/buffer_organizer.cc b/src/buffer_organizer.cc index 6debd42ff..be767f9b0 100644 --- a/src/buffer_organizer.cc +++ b/src/buffer_organizer.cc @@ -23,8 +23,8 @@ namespace hermes { * */ void BufferOrganizer::shm_init() { mdm_ = &HERMES->mdm_; - for (lipc::ShmRef target : (*mdm_->targets_)) { - lipc::ShmRef dev_info = + for (hipc::ShmRef target : (*mdm_->targets_)) { + hipc::ShmRef dev_info = (*mdm_->devices_)[target->id_.GetDeviceId()]; if (dev_info->mount_dir_->size() == 0) { dev_info->header_->io_api_ = IoInterface::kRam; @@ -50,13 +50,13 @@ void BufferOrganizer::shm_deserialize() { /** Stores a blob into a set of buffers */ RPC void BufferOrganizer::LocalPlaceBlobInBuffers( - const Blob &blob, lipc::vector &buffers) { + const Blob &blob, hipc::vector &buffers) { size_t blob_off = 0; - for (lipc::ShmRef buffer_info : buffers) { + for (hipc::ShmRef buffer_info : buffers) { if (buffer_info->tid_.GetNodeId() != mdm_->rpc_->node_id_) { continue; } - lipc::ShmRef dev_info = + hipc::ShmRef dev_info = (*mdm_->devices_)[buffer_info->tid_.GetDeviceId()]; auto io_client = borg::BorgIoClientFactory::Get(dev_info->header_->io_api_); bool ret = io_client->Write(*dev_info, @@ -72,14 +72,14 @@ RPC void BufferOrganizer::LocalPlaceBlobInBuffers( /** Stores a blob into a set of buffers */ RPC Blob BufferOrganizer::LocalReadBlobFromBuffers( - lipc::vector &buffers) { + hipc::vector &buffers) { Blob blob(SumBufferBlobSizes(buffers)); size_t blob_off = 0; - for (lipc::ShmRef buffer_info : buffers) { + for (hipc::ShmRef buffer_info : buffers) { if (buffer_info->tid_.GetNodeId() != mdm_->rpc_->node_id_) { continue; } - lipc::ShmRef dev_info = + hipc::ShmRef dev_info = (*mdm_->devices_)[buffer_info->tid_.GetDeviceId()]; auto io_client = borg::BorgIoClientFactory::Get(dev_info->header_->io_api_); bool ret = io_client->Read(*dev_info, blob.data() + blob_off, @@ -94,8 +94,8 @@ RPC Blob BufferOrganizer::LocalReadBlobFromBuffers( } /** Copies one buffer set into another buffer set */ -RPC void BufferOrganizer::LocalCopyBuffers(lipc::vector &dst, - lipc::vector &src) { +RPC void BufferOrganizer::LocalCopyBuffers(hipc::vector &dst, + hipc::vector &src) { } } // namespace hermes diff --git a/src/buffer_organizer.h b/src/buffer_organizer.h index c1f6be58a..481d0a3da 100644 --- a/src/buffer_organizer.h +++ b/src/buffer_organizer.h @@ -20,9 +20,9 @@ namespace hermes { /** Calculates the total size of a blob's buffers */ -static inline size_t SumBufferBlobSizes(lipc::vector &buffers) { +static inline size_t SumBufferBlobSizes(hipc::vector &buffers) { size_t sum = 0; - for (lipc::ShmRef buffer_ref : buffers) { + for (hipc::ShmRef buffer_ref : buffers) { sum += (*buffer_ref).blob_size_; } return sum; @@ -55,14 +55,14 @@ class BufferOrganizer { /** Stores a blob into a set of buffers */ RPC void LocalPlaceBlobInBuffers(const Blob &blob, - lipc::vector &buffers); + hipc::vector &buffers); /** Stores a blob into a set of buffers */ - RPC Blob LocalReadBlobFromBuffers(lipc::vector &buffers); + RPC Blob LocalReadBlobFromBuffers(hipc::vector &buffers); /** Copies one buffer set into another buffer set */ - RPC void LocalCopyBuffers(lipc::vector &dst, - lipc::vector &src); + RPC void LocalCopyBuffers(hipc::vector &dst, + hipc::vector &src); }; } // namespace hermes diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index f845a4fdb..c47263038 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -24,7 +24,7 @@ namespace hermes { void BufferPool::shm_init(BufferPoolShmHeader *header) { mdm_ = &HERMES->mdm_; borg_ = &HERMES->borg_; - target_allocs_ = lipc::make_mptr>( + target_allocs_ = hipc::make_mptr>( HERMES->main_alloc_); target_allocs_->resize(mdm_->targets_->size()); shm_serialize(header); @@ -52,17 +52,17 @@ void BufferPool::shm_deserialize(BufferPoolShmHeader *header) { * * TODO(llogan): use better allocator policy * */ -lipc::vector +hipc::vector BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, const Blob &blob) { - lipc::vector buffers(HERMES->main_alloc_); + hipc::vector buffers(HERMES->main_alloc_); size_t blob_off_ = 0; for (auto plcmnt : schema.plcmnts_) { if (plcmnt.tid_.GetNodeId() != mdm_->rpc_->node_id_) { blob_off_ += plcmnt.size_; continue; } - lipc::ShmRef alloc = + hipc::ShmRef alloc = (*target_allocs_)[plcmnt.tid_.GetDeviceId()]; BufferInfo info; info.t_off_ = alloc->cur_off_.load(); @@ -85,7 +85,7 @@ BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, * * TODO(llogan): actually implement * */ -bool BufferPool::LocalReleaseBuffers(lipc::vector &buffers) { +bool BufferPool::LocalReleaseBuffers(hipc::vector &buffers) { return true; } diff --git a/src/buffer_pool.h b/src/buffer_pool.h index 16dc6ebec..5ca1bc6ea 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -22,8 +22,8 @@ class MetadataManager; class BufferOrganizer; struct BufferPoolAllocator { - lipc::atomic max_size_; - lipc::atomic cur_off_; + hipc::atomic max_size_; + hipc::atomic cur_off_; /** Default constructor */ BufferPoolAllocator() = default; @@ -41,7 +41,7 @@ struct BufferPoolAllocator { * The shared-memory representation of the BufferPool * */ struct BufferPoolShmHeader { - lipc::TypedPointer> alloc_ar_; + hipc::TypedPointer> alloc_ar_; }; /** @@ -52,7 +52,7 @@ class BufferPool { MetadataManager *mdm_; BufferOrganizer *borg_; /** Per-target allocator */ - lipc::mptr> target_allocs_; + hipc::mptr> target_allocs_; public: BufferPool() = default; @@ -75,14 +75,14 @@ class BufferPool { /** * Allocate buffers from the targets according to the schema * */ - RPC lipc::vector + RPC hipc::vector LocalAllocateAndSetBuffers(PlacementSchema &schema, const Blob &blob); /** * Free buffers from the BufferPool * */ - RPC bool LocalReleaseBuffers(lipc::vector &buffers); + RPC bool LocalReleaseBuffers(hipc::vector &buffers); }; } // namespace hermes diff --git a/src/config_server.cc b/src/config_server.cc index 7f1cf3b7e..a19fcf132 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -31,11 +31,11 @@ namespace hermes::config { void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { devices_.clear(); for (auto device : yaml_conf) { - DeviceInfo dev(lipc::typed_nullptr()); + DeviceInfo dev(hipc::typed_nullptr()); auto dev_info = device.second; - (*dev.dev_name_) = lipc::string( + (*dev.dev_name_) = hipc::string( device.first.as()); - (*dev.mount_dir_) = lipc::string( + (*dev.mount_dir_) = hipc::string( dev_info["mount_point"].as()); dev.header_->borg_min_thresh_ = dev_info["borg_capacity_thresh"][0].as(); @@ -51,7 +51,7 @@ void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { ParseSize(dev_info["bandwidth"].as()); dev.header_->latency_ = ParseLatency(dev_info["latency"].as()); - ParseVector>( + ParseVector>( dev_info["slab_sizes"], *dev.slab_sizes_); devices_.emplace_back(std::move(dev)); } diff --git a/src/config_server.h b/src/config_server.h index 5586a6e75..f786c08ac 100644 --- a/src/config_server.h +++ b/src/config_server.h @@ -31,19 +31,19 @@ enum class IoInterface { * DeviceInfo shared-memory representation * */ template<> -struct ShmHeader : public lipc::ShmBaseHeader { +struct ShmHeader : public hipc::ShmBaseHeader { /** The human-readable name of the device */ - lipc::TypedPointer dev_name_; + hipc::TypedPointer dev_name_; /** The I/O interface for the device */ IoInterface io_api_; /** The minimum transfer size of each device */ size_t block_size_; /** The unit of each slab, a multiple of the Device's block size */ - lipc::TypedPointer> slab_sizes_; + hipc::TypedPointer> slab_sizes_; /** The directory the device is mounted on */ - lipc::TypedPointer mount_dir_; + hipc::TypedPointer mount_dir_; /** The file to create on the device */ - lipc::TypedPointer mount_point_; + hipc::TypedPointer mount_point_; /** Device capacity (bytes) */ size_t capacity_; /** Bandwidth of a device (MBps) */ @@ -59,24 +59,24 @@ struct ShmHeader : public lipc::ShmBaseHeader { /** * Device information defined in server config * */ -struct DeviceInfo : public lipc::ShmContainer { +struct DeviceInfo : public hipc::ShmContainer { SHM_CONTAINER_TEMPLATE(DeviceInfo, DeviceInfo, ShmHeader) /** The human-readable name of the device */ - lipc::mptr dev_name_; + hipc::mptr dev_name_; /** The unit of each slab, a multiple of the Device's block size */ - lipc::mptr> slab_sizes_; + hipc::mptr> slab_sizes_; /** The directory the device is mounted on */ - lipc::mptr mount_dir_; + hipc::mptr mount_dir_; /** The file to create on the device */ - lipc::mptr mount_point_; + hipc::mptr mount_point_; /** Default Constructor */ DeviceInfo() = default; /** Default SHM Constructor */ void shm_init_main(ShmHeader *header, - lipc::Allocator *alloc) { + hipc::Allocator *alloc) { shm_init_allocator(alloc); shm_init_header(header); dev_name_.shm_init(alloc_); @@ -112,7 +112,7 @@ struct DeviceInfo : public lipc::ShmContainer { /** Move another object into this object. */ void shm_weak_move_main(ShmHeader *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, DeviceInfo &other) { shm_init_allocator(alloc); shm_init_header(header); @@ -126,7 +126,7 @@ struct DeviceInfo : public lipc::ShmContainer { /** Copy another object into this object */ void shm_strong_copy_main(ShmHeader *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, const DeviceInfo &other) { shm_init_allocator(alloc); shm_init_header(header); diff --git a/src/constants.h b/src/constants.h index 3e3123f23..4889e3dce 100644 --- a/src/constants.h +++ b/src/constants.h @@ -17,7 +17,7 @@ namespace hermes { -static const lipc::allocator_id_t main_alloc_id(0, 1); +static const hipc::allocator_id_t main_alloc_id(0, 1); static const char* kHermesServerConf = "HERMES_CONF"; static const char* kHermesClientConf = "HERMES_CLIENT_CONF"; diff --git a/src/data_placement_engine.cc b/src/data_placement_engine.cc index 187b3fc48..d02aadb8c 100644 --- a/src/data_placement_engine.cc +++ b/src/data_placement_engine.cc @@ -40,7 +40,7 @@ Status DPE::CalculatePlacement(const std::vector &blob_sizes, // Reset the output schema output.clear(); // Get the capacity/bandwidth of targets - lipc::vector targets; + hipc::vector targets; switch (static_cast(i)) { case TopologyType::Local: { targets = mdm_->LocalGetTargetInfo(); diff --git a/src/data_placement_engine.h b/src/data_placement_engine.h index 0bab00138..a7d2d25ee 100644 --- a/src/data_placement_engine.h +++ b/src/data_placement_engine.h @@ -44,7 +44,7 @@ class DPE { * algorithm given a context. * */ virtual Status Placement(const std::vector &blob_sizes, - const lipc::vector &targets, + const hipc::vector &targets, const api::Context &ctx, std::vector &output) = 0; diff --git a/src/data_structures.h b/src/data_structures.h index ae4bbc660..122f25b4f 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -21,7 +21,7 @@ #include #include -namespace lipc = hermes_shm::ipc; +namespace hipc = hermes_shm::ipc; using hermes_shm::RwLock; using hermes_shm::Mutex; diff --git a/src/dpe/minimize_io_time.cc b/src/dpe/minimize_io_time.cc index 1fa5b5e5c..28aaef452 100644 --- a/src/dpe/minimize_io_time.cc +++ b/src/dpe/minimize_io_time.cc @@ -19,7 +19,7 @@ namespace hermes { Status MinimizeIoTime::Placement(const std::vector &blob_sizes, - const lipc::vector &targets, + const hipc::vector &targets, const api::Context &ctx, std::vector &output) { Status result; @@ -132,7 +132,7 @@ Status MinimizeIoTime::Placement(const std::vector &blob_sizes, void MinimizeIoTime::PlaceBytes(size_t j, ssize_t bytes, std::vector &vars_bytes, - const lipc::vector &targets) { + const hipc::vector &targets) { if (vars_bytes[j] == 0) { PlaceBytes(j+1, bytes, vars_bytes, targets); return; @@ -154,7 +154,7 @@ void MinimizeIoTime::PlaceBytes(size_t j, ssize_t bytes, PlaceBytes(j+1, io_diff, vars_bytes, targets); } -void MinimizeIoTime::GetPlacementRatios(const lipc::vector &targets, +void MinimizeIoTime::GetPlacementRatios(const hipc::vector &targets, const api::Context &ctx) { placement_ratios_.reserve(targets.size()); if (ctx.minimize_io_time_options.use_placement_ratio) { diff --git a/src/dpe/minimize_io_time.h b/src/dpe/minimize_io_time.h index dbab495fc..4dc9acd85 100644 --- a/src/dpe/minimize_io_time.h +++ b/src/dpe/minimize_io_time.h @@ -27,7 +27,7 @@ class MinimizeIoTime : public DPE { MinimizeIoTime() = default; ~MinimizeIoTime() = default; Status Placement(const std::vector &blob_sizes, - const lipc::vector &targets, + const hipc::vector &targets, const api::Context &ctx, std::vector &output); @@ -36,9 +36,9 @@ class MinimizeIoTime : public DPE { size_t AbsDiff(size_t x, size_t y, bool &y_gt_x); /** place bytes */ void PlaceBytes(size_t j, ssize_t bytes, std::vector &vars_bytes, - const lipc::vector &targets); + const hipc::vector &targets); /** get placement ratios from node states in \a ctx context */ - void GetPlacementRatios(const lipc::vector &targets, + void GetPlacementRatios(const hipc::vector &targets, const api::Context &ctx); }; diff --git a/src/dpe/random.cc b/src/dpe/random.cc index a60824268..236a9372d 100644 --- a/src/dpe/random.cc +++ b/src/dpe/random.cc @@ -19,7 +19,7 @@ namespace hermes { Status Random::Placement(const std::vector &blob_sizes, - const lipc::vector &targets, + const hipc::vector &targets, const api::Context &ctx, std::vector &output) { throw std::logic_error("Not currently implemented"); diff --git a/src/dpe/random.h b/src/dpe/random.h index 25def820e..4998190f7 100644 --- a/src/dpe/random.h +++ b/src/dpe/random.h @@ -24,7 +24,7 @@ class Random : public DPE { Random() = default; ~Random() = default; Status Placement(const std::vector &blob_sizes, - const lipc::vector &targets, + const hipc::vector &targets, const api::Context &ctx, std::vector &output) override; }; diff --git a/src/dpe/round_robin.cc b/src/dpe/round_robin.cc index eb1f81410..b680a6d19 100644 --- a/src/dpe/round_robin.cc +++ b/src/dpe/round_robin.cc @@ -16,7 +16,7 @@ namespace hermes { Status RoundRobin::Placement(const std::vector &blob_sizes, - const lipc::vector &targets, + const hipc::vector &targets, const api::Context &ctx, std::vector &output) { throw std::logic_error("Not currently implemented"); diff --git a/src/dpe/round_robin.h b/src/dpe/round_robin.h index 9bec740d6..e3abf6634 100644 --- a/src/dpe/round_robin.h +++ b/src/dpe/round_robin.h @@ -27,7 +27,7 @@ class RoundRobin : public DPE { RoundRobin() = default; Status Placement(const std::vector &blob_sizes, - const lipc::vector &targets, + const hipc::vector &targets, const api::Context &ctx, std::vector &output); }; diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index e64c4f71c..cada1542a 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -32,17 +32,17 @@ void MetadataManager::shm_init(ServerConfig *config, header_->id_alloc_ = 1; // Create the metadata maps - blob_id_map_ = lipc::make_mptr(16384); - bkt_id_map_ = lipc::make_mptr(16384); - vbkt_id_map_ = lipc::make_mptr(16384); - blob_map_ = lipc::make_mptr(16384); - bkt_map_ = lipc::make_mptr(16384); - vbkt_map_ = lipc::make_mptr(16384); + blob_id_map_ = hipc::make_mptr(16384); + bkt_id_map_ = hipc::make_mptr(16384); + vbkt_id_map_ = hipc::make_mptr(16384); + blob_map_ = hipc::make_mptr(16384); + bkt_map_ = hipc::make_mptr(16384); + vbkt_map_ = hipc::make_mptr(16384); // Create the DeviceInfo vector - devices_ = lipc::make_mptr>( + devices_ = hipc::make_mptr>( HERMES->main_alloc_, config->devices_); - targets_ = lipc::make_mptr>( + targets_ = hipc::make_mptr>( HERMES->main_alloc_); // Create the TargetInfo vector @@ -116,7 +116,7 @@ void MetadataManager::shm_deserialize(MetadataManagerShmHeader *header) { * Get or create a bucket with \a bkt_name bucket name * */ BucketId MetadataManager::LocalGetOrCreateBucket( - lipc::charbuf &bkt_name, + hipc::charbuf &bkt_name, const IoClientContext &opts) { // Acquire MD write lock (modifying bkt_map) ScopedRwWriteLock md_lock(lock_); @@ -143,7 +143,7 @@ BucketId MetadataManager::LocalGetOrCreateBucket( if (iter == bkt_id_map_->end()) { return BucketId::GetNull(); } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); bkt_id = *info->second_; } @@ -153,14 +153,14 @@ BucketId MetadataManager::LocalGetOrCreateBucket( /** * Get the BucketId with \a bkt_name bucket name * */ -BucketId MetadataManager::LocalGetBucketId(lipc::charbuf &bkt_name) { +BucketId MetadataManager::LocalGetBucketId(hipc::charbuf &bkt_name) { // Acquire MD read lock (reading bkt_id_map) ScopedRwReadLock md_lock(lock_); auto iter = bkt_id_map_->find(bkt_name); if (iter == bkt_id_map_->end()) { return BucketId::GetNull(); } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); BucketId bkt_id = *info->second_; return bkt_id; } @@ -177,7 +177,7 @@ size_t MetadataManager::LocalGetBucketSize(BucketId bkt_id, if (iter == bkt_map_->end()) { return 0; } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); BucketInfo &bkt_info = *info->second_; auto io_client = IoClientFactory::Get(opts.type_); if (io_client) { @@ -216,7 +216,7 @@ bool MetadataManager::LocalBucketContainsBlob(BucketId bkt_id, return false; } // Get the blob info - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; return blob_info.bkt_id_ == bkt_id; } @@ -233,10 +233,10 @@ MetadataManager::LocalBucketGetContainedBlobIds(BucketId bkt_id) { if (iter == bkt_map_->end()) { return blob_ids; } - lipc::ShmRef> info = *iter; + hipc::ShmRef> info = *iter; BucketInfo &bkt_info = *info->second_; blob_ids.reserve(bkt_info.blobs_->size()); - for (lipc::ShmRef blob_id : *bkt_info.blobs_) { + for (hipc::ShmRef blob_id : *bkt_info.blobs_) { blob_ids.emplace_back(*blob_id); } return blob_ids; @@ -246,15 +246,15 @@ MetadataManager::LocalBucketGetContainedBlobIds(BucketId bkt_id) { * Rename \a bkt_id bucket to \a new_bkt_name new name * */ bool MetadataManager::LocalRenameBucket(BucketId bkt_id, - lipc::charbuf &new_bkt_name) { + hipc::charbuf &new_bkt_name) { // Acquire MD write lock (modifying bkt_map_) ScopedRwWriteLock md_lock(lock_); auto iter = bkt_map_->find(bkt_id); if (iter == bkt_map_->end()) { return true; } - lipc::ShmRef> info = (*iter); - lipc::string &old_bkt_name = *info->second_->name_; + hipc::ShmRef> info = (*iter); + hipc::string &old_bkt_name = *info->second_->name_; bkt_id_map_->emplace(new_bkt_name, bkt_id); bkt_id_map_->erase(old_bkt_name); return true; @@ -284,7 +284,7 @@ Status MetadataManager::LocalBucketRegisterBlobId( if (iter == bkt_map_->end()) { return Status(); } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); BucketInfo &bkt_info = *info->second_; // Acquire BktInfo Write Lock (modifying bkt_info) ScopedRwWriteLock info_lock(bkt_info.header_->lock_[0]); @@ -317,11 +317,11 @@ Status MetadataManager::LocalBucketUnregisterBlobId( return Status(); } // Acquire the blob read lock (read blob_size) - lipc::ShmRef> info_blob = (*iter_blob); + hipc::ShmRef> info_blob = (*iter_blob); BlobInfo &blob_info = *info_blob->second_; size_t blob_size = blob_info.header_->blob_size_; // Acquire the bkt_info write lock (modifying bkt_info) - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); BucketInfo &bkt_info = *info->second_; ScopedRwWriteLock(bkt_info.header_->lock_[0]); // Update I/O client bucket stats @@ -348,12 +348,12 @@ Status MetadataManager::LocalBucketUnregisterBlobId( * */ std::pair MetadataManager::LocalBucketTryCreateBlob( BucketId bkt_id, - const lipc::charbuf &blob_name) { + const hipc::charbuf &blob_name) { size_t orig_blob_size = 0; // Acquire MD write lock (modify blob_map_) ScopedRwWriteLock md_lock(lock_); // Get internal blob name - lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); + hipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); // Create unique ID for the Blob BlobId blob_id; blob_id.unique_ = header_->id_alloc_.fetch_add(1); @@ -380,14 +380,14 @@ std::pair MetadataManager::LocalBucketTryCreateBlob( * */ std::tuple MetadataManager::LocalBucketPutBlob( BucketId bkt_id, - const lipc::charbuf &blob_name, + const hipc::charbuf &blob_name, size_t blob_size, - lipc::vector &buffers) { + hipc::vector &buffers) { size_t orig_blob_size = 0; // Acquire MD write lock (modify blob_map_) ScopedRwWriteLock md_lock(lock_); // Get internal blob name - lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); + hipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); // Create unique ID for the Blob BlobId blob_id; blob_id.unique_ = header_->id_alloc_.fetch_add(1); @@ -404,7 +404,7 @@ std::tuple MetadataManager::LocalBucketPutBlob( } else { blob_id = *(*blob_id_map_)[internal_blob_name]; auto iter = blob_map_->find(blob_id); - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; // Acquire blob_info write lock before modifying buffers ScopedRwWriteLock(blob_info.header_->lock_[0]); @@ -423,11 +423,11 @@ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { if (iter == blob_map_->end()) { return Blob(); } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; // Acquire blob_info read lock (read buffers) ScopedRwReadLock blob_info_lock(blob_info.header_->lock_[0]); - lipc::vector &buffers = *blob_info.buffers_; + hipc::vector &buffers = *blob_info.buffers_; return borg_->LocalReadBlobFromBuffers(buffers);; } @@ -435,15 +435,15 @@ Blob MetadataManager::LocalBucketGetBlob(BlobId blob_id) { * Get \a blob_name blob from \a bkt_id bucket * */ BlobId MetadataManager::LocalGetBlobId(BucketId bkt_id, - const lipc::charbuf &blob_name) { + const hipc::charbuf &blob_name) { // Acquire MD read lock (read blob_id_map_) ScopedRwReadLock md_lock(lock_); - lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); + hipc::charbuf internal_blob_name = CreateBlobName(bkt_id, blob_name); auto iter = blob_id_map_->find(internal_blob_name); if (iter == blob_id_map_->end()) { return BlobId::GetNull(); } - lipc::ShmRef> info = *iter; + hipc::ShmRef> info = *iter; return *info->second_; } @@ -457,7 +457,7 @@ RPC std::string MetadataManager::LocalGetBlobName(BlobId blob_id) { if (iter == blob_map_->end()) { return ""; } - lipc::ShmRef> info = *iter; + hipc::ShmRef> info = *iter; BlobInfo &blob_info = *info->second_; return blob_info.name_->str(); } @@ -494,7 +494,7 @@ std::vector MetadataManager::LocalGetBlobBuffers(BlobId blob_id) { if (iter == blob_map_->end()) { return std::vector(); } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; // Acquire blob_info read lock ScopedRwReadLock blob_info_lock(blob_info.header_->lock_[0]); @@ -506,17 +506,17 @@ std::vector MetadataManager::LocalGetBlobBuffers(BlobId blob_id) { * in \a bkt_id bucket. * */ bool MetadataManager::LocalRenameBlob(BucketId bkt_id, BlobId blob_id, - lipc::charbuf &new_blob_name) { + hipc::charbuf &new_blob_name) { // Acquire MD write lock (modify blob_id_map_) ScopedRwWriteLock md_lock(lock_); auto iter = (*blob_map_).find(blob_id); if (iter == blob_map_->end()) { return true; } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; - lipc::charbuf old_blob_name = CreateBlobName(bkt_id, *blob_info.name_); - lipc::charbuf internal_blob_name = CreateBlobName(bkt_id, new_blob_name); + hipc::charbuf old_blob_name = CreateBlobName(bkt_id, *blob_info.name_); + hipc::charbuf internal_blob_name = CreateBlobName(bkt_id, new_blob_name); blob_id_map_->erase(old_blob_name); blob_id_map_->emplace(internal_blob_name, blob_id); return true; @@ -534,9 +534,9 @@ bool MetadataManager::LocalDestroyBlob(BucketId bkt_id, if (iter == blob_map_->end()) { return true; } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); BlobInfo &blob_info = *info->second_; - lipc::charbuf blob_name = CreateBlobName(bkt_id, *blob_info.name_); + hipc::charbuf blob_name = CreateBlobName(bkt_id, *blob_info.name_); blob_id_map_->erase(blob_name); blob_map_->erase(blob_id); return true; @@ -550,7 +550,7 @@ bool MetadataManager::LocalDestroyBlob(BucketId bkt_id, * Get or create \a vbkt_name VBucket * */ VBucketId MetadataManager::LocalGetOrCreateVBucket( - lipc::charbuf &vbkt_name, + hipc::charbuf &vbkt_name, const IoClientContext &opts) { (void) opts; // Acquire MD write lock (read vbkt_map_) @@ -570,7 +570,7 @@ VBucketId MetadataManager::LocalGetOrCreateVBucket( if (iter == vbkt_id_map_->end()) { return VBucketId::GetNull(); } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); vbkt_id = *info->second_; } return vbkt_id; @@ -579,14 +579,14 @@ VBucketId MetadataManager::LocalGetOrCreateVBucket( /** * Get the VBucketId of \a vbkt_name VBucket * */ -VBucketId MetadataManager::LocalGetVBucketId(lipc::charbuf &vbkt_name) { +VBucketId MetadataManager::LocalGetVBucketId(hipc::charbuf &vbkt_name) { // Acquire MD read lock (read vbkt_id_map_) ScopedRwReadLock md_lock(lock_); auto iter = vbkt_id_map_->find(vbkt_name); if (iter == vbkt_id_map_->end()) { return VBucketId::GetNull(); } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); VBucketId vbkt_id = *info->second_; return vbkt_id; } @@ -602,7 +602,7 @@ bool MetadataManager::LocalVBucketLinkBlob(VBucketId vbkt_id, if (iter == vbkt_map_->end()) { return true; } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); VBucketInfo &vbkt_info = *info->second_; // Acquire vbkt_info write lock (modify blobs) ScopedRwWriteLock vbkt_info_lock(vbkt_info.header_->lock_); @@ -622,7 +622,7 @@ bool MetadataManager::LocalVBucketUnlinkBlob(VBucketId vbkt_id, if (iter == vbkt_map_->end()) { return true; } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); VBucketInfo &vbkt_info = *info->second_; // Acquire vbkt_info write lock (modify blobs) ScopedRwWriteLock vbkt_info_lock(vbkt_info.header_->lock_); @@ -649,7 +649,7 @@ bool MetadataManager::LocalVBucketContainsBlob(VBucketId vbkt_id, if (iter == vbkt_map_->end()) { return true; } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); VBucketInfo &vbkt_info = *info->second_; // Acquire vbkt_info read lock (read blobs) ScopedRwReadLock vbkt_info_lock(vbkt_info.header_->lock_); @@ -661,16 +661,16 @@ bool MetadataManager::LocalVBucketContainsBlob(VBucketId vbkt_id, * Rename \a vbkt_id VBucket to \a new_vbkt_name name * */ bool MetadataManager::LocalRenameVBucket(VBucketId vbkt_id, - lipc::charbuf &new_vbkt_name) { + hipc::charbuf &new_vbkt_name) { // Acquire MD write lock (modify vbkt_id_map_) ScopedRwWriteLock md_lock(lock_); auto iter = vbkt_map_->find(vbkt_id); if (iter == vbkt_map_->end()) { return true; } - lipc::ShmRef> info = (*iter); + hipc::ShmRef> info = (*iter); VBucketInfo &vbkt_info = *info->second_; - lipc::string &old_bkt_name = *vbkt_info.name_; + hipc::string &old_bkt_name = *vbkt_info.name_; vbkt_id_map_->emplace(new_vbkt_name, vbkt_id); vbkt_id_map_->erase(old_bkt_name); return true; diff --git a/src/metadata_manager.h b/src/metadata_manager.h index 61929f126..ee5e27631 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -35,33 +35,33 @@ class BufferOrganizer; /** * Type name simplification for the various map types * */ -typedef lipc::unordered_map BLOB_ID_MAP_T; -typedef lipc::unordered_map BKT_ID_MAP_T; -typedef lipc::unordered_map VBKT_ID_MAP_T; -typedef lipc::unordered_map BLOB_MAP_T; -typedef lipc::unordered_map BKT_MAP_T; -typedef lipc::unordered_map VBKT_MAP_T; +typedef hipc::unordered_map BLOB_ID_MAP_T; +typedef hipc::unordered_map BKT_ID_MAP_T; +typedef hipc::unordered_map VBKT_ID_MAP_T; +typedef hipc::unordered_map BLOB_MAP_T; +typedef hipc::unordered_map BKT_MAP_T; +typedef hipc::unordered_map VBKT_MAP_T; /** * The SHM representation of the MetadataManager * */ struct MetadataManagerShmHeader { /// SHM representation of blob id map - lipc::TypedPointer> blob_id_map_ar_; + hipc::TypedPointer> blob_id_map_ar_; /// SHM representation of bucket id map - lipc::TypedPointer> bkt_id_map_ar_; + hipc::TypedPointer> bkt_id_map_ar_; /// SHM representation of vbucket id map - lipc::TypedPointer> vbkt_id_map_ar_; + hipc::TypedPointer> vbkt_id_map_ar_; /// SHM representation of blob map - lipc::TypedPointer> blob_map_ar_; + hipc::TypedPointer> blob_map_ar_; /// SHM representation of bucket map - lipc::TypedPointer> bkt_map_ar_; + hipc::TypedPointer> bkt_map_ar_; /// SHM representation of vbucket map - lipc::TypedPointer> vbkt_map_ar_; + hipc::TypedPointer> vbkt_map_ar_; /// SHM representation of device vector - lipc::TypedPointer>> devices_; + hipc::TypedPointer>> devices_; /// SHM representation of target info vector - lipc::TypedPointer>> targets_; + hipc::TypedPointer>> targets_; /// Used to create unique ids. Starts at 1. std::atomic id_alloc_; /// Synchronization @@ -80,18 +80,18 @@ class MetadataManager { /** * The manual pointers representing the different map types. * */ - lipc::mptr blob_id_map_; - lipc::mptr bkt_id_map_; - lipc::mptr vbkt_id_map_; - lipc::mptr blob_map_; - lipc::mptr bkt_map_; - lipc::mptr vbkt_map_; + hipc::mptr blob_id_map_; + hipc::mptr bkt_id_map_; + hipc::mptr vbkt_id_map_; + hipc::mptr blob_map_; + hipc::mptr bkt_map_; + hipc::mptr vbkt_map_; /** * Information about targets and devices * */ - lipc::mptr> devices_; - lipc::mptr> targets_; + hipc::mptr> devices_; + hipc::mptr> targets_; /** A global lock for simplifying MD management */ RwLock lock_; @@ -122,9 +122,9 @@ class MetadataManager { /** * Create a unique blob name using BucketId * */ - lipc::charbuf CreateBlobName(BucketId bkt_id, - const lipc::charbuf &blob_name) { - lipc::charbuf new_name(sizeof(bkt_id) + blob_name.size()); + hipc::charbuf CreateBlobName(BucketId bkt_id, + const hipc::charbuf &blob_name) { + hipc::charbuf new_name(sizeof(bkt_id) + blob_name.size()); size_t off = 0; memcpy(new_name.data_mutable() + off, &bkt_id, sizeof(BucketId)); off += sizeof(BucketId); @@ -135,13 +135,13 @@ class MetadataManager { /** * Get or create a bucket with \a bkt_name bucket name * */ - RPC BucketId LocalGetOrCreateBucket(lipc::charbuf &bkt_name, + RPC BucketId LocalGetOrCreateBucket(hipc::charbuf &bkt_name, const IoClientContext &opts); /** * Get the BucketId with \a bkt_name bucket name * */ - RPC BucketId LocalGetBucketId(lipc::charbuf &bkt_name); + RPC BucketId LocalGetBucketId(hipc::charbuf &bkt_name); /** * Get the size of a bucket (depends on the IoClient used). @@ -176,7 +176,7 @@ class MetadataManager { * Rename \a bkt_id bucket to \a new_bkt_name new name * */ RPC bool LocalRenameBucket(BucketId bkt_id, - lipc::charbuf &new_bkt_name); + hipc::charbuf &new_bkt_name); /** * Destroy \a bkt_id bucket @@ -193,9 +193,9 @@ class MetadataManager { * */ RPC std::tuple LocalBucketPutBlob( BucketId bkt_id, - const lipc::charbuf &blob_name, + const hipc::charbuf &blob_name, size_t blob_size, - lipc::vector &buffers); + hipc::vector &buffers); /** * Registers the existence of a Blob with the Bucket. Required for @@ -224,7 +224,7 @@ class MetadataManager { * */ std::pair LocalBucketTryCreateBlob( BucketId bkt_id, - const lipc::charbuf &blob_name); + const hipc::charbuf &blob_name); /** * Get a blob from a bucket @@ -237,7 +237,7 @@ class MetadataManager { /** * Get \a blob_name BLOB from \a bkt_id bucket * */ - RPC BlobId LocalGetBlobId(BucketId bkt_id, const lipc::charbuf &blob_name); + RPC BlobId LocalGetBlobId(BucketId bkt_id, const hipc::charbuf &blob_name); /** * Get \a blob_name BLOB name from \a blob_id BLOB id @@ -266,7 +266,7 @@ class MetadataManager { * in \a bkt_id bucket. * */ RPC bool LocalRenameBlob(BucketId bkt_id, BlobId blob_id, - lipc::charbuf &new_blob_name); + hipc::charbuf &new_blob_name); /** * Destroy \a blob_id blob in \a bkt_id bucket @@ -276,13 +276,13 @@ class MetadataManager { /** * Get or create \a vbkt_name VBucket * */ - RPC VBucketId LocalGetOrCreateVBucket(lipc::charbuf &vbkt_name, + RPC VBucketId LocalGetOrCreateVBucket(hipc::charbuf &vbkt_name, const IoClientContext &opts); /** * Get the VBucketId of \a vbkt_name VBucket * */ - RPC VBucketId LocalGetVBucketId(lipc::charbuf &vbkt_name); + RPC VBucketId LocalGetVBucketId(hipc::charbuf &vbkt_name); /** * Link \a vbkt_id VBucketId @@ -308,7 +308,7 @@ class MetadataManager { /** * Rename \a vbkt_id VBucket to \a new_vbkt_name name * */ - RPC bool LocalRenameVBucket(VBucketId vbkt_id, lipc::charbuf &new_vbkt_name); + RPC bool LocalRenameVBucket(VBucketId vbkt_id, hipc::charbuf &new_vbkt_name); /** * Destroy \a vbkt_id VBucket @@ -327,28 +327,28 @@ class MetadataManager { /** * Update the capacity of the target device * */ - RPC const lipc::vector& LocalGetTargetInfo() { + RPC const hipc::vector& LocalGetTargetInfo() { return (*targets_); } /** * Get the TargetInfo for neighborhood * */ - lipc::vector GetNeighborhoodTargetInfo() { + hipc::vector GetNeighborhoodTargetInfo() { return {}; } /** * Get all TargetInfo in the system * */ - lipc::vector GetGlobalTargetInfo() { + hipc::vector GetGlobalTargetInfo() { return {}; } private: /** Acquire the external lock to Bucket or Blob */ template - bool LockMdObject(lipc::unordered_map &map, + bool LockMdObject(hipc::unordered_map &map, IdT id, MdLockType lock_type) { ScopedRwReadLock md_lock(lock_); @@ -356,7 +356,7 @@ class MetadataManager { if (iter == map.end()) { return false; } - lipc::ShmRef> info = *iter; + hipc::ShmRef> info = *iter; MapSecond &obj_info = *info->second_; switch (lock_type) { case MdLockType::kExternalRead: { @@ -375,7 +375,7 @@ class MetadataManager { /** Release the external lock to Bucket or Blob */ template - bool UnlockMdObject(lipc::unordered_map &map, + bool UnlockMdObject(hipc::unordered_map &map, IdT id, MdLockType lock_type) { ScopedRwReadLock md_lock(lock_); @@ -383,7 +383,7 @@ class MetadataManager { if (iter == map.end()) { return false; } - lipc::ShmRef> info = *iter; + hipc::ShmRef> info = *iter; MapSecond &obj_info = *info->second_; switch (lock_type) { case MdLockType::kExternalRead: { diff --git a/src/metadata_types.h b/src/metadata_types.h index 234696ca5..77a82edfc 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -107,10 +107,10 @@ struct BufferInfo { /** Represents BlobInfo in shared memory */ template<> -struct ShmHeader : public lipc::ShmBaseHeader { +struct ShmHeader : public hipc::ShmBaseHeader { BucketId bkt_id_; /**< The bucket containing the blob */ - lipc::TypedPointer name_ar_; /**< SHM pointer to string */ - lipc::TypedPointer> + hipc::TypedPointer name_ar_; /**< SHM pointer to string */ + hipc::TypedPointer> buffers_ar_; /**< SHM pointer to BufferInfo vector */ size_t blob_size_; /**< The overall size of the blob */ RwLock lock_[2]; /**< Ensures BlobInfo access is synchronized */ @@ -154,7 +154,7 @@ struct ShmHeader : public lipc::ShmBaseHeader { }; /** Blob metadata */ -struct BlobInfo : public lipc::ShmContainer { +struct BlobInfo : public hipc::ShmContainer { public: SHM_CONTAINER_TEMPLATE(BlobInfo, BlobInfo, ShmHeader); @@ -162,9 +162,9 @@ struct BlobInfo : public lipc::ShmContainer { /// The bucket containing the blob BucketId bkt_id_; /// The name of the blob - lipc::mptr name_; + hipc::mptr name_; /// The BufferInfo vector - lipc::mptr> buffers_; + hipc::mptr> buffers_; /// Synchronize access to blob Mutex lock_; /// Ensure that operations belonging to a transaction are not locked forever @@ -175,7 +175,7 @@ struct BlobInfo : public lipc::ShmContainer { /** Initialize the data structure */ void shm_init_main(ShmHeader *header, - lipc::Allocator *alloc) { + hipc::Allocator *alloc) { shm_init_allocator(alloc); shm_init_header(header); name_.shm_init(alloc_); @@ -205,7 +205,7 @@ struct BlobInfo : public lipc::ShmContainer { /** Move pointers into another BlobInfo */ void shm_weak_move_main(ShmHeader *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, BlobInfo &other) { shm_init_allocator(alloc); shm_init_header(header); @@ -218,7 +218,7 @@ struct BlobInfo : public lipc::ShmContainer { /** Deep copy data into another BlobInfo */ void shm_strong_copy_main(ShmHeader *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, const BlobInfo &other) { shm_init_allocator(alloc); shm_init_header(header); @@ -232,11 +232,11 @@ struct BlobInfo : public lipc::ShmContainer { /** Represents BucketInfo in shared memory */ template<> -struct ShmHeader : public lipc::ShmBaseHeader { +struct ShmHeader : public hipc::ShmBaseHeader { /** Name of the bucket */ - lipc::TypedPointer name_ar_; + hipc::TypedPointer name_ar_; /** Archive of blob vector */ - lipc::TypedPointer> blobs_ar_; + hipc::TypedPointer> blobs_ar_; size_t internal_size_; /**< Current bucket size */ /** State needed to be maintained for I/O clients */ GlobalIoClientState client_state_; @@ -283,13 +283,13 @@ struct ShmHeader : public lipc::ShmBaseHeader { }; /** Metadata for a Bucket */ -struct BucketInfo : public lipc::ShmContainer { +struct BucketInfo : public hipc::ShmContainer { public: SHM_CONTAINER_TEMPLATE(BucketInfo, BucketInfo, ShmHeader); public: - lipc::mptr name_; /**< The name of the bucket */ - lipc::mptr> blobs_; /**< All blobs in this Bucket */ + hipc::mptr name_; /**< The name of the bucket */ + hipc::mptr> blobs_; /**< All blobs in this Bucket */ public: /** Default constructor */ @@ -297,11 +297,11 @@ struct BucketInfo : public lipc::ShmContainer { /** Initialize the data structure */ void shm_init_main(ShmHeader *header, - lipc::Allocator *alloc) { + hipc::Allocator *alloc) { shm_init_allocator(alloc); shm_init_header(header); - name_ = lipc::make_mptr(alloc); - blobs_ = lipc::make_mptr>(alloc); + name_ = hipc::make_mptr(alloc); + blobs_ = hipc::make_mptr>(alloc); } /** Destroy all allocated data */ @@ -323,7 +323,7 @@ struct BucketInfo : public lipc::ShmContainer { /** Move other object into this one */ void shm_weak_move_main(ShmHeader *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, BucketInfo &other) { shm_init_allocator(alloc); shm_init_header(header); @@ -335,7 +335,7 @@ struct BucketInfo : public lipc::ShmContainer { /** Copy other object into this one */ void shm_strong_copy_main(ShmHeader *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, const BucketInfo &other) { shm_init_allocator(alloc); shm_init_header(header); @@ -348,9 +348,9 @@ struct BucketInfo : public lipc::ShmContainer { /** Represents a VBucket in shared memory */ template<> -struct ShmHeader : public lipc::ShmBaseHeader { - lipc::TypedPointer name_ar_; - lipc::TypedPointer> blobs_ar_; +struct ShmHeader : public hipc::ShmBaseHeader { + hipc::TypedPointer name_ar_; + hipc::TypedPointer> blobs_ar_; RwLock lock_; /** Default constructor */ @@ -386,13 +386,13 @@ struct ShmHeader : public lipc::ShmBaseHeader { }; /** Metadata for a VBucket */ -struct VBucketInfo : public lipc::ShmContainer { +struct VBucketInfo : public hipc::ShmContainer { public: SHM_CONTAINER_TEMPLATE(VBucketInfo, VBucketInfo, ShmHeader); public: - lipc::mptr name_; - lipc::mptr> blobs_; + hipc::mptr name_; + hipc::mptr> blobs_; public: /** Default constructor. */ @@ -400,11 +400,11 @@ struct VBucketInfo : public lipc::ShmContainer { /** Default SHM Constructor */ void shm_init_main(ShmHeader *header, - lipc::Allocator *alloc) { + hipc::Allocator *alloc) { shm_init_allocator(alloc); shm_init_header(header); - name_ = lipc::make_mptr(alloc_); - blobs_ = lipc::make_mptr>(alloc_); + name_ = hipc::make_mptr(alloc_); + blobs_ = hipc::make_mptr>(alloc_); } /** Free shared memory */ @@ -427,7 +427,7 @@ struct VBucketInfo : public lipc::ShmContainer { /** Move other object into this one */ void shm_weak_move_main(ShmHeader *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, VBucketInfo &other) { shm_init_allocator(alloc); shm_init_header(header); @@ -439,7 +439,7 @@ struct VBucketInfo : public lipc::ShmContainer { /** Copy other object into this one */ void shm_strong_copy_main(ShmHeader *header, - lipc::Allocator *alloc, + hipc::Allocator *alloc, const VBucketInfo &other) { shm_init_allocator(alloc); shm_init_header(header); From b939568419a426b5a220717249bf17f1835cc102 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 11:15:37 -0600 Subject: [PATCH 144/511] SHM data structures --- CMakeLists.txt | 2 + hermes_shm/CMakeLists.txt | 63 ++ .../data_structure_singleton_macros.h | 27 + .../include/hermes_shm/constants/macros.h | 30 + .../data_structures/data_structure.h | 22 + .../data_structures/internal/shm_archive.h | 105 +++ .../internal/shm_archive_or_t.h | 249 ++++++ .../data_structures/internal/shm_container.h | 84 ++ .../internal/shm_container_extend_macro.h | 255 ++++++ .../internal/shm_container_macro.h | 360 ++++++++ .../internal/shm_deserialize.h | 92 +++ .../data_structures/internal/shm_macros.h | 80 ++ .../internal/shm_null_container.h | 127 +++ .../data_structures/internal/shm_ref.h | 201 +++++ .../data_structures/internal/shm_smart_ptr.h | 162 ++++ .../template/shm_container_base_example.h | 422 ++++++++++ .../template/shm_container_base_template.h | 355 ++++++++ .../template/shm_container_extend_example.h | 316 ++++++++ .../template/shm_container_extend_template.h | 250 ++++++ .../include/hermes_shm/data_structures/pair.h | 203 +++++ .../data_structures/smart_ptr/manual_ptr.h | 112 +++ .../hermes_shm/data_structures/string.h | 301 +++++++ .../data_structures/thread_unsafe/list.h | 517 ++++++++++++ .../thread_unsafe/unordered_map.h | 540 ++++++++++++ .../data_structures/thread_unsafe/vector.h | 767 ++++++++++++++++++ .../hermes_shm/introspect/system_info.h | 39 + .../hermes_shm/memory/allocator/allocator.h | 496 +++++++++++ .../memory/allocator/allocator_factory.h | 79 ++ .../memory/allocator/malloc_allocator.h | 98 +++ .../hermes_shm/memory/allocator/mp_page.h | 39 + .../memory/allocator/stack_allocator.h | 104 +++ .../hermes_shm/memory/backend/array_backend.h | 65 ++ .../memory/backend/memory_backend.h | 90 ++ .../memory/backend/memory_backend_factory.h | 103 +++ .../hermes_shm/memory/backend/null_backend.h | 81 ++ .../hermes_shm/memory/backend/posix_mmap.h | 111 +++ .../memory/backend/posix_shm_mmap.h | 136 ++++ hermes_shm/include/hermes_shm/memory/memory.h | 383 +++++++++ .../hermes_shm/memory/memory_manager.h | 204 +++++ hermes_shm/include/hermes_shm/thread/lock.h | 20 + .../include/hermes_shm/thread/lock/mutex.h | 47 ++ .../include/hermes_shm/thread/lock/rwlock.h | 99 +++ .../include/hermes_shm/thread/pthread.h | 100 +++ hermes_shm/include/hermes_shm/thread/thread.h | 47 ++ .../hermes_shm/thread/thread_factory.h | 51 ++ .../hermes_shm/thread/thread_manager.h | 43 + hermes_shm/include/hermes_shm/types/argpack.h | 234 ++++++ hermes_shm/include/hermes_shm/types/atomic.h | 252 ++++++ hermes_shm/include/hermes_shm/types/basic.h | 139 ++++ .../include/hermes_shm/types/bitfield.h | 75 ++ hermes_shm/include/hermes_shm/types/charbuf.h | 204 +++++ .../include/hermes_shm/types/messages.h | 49 ++ .../include/hermes_shm/types/tuple_base.h | 247 ++++++ .../include/hermes_shm/util/auto_trace.h | 52 ++ hermes_shm/include/hermes_shm/util/debug.h | 77 ++ hermes_shm/include/hermes_shm/util/error.h | 60 ++ hermes_shm/include/hermes_shm/util/errors.h | 62 ++ .../include/hermes_shm/util/formatter.h | 100 +++ .../include/hermes_shm/util/partitioner.h | 156 ++++ .../include/hermes_shm/util/path_parser.h | 50 ++ .../include/hermes_shm/util/singleton.h | 34 + hermes_shm/include/hermes_shm/util/timer.h | 96 +++ hermes_shm/src/CMakeLists.txt | 44 + hermes_shm/src/data_structure_singleton.cc | 23 + hermes_shm/src/memory/malloc_allocator.cc | 79 ++ hermes_shm/src/memory/memory_intercept.cc | 93 +++ hermes_shm/src/memory/memory_intercept.h | 18 + hermes_shm/src/memory/memory_manager.cc | 45 + hermes_shm/src/memory/stack_allocator.cc | 76 ++ hermes_shm/src/thread/mutex.cc | 96 +++ hermes_shm/src/thread/rwlock.cc | 192 +++++ hermes_shm/test/CMakeLists.txt | 6 + hermes_shm/test/unit/CMakeLists.txt | 11 + .../test/unit/allocators/CMakeLists.txt | 19 + hermes_shm/test/unit/allocators/allocator.cc | 135 +++ .../test/unit/allocators/allocator_thread.cc | 42 + hermes_shm/test/unit/allocators/test_init.cc | 23 + hermes_shm/test/unit/allocators/test_init.h | 52 ++ hermes_shm/test/unit/basic_test.h | 68 ++ .../test/unit/data_structures/CMakeLists.txt | 10 + .../data_structures/backend/CMakeLists.txt | 22 + .../unit/data_structures/backend/backend.cc | 30 + .../data_structures/backend/memory_manager.cc | 78 ++ .../data_structures/backend/memory_slots.cc | 53 ++ .../unit/data_structures/backend/test_init.cc | 17 + .../data_structures/containers/CMakeLists.txt | 55 ++ .../unit/data_structures/containers/list.cc | 60 ++ .../unit/data_structures/containers/list.h | 192 +++++ .../data_structures/containers/manual_ptr.cc | 47 ++ .../unit/data_structures/containers/pair.cc | 64 ++ .../data_structures/containers/smart_ptr.h | 84 ++ .../unit/data_structures/containers/string.cc | 51 ++ .../data_structures/containers/test_init.cc | 34 + .../data_structures/containers/test_init.h | 49 ++ .../containers/unordered_map.cc | 226 ++++++ .../containers/unordered_map_thread.cc | 85 ++ .../unit/data_structures/containers/vector.cc | 81 ++ .../unit/data_structures/containers/vector.h | 37 + .../containers_mpi/CMakeLists.txt | 28 + .../containers_mpi/list_vec_mpi.cc | 110 +++ .../containers_mpi/test_init.cc | 52 ++ .../containers_mpi/test_init.h | 39 + .../unit/data_structures/lock/CMakeLists.txt | 19 + .../test/unit/data_structures/lock/lock.cc | 111 +++ .../unit/data_structures/lock/test_init.cc | 17 + hermes_shm/test/unit/main.cc | 28 + hermes_shm/test/unit/main_mpi.cc | 30 + hermes_shm/test/unit/types/CMakeLists.txt | 11 + hermes_shm/test/unit/types/test_argpack.cc | 180 ++++ hermes_shm/test/unit/types/test_init.cc | 17 + 110 files changed, 12903 insertions(+) create mode 100644 hermes_shm/CMakeLists.txt create mode 100644 hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h create mode 100644 hermes_shm/include/hermes_shm/constants/macros.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/data_structure.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/pair.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/string.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h create mode 100644 hermes_shm/include/hermes_shm/introspect/system_info.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/allocator.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/mp_page.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h create mode 100644 hermes_shm/include/hermes_shm/memory/backend/array_backend.h create mode 100644 hermes_shm/include/hermes_shm/memory/backend/memory_backend.h create mode 100644 hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h create mode 100644 hermes_shm/include/hermes_shm/memory/backend/null_backend.h create mode 100644 hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h create mode 100644 hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h create mode 100644 hermes_shm/include/hermes_shm/memory/memory.h create mode 100644 hermes_shm/include/hermes_shm/memory/memory_manager.h create mode 100644 hermes_shm/include/hermes_shm/thread/lock.h create mode 100644 hermes_shm/include/hermes_shm/thread/lock/mutex.h create mode 100644 hermes_shm/include/hermes_shm/thread/lock/rwlock.h create mode 100644 hermes_shm/include/hermes_shm/thread/pthread.h create mode 100644 hermes_shm/include/hermes_shm/thread/thread.h create mode 100644 hermes_shm/include/hermes_shm/thread/thread_factory.h create mode 100644 hermes_shm/include/hermes_shm/thread/thread_manager.h create mode 100644 hermes_shm/include/hermes_shm/types/argpack.h create mode 100644 hermes_shm/include/hermes_shm/types/atomic.h create mode 100644 hermes_shm/include/hermes_shm/types/basic.h create mode 100644 hermes_shm/include/hermes_shm/types/bitfield.h create mode 100644 hermes_shm/include/hermes_shm/types/charbuf.h create mode 100644 hermes_shm/include/hermes_shm/types/messages.h create mode 100644 hermes_shm/include/hermes_shm/types/tuple_base.h create mode 100644 hermes_shm/include/hermes_shm/util/auto_trace.h create mode 100644 hermes_shm/include/hermes_shm/util/debug.h create mode 100644 hermes_shm/include/hermes_shm/util/error.h create mode 100644 hermes_shm/include/hermes_shm/util/errors.h create mode 100644 hermes_shm/include/hermes_shm/util/formatter.h create mode 100644 hermes_shm/include/hermes_shm/util/partitioner.h create mode 100644 hermes_shm/include/hermes_shm/util/path_parser.h create mode 100644 hermes_shm/include/hermes_shm/util/singleton.h create mode 100644 hermes_shm/include/hermes_shm/util/timer.h create mode 100644 hermes_shm/src/CMakeLists.txt create mode 100644 hermes_shm/src/data_structure_singleton.cc create mode 100644 hermes_shm/src/memory/malloc_allocator.cc create mode 100644 hermes_shm/src/memory/memory_intercept.cc create mode 100644 hermes_shm/src/memory/memory_intercept.h create mode 100644 hermes_shm/src/memory/memory_manager.cc create mode 100644 hermes_shm/src/memory/stack_allocator.cc create mode 100644 hermes_shm/src/thread/mutex.cc create mode 100644 hermes_shm/src/thread/rwlock.cc create mode 100644 hermes_shm/test/CMakeLists.txt create mode 100644 hermes_shm/test/unit/CMakeLists.txt create mode 100644 hermes_shm/test/unit/allocators/CMakeLists.txt create mode 100644 hermes_shm/test/unit/allocators/allocator.cc create mode 100644 hermes_shm/test/unit/allocators/allocator_thread.cc create mode 100644 hermes_shm/test/unit/allocators/test_init.cc create mode 100644 hermes_shm/test/unit/allocators/test_init.h create mode 100644 hermes_shm/test/unit/basic_test.h create mode 100644 hermes_shm/test/unit/data_structures/CMakeLists.txt create mode 100644 hermes_shm/test/unit/data_structures/backend/CMakeLists.txt create mode 100644 hermes_shm/test/unit/data_structures/backend/backend.cc create mode 100644 hermes_shm/test/unit/data_structures/backend/memory_manager.cc create mode 100644 hermes_shm/test/unit/data_structures/backend/memory_slots.cc create mode 100644 hermes_shm/test/unit/data_structures/backend/test_init.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/CMakeLists.txt create mode 100644 hermes_shm/test/unit/data_structures/containers/list.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/list.h create mode 100644 hermes_shm/test/unit/data_structures/containers/manual_ptr.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/pair.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/smart_ptr.h create mode 100644 hermes_shm/test/unit/data_structures/containers/string.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/test_init.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/test_init.h create mode 100644 hermes_shm/test/unit/data_structures/containers/unordered_map.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/vector.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/vector.h create mode 100644 hermes_shm/test/unit/data_structures/containers_mpi/CMakeLists.txt create mode 100644 hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc create mode 100644 hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc create mode 100644 hermes_shm/test/unit/data_structures/containers_mpi/test_init.h create mode 100644 hermes_shm/test/unit/data_structures/lock/CMakeLists.txt create mode 100644 hermes_shm/test/unit/data_structures/lock/lock.cc create mode 100644 hermes_shm/test/unit/data_structures/lock/test_init.cc create mode 100644 hermes_shm/test/unit/main.cc create mode 100644 hermes_shm/test/unit/main_mpi.cc create mode 100644 hermes_shm/test/unit/types/CMakeLists.txt create mode 100644 hermes_shm/test/unit/types/test_argpack.cc create mode 100644 hermes_shm/test/unit/types/test_init.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 121ec0ca5..1c8e25451 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -399,6 +399,8 @@ if(HERMES_BUILD_BUFFER_POOL_VISUALIZER AND SDL2_FOUND) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/buffer_pool_visualizer) endif() +include_directories(${CMAKE_SOURCE_DIR}/hermes_shm/include) +add_subdirectory(hermes_shm) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/data_stager) #----------------------------------------------------------------------------- diff --git a/hermes_shm/CMakeLists.txt b/hermes_shm/CMakeLists.txt new file mode 100644 index 000000000..31484fb5f --- /dev/null +++ b/hermes_shm/CMakeLists.txt @@ -0,0 +1,63 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +include_directories(${CMAKE_SOURCE_DIR}/include) + +###################OPTIONS +option(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" ON) +option(BUILD_TESTS "Wether or not to build unit tests" OFF) +option(BUILD_MPI_TESTS "Build tests which depend on MPI" OFF) +option(BUILD_OpenMP_TESTS "Build tests which depend on OpenMP" OFF) +option(BUILD_Boost_TESTS "Build tests which depend on libboost" OFF) + +##################CMAKE MODULES +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake) + +##################OPTIMIZATION +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + message("IN DEBUG MODE") + set(CMAKE_CXX_FLAGS "-g -O0") +elseif(CMAKE_BUILD_TYPE STREQUAL "Release") + message("IN RELEASE MODE") + set(CMAKE_CXX_FLAGS "-g -O3") +endif() +function(make_gprof exec_name exec_dir) + message("gprof -b -A -p -q ${exec_dir}/${exec_name} gmon.out > gprof_out.txt") + add_custom_target( + ${exec_name}_gprof + COMMAND gprof -b -A -p -q ${exec_dir}/${exec_name} gmon.out) +endfunction() + +##################REQUIRED EXTERNAL LIBRARIES + +# YAML-CPP +find_package(yaml-cpp REQUIRED) +message(STATUS "found yaml-cpp at ${yaml-cpp_DIR}") + +# Catch2 +find_package(Catch2 3.0.1 REQUIRED) +message(STATUS "found catch2.h at ${Catch2_CXX_INCLUDE_DIRS}") + +# MPICH +if(BUILD_MPI_TESTS) + find_package(MPI REQUIRED COMPONENTS C CXX) + message(STATUS "found mpi.h at ${MPI_CXX_INCLUDE_DIRS}") +endif() + +# OpenMP +if(BUILD_OpenMP_TESTS) + find_package(OpenMP REQUIRED COMPONENTS C CXX) + message(STATUS "found omp.h at ${OpenMP_CXX_INCLUDE_DIRS}") +endif() + +##################Build HermesShm main packages +add_subdirectory(src) + +##################MODULES & TESTS +set(TEST_MAIN ${CMAKE_SOURCE_DIR}/test/unit) +if (BUILD_TESTS) + enable_testing() + add_subdirectory(test) +endif() \ No newline at end of file diff --git a/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h b/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h new file mode 100644 index 000000000..3f1519c23 --- /dev/null +++ b/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h @@ -0,0 +1,27 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_CONSTANTS_DATA_STRUCTURE_SINGLETON_MACROS_H_H +#define HERMES_SHM_INCLUDE_HERMES_SHM_CONSTANTS_DATA_STRUCTURE_SINGLETON_MACROS_H_H + +#include + +#define HERMES_SHM_SYSTEM_INFO scs::Singleton::GetInstance() +#define HERMES_SHM_SYSTEM_INFO_T hermes_shm::SystemInfo* + +#define HERMES_SHM_MEMORY_MANAGER scs::Singleton::GetInstance() +#define HERMES_SHM_MEMORY_MANAGER_T hermes_shm::ipc::MemoryManager* + +#define HERMES_SHM_THREAD_MANAGER scs::Singleton::GetInstance() +#define HERMES_SHM_THREAD_MANAGER_T hermes_shm::ThreadManager* + +#endif // include_labstor_constants_data_structure_singleton_macros_h diff --git a/hermes_shm/include/hermes_shm/constants/macros.h b/hermes_shm/include/hermes_shm/constants/macros.h new file mode 100644 index 000000000..884527725 --- /dev/null +++ b/hermes_shm/include/hermes_shm/constants/macros.h @@ -0,0 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_MACROS_H +#define HERMES_SHM_MACROS_H + +#define KILOBYTES(n) ((size_t)(n) * (1<<10)) +#define MEGABYTES(n) ((size_t)(n) * (1<<20)) +#define GIGABYTES(n) ((size_t)(n) * (1<<30)) + +#define TYPE_BITS(type) ((sizeof(type)*8)) + +#define TYPE_WRAP(...) (__VA_ARGS__) + +#define TYPE_UNWRAP(X) ESC(ISH X) +#define ISH(...) ISH __VA_ARGS__ +#define ESC(...) ESC_(__VA_ARGS__) +#define ESC_(...) VAN ## __VA_ARGS__ +#define VANISH + +#endif // HERMES_SHM_MACROS_H diff --git a/hermes_shm/include/hermes_shm/data_structures/data_structure.h b/hermes_shm/include/hermes_shm/data_structures/data_structure.h new file mode 100644 index 000000000..ce21574c3 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/data_structure.h @@ -0,0 +1,22 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_DATA_STRUCTURES_DATA_STRUCTURE_H_ +#define HERMES_SHM_DATA_STRUCTURES_DATA_STRUCTURE_H_ + +#include "internal/shm_archive.h" +#include "internal/shm_container.h" +#include "internal/shm_smart_ptr.h" +#include "internal/shm_macros.h" +#include "internal/shm_container.h" + +#endif // HERMES_SHM_DATA_STRUCTURES_DATA_STRUCTURE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h new file mode 100644 index 000000000..d0f12ca10 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h @@ -0,0 +1,105 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_DATA_STRUCTURES_SHM_ARCHIVE_H_ +#define HERMES_SHM_DATA_STRUCTURES_SHM_ARCHIVE_H_ + +#include "hermes_shm/memory/memory_manager.h" +#include "shm_macros.h" + +namespace hermes_shm::ipc { + +/** + * Indicates that a data structure can be stored directly in memory or + * shared memory. + * */ +class ShmPredictable {}; + +/** + * Indicates that a data structure can be archived in shared memory + * and has a corresponding TypedPointer override. + * */ +class ShmArchiveable : public ShmPredictable { + /** + * Initialize a SHM data structure in shared-memory. + * Constructors may wrap around these. + * */ + // void shm_init(...); + + /** + * Destroys the shared-memory allocated by the object. + * Destructors may wrap around this. + * */ + // void shm_destroy(); + + /** + * Deep copy of an object. Wrapped by copy constructor + * */ + // void shm_strong_copy(const CLASS_NAME &other); + // SHM_INHERIT_COPY_OPS(CLASS_NAME) + + /** + * Copies only the object's pointers. + * */ + // void WeakCopy(const CLASS_NAME &other); + + /** + * Moves the object's contents into another object + * */ + // void shm_weak_move(CLASS_NAME &other); + // SHM_INHERIT_MOVE_OPS(CLASS_NAME) + + /** + * Store object into a TypedPointer + * */ + // void shm_serialize(TypedPointer &ar) const; + // SHM_SERIALIZE_OPS(TYPED_CLASS) + + /** + * Construct object from a TypedPointer. + * */ + // void shm_deserialize(const TypedPointer &ar); + // SHM_DESERIALIZE_OPS(TYPED_CLASS) +}; + +/** + * Enables a specific TypedPointer type to be serialized + * */ +#define SHM_SERIALIZE_OPS(TYPED_CLASS)\ + void operator>>(hipc::TypedPointer &ar) const {\ + shm_serialize(ar);\ + }\ + void operator>>(hipc::TypedAtomicPointer &ar) const {\ + shm_serialize(ar);\ + } + +/** + * Enables a specific TypedPointer type to be deserialized + * */ +#define SHM_DESERIALIZE_OPS(TYPED_CLASS)\ + void operator<<(const hipc::TypedPointer &ar) {\ + shm_deserialize(ar);\ + }\ + void operator<<(\ + const hipc::TypedAtomicPointer &ar) {\ + shm_deserialize(ar);\ + } + +/** Enables serialization + deserialization for data structures */ +#define SHM_SERIALIZE_DESERIALIZE_OPS(AR_TYPE)\ + SHM_SERIALIZE_OPS(AR_TYPE)\ + SHM_DESERIALIZE_OPS(AR_TYPE) + + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_DATA_STRUCTURES_SHM_ARCHIVE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h new file mode 100644 index 000000000..52b4e9ae4 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h @@ -0,0 +1,249 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_DATA_STRUCTURES_SHM_AR_H_ +#define HERMES_SHM_DATA_STRUCTURES_SHM_AR_H_ + +#include "hermes_shm/memory/memory.h" +#include "hermes_shm/data_structures/data_structure.h" +#include "hermes_shm/types/tuple_base.h" + +namespace hermes_shm::ipc { + +/** + * Constructs a TypedPointer in-place + * */ +template +class _ShmHeaderOrT_Header { + public: + typedef typename T::header_t header_t; + header_t obj_hdr_; + + public: + /** Default constructor */ + _ShmHeaderOrT_Header() = default; + + /** Construct + store object */ + template + explicit _ShmHeaderOrT_Header(Allocator *alloc, Args&& ...args) { + T(obj_hdr_, alloc, std::forward(args)...).UnsetDestructable(); + } + + /** Construct + store object (hermes_shm rval argpack) */ + template + void PiecewiseInit(Allocator *alloc, + ArgPackT &&args) { + T obj; + PassArgPack::Call( + MergeArgPacks::Merge(make_argpack(obj, obj_hdr_, alloc), + std::forward(args)), + [](auto&& ...Args) constexpr { + Allocator::ConstructObj(std::forward(Args)...); + }); + obj.UnsetDestructable(); + } + + /** Destructor */ + ~_ShmHeaderOrT_Header() = default; + + /** Shm destructor */ + void shm_destroy(Allocator *alloc) { + auto ar = internal_ref(alloc); + T obj; + obj.shm_deserialize(ar); + obj.shm_destroy(); + } + + /** Returns a reference to the internal object */ + TypedPointer internal_ref(Allocator *alloc) { + return TypedPointer(alloc->Convert(&obj_hdr_)); + } + + /** Returns a reference to the internal object */ + TypedPointer internal_ref(Allocator *alloc) const { + return TypedPointer(alloc->Convert(&obj_hdr_)); + } + + /** Move constructor */ + _ShmHeaderOrT_Header(_ShmHeaderOrT_Header &&other) noexcept + : obj_hdr_(std::move(other.obj_hdr_)) {} + + /** Move assignment operator */ + _ShmHeaderOrT_Header& operator=(_ShmHeaderOrT_Header &&other) noexcept { + obj_hdr_ = std::move(other.obj_hdr_); + return *this; + } + + /** Copy constructor */ + _ShmHeaderOrT_Header(const _ShmHeaderOrT_Header &other) + : obj_hdr_(other.obj_hdr_) { + } + + /** Copy assignment operator */ + _ShmHeaderOrT_Header& operator=(const _ShmHeaderOrT_Header &other) { + obj_hdr_ = other.obj_hdr_; + } +}; + +/** + * Constructs an object in-place + * */ +template +class _ShmHeaderOrT_T { + public: + char obj_[sizeof(T)]; /**< Store object without constructing */ + + public: + /** Default constructor */ + _ShmHeaderOrT_T() { + Allocator::ConstructObj(internal_ref(nullptr)); + } + + /** Construct + store object (C++ argpack) */ + template + explicit _ShmHeaderOrT_T(Allocator *alloc, Args&& ...args) { + Allocator::ConstructObj( + internal_ref(alloc), std::forward(args)...); + } + + /** Construct + store object (hermes_shm rval argpack) */ + template + void PiecewiseInit(Allocator *alloc, + ArgPackT &&args) { + hermes_shm::PassArgPack::Call( + MergeArgPacks::Merge( + make_argpack(internal_ref(alloc)), + std::forward(args)), + [](auto&& ...Args) constexpr { + Allocator::ConstructObj(std::forward(Args)...); + }); + } + + /** Shm destructor */ + void shm_destroy(Allocator *alloc) {} + + /** Destructor. Does nothing. */ + ~_ShmHeaderOrT_T() = default; + + /** Returns a reference to the internal object */ + T& internal_ref(Allocator *alloc) { + (void) alloc; + return reinterpret_cast(obj_); + } + + /** Returns a reference to the internal object */ + T& internal_ref(Allocator *alloc) const { + (void) alloc; + return reinterpret_cast(obj_); + } + + /** Move constructor */ + _ShmHeaderOrT_T(_ShmHeaderOrT_T &&other) noexcept { + Allocator::ConstructObj<_ShmHeaderOrT_T>( + obj_, std::move(other.internal_ref())); + } + + /** Move assignment operator */ + _ShmHeaderOrT_T& operator=(_ShmHeaderOrT_T &&other) noexcept { + internal_ref() = std::move(other.internal_ref()); + return *this; + } + + /** Copy constructor */ + _ShmHeaderOrT_T(const _ShmHeaderOrT_T &other) { + Allocator::ConstructObj<_ShmHeaderOrT_T>( + obj_, other); + } + + /** Copy assignment operator */ + _ShmHeaderOrT_T& operator=(const _ShmHeaderOrT_T &other) { + internal_ref() = other.internal_ref(); + return *this; + } +}; + +/** + * Whether or not to use _ShmHeaderOrT or _ShmHeaderOrT_T + * */ +#define SHM_MAKE_HEADER_OR_T(T) \ + SHM_X_OR_Y(T, _ShmHeaderOrT_Header, _ShmHeaderOrT_T) + +/** + * Used for data structures which intend to store: + * 1. An archive if the data type is SHM_ARCHIVEABLE + * 2. The raw type if the data type is anything else + * + * E.g., used in unordered_map for storing collision entries. + * E.g., used in a list for storing list entries. + * */ +template +class ShmHeaderOrT { + public: + typedef SHM_ARCHIVE_OR_REF(T) T_Ar; + typedef SHM_MAKE_HEADER_OR_T(T) T_Hdr; + T_Hdr obj_; + + /** Default constructor */ + ShmHeaderOrT() = default; + + /** Construct + store object */ + template + explicit ShmHeaderOrT(Args&& ...args) + : obj_(std::forward(args)...) {} + + /** Construct + store object (hermes_shm rval argpack) */ + template + void PiecewiseInit(Allocator *alloc, ArgPackT &&args) { + obj_.PiecewiseInit(alloc, std::forward(args)); + } + + /** Destructor */ + ~ShmHeaderOrT() = default; + + /** Returns a reference to the internal object */ + T_Ar internal_ref(Allocator *alloc) { + return obj_.internal_ref(alloc); + } + + /** Returns a reference to the internal object */ + T_Ar internal_ref(Allocator *alloc) const { + return obj_.internal_ref(alloc); + } + + /** Shm destructor */ + void shm_destroy(Allocator *alloc) { + obj_.shm_destroy(alloc); + } + + /** Move constructor */ + ShmHeaderOrT(ShmHeaderOrT &&other) noexcept + : obj_(std::move(other.obj_)) {} + + /** Move assignment operator */ + ShmHeaderOrT& operator=(ShmHeaderOrT &&other) noexcept { + obj_ = std::move(other.obj_); + return *this; + } + + /** Copy constructor */ + ShmHeaderOrT(const ShmHeaderOrT &other) + : obj_(other.obj_) {} + + /** Copy assignment operator */ + ShmHeaderOrT& operator=(const ShmHeaderOrT &other) { + obj_ = other.obj_; + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_DATA_STRUCTURES_SHM_AR_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h new file mode 100644 index 000000000..3df01401f --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h @@ -0,0 +1,84 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_SHM_CONTAINER_H_ +#define HERMES_SHM_SHM_CONTAINER_H_ + +#include "hermes_shm/memory/memory_manager.h" +#include "hermes_shm/constants/macros.h" +#include "shm_container_macro.h" +#include "shm_macros.h" +#include "shm_archive.h" +#include "shm_ref.h" +#include "shm_deserialize.h" + +namespace hipc = hermes_shm::ipc; + +namespace hermes_shm::ipc { + +/** Bits used for determining how to destroy an object */ +/// The container's header has been allocated +#define SHM_CONTAINER_VALID BIT_OPT(uint16_t, 0) +/// The container header is initialized +#define SHM_CONTAINER_DATA_VALID BIT_OPT(uint16_t, 1) +/// The header was allocated by this container +#define SHM_CONTAINER_HEADER_DESTRUCTABLE BIT_OPT(uint16_t, 2) +/// The container should free all data when destroyed +#define SHM_CONTAINER_DESTRUCTABLE BIT_OPT(uint16_t, 3) + +/** The shared-memory header used for data structures */ +template +struct ShmHeader; + +/** The ShmHeader used for base containers */ +struct ShmBaseHeader { + bitfield32_t flags_; + + /** Default constructor */ + ShmBaseHeader() = default; + + /** Copy constructor */ + ShmBaseHeader(const ShmBaseHeader &other) {} + + /** Copy assignment operator */ + ShmBaseHeader& operator=(const ShmBaseHeader &other) { + return *this; + } + + /** + * Disable copying of the flag field, as all flags + * pertain to a particular ShmHeader allocation. + * */ + void strong_copy(const ShmBaseHeader &other) {} + + /** Publicize bitfield operations */ + INHERIT_BITFIELD_OPS(flags_, uint16_t) +}; + +/** The ShmHeader used for wrapper containers */ +struct ShmWrapperHeader {}; + +/** + * ShmContainers all have a header, which is stored in + * shared memory as a TypedPointer. + * */ +class ShmContainer : public ShmArchiveable {}; + +/** Typed nullptr */ +template +static inline T* typed_nullptr() { + return reinterpret_cast(NULL); +} + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_SHM_CONTAINER_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h new file mode 100644 index 000000000..8cf120288 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h @@ -0,0 +1,255 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ +#define HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ +#define SHM_CONTAINER_EXTEND_TEMPLATE(CLASS_NAME,TYPED_CLASS,TYPED_HEADER)\ +public:\ +/**====================================\ + * Variables & Types\ + *===================================*/\ +\ +typedef TYPE_UNWRAP(TYPED_HEADER) header_t; /**< Required by all ShmContainers */\ +header_t *header_; /**< The shared-memory header for this container */\ +ContainerT obj_; /**< The object being wrapped around */\ +\ +public:\ +/**====================================\ + * Constructors\ + * ===================================*/\ +\ +/** Constructor. Allocate header with default allocator. */\ +template\ +explicit TYPE_UNWRAP(CLASS_NAME)(Args &&...args) {\ +shm_init(std::forward(args)...);\ +}\ +\ +/** Constructor. Allocate header with default allocator. */\ +template\ +void shm_init(Args &&...args) {\ +}\ +\ +/**====================================\ + * Serialization\ + * ===================================*/\ +\ +/** Serialize into a Pointer */\ +void shm_serialize(TypedPointer &ar) const {\ + obj_.shm_serialize(ar);\ +}\ +\ +/** Serialize into an AtomicPointer */\ +void shm_serialize(TypedAtomicPointer &ar) const {\ + obj_.shm_serialize(ar);\ +}\ +\ +/** Override << operators */\ +SHM_SERIALIZE_OPS((TYPE_UNWRAP(TYPED_CLASS)))\ +\ +/**====================================\ + * Deserialization\ + * ===================================*/\ +\ +/** Deserialize object from a raw pointer */\ +bool shm_deserialize(const TypedPointer &ar) {\ + return obj_.shm_deserialize(ar);\ +}\ +\ +/** Deserialize object from allocator + offset */\ +bool shm_deserialize(Allocator *alloc, OffsetPointer header_ptr) {\ + return obj_.shm_deserialize(alloc, header_ptr);\ +}\ +\ +/** Deserialize object from another object (weak copy) */\ +bool shm_deserialize(const TYPE_UNWRAP(CLASS_NAME) &other) {\ + return obj_.shm_deserialize(other);\ +}\ +\ +/** Deserialize object from allocator + header */\ +bool shm_deserialize(Allocator *alloc,\ + TYPE_UNWRAP(TYPED_HEADER) *header) {\ + return obj_.shm_deserialize(alloc, header);\ +}\ +\ +/** Constructor. Deserialize the object from the reference. */\ +template\ +void shm_init(hipc::ShmRef &obj) {\ + shm_deserialize(obj->GetAllocator(), obj->header_);\ +}\ +\ +/** Override >> operators */\ +SHM_DESERIALIZE_OPS ((TYPE_UNWRAP(TYPED_CLASS)))\ +\ +/**====================================\ + * Destructors\ + * ===================================*/\ +\ +/** Destructor */\ +~TYPE_UNWRAP(CLASS_NAME)() {\ + obj_.shm_destroy(true);\ +}\ +\ +/** Shm Destructor */\ +void shm_destroy(bool destroy_header = true) {\ + obj_.shm_destroy(false);\ + if (!IsValid()) { return; }\ + if (IsDataValid()) {\ + shm_destroy_main();\ + }\ + UnsetDataValid();\ + if (destroy_header &&\ + obj_.header_->OrBits(SHM_CONTAINER_HEADER_DESTRUCTABLE)) {\ + GetAllocator()->template\ + FreePtr(header_);\ + UnsetValid();\ + }\ +}\ +\ +/**====================================\ + * Move Operations\ + * ===================================*/\ +\ +/** Move constructor */\ +TYPE_UNWRAP(CLASS_NAME)(TYPE_UNWRAP(CLASS_NAME) &&other) noexcept\ +: obj_(std::move(other)) {}\ +\ +/** Move assignment operator */\ +TYPE_UNWRAP(CLASS_NAME)& operator=(TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ +obj_ = std::move(other.obj_);\ +return *this;\ +}\ +\ +/** Move shm_init constructor */\ +void shm_init_main(TYPE_UNWRAP(TYPED_HEADER) *header,\ + hipc::Allocator *alloc,\ + TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ + shm_weak_move(header, alloc, other);\ +}\ +\ +/** Move operation */\ +void shm_weak_move(TYPE_UNWRAP(TYPED_HEADER) *header,\ + hipc::Allocator *alloc,\ + TYPE_UNWRAP(CLASS_NAME) &other) {\ + obj_.shm_weak_move(header, alloc, other);\ +}\ +\ +/**====================================\ + * Copy Operations\ + * ===================================*/\ +\ +/** Copy constructor */\ +TYPE_UNWRAP(CLASS_NAME)(const TYPE_UNWRAP(CLASS_NAME) &other) noexcept {\ + shm_init(other);\ +}\ +\ +/** Copy assignment constructor */\ +TYPE_UNWRAP(CLASS_NAME) &operator=(const TYPE_UNWRAP(CLASS_NAME) &other) {\ + if (this != &other) {\ + shm_strong_copy(\ + typed_nullptr(),\ + typed_nullptr(),\ + other);\ + }\ + return *this;\ +}\ +\ +/** Copy shm_init constructor */\ +void shm_init_main(TYPE_UNWRAP(TYPED_HEADER) *header,\ + hipc::Allocator *alloc,\ + const TYPE_UNWRAP(CLASS_NAME) &other) {\ + shm_strong_copy(header, alloc, other);\ +}\ +\ +/** Strong Copy operation */\ +void shm_strong_copy(TYPE_UNWRAP(TYPED_HEADER) *header, hipc::Allocator *alloc,\ + const TYPE_UNWRAP(CLASS_NAME) &other) {\ + if (other.IsNull()) { return; }\ + shm_destroy(false);\ + shm_strong_copy_main(header, alloc, other);\ + SetDestructable();\ +}\ +\ +/**====================================\ + * Container Flag Operations\ + * ===================================*/\ +\ +/** Sets this object as destructable */\ +void SetDestructable() {\ + obj_.SetDestructable();\ +}\ +\ +/** Sets this object as not destructable */\ +void UnsetDestructable() {\ + obj_.UnsetDestructable();\ +}\ +\ +/** Check if this container is destructable */\ +bool IsDestructable() const {\ + return obj_.IsDestructable();\ +}\ +\ +/** Check if container has a valid header */\ +bool IsValid() const {\ + return obj_.IsValid();\ +}\ +\ +/** Set container header invalid */\ +void UnsetValid() {\ + obj_.UnsetValid();\ +}\ +\ +/**====================================\ + * Header Flag Operations\ + * ===================================*/\ +\ +/** Check if header's data is valid */\ +bool IsDataValid() const {\ + return obj_.IsDataValid();\ +}\ +\ +/** Check if header's data is valid */\ +void UnsetDataValid() const {\ + return obj_.UnsetDataValid();\ +}\ +\ +/** Check if null */\ +bool IsNull() const {\ + return obj_.IsNull();\ +}\ +\ +/** Get a typed pointer to the object */\ +template\ +POINTER_T GetShmPointer() const {\ + return GetAllocator()->template\ + Convert(header_);\ +}\ +\ +/**====================================\ + * Query Operations\ + * ===================================*/\ +\ +/** Get the allocator for this container */\ +Allocator* GetAllocator() {\ + return obj_.GetAllocator();\ +}\ +\ +/** Get the allocator for this container */\ +Allocator* GetAllocator() const {\ + return obj_.GetAllocator();\ +}\ +\ +/** Get the shared-memory allocator id */\ +allocator_id_t GetAllocatorId() const {\ + return GetAllocator()->GetId();\ +}\ + +#endif // HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h new file mode 100644 index 000000000..20b285082 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h @@ -0,0 +1,360 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ +#define HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ +#define SHM_CONTAINER_TEMPLATE(CLASS_NAME,TYPED_CLASS,TYPED_HEADER)\ +public:\ +/**====================================\ + * Variables & Types\ + * ===================================*/\ +\ +typedef TYPE_UNWRAP(TYPED_HEADER) header_t; /** Header type query */\ +header_t *header_; /**< Header of the shared-memory data structure */\ +hipc::Allocator *alloc_; /**< hipc::Allocator used for this data structure */\ +hermes_shm::bitfield32_t flags_; /**< Flags used data structure status */\ +\ +public:\ +/**====================================\ + * Constructors\ + * ===================================*/\ +\ +/** Constructor. Allocate header with default allocator. */\ +template\ +explicit TYPE_UNWRAP(CLASS_NAME)(Args&& ...args) {\ +shm_init(std::forward(args)...);\ +}\ +\ +/** Constructor. Allocate header with default allocator. */\ +template\ +void shm_init(Args&& ...args) {\ + shm_destroy(false);\ + shm_init_main(hipc::typed_nullptr(),\ + hipc::typed_nullptr(),\ + std::forward(args)...);\ +}\ +\ +/** Constructor. Allocate header with specific allocator. */\ +template\ +void shm_init(hipc::Allocator *alloc, Args&& ...args) {\ + shm_destroy(false);\ + shm_init_main(hipc::typed_nullptr(),\ + alloc,\ + std::forward(args)...);\ +}\ +\ +/** Constructor. Initialize an already-allocated header. */\ +template\ +void shm_init(TYPE_UNWRAP(TYPED_HEADER) &header,\ + hipc::Allocator *alloc, Args&& ...args) {\ + shm_destroy(false);\ + shm_init_main(&header, alloc, std::forward(args)...);\ +}\ +\ +/** Initialize the data structure's allocator */\ +inline void shm_init_allocator(hipc::Allocator *alloc) {\ + if (IsValid()) { return; }\ + if (alloc == nullptr) {\ + alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator();\ + } else {\ + alloc_ = alloc;\ + }\ +}\ +\ +/**\ + * Initialize a data structure's header.\ + * A container will never re-set or re-allocate its header once it has\ + * been set the first time.\ + * */\ +template\ +void shm_init_header(TYPE_UNWRAP(TYPED_HEADER) *header,\ + Args&& ...args) {\ + if (IsValid()) {\ + header_->SetBits(SHM_CONTAINER_DATA_VALID);\ + } else if (header == nullptr) {\ + hipc::Pointer p;\ + header_ = alloc_->template\ + AllocateConstructObjs(\ + 1, p, std::forward(args)...);\ + header_->SetBits(\ + SHM_CONTAINER_DATA_VALID |\ + SHM_CONTAINER_HEADER_DESTRUCTABLE);\ + flags_.SetBits(\ + SHM_CONTAINER_VALID |\ + SHM_CONTAINER_DESTRUCTABLE);\ + } else {\ + hipc::Pointer header_ptr;\ + header_ = header;\ + hipc::Allocator::ConstructObj(\ + *header_, std::forward(args)...);\ + header_->SetBits(\ + SHM_CONTAINER_DATA_VALID);\ + flags_.SetBits(\ + SHM_CONTAINER_VALID |\ + SHM_CONTAINER_DESTRUCTABLE);\ + }\ +}\ +\ +/**====================================\ + * Serialization\ + * ===================================*/\ +\ +/** Serialize into a Pointer */\ +void shm_serialize(hipc::TypedPointer &ar) const {\ + ar = alloc_->template\ + Convert(header_);\ + shm_serialize_main();\ +}\ +\ +/** Serialize into an AtomicPointer */\ +void shm_serialize(hipc::TypedAtomicPointer &ar) const {\ + ar = alloc_->template\ + Convert(header_);\ + shm_serialize_main();\ +}\ +\ +/** Override << operators */\ +SHM_SERIALIZE_OPS((TYPE_UNWRAP(TYPED_CLASS)))\ +\ +/**====================================\ + * Deserialization\ + * ===================================*/\ +\ +/** Deserialize object from a raw pointer */\ +bool shm_deserialize(const hipc::TypedPointer &ar) {\ + return shm_deserialize(\ + HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_),\ + ar.ToOffsetPointer()\ + );\ +}\ +\ +/** Deserialize object from allocator + offset */\ +bool shm_deserialize(hipc::Allocator *alloc, hipc::OffsetPointer header_ptr) {\ + if (header_ptr.IsNull()) { return false; }\ + return shm_deserialize(alloc,\ + alloc->Convert<\ + TYPE_UNWRAP(TYPED_HEADER),\ + hipc::OffsetPointer>(header_ptr));\ +}\ +\ +/** Deserialize object from another object (weak copy) */\ +bool shm_deserialize(const TYPE_UNWRAP(CLASS_NAME) &other) {\ + if (other.IsNull()) { return false; }\ + return shm_deserialize(other.GetAllocator(), other.header_);\ +}\ +\ +/** Deserialize object from allocator + header */\ +bool shm_deserialize(hipc::Allocator *alloc,\ + TYPE_UNWRAP(TYPED_HEADER) *header) {\ + flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE);\ + alloc_ = alloc;\ + header_ = header;\ + flags_.SetBits(SHM_CONTAINER_VALID);\ + shm_deserialize_main();\ + return true;\ +}\ +\ +/** Constructor. Deserialize the object from the reference. */\ +template\ +void shm_init(hipc::ShmRef &obj) {\ + shm_deserialize(obj->GetAllocator(), obj->header_);\ +}\ +\ +/** Override >> operators */\ +SHM_DESERIALIZE_OPS((TYPE_UNWRAP(TYPED_CLASS)))\ +\ +/**====================================\ + * Destructors\ + * ===================================*/\ +\ +/** Destructor */\ +~TYPE_UNWRAP(CLASS_NAME)() {\ + if (IsDestructable()) {\ + shm_destroy(true);\ + }\ +}\ +\ +/** Shm Destructor */\ +void shm_destroy(bool destroy_header = true) {\ + if (!IsValid()) { return; }\ + if (IsDataValid()) {\ + shm_destroy_main();\ + }\ + UnsetDataValid();\ + if (destroy_header &&\ + header_->OrBits(SHM_CONTAINER_HEADER_DESTRUCTABLE)) {\ + alloc_->FreePtr(header_);\ + UnsetValid();\ + }\ +}\ +\ +/**====================================\ + * Move Operations\ + * ===================================*/\ +\ +/** Move constructor */\ +TYPE_UNWRAP(CLASS_NAME)(TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ +shm_weak_move(\ + hipc::typed_nullptr(),\ + hipc::typed_nullptr(),\ + other);\ +}\ +\ +/** Move assignment operator */\ +TYPE_UNWRAP(CLASS_NAME)& operator=(TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ +if (this != &other) {\ +shm_weak_move(\ + hipc::typed_nullptr(),\ + hipc::typed_nullptr(),\ + other);\ +}\ +return *this;\ +}\ +\ +/** Move shm_init constructor */\ +void shm_init_main(TYPE_UNWRAP(TYPED_HEADER) *header,\ + hipc::Allocator *alloc,\ + TYPE_UNWRAP(CLASS_NAME) &&other) noexcept {\ + shm_weak_move(header, alloc, other);\ +}\ +\ +/** Move operation */\ +void shm_weak_move(TYPE_UNWRAP(TYPED_HEADER) *header,\ + hipc::Allocator *alloc,\ + TYPE_UNWRAP(CLASS_NAME) &other) {\ + if (other.IsNull()) { return; }\ + if (IsValid() && other.GetAllocator() != GetAllocator()) {\ + shm_strong_copy(header, alloc, other);\ + other.shm_destroy(true);\ + return;\ + }\ + shm_destroy(false);\ + shm_weak_move_main(header, alloc, other);\ + if (!other.IsDestructable()) {\ + UnsetDestructable();\ + }\ + other.UnsetDataValid();\ + other.shm_destroy(true);\ +}\ +\ +/**====================================\ + * Copy Operations\ + * ===================================*/\ +\ +/** Copy constructor */\ +TYPE_UNWRAP(CLASS_NAME)(const TYPE_UNWRAP(CLASS_NAME) &other) noexcept {\ + shm_init(other);\ +}\ +\ +/** Copy assignment constructor */\ +TYPE_UNWRAP(CLASS_NAME)& operator=(const TYPE_UNWRAP(CLASS_NAME) &other) {\ + if (this != &other) {\ + shm_strong_copy(\ + hipc::typed_nullptr(),\ + hipc::typed_nullptr(),\ + other);\ + }\ + return *this;\ +}\ +\ +/** Copy shm_init constructor */\ +void shm_init_main(TYPE_UNWRAP(TYPED_HEADER) *header,\ + hipc::Allocator *alloc,\ + const TYPE_UNWRAP(CLASS_NAME) &other) {\ + shm_strong_copy(header, alloc, other);\ +}\ +\ +/** Strong Copy operation */\ +void shm_strong_copy(TYPE_UNWRAP(TYPED_HEADER) *header,\ + hipc::Allocator *alloc,\ + const TYPE_UNWRAP(CLASS_NAME) &other) {\ + if (other.IsNull()) { return; }\ + shm_destroy(false);\ + shm_strong_copy_main(header, alloc, other);\ + SetDestructable();\ +}\ +\ +/**====================================\ + * Container Flag Operations\ + * ===================================*/\ +\ +/** Sets this object as destructable */\ +void SetDestructable() {\ + flags_.SetBits(SHM_CONTAINER_DESTRUCTABLE);\ +}\ +\ +/** Sets this object as not destructable */\ +void UnsetDestructable() {\ + flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE);\ +}\ +\ +/** Check if this container is destructable */\ +bool IsDestructable() const {\ + return flags_.OrBits(SHM_CONTAINER_DESTRUCTABLE);\ +}\ +\ +/** Check if container has a valid header */\ +bool IsValid() const {\ + return flags_.OrBits(SHM_CONTAINER_VALID);\ +}\ +\ +/** Set container header invalid */\ +void UnsetValid() {\ + flags_.UnsetBits(SHM_CONTAINER_VALID |\ + SHM_CONTAINER_DESTRUCTABLE | SHM_CONTAINER_HEADER_DESTRUCTABLE);\ +}\ +\ +/**====================================\ + * Header Flag Operations\ + * ===================================*/\ +\ +/** Check if header's data is valid */\ +bool IsDataValid() const {\ + return header_->OrBits(SHM_CONTAINER_DATA_VALID);\ +}\ +\ +/** Check if header's data is valid */\ +void UnsetDataValid() const {\ + header_->UnsetBits(SHM_CONTAINER_DATA_VALID);\ +}\ +\ +/** Check if null */\ +bool IsNull() const {\ + return !IsValid() || !IsDataValid();\ +}\ +\ +/** Get a typed pointer to the object */\ +template\ +POINTER_T GetShmPointer() const {\ + return alloc_->Convert(header_);\ +}\ +\ +/**====================================\ + * Query Operations\ + * ===================================*/\ +\ +/** Get the allocator for this container */\ +hipc::Allocator* GetAllocator() {\ + return alloc_;\ +}\ +\ +/** Get the allocator for this container */\ +hipc::Allocator* GetAllocator() const {\ + return alloc_;\ +}\ +\ +/** Get the shared-memory allocator id */\ +hipc::allocator_id_t GetAllocatorId() const {\ + return alloc_->GetId();\ +}\ + +#endif // HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h new file mode 100644 index 000000000..e674177d9 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h @@ -0,0 +1,92 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ + +#include "hermes_shm/memory/memory_manager.h" + +namespace hermes_shm::ipc { + +/** + * The parameters used to deserialize an object. + * */ +template +struct ShmDeserialize { + public: + typedef typename ContainerT::header_t header_t; + Allocator *alloc_; + header_t *header_; + + public: + /** Default constructor */ + ShmDeserialize() = default; + + /** Construct from TypedPointer */ + ShmDeserialize(const TypedPointer &ar) { + alloc_ = HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_); + header_ = alloc_->Convert< + TypedPointer, + OffsetPointer>(ar.ToOffsetPointer()); + } + + /** Construct from allocator + offset pointer */ + ShmDeserialize(Allocator *alloc, TypedOffsetPointer &ar) { + alloc_ = alloc; + header_ = alloc_->Convert< + TypedPointer, + OffsetPointer>(ar.ToOffsetPointer()); + } + + /** Construct from allocator + offset pointer */ + ShmDeserialize(Allocator *alloc, header_t *header) { + alloc_ = alloc; + header_ = header; + } + + /** Copy constructor */ + ShmDeserialize(const ShmDeserialize &other) { + shm_strong_copy(other); + } + + /** Copy assign operator */ + ShmDeserialize& operator=(const ShmDeserialize &other) { + shm_strong_copy(other); + return *this; + } + + /** Copy operation */ + void shm_strong_copy(const ShmDeserialize &other) { + alloc_ = other.alloc_; + header_ = other.header_; + } + + /** Move constructor */ + ShmDeserialize(ShmDeserialize &&other) { + shm_weak_move(other); + } + + /** Move assign operator */ + ShmDeserialize& operator=(ShmDeserialize &&other) { + shm_weak_move(); + return *this; + } + + /** Move operation */ + void shm_weak_move(ShmDeserialize &other) { + shm_strong_copy(other); + } +}; + +} // namespace hermes_shm::ipc + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h new file mode 100644 index 000000000..179785009 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h @@ -0,0 +1,80 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_MEMORY_SHM_MACROS_H_ +#define HERMES_SHM_MEMORY_SHM_MACROS_H_ + +#include + +/** + * Determine whether or not \a T type is designed for shared memory + * */ +#define IS_SHM_ARCHIVEABLE(T) \ + std::is_base_of::value + +/** + * Determine whether or not \a T type is a SHM smart pointer + * */ +#define IS_SHM_SMART_POINTER(T) \ + std::is_base_of::value + +/** + * SHM_X_OR_Y: X if T is SHM_SERIALIZEABLE, Y otherwise + * */ +#define SHM_X_OR_Y(T, X, Y) \ + typename std::conditional< \ + IS_SHM_ARCHIVEABLE(T), \ + X, Y>::type + +/** + * SHM_T_OR_PTR_T: Returns T if SHM_ARCHIVEABLE, and T* otherwise. Used + * internally by hipc::ShmRef. + * + * @param T: The type being stored in the shmem data structure + * */ +#define SHM_T_OR_PTR_T(T) \ + SHM_X_OR_Y(T, T, T*) + +/** + * ShmHeaderOrT: Returns TypedPointer if SHM_ARCHIVEABLE, and T + * otherwise. Used to construct an hipc::ShmRef. + * + * @param T The type being stored in the shmem data structure + * */ +#define SHM_ARCHIVE_OR_T(T) \ + SHM_X_OR_Y(T, hipc::TypedPointer, T) + +/** + * SHM_T_OR_SHM_STRUCT_T: Used by unique_ptr and manual_ptr to internally + * store either a shm-compatible type or a POD (piece of data) type. + * + * @param T: The type being stored in the shmem data structure + * */ +#define SHM_T_OR_SHM_STRUCT_T(T) \ + SHM_X_OR_Y(T, T, ShmStruct) + +/** + * SHM_T_OR_CONST_T: Determines whether or not an object should be + * a constant or not. + * */ +#define SHM_CONST_T_OR_T(T, IS_CONST) \ + typename std::conditional< \ + IS_CONST, \ + const T, T>::type + +/** + * SHM_ARCHIVE_OR_REF: Return value of shm_ar::internal_ref(). + * */ +#define SHM_ARCHIVE_OR_REF(T)\ + SHM_X_OR_Y(T, TypedPointer, T&) + +#endif // HERMES_SHM_MEMORY_SHM_MACROS_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h new file mode 100644 index 000000000..dba9ce461 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h @@ -0,0 +1,127 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ + +#include "shm_container.h" +#include + +namespace hermes_shm::ipc { + +/** forward declaration for string */ +class NullContainer; + +/** + * MACROS used to simplify the string namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ +#define CLASS_NAME NullContainer +#define TYPED_CLASS NullContainer +#define TYPED_HEADER ShmHeader + +/** string shared-memory header */ +template<> +struct ShmHeader : public ShmBaseHeader { + /** Default constructor */ + ShmHeader() = default; + + /** Copy constructor */ + ShmHeader(const ShmHeader &other) { + strong_copy(other); + } + + /** Copy assignment operator */ + ShmHeader& operator=(const ShmHeader &other) { + if (this != &other) { + strong_copy(other); + } + return *this; + } + + /** Strong copy operation */ + void strong_copy(const ShmHeader &other) {} + + /** Move constructor */ + ShmHeader(ShmHeader &&other) { + weak_move(other); + } + + /** Move operator */ + ShmHeader& operator=(ShmHeader &&other) { + if (this != &other) { + weak_move(other); + } + return *this; + } + + /** Move operation */ + void weak_move(ShmHeader &other) { + strong_copy(other); + } +}; + +/** + * A string of characters. + * */ +class NullContainer : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) + + public: + //////////////////////////// + /// SHM Overrides + //////////////////////////// + + /** Default constructor */ + NullContainer() = default; + + /** Default shm constructor */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header); + } + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, + NullContainer &other) {} + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, + const NullContainer &other) {} + + /** + * Destroy the shared-memory data. + * */ + void shm_destroy_main() {} + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} +}; + +} // namespace hermes_shm::ipc + +namespace std { + +} // namespace std + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h new file mode 100644 index 000000000..2bbf3a9fd --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h @@ -0,0 +1,201 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ + +#include "hermes_shm/constants/macros.h" +#include "shm_macros.h" +#include "shm_archive.h" + +namespace hermes_shm::ipc { + +/** + * A ShmReference to a shared-memory object + * */ +template +struct _ShmRefShm { + T obj_; + + /** Default constructor */ + _ShmRefShm() = default; + + /** Destructor */ + ~_ShmRefShm() { + obj_.UnsetDestructable(); + } + + /** Constructor. */ + explicit _ShmRefShm(TypedPointer other) { + obj_.shm_deserialize(other); + } + + /** Copy constructor */ + _ShmRefShm(const _ShmRefShm &other) { + obj_.shm_deserialize(other.obj_); + } + + /** Move constructor */ + _ShmRefShm(_ShmRefShm &&other) noexcept { + obj_.shm_deserialize(other.obj_); + } + + /** Copy assign operator */ + _ShmRefShm& operator=(const _ShmRefShm &other) { + if (this != &other) { + obj_.shm_deserialize(other.obj_); + } + return *this; + } + + /** Move assign operator */ + _ShmRefShm& operator=(_ShmRefShm &&other) noexcept { + if (this != &other) { + obj_.shm_deserialize(other.obj_); + } + return *this; + } + + /** Get ShmReference to the internal data structure */ + T& get_ref() { + return obj_; + } + + /** Get a constant ShmReference */ + const T& get_ref_const() const { + return obj_; + } +}; + +/** + * A ShmReference to a POD type stored in shared memory. + * */ +template +struct _ShmRefNoShm { + T *obj_; + + /** Default constructor */ + _ShmRefNoShm() = default; + + /** Constructor. */ + explicit _ShmRefNoShm(T &other) { + obj_ = &other; + } + + /** Copy constructor */ + _ShmRefNoShm(const _ShmRefNoShm &other) { + obj_ = other.obj_; + } + + /** Move constructor */ + _ShmRefNoShm(_ShmRefNoShm &&other) noexcept { + obj_ = other.obj_; + } + + /** Copy assign operator */ + _ShmRefNoShm& operator=(const _ShmRefNoShm &other) { + if (this != &other) { + obj_ = other.obj_; + } + return *this; + } + + /** Move assign operator */ + _ShmRefNoShm& operator=(_ShmRefNoShm &&other) noexcept { + if (this != &other) { + obj_ = other.obj_; + } + return *this; + } + + /** Get ShmReference to the internal data structure */ + T& get_ref() { + return *obj_; + } + + /** Get a constant ShmReference */ + const T& get_ref_const() const { + return *obj_; + } +}; + +/** Determine whether ShmRef stores _ShmRefShm or _ShmRefNoShm */ +#define CHOOSE_SHM_ShmRef_TYPE(T) SHM_X_OR_Y(T, _ShmRefShm, _ShmRefNoShm) + +/** + * A Reference to a shared-memory object or a simple object + * stored in shared-memory. + * */ +template +struct ShmRef { + typedef CHOOSE_SHM_ShmRef_TYPE(T) T_ShmRef; + T_ShmRef obj_; + + /** Constructor. */ + template + explicit ShmRef(Args&& ...args) : obj_(std::forward(args)...) {} + + /** Default constructor */ + ShmRef() = default; + + /** Copy Constructor */ + ShmRef(const ShmRef &other) : obj_(other.obj_) {} + + /** Copy assign operator */ + ShmRef& operator=(const ShmRef &other) { + obj_ = other.obj_; + return *this; + } + + /** Move Constructor */ + ShmRef(ShmRef &&other) noexcept : obj_(std::move(other.obj_)) {} + + /** Move assign operator */ + ShmRef& operator=(ShmRef &&other) noexcept { + obj_ = std::move(other.obj_); + return *this; + } + + /** Get ShmReference to the internal data structure */ + T& get_ref() { + return obj_.get_ref(); + } + + /** Get a constant ShmReference */ + const T& get_ref_const() const { + return obj_.get_ref_const(); + } + + /** DeShmReference operator */ + T& operator*() { + return get_ref(); + } + + /** Constant deShmReference operator */ + const T& operator*() const { + return get_ref_const(); + } + + /** Pointer operator */ + T* operator->() { + return &get_ref(); + } + + /** Constant pointer operator */ + const T* operator->() const { + return &get_ref_const(); + } +}; + +} // namespace hermes_shm::ipc + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h new file mode 100644 index 000000000..4db23e2ae --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h @@ -0,0 +1,162 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ +#define HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ + +#include "hermes_shm/memory/memory.h" +#include "hermes_shm/memory/allocator/allocator.h" +#include "hermes_shm/memory/memory_manager.h" +#include "hermes_shm/data_structures/internal/shm_macros.h" +#include + +#include "hermes_shm/data_structures/internal/shm_archive.h" + +namespace hermes_shm::ipc { + +/** + * Indicates a data structure represents a memory paradigm for Shm. + * */ +class ShmSmartPointer : public ShmArchiveable {}; + +/** + * A base class used for creating shared-memory pointer management + * classes (manual_ptr, unique_ptr, shared_ptr). + * + * Smart pointers are not stored directly in shared memory. They are + * wrappers around shared-memory objects which manage the construction + * and destruction of objects. + * */ +template +class ShmSmartPtr : public ShmSmartPointer { + public: + T obj_; /**< The stored shared-memory object */ + + public: + /** Default constructor */ + ShmSmartPtr() = default; + + /** Sets this pointer to NULL */ + void SetNull() { + obj_.SetNull(); + } + + /** Checks if this pointer is null */ + bool IsNull() const { + return obj_.IsNull(); + } + + /** Gets a pointer to the internal object */ + T* get() { + return &obj_; + } + + /** Gets a pointer to the internal object */ + T* get() const { + return &obj_; + } + + /** Gets a pointer to the internal object */ + T* get_const() const { + return &obj_; + } + + /** Gets a reference to the internal object */ + T& get_ref() { + return obj_; + } + + /** Gets a reference to the internal object */ + T& get_ref() const { + return obj_; + } + + /** Gets a reference to the internal object */ + const T& get_ref_const() const { + return obj_; + } + + /** Dereference operator */ + T& operator*() { + return get_ref(); + } + + /** Constant dereference operator */ + const T& operator*() const { + return get_ref_const(); + } + + /** Pointer operator */ + T* operator->() { + return get(); + } + + /** Constant pointer operator */ + const T* operator->() const { + return get_const(); + } + + /** Destroy the data allocated by this pointer */ + void shm_destroy() { + obj_.shm_destroy(); + } +}; + + + +} // namespace hermes_shm::ipc + +/** + * Namespace simplification for a SHM data structure pointer + * */ +#define SHM_SMART_PTR_TEMPLATE(T) \ + using ShmSmartPtr::shm_destroy;\ + using ShmSmartPtr::obj_;\ + using ShmSmartPtr::get;\ + using ShmSmartPtr::get_ref;\ + using ShmSmartPtr::get_const;\ + using ShmSmartPtr::get_ref_const;\ + using ShmSmartPtr::SetNull;\ + using ShmSmartPtr::IsNull; + +/** + * A macro for defining shared memory serializations + * */ +#define SHM_SERIALIZE_WRAPPER(AR_TYPE)\ + void shm_serialize(hipc::TypedPointer &type) const {\ + obj_.shm_serialize(type);\ + }\ + void shm_serialize(hipc::TypedAtomicPointer &type) const {\ + obj_.shm_serialize(type);\ + }\ + SHM_SERIALIZE_OPS(AR_TYPE) + +/** + * A macro for defining shared memory deserializations + * */ +#define SHM_DESERIALIZE_WRAPPER(AR_TYPE)\ + void shm_deserialize(const hipc::TypedPointer &type) {\ + obj_.shm_deserialize(type);\ + }\ + void shm_deserialize(const hipc::TypedAtomicPointer &type) {\ + obj_.shm_deserialize(type);\ + }\ + SHM_DESERIALIZE_OPS(AR_TYPE) + +/** + * A macro for defining shared memory (de)serializations + * */ +#define SHM_SERIALIZE_DESERIALIZE_WRAPPER(AR_TYPE)\ + SHM_SERIALIZE_WRAPPER(AR_TYPE)\ + SHM_DESERIALIZE_WRAPPER(AR_TYPE) + +#endif // HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h new file mode 100644 index 000000000..bb5b8c96b --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h @@ -0,0 +1,422 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ + +#include "hermes_shm/data_structures/internal/shm_container.h" + +namespace honey { + +class ShmContainerExample; + +#define CLASS_NAME ShmContainerExample +#define TYPED_CLASS ShmContainerExample +#define TYPED_HEADER ShmHeader + +template +class ShmHeader; + +template<> + class ShmHeader : public hipc::ShmBaseHeader { +}; + +class ShmContainerExample { + public: + /**==================================== + * Variables & Types + * ===================================*/ + + typedef TYPED_HEADER header_t; /** Header type query */ + header_t *header_; /**< Header of the shared-memory data structure */ + hipc::Allocator *alloc_; /**< hipc::Allocator used for this data structure */ + hermes_shm::bitfield32_t flags_; /**< Flags used data structure status */ + + public: + /**==================================== + * Shm Overrides + * ===================================*/ + + /** Default constructor */ + CLASS_NAME() = default; + + /** Default shm constructor */ + void shm_init_main(TYPED_HEADER *header, + hipc::Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header); + } + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + hipc::Allocator *alloc, + CLASS_NAME &other) { + shm_init_main(header, alloc); + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + hipc::Allocator *alloc, + const CLASS_NAME &other) { + shm_init_main(header, alloc); + } + + /** Destroy the shared-memory data. */ + void shm_destroy_main() {} + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} + + /**==================================== + * Constructors + * ===================================*/ + + /** Constructor. Allocate header with default allocator. */ + template + explicit CLASS_NAME(Args&& ...args) { + shm_init(std::forward(args)...); + } + + /** Constructor. Allocate header with default allocator. */ + template + void shm_init(Args&& ...args) { + shm_destroy(false); + shm_init_main(hipc::typed_nullptr(), + hipc::typed_nullptr(), + std::forward(args)...); + } + + /** Constructor. Allocate header with specific allocator. */ + template + void shm_init(hipc::Allocator *alloc, Args&& ...args) { + shm_destroy(false); + shm_init_main(hipc::typed_nullptr(), + alloc, + std::forward(args)...); + } + + /** Constructor. Initialize an already-allocated header. */ + template + void shm_init(TYPED_HEADER &header, + hipc::Allocator *alloc, Args&& ...args) { + shm_destroy(false); + shm_init_main(&header, alloc, std::forward(args)...); + } + + /** Initialize the data structure's allocator */ + inline void shm_init_allocator(hipc::Allocator *alloc) { + if (IsValid()) { return; } + if (alloc == nullptr) { + alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + } else { + alloc_ = alloc; + } + } + + /** + * Initialize a data structure's header. + * A container will never re-set or re-allocate its header once it has + * been set the first time. + * */ + template + void shm_init_header(TYPED_HEADER *header, + Args&& ...args) { + if (IsValid()) { + header_->SetBits(SHM_CONTAINER_DATA_VALID); + } else if (header == nullptr) { + hipc::Pointer p; + header_ = alloc_->template + AllocateConstructObjs( + 1, p, std::forward(args)...); + header_->SetBits( + SHM_CONTAINER_DATA_VALID | + SHM_CONTAINER_HEADER_DESTRUCTABLE); + flags_.SetBits( + SHM_CONTAINER_VALID | + SHM_CONTAINER_DESTRUCTABLE); + } else { + hipc::Pointer header_ptr; + header_ = header; + hipc::Allocator::ConstructObj( + *header_, std::forward(args)...); + header_->SetBits( + SHM_CONTAINER_DATA_VALID); + flags_.SetBits( + SHM_CONTAINER_VALID | + SHM_CONTAINER_DESTRUCTABLE); + } + } + + /**==================================== + * Serialization + * ===================================*/ + + /** Serialize into a Pointer */ + void shm_serialize(hipc::TypedPointer &ar) const { + ar = alloc_->template + Convert(header_); + shm_serialize_main(); + } + + /** Serialize into an AtomicPointer */ + void shm_serialize(hipc::TypedAtomicPointer &ar) const { + ar = alloc_->template + Convert(header_); + shm_serialize_main(); + } + + /** Override << operators */ + SHM_SERIALIZE_OPS((TYPED_CLASS)) + + /**==================================== + * Deserialization + * ===================================*/ + + /** Deserialize object from a raw pointer */ + bool shm_deserialize(const hipc::TypedPointer &ar) { + return shm_deserialize( + HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_), + ar.ToOffsetPointer() + ); + } + + /** Deserialize object from allocator + offset */ + bool shm_deserialize(hipc::Allocator *alloc, hipc::OffsetPointer header_ptr) { + if (header_ptr.IsNull()) { return false; } + return shm_deserialize(alloc, + alloc->Convert< + TYPED_HEADER, + hipc::OffsetPointer>(header_ptr)); + } + + /** Deserialize object from another object (weak copy) */ + bool shm_deserialize(const CLASS_NAME &other) { + if (other.IsNull()) { return false; } + return shm_deserialize(other.GetAllocator(), other.header_); + } + + /** Deserialize object from allocator + header */ + bool shm_deserialize(hipc::Allocator *alloc, + TYPED_HEADER *header) { + flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE); + alloc_ = alloc; + header_ = header; + flags_.SetBits(SHM_CONTAINER_VALID); + shm_deserialize_main(); + return true; + } + + /** Constructor. Deserialize the object from the reference. */ + template + void shm_init(hipc::ShmRef &obj) { + shm_deserialize(obj->GetAllocator(), obj->header_); + } + + /** Override >> operators */ + SHM_DESERIALIZE_OPS((TYPED_CLASS)) + + /**==================================== + * Destructors + * ===================================*/ + + /** Destructor */ + ~CLASS_NAME() { + if (IsDestructable()) { + shm_destroy(true); + } + } + + /** Shm Destructor */ + void shm_destroy(bool destroy_header = true) { + if (!IsValid()) { return; } + if (IsDataValid()) { + shm_destroy_main(); + } + UnsetDataValid(); + if (destroy_header && + header_->OrBits(SHM_CONTAINER_HEADER_DESTRUCTABLE)) { + alloc_->FreePtr(header_); + UnsetValid(); + } + } + + /**==================================== + * Move Operations + * ===================================*/ + + /** Move constructor */ + CLASS_NAME(CLASS_NAME &&other) noexcept { + shm_weak_move( + hipc::typed_nullptr(), + hipc::typed_nullptr(), + other); + } + + /** Move assignment operator */ + CLASS_NAME& operator=(CLASS_NAME &&other) noexcept { + if (this != &other) { + shm_weak_move( + hipc::typed_nullptr(), + hipc::typed_nullptr(), + other); + } + return *this; + } + + /** Move shm_init constructor */ + void shm_init_main(TYPED_HEADER *header, + hipc::Allocator *alloc, + CLASS_NAME &&other) noexcept { + shm_weak_move(header, alloc, other); + } + + /** Move operation */ + void shm_weak_move(TYPED_HEADER *header, + hipc::Allocator *alloc, + CLASS_NAME &other) { + if (other.IsNull()) { return; } + if (IsValid() && other.GetAllocator() != GetAllocator()) { + shm_strong_copy(header, alloc, other); + other.shm_destroy(true); + return; + } + shm_destroy(false); + shm_weak_move_main(header, alloc, other); + if (!other.IsDestructable()) { + UnsetDestructable(); + } + other.UnsetDataValid(); + other.shm_destroy(true); + } + + /**==================================== + * Copy Operations + * ===================================*/ + + /** Copy constructor */ + CLASS_NAME(const CLASS_NAME &other) noexcept { + shm_init(other); + } + + /** Copy assignment constructor */ + CLASS_NAME& operator=(const CLASS_NAME &other) { + if (this != &other) { + shm_strong_copy( + hipc::typed_nullptr(), + hipc::typed_nullptr(), + other); + } + return *this; + } + + /** Copy shm_init constructor */ + void shm_init_main(TYPED_HEADER *header, + hipc::Allocator *alloc, + const CLASS_NAME &other) { + shm_strong_copy(header, alloc, other); + } + + /** Strong Copy operation */ + void shm_strong_copy(TYPED_HEADER *header, + hipc::Allocator *alloc, + const CLASS_NAME &other) { + if (other.IsNull()) { return; } + shm_destroy(false); + shm_strong_copy_main(header, alloc, other); + SetDestructable(); + } + + /**==================================== + * Container Flag Operations + * ===================================*/ + + /** Sets this object as destructable */ + void SetDestructable() { + flags_.SetBits(SHM_CONTAINER_DESTRUCTABLE); + } + + /** Sets this object as not destructable */ + void UnsetDestructable() { + flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE); + } + + /** Check if this container is destructable */ + bool IsDestructable() const { + return flags_.OrBits(SHM_CONTAINER_DESTRUCTABLE); + } + + /** Check if container has a valid header */ + bool IsValid() const { + return flags_.OrBits(SHM_CONTAINER_VALID); + } + + /** Set container header invalid */ + void UnsetValid() { + flags_.UnsetBits(SHM_CONTAINER_VALID | + SHM_CONTAINER_DESTRUCTABLE | SHM_CONTAINER_HEADER_DESTRUCTABLE); + } + + /**==================================== + * Header Flag Operations + * ===================================*/ + + /** Check if header's data is valid */ + bool IsDataValid() const { + return header_->OrBits(SHM_CONTAINER_DATA_VALID); + } + + /** Check if header's data is valid */ + void UnsetDataValid() const { + header_->UnsetBits(SHM_CONTAINER_DATA_VALID); + } + + /** Check if null */ + bool IsNull() const { + return !IsValid() || !IsDataValid(); + } + + /** Get a typed pointer to the object */ + template + POINTER_T GetShmPointer() const { + return alloc_->Convert(header_); + } + + /**==================================== + * Query Operations + * ===================================*/ + + /** Get the allocator for this container */ + hipc::Allocator* GetAllocator() { + return alloc_; + } + + /** Get the allocator for this container */ + hipc::Allocator* GetAllocator() const { + return alloc_; + } + + /** Get the shared-memory allocator id */ + hipc::allocator_id_t GetAllocatorId() const { + return alloc_->GetId(); + } +}; + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h new file mode 100644 index 000000000..e6aff6dd9 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h @@ -0,0 +1,355 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +public: +/**==================================== + * Variables & Types + * ===================================*/ + +typedef TYPED_HEADER header_t; /** Header type query */ +header_t *header_; /**< Header of the shared-memory data structure */ +hipc::Allocator *alloc_; /**< hipc::Allocator used for this data structure */ +hermes_shm::bitfield32_t flags_; /**< Flags used data structure status */ + +public: +/**==================================== + * Constructors + * ===================================*/ + +/** Constructor. Allocate header with default allocator. */ +template +explicit CLASS_NAME(Args&& ...args) { +shm_init(std::forward(args)...); +} + +/** Constructor. Allocate header with default allocator. */ +template +void shm_init(Args&& ...args) { + shm_destroy(false); + shm_init_main(hipc::typed_nullptr(), + hipc::typed_nullptr(), + std::forward(args)...); +} + +/** Constructor. Allocate header with specific allocator. */ +template +void shm_init(hipc::Allocator *alloc, Args&& ...args) { + shm_destroy(false); + shm_init_main(hipc::typed_nullptr(), + alloc, + std::forward(args)...); +} + +/** Constructor. Initialize an already-allocated header. */ +template +void shm_init(TYPED_HEADER &header, + hipc::Allocator *alloc, Args&& ...args) { + shm_destroy(false); + shm_init_main(&header, alloc, std::forward(args)...); +} + +/** Initialize the data structure's allocator */ +inline void shm_init_allocator(hipc::Allocator *alloc) { + if (IsValid()) { return; } + if (alloc == nullptr) { + alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + } else { + alloc_ = alloc; + } +} + +/** + * Initialize a data structure's header. + * A container will never re-set or re-allocate its header once it has + * been set the first time. + * */ +template +void shm_init_header(TYPED_HEADER *header, + Args&& ...args) { + if (IsValid()) { + header_->SetBits(SHM_CONTAINER_DATA_VALID); + } else if (header == nullptr) { + hipc::Pointer p; + header_ = alloc_->template + AllocateConstructObjs( + 1, p, std::forward(args)...); + header_->SetBits( + SHM_CONTAINER_DATA_VALID | + SHM_CONTAINER_HEADER_DESTRUCTABLE); + flags_.SetBits( + SHM_CONTAINER_VALID | + SHM_CONTAINER_DESTRUCTABLE); + } else { + hipc::Pointer header_ptr; + header_ = header; + hipc::Allocator::ConstructObj( + *header_, std::forward(args)...); + header_->SetBits( + SHM_CONTAINER_DATA_VALID); + flags_.SetBits( + SHM_CONTAINER_VALID | + SHM_CONTAINER_DESTRUCTABLE); + } +} + +/**==================================== + * Serialization + * ===================================*/ + +/** Serialize into a Pointer */ +void shm_serialize(hipc::TypedPointer &ar) const { + ar = alloc_->template + Convert(header_); + shm_serialize_main(); +} + +/** Serialize into an AtomicPointer */ +void shm_serialize(hipc::TypedAtomicPointer &ar) const { + ar = alloc_->template + Convert(header_); + shm_serialize_main(); +} + +/** Override << operators */ +SHM_SERIALIZE_OPS((TYPED_CLASS)) + +/**==================================== + * Deserialization + * ===================================*/ + +/** Deserialize object from a raw pointer */ +bool shm_deserialize(const hipc::TypedPointer &ar) { + return shm_deserialize( + HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_), + ar.ToOffsetPointer() + ); +} + +/** Deserialize object from allocator + offset */ +bool shm_deserialize(hipc::Allocator *alloc, hipc::OffsetPointer header_ptr) { + if (header_ptr.IsNull()) { return false; } + return shm_deserialize(alloc, + alloc->Convert< + TYPED_HEADER, + hipc::OffsetPointer>(header_ptr)); +} + +/** Deserialize object from another object (weak copy) */ +bool shm_deserialize(const CLASS_NAME &other) { + if (other.IsNull()) { return false; } + return shm_deserialize(other.GetAllocator(), other.header_); +} + +/** Deserialize object from allocator + header */ +bool shm_deserialize(hipc::Allocator *alloc, + TYPED_HEADER *header) { + flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE); + alloc_ = alloc; + header_ = header; + flags_.SetBits(SHM_CONTAINER_VALID); + shm_deserialize_main(); + return true; +} + +/** Constructor. Deserialize the object from the reference. */ +template +void shm_init(hipc::ShmRef &obj) { + shm_deserialize(obj->GetAllocator(), obj->header_); +} + +/** Override >> operators */ +SHM_DESERIALIZE_OPS((TYPED_CLASS)) + +/**==================================== + * Destructors + * ===================================*/ + +/** Destructor */ +~CLASS_NAME() { + if (IsDestructable()) { + shm_destroy(true); + } +} + +/** Shm Destructor */ +void shm_destroy(bool destroy_header = true) { + if (!IsValid()) { return; } + if (IsDataValid()) { + shm_destroy_main(); + } + UnsetDataValid(); + if (destroy_header && + header_->OrBits(SHM_CONTAINER_HEADER_DESTRUCTABLE)) { + alloc_->FreePtr(header_); + UnsetValid(); + } +} + +/**==================================== + * Move Operations + * ===================================*/ + +/** Move constructor */ +CLASS_NAME(CLASS_NAME &&other) noexcept { +shm_weak_move( + hipc::typed_nullptr(), + hipc::typed_nullptr(), + other); +} + +/** Move assignment operator */ +CLASS_NAME& operator=(CLASS_NAME &&other) noexcept { +if (this != &other) { +shm_weak_move( + hipc::typed_nullptr(), + hipc::typed_nullptr(), + other); +} +return *this; +} + +/** Move shm_init constructor */ +void shm_init_main(TYPED_HEADER *header, + hipc::Allocator *alloc, + CLASS_NAME &&other) noexcept { + shm_weak_move(header, alloc, other); +} + +/** Move operation */ +void shm_weak_move(TYPED_HEADER *header, + hipc::Allocator *alloc, + CLASS_NAME &other) { + if (other.IsNull()) { return; } + if (IsValid() && other.GetAllocator() != GetAllocator()) { + shm_strong_copy(header, alloc, other); + other.shm_destroy(true); + return; + } + shm_destroy(false); + shm_weak_move_main(header, alloc, other); + if (!other.IsDestructable()) { + UnsetDestructable(); + } + other.UnsetDataValid(); + other.shm_destroy(true); +} + +/**==================================== + * Copy Operations + * ===================================*/ + +/** Copy constructor */ +CLASS_NAME(const CLASS_NAME &other) noexcept { + shm_init(other); +} + +/** Copy assignment constructor */ +CLASS_NAME& operator=(const CLASS_NAME &other) { + if (this != &other) { + shm_strong_copy( + hipc::typed_nullptr(), + hipc::typed_nullptr(), + other); + } + return *this; +} + +/** Copy shm_init constructor */ +void shm_init_main(TYPED_HEADER *header, + hipc::Allocator *alloc, + const CLASS_NAME &other) { + shm_strong_copy(header, alloc, other); +} + +/** Strong Copy operation */ +void shm_strong_copy(TYPED_HEADER *header, + hipc::Allocator *alloc, + const CLASS_NAME &other) { + if (other.IsNull()) { return; } + shm_destroy(false); + shm_strong_copy_main(header, alloc, other); + SetDestructable(); +} + +/**==================================== + * Container Flag Operations + * ===================================*/ + +/** Sets this object as destructable */ +void SetDestructable() { + flags_.SetBits(SHM_CONTAINER_DESTRUCTABLE); +} + +/** Sets this object as not destructable */ +void UnsetDestructable() { + flags_.UnsetBits(SHM_CONTAINER_DESTRUCTABLE); +} + +/** Check if this container is destructable */ +bool IsDestructable() const { + return flags_.OrBits(SHM_CONTAINER_DESTRUCTABLE); +} + +/** Check if container has a valid header */ +bool IsValid() const { + return flags_.OrBits(SHM_CONTAINER_VALID); +} + +/** Set container header invalid */ +void UnsetValid() { + flags_.UnsetBits(SHM_CONTAINER_VALID | + SHM_CONTAINER_DESTRUCTABLE | SHM_CONTAINER_HEADER_DESTRUCTABLE); +} + +/**==================================== + * Header Flag Operations + * ===================================*/ + +/** Check if header's data is valid */ +bool IsDataValid() const { + return header_->OrBits(SHM_CONTAINER_DATA_VALID); +} + +/** Check if header's data is valid */ +void UnsetDataValid() const { + header_->UnsetBits(SHM_CONTAINER_DATA_VALID); +} + +/** Check if null */ +bool IsNull() const { + return !IsValid() || !IsDataValid(); +} + +/** Get a typed pointer to the object */ +template +POINTER_T GetShmPointer() const { + return alloc_->Convert(header_); +} + +/**==================================== + * Query Operations + * ===================================*/ + +/** Get the allocator for this container */ +hipc::Allocator* GetAllocator() { + return alloc_; +} + +/** Get the allocator for this container */ +hipc::Allocator* GetAllocator() const { + return alloc_; +} + +/** Get the shared-memory allocator id */ +hipc::allocator_id_t GetAllocatorId() const { + return alloc_->GetId(); +} diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h new file mode 100644 index 000000000..9f98382ff --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h @@ -0,0 +1,316 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/** + * Let's say we want a data structure + * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_INHERIT_EXAMPLE_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_INHERIT_EXAMPLE_H_ + +#define CLASS_NAME ShmContainerExtendExample +#define TYPED_CLASS ShmContainerExtendExample +#define TYPED_HEADER ShmHeader> + +#include "hermes_shm/data_structures/internal/shm_container.h" + +namespace hermes_shm::ipc { + +template +class ShmContainerExtendExample; + +template +class ShmHeader> +: public ShmWrapperHeader { + typename ContainerT::header_t obj_; +}; + +template +class ShmContainerExtendExample : public ShmContainer { + public: + /**==================================== + * Variables & Types + *===================================*/ + + typedef TYPED_HEADER header_t; /**< Required by all ShmContainers */ + header_t *header_; /**< The shared-memory header for this container */ + ContainerT obj_; /**< The object being wrapped around */ + + public: + /**==================================== + * Shm Overrides + * ===================================*/ + + /** Default constructor */ + CLASS_NAME() = default; + + /** Default shm constructor */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc) { + } + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, CLASS_NAME &other) { + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const CLASS_NAME &other) { + } + + /** Destroy the shared-memory data. */ + void shm_destroy_main() {} + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} + + /**==================================== + * Constructors + * ===================================*/ + + /** Constructor. Allocate header with default allocator. */ + template + explicit CLASS_NAME(Args &&...args) { + shm_init(std::forward(args)...); + } + + /** Constructor. Allocate header with default allocator. */ + template + void shm_init(Args &&...args) { + } + + /**==================================== + * Serialization + * ===================================*/ + + /** Serialize into a Pointer */ + void shm_serialize(TypedPointer &ar) const { + obj_.shm_serialize(ar); + } + + /** Serialize into an AtomicPointer */ + void shm_serialize(TypedAtomicPointer &ar) const { + obj_.shm_serialize(ar); + } + + /** Override << operators */ + SHM_SERIALIZE_OPS((TYPED_CLASS)) + + /**==================================== + * Deserialization + * ===================================*/ + + /** Deserialize object from a raw pointer */ + bool shm_deserialize(const TypedPointer &ar) { + return obj_.shm_deserialize(ar); + } + + /** Deserialize object from allocator + offset */ + bool shm_deserialize(Allocator *alloc, OffsetPointer header_ptr) { + return obj_.shm_deserialize(alloc, header_ptr); + } + + /** Deserialize object from another object (weak copy) */ + bool shm_deserialize(const CLASS_NAME &other) { + return obj_.shm_deserialize(other); + } + + /** Deserialize object from allocator + header */ + bool shm_deserialize(Allocator *alloc, + TYPED_HEADER *header) { + return obj_.shm_deserialize(alloc, header); + } + + /** Constructor. Deserialize the object from the reference. */ + template + void shm_init(hipc::ShmRef &obj) { + shm_deserialize(obj->GetAllocator(), obj->header_); + } + + /** Override >> operators */ + SHM_DESERIALIZE_OPS ((TYPED_CLASS)) + + /**==================================== + * Destructors + * ===================================*/ + + /** Destructor */ + ~CLASS_NAME() { + obj_.shm_destroy(true); + } + + /** Shm Destructor */ + void shm_destroy(bool destroy_header = true) { + obj_.shm_destroy(false); + if (!IsValid()) { return; } + if (IsDataValid()) { + shm_destroy_main(); + } + UnsetDataValid(); + if (destroy_header && + obj_.header_->OrBits(SHM_CONTAINER_HEADER_DESTRUCTABLE)) { + GetAllocator()->template + FreePtr(header_); + UnsetValid(); + } + } + + /**==================================== + * Move Operations + * ===================================*/ + + /** Move constructor */ + CLASS_NAME(CLASS_NAME &&other) noexcept + : obj_(std::move(other)) {} + + /** Move assignment operator */ + CLASS_NAME& operator=(CLASS_NAME &&other) noexcept { + obj_ = std::move(other.obj_); + return *this; + } + + /** Move shm_init constructor */ + void shm_init_main(TYPED_HEADER *header, + hipc::Allocator *alloc, + CLASS_NAME &&other) noexcept { + shm_weak_move(header, alloc, other); + } + + /** Move operation */ + void shm_weak_move(TYPED_HEADER *header, + hipc::Allocator *alloc, + CLASS_NAME &other) { + obj_.shm_weak_move(header, alloc, other); + } + + /**==================================== + * Copy Operations + * ===================================*/ + + /** Copy constructor */ + CLASS_NAME(const CLASS_NAME &other) noexcept { + shm_init(other); + } + + /** Copy assignment constructor */ + CLASS_NAME &operator=(const CLASS_NAME &other) { + if (this != &other) { + shm_strong_copy( + typed_nullptr(), + typed_nullptr(), + other); + } + return *this; + } + + /** Copy shm_init constructor */ + void shm_init_main(TYPED_HEADER *header, + hipc::Allocator *alloc, + const CLASS_NAME &other) { + shm_strong_copy(header, alloc, other); + } + + /** Strong Copy operation */ + void shm_strong_copy(TYPED_HEADER *header, hipc::Allocator *alloc, + const CLASS_NAME &other) { + if (other.IsNull()) { return; } + shm_destroy(false); + shm_strong_copy_main(header, alloc, other); + SetDestructable(); + } + + /**==================================== + * Container Flag Operations + * ===================================*/ + + /** Sets this object as destructable */ + void SetDestructable() { + obj_.SetDestructable(); + } + + /** Sets this object as not destructable */ + void UnsetDestructable() { + obj_.UnsetDestructable(); + } + + /** Check if this container is destructable */ + bool IsDestructable() const { + return obj_.IsDestructable(); + } + + /** Check if container has a valid header */ + bool IsValid() const { + return obj_.IsValid(); + } + + /** Set container header invalid */ + void UnsetValid() { + obj_.UnsetValid(); + } + + /**==================================== + * Header Flag Operations + * ===================================*/ + + /** Check if header's data is valid */ + bool IsDataValid() const { + return obj_.IsDataValid(); + } + + /** Check if header's data is valid */ + void UnsetDataValid() const { + return obj_.UnsetDataValid(); + } + + /** Check if null */ + bool IsNull() const { + return obj_.IsNull(); + } + + /** Get a typed pointer to the object */ + template + POINTER_T GetShmPointer() const { + return GetAllocator()->template + Convert(header_); + } + + /**==================================== + * Query Operations + * ===================================*/ + + /** Get the allocator for this container */ + Allocator* GetAllocator() { + return obj_.GetAllocator(); + } + + /** Get the allocator for this container */ + Allocator* GetAllocator() const { + return obj_.GetAllocator(); + } + + /** Get the shared-memory allocator id */ + allocator_id_t GetAllocatorId() const { + return GetAllocator()->GetId(); + } +}; + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_INHERIT_EXAMPLE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h new file mode 100644 index 000000000..9a08e22e7 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_template.h @@ -0,0 +1,250 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +public: +/**==================================== + * Variables & Types + *===================================*/ + +typedef TYPED_HEADER header_t; /**< Required by all ShmContainers */ +header_t *header_; /**< The shared-memory header for this container */ +ContainerT obj_; /**< The object being wrapped around */ + +public: +/**==================================== + * Constructors + * ===================================*/ + +/** Constructor. Allocate header with default allocator. */ +template +explicit CLASS_NAME(Args &&...args) { +shm_init(std::forward(args)...); +} + +/** Constructor. Allocate header with default allocator. */ +template +void shm_init(Args &&...args) { +} + +/**==================================== + * Serialization + * ===================================*/ + +/** Serialize into a Pointer */ +void shm_serialize(TypedPointer &ar) const { + obj_.shm_serialize(ar); +} + +/** Serialize into an AtomicPointer */ +void shm_serialize(TypedAtomicPointer &ar) const { + obj_.shm_serialize(ar); +} + +/** Override << operators */ +SHM_SERIALIZE_OPS((TYPED_CLASS)) + +/**==================================== + * Deserialization + * ===================================*/ + +/** Deserialize object from a raw pointer */ +bool shm_deserialize(const TypedPointer &ar) { + return obj_.shm_deserialize(ar); +} + +/** Deserialize object from allocator + offset */ +bool shm_deserialize(Allocator *alloc, OffsetPointer header_ptr) { + return obj_.shm_deserialize(alloc, header_ptr); +} + +/** Deserialize object from another object (weak copy) */ +bool shm_deserialize(const CLASS_NAME &other) { + return obj_.shm_deserialize(other); +} + +/** Deserialize object from allocator + header */ +bool shm_deserialize(Allocator *alloc, + TYPED_HEADER *header) { + return obj_.shm_deserialize(alloc, header); +} + +/** Constructor. Deserialize the object from the reference. */ +template +void shm_init(hipc::ShmRef &obj) { + shm_deserialize(obj->GetAllocator(), obj->header_); +} + +/** Override >> operators */ +SHM_DESERIALIZE_OPS ((TYPED_CLASS)) + +/**==================================== + * Destructors + * ===================================*/ + +/** Destructor */ +~CLASS_NAME() { + obj_.shm_destroy(true); +} + +/** Shm Destructor */ +void shm_destroy(bool destroy_header = true) { + obj_.shm_destroy(false); + if (!IsValid()) { return; } + if (IsDataValid()) { + shm_destroy_main(); + } + UnsetDataValid(); + if (destroy_header && + obj_.header_->OrBits(SHM_CONTAINER_HEADER_DESTRUCTABLE)) { + GetAllocator()->template + FreePtr(header_); + UnsetValid(); + } +} + +/**==================================== + * Move Operations + * ===================================*/ + +/** Move constructor */ +CLASS_NAME(CLASS_NAME &&other) noexcept +: obj_(std::move(other)) {} + +/** Move assignment operator */ +CLASS_NAME& operator=(CLASS_NAME &&other) noexcept { +obj_ = std::move(other.obj_); +return *this; +} + +/** Move shm_init constructor */ +void shm_init_main(TYPED_HEADER *header, + hipc::Allocator *alloc, + CLASS_NAME &&other) noexcept { + shm_weak_move(header, alloc, other); +} + +/** Move operation */ +void shm_weak_move(TYPED_HEADER *header, + hipc::Allocator *alloc, + CLASS_NAME &other) { + obj_.shm_weak_move(header, alloc, other); +} + +/**==================================== + * Copy Operations + * ===================================*/ + +/** Copy constructor */ +CLASS_NAME(const CLASS_NAME &other) noexcept { + shm_init(other); +} + +/** Copy assignment constructor */ +CLASS_NAME &operator=(const CLASS_NAME &other) { + if (this != &other) { + shm_strong_copy( + typed_nullptr(), + typed_nullptr(), + other); + } + return *this; +} + +/** Copy shm_init constructor */ +void shm_init_main(TYPED_HEADER *header, + hipc::Allocator *alloc, + const CLASS_NAME &other) { + shm_strong_copy(header, alloc, other); +} + +/** Strong Copy operation */ +void shm_strong_copy(TYPED_HEADER *header, hipc::Allocator *alloc, + const CLASS_NAME &other) { + if (other.IsNull()) { return; } + shm_destroy(false); + shm_strong_copy_main(header, alloc, other); + SetDestructable(); +} + +/**==================================== + * Container Flag Operations + * ===================================*/ + +/** Sets this object as destructable */ +void SetDestructable() { + obj_.SetDestructable(); +} + +/** Sets this object as not destructable */ +void UnsetDestructable() { + obj_.UnsetDestructable(); +} + +/** Check if this container is destructable */ +bool IsDestructable() const { + return obj_.IsDestructable(); +} + +/** Check if container has a valid header */ +bool IsValid() const { + return obj_.IsValid(); +} + +/** Set container header invalid */ +void UnsetValid() { + obj_.UnsetValid(); +} + +/**==================================== + * Header Flag Operations + * ===================================*/ + +/** Check if header's data is valid */ +bool IsDataValid() const { + return obj_.IsDataValid(); +} + +/** Check if header's data is valid */ +void UnsetDataValid() const { + return obj_.UnsetDataValid(); +} + +/** Check if null */ +bool IsNull() const { + return obj_.IsNull(); +} + +/** Get a typed pointer to the object */ +template +POINTER_T GetShmPointer() const { + return GetAllocator()->template + Convert(header_); +} + +/**==================================== + * Query Operations + * ===================================*/ + +/** Get the allocator for this container */ +Allocator* GetAllocator() { + return obj_.GetAllocator(); +} + +/** Get the allocator for this container */ +Allocator* GetAllocator() const { + return obj_.GetAllocator(); +} + +/** Get the shared-memory allocator id */ +allocator_id_t GetAllocatorId() const { + return GetAllocator()->GetId(); +} diff --git a/hermes_shm/include/hermes_shm/data_structures/pair.h b/hermes_shm/include/hermes_shm/data_structures/pair.h new file mode 100644 index 000000000..035854acf --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/pair.h @@ -0,0 +1,203 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_PAIR_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_PAIR_H_ + +#include "data_structure.h" +#include "internal/shm_archive_or_t.h" + +namespace hermes_shm::ipc { + +/** forward declaration for string */ +template +class pair; + +/** + * MACROS used to simplify the string namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ +#define CLASS_NAME pair +#define TYPED_CLASS pair +#define TYPED_HEADER ShmHeader + +/** pair shared-memory header */ +template +struct ShmHeader : public ShmBaseHeader { + ShmHeaderOrT first_; + ShmHeaderOrT second_; + + /** Default constructor */ + ShmHeader() = default; + + /** Constructor. Default shm allocate. */ + explicit ShmHeader(Allocator *alloc) + : first_(alloc), second_(alloc) {} + + /** Piecewise constructor. */ + template + explicit ShmHeader(Allocator *alloc, + PiecewiseConstruct &&hint, + FirstArgPackT &&first, + SecondArgPackT &&second) { + (void) hint; + first_.PiecewiseInit(alloc, std::forward(first)); + second_.PiecewiseInit(alloc, std::forward(second)); + } + + /** Move constructor. */ + explicit ShmHeader(Allocator *alloc, + FirstT &&first, + SecondT &&second) + : first_(alloc, std::forward(first)), + second_(alloc, std::forward(second)) {} + + /** Copy constructor. */ + explicit ShmHeader(Allocator *alloc, + const FirstT &first, + const SecondT &second) + : first_(alloc, first), second_(alloc, second) {} + + /** Shm destructor */ + void shm_destroy(Allocator *alloc) { + first_.shm_destroy(alloc); + second_.shm_destroy(alloc); + } +}; + +/** + * A string of characters. + * */ +template +class pair : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) + + public: + hipc::ShmRef first_; + hipc::ShmRef second_; + + public: + /** Default constructor */ + pair() = default; + + /** Default shm constructor */ + void shm_init_main(TYPED_HEADER *header, Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header, alloc); + } + + /** Construct pair by moving parameters */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, + FirstT &&first, SecondT &&second) { + shm_init_allocator(alloc); + shm_init_header(header, + alloc_, + std::forward(first), + std::forward(second)); + first_ = hipc::ShmRef(header_->first_.internal_ref(alloc_)); + second_ = hipc::ShmRef(header_->second_.internal_ref(alloc_)); + } + + /** Construct pair by copying parameters */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, + const FirstT &first, const SecondT &second) { + shm_init_allocator(alloc); + shm_init_header(header, + alloc_, first, second); + first_ = hipc::ShmRef(header_->first_.internal_ref(alloc_)); + second_ = hipc::ShmRef(header_->second_.internal_ref(alloc_)); + } + + /** Construct pair piecewise */ + template + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, + PiecewiseConstruct &&hint, + FirstArgPackT &&first, + SecondArgPackT &&second) { + shm_init_allocator(alloc); + shm_init_header(header, + alloc_, + std::forward(hint), + std::forward(first), + std::forward(second)); + first_ = hipc::ShmRef(header_->first_.internal_ref(alloc_)); + second_ = hipc::ShmRef(header_->second_.internal_ref(alloc_)); + } + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, pair &other) { + shm_init_main(header, + alloc, + std::move(*other.first_), + std::move(*other.second_)); + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const pair &other) { + shm_init_main(header, + alloc, *other.first_, *other.second_); + } + + /** + * Destroy the shared-memory data. + * */ + void shm_destroy_main() { + header_->shm_destroy(alloc_); + } + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() { + first_ = hipc::ShmRef(header_->first_.internal_ref(alloc_)); + second_ = hipc::ShmRef(header_->second_.internal_ref(alloc_)); + } + + /** Get the first object */ + FirstT& GetFirst() { return *first_; } + + /** Get the first object (const) */ + FirstT& GetFirst() const { return *first_; } + + /** Get the second object */ + SecondT& GetSecond() { return *second_; } + + /** Get the second object (const) */ + SecondT& GetSecond() const { return *second_; } + + /** Get the first object (treated as key) */ + FirstT& GetKey() { return *first_; } + + /** Get the first object (treated as key) (const) */ + FirstT& GetKey() const { return *first_; } + + /** Get the second object (treated as value) */ + SecondT& GetVal() { return *second_; } + + /** Get the second object (treated as value) (const) */ + SecondT& GetVal() const { return *second_; } +}; + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +} // namespace hermes_shm::ipc + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_PAIR_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h b/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h new file mode 100644 index 000000000..892bbfe9f --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h @@ -0,0 +1,112 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_DATA_STRUCTURES_PTR_H_ +#define HERMES_SHM_DATA_STRUCTURES_PTR_H_ + +#include "hermes_shm/memory/memory.h" +#include "hermes_shm/data_structures/data_structure.h" +#include "hermes_shm/data_structures/internal/shm_archive_or_t.h" + +namespace hermes_shm::ipc { + +/** + * MACROS to simplify the ptr namespace + * */ +#define CLASS_NAME manual_ptr +#define TYPED_CLASS manual_ptr + +/** + * Creates a unique instance of a shared-memory data structure + * and deletes eventually. + * */ +template +class manual_ptr : public ShmSmartPtr { + public: + SHM_SMART_PTR_TEMPLATE(T); + + public: + /** Default constructor does nothing */ + manual_ptr() = default; + + /** Allocates + constructs an object in shared memory */ + template + void shm_init(Args&& ...args) { + obj_.shm_init(std::forward(args)...); + obj_.UnsetDestructable(); + } + + /** Destructor. Does not free data. */ + ~manual_ptr() { + obj_.UnsetDestructable(); + } + + /** Copy constructor */ + manual_ptr(const manual_ptr &other) { + obj_.shm_deserialize(other.obj_); + } + + /** Copy assignment operator */ + manual_ptr& operator=(const manual_ptr &other) { + if (this != &other) { + obj_.shm_deserialize(other.obj_); + } + return *this; + } + + /** Move constructor */ + manual_ptr(manual_ptr&& other) noexcept { + obj_ = std::move(other.obj_); + } + + /** Constructor. From a TypedPointer */ + explicit manual_ptr(const TypedPointer &ar) { + obj_.shm_deserialize(ar); + } + + /** Constructor. From a TypedAtomicPointer */ + explicit manual_ptr(const TypedAtomicPointer &ar) { + obj_.shm_deserialize(ar); + } + + /** (De)serialize the obj from a TypedPointer */ + SHM_SERIALIZE_DESERIALIZE_WRAPPER((T)); +}; + +template +using mptr = manual_ptr; + +template +static mptr make_mptr(Args&& ...args) { + mptr ptr; + ptr.shm_init(std::forward(args)...); + return ptr; +} + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS + +namespace std { + +/** Hash function for ptr */ +template +struct hash> { + size_t operator()(const hermes_shm::ipc::manual_ptr &obj) const { + return std::hash{}(obj.get_ref_const()); + } +}; + +} // namespace std + +#endif // HERMES_SHM_DATA_STRUCTURES_PTR_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/string.h b/hermes_shm/include/hermes_shm/data_structures/string.h new file mode 100644 index 000000000..e5d968eb9 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/string.h @@ -0,0 +1,301 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_DATA_STRUCTURES_LOCKLESS_STRING_H_ +#define HERMES_SHM_DATA_STRUCTURES_LOCKLESS_STRING_H_ + +#include "data_structure.h" +#include + +namespace hermes_shm::ipc { + +/** forward declaration for string */ +class string; + +/** + * MACROS used to simplify the string namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ +#define CLASS_NAME string +#define TYPED_CLASS string +#define TYPED_HEADER ShmHeader + +/** string shared-memory header */ +template<> +struct ShmHeader : public ShmBaseHeader { + size_t length_; + AtomicPointer text_; + + /** Default constructor */ + ShmHeader() = default; + + /** Copy constructor */ + ShmHeader(const ShmHeader &other) { + strong_copy(other); + } + + /** Copy assignment operator */ + ShmHeader& operator=(const ShmHeader &other) { + if (this != &other) { + strong_copy(other); + } + return *this; + } + + /** Strong copy operation */ + void strong_copy(const ShmHeader &other) { + length_ = other.length_; + text_ = other.text_; + } + + /** Move constructor */ + ShmHeader(ShmHeader &&other) { + weak_move(other); + } + + /** Move operator */ + ShmHeader& operator=(ShmHeader &&other) { + if (this != &other) { + weak_move(other); + } + return *this; + } + + /** Move operation */ + void weak_move(ShmHeader &other) { + strong_copy(other); + } +}; + +/** + * A string of characters. + * */ +class string : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) + + public: + char *text_; + size_t length_; + + public: + //////////////////////////// + /// SHM Overrides + //////////////////////////// + + /** Default constructor */ + string() : length_(0) {} + + /** Default shm constructor */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header); + } + + /** Construct from a C-style string with allocator in shared memory */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, const char *text) { + size_t length = strlen(text); + shm_init_main(header, alloc, length); + _create_str(text, length); + } + + /** Construct for an std::string with allocator in shared-memory */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, const std::string &text) { + shm_init_main(header, alloc, text.size()); + _create_str(text.data(), text.size()); + } + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, string &other) { + shm_init_main(header, alloc); + header_->length_ = other.header_->length_; + header_->text_ = other.header_->text_; + shm_deserialize_main(); + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const string &other) { + shm_init_main(header, alloc, other.size()); + _create_str(other.data(), other.size()); + shm_deserialize_main(); + } + + /** Construct by concatenating two string in shared-memory */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, + const string &text1, const string &text2) { + size_t length = text1.size() + text2.size(); + shm_init_main(header, alloc, length); + memcpy(text_, + text1.data(), text1.size()); + memcpy(text_ + text1.size(), + text2.data(), text2.size()); + text_[length] = 0; + } + + /** + * Construct a string of specific length and allocator in shared memory + * */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, size_t length) { + shm_init_allocator(alloc); + shm_init_header(header); + text_ = alloc_->template + AllocatePtr( + length + 1, + header_->text_); + header_->length_ = length; + length_ = length; + text_[length] = 0; + } + + /** + * Destroy the shared-memory data. + * */ + void shm_destroy_main() { + if (length_) { + alloc_->Free(header_->text_); + length_ = 0; + } + } + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() { + text_ = alloc_->template + Convert(header_->text_); + length_ = header_->length_; + } + + //////////////////////////// + /// String Operations + //////////////////////////// + + /** Get character at index i in the string */ + char& operator[](size_t i) const { + return text_[i]; + } + + /** Convert into a std::string */ + std::string str() const { + return {text_, length_}; + } + + /** Add two strings together */ + string operator+(const std::string &other) { + string tmp(other); + return string(GetAllocator(), *this, tmp); + } + + /** Add two strings together */ + string operator+(const string &other) { + return string(GetAllocator(), *this, other); + } + + /** Get the size of the current string */ + size_t size() const { + return length_; + } + + /** Get a constant reference to the C-style string */ + char* c_str() const { + return text_; + } + + /** Get a constant reference to the C-style string */ + char* data() const { + return text_; + } + + /** Get a mutable reference to the C-style string */ + char* data_mutable() { + return text_; + } + + /** + * Comparison operators + * */ + + int _strncmp(const char *a, size_t len_a, + const char *b, size_t len_b) const { + if (len_a != len_b) { + return int((int64_t)len_a - (int64_t)len_b); + } + int sum = 0; + for (size_t i = 0; i < len_a; ++i) { + sum += a[i] - b[i]; + } + return sum; + } + +#define HERMES_SHM_STR_CMP_OPERATOR(op) \ + bool operator op(const char *other) const { \ + return _strncmp(data(), size(), other, strlen(other)) op 0; \ + } \ + bool operator op(const std::string &other) const { \ + return _strncmp(data(), size(), other.data(), other.size()) op 0; \ + } \ + bool operator op(const string &other) const { \ + return _strncmp(data(), size(), other.data(), other.size()) op 0; \ + } + + HERMES_SHM_STR_CMP_OPERATOR(==) + HERMES_SHM_STR_CMP_OPERATOR(!=) + HERMES_SHM_STR_CMP_OPERATOR(<) + HERMES_SHM_STR_CMP_OPERATOR(>) + HERMES_SHM_STR_CMP_OPERATOR(<=) + HERMES_SHM_STR_CMP_OPERATOR(>=) + +#undef HERMES_SHM_STR_CMP_OPERATOR + + private: + inline void _create_str(const char *text, size_t length) { + memcpy(text_, text, length); + text_[length] = 0; + } +}; + +/** Consider the string as an uniterpreted set of bytes */ +typedef string charbuf; + +} // namespace hermes_shm::ipc + +namespace std { + +/** Hash function for string */ +template<> +struct hash { + size_t operator()(const hermes_shm::ipc::string &text) const { + size_t sum = 0; + for (size_t i = 0; i < text.size(); ++i) { + auto shift = static_cast(i % sizeof(size_t)); + auto c = static_cast((unsigned char)text[i]); + sum = 31*sum + (c << shift); + } + return sum; + } +}; + +} // namespace std + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif // HERMES_SHM_DATA_STRUCTURES_LOCKLESS_STRING_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h new file mode 100644 index 000000000..e80ce4b3e --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h @@ -0,0 +1,517 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ +#define HERMES_SHM_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ + +#include "hermes_shm/data_structures/data_structure.h" +#include "hermes_shm/data_structures/internal/shm_archive_or_t.h" + +#include + +namespace hermes_shm::ipc { + +/** forward pointer for list */ +template +class list; + +/** represents an object within a list */ +template +struct list_entry { + public: + OffsetPointer next_ptr_, prior_ptr_; + ShmHeaderOrT data_; + + /** Constructor */ + template + explicit list_entry(Allocator *alloc, Args ...args) + : data_(alloc, std::forward(args)...) {} + + /** Destructor */ + void shm_destroy(Allocator *alloc) { + data_.shm_destroy(alloc); + } + + /** Returns the element stored in the list */ + ShmRef internal_ref(Allocator *alloc) { + return ShmRef(data_.internal_ref(alloc)); + } + + /** Returns the element stored in the list */ + ShmRef internal_ref(Allocator *alloc) const { + return ShmRef(data_.internal_ref(alloc)); + } +}; + +/** + * The list iterator + * */ +template +struct list_iterator_templ { + public: + /**< A shm reference to the containing list object. */ + hipc::ShmRef> list_; + /**< A pointer to the entry in shared memory */ + list_entry *entry_; + /**< The offset of the entry in the shared-memory allocator */ + OffsetPointer entry_ptr_; + + /** Default constructor */ + list_iterator_templ() = default; + + /** End iterator */ + explicit list_iterator_templ(bool) + : entry_(nullptr), entry_ptr_(OffsetPointer::GetNull()) {} + + /** Construct an iterator */ + explicit list_iterator_templ(TypedPointer> list) + : list_(list), entry_(nullptr), entry_ptr_(OffsetPointer::GetNull()) {} + + /** Construct an iterator */ + explicit list_iterator_templ(TypedPointer> list, + list_entry *entry, + OffsetPointer entry_ptr) + : list_(list), entry_(entry), entry_ptr_(entry_ptr) {} + + /** Copy constructor */ + list_iterator_templ(const list_iterator_templ &other) { + list_ = other.list_; + entry_ = other.entry_; + entry_ptr_ = other.entry_ptr_; + } + + /** Assign this iterator from another iterator */ + list_iterator_templ& operator=(const list_iterator_templ &other) { + if (this != &other) { + list_ = other.list_; + entry_ = other.entry_; + entry_ptr_ = other.entry_ptr_; + } + return *this; + } + + /** Get the object the iterator points to */ + ShmRef operator*() { + return entry_->internal_ref(list_->GetAllocator()); + } + + /** Get the object the iterator points to */ + const ShmRef operator*() const { + return entry_->internal_ref(); + } + + /** Get the next iterator (in place) */ + list_iterator_templ& operator++() { + if (is_end()) { return *this; } + entry_ptr_ = entry_->next_ptr_; + entry_ = list_->alloc_->template + Convert>(entry_->next_ptr_); + return *this; + } + + /** Get the prior iterator (in place) */ + list_iterator_templ& operator--() { + if (is_end() || is_begin()) { return *this; } + entry_ptr_ = entry_->prior_ptr_; + entry_ = list_->alloc_->template + Convert>(entry_->prior_ptr_); + return *this; + } + + /** Return the next iterator */ + list_iterator_templ operator++(int) const { + list_iterator_templ next_iter(*this); + ++next_iter; + return next_iter; + } + + /** Return the prior iterator */ + list_iterator_templ operator--(int) const { + list_iterator_templ prior_iter(*this); + --prior_iter; + return prior_iter; + } + + /** Return the iterator at count after this one */ + list_iterator_templ operator+(size_t count) const { + list_iterator_templ pos(*this); + for (size_t i = 0; i < count; ++i) { + ++pos; + } + return pos; + } + + /** Return the iterator at count before this one */ + list_iterator_templ operator-(size_t count) const { + list_iterator_templ pos(*this); + for (size_t i = 0; i < count; ++i) { + --pos; + } + return pos; + } + + /** Get the iterator at count after this one (in-place) */ + void operator+=(size_t count) { + list_iterator_templ pos = (*this) + count; + entry_ = pos.entry_; + entry_ptr_ = pos.entry_ptr_; + } + + /** Get the iterator at count before this one (in-place) */ + void operator-=(size_t count) { + list_iterator_templ pos = (*this) - count; + entry_ = pos.entry_; + entry_ptr_ = pos.entry_ptr_; + } + + /** Determine if two iterators are equal */ + friend bool operator==(const list_iterator_templ &a, + const list_iterator_templ &b) { + return (a.is_end() && b.is_end()) || (a.entry_ == b.entry_); + } + + /** Determine if two iterators are inequal */ + friend bool operator!=(const list_iterator_templ &a, + const list_iterator_templ &b) { + return !(a.is_end() && b.is_end()) && (a.entry_ != b.entry_); + } + + /** Create the end iterator */ + static list_iterator_templ const end() { + const static list_iterator_templ end_iter(true); + return end_iter; + } + + /** Determine whether this iterator is the end iterator */ + bool is_end() const { + return entry_ == nullptr; + } + + /** Determine whether this iterator is the begin iterator */ + bool is_begin() const { + if (entry_) { + return entry_->prior_ptr_.IsNull(); + } else { + return false; + } + } +}; + +/** forward iterator typedef */ +template +using list_iterator = list_iterator_templ; + +/** const forward iterator typedef */ +template +using list_citerator = list_iterator_templ; + + +/** + * MACROS used to simplify the list namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ +#define CLASS_NAME list +#define TYPED_CLASS list +#define TYPED_HEADER ShmHeader> + +/** + * The list shared-memory header + * */ +template +struct ShmHeader> : public ShmBaseHeader { + OffsetPointer head_ptr_, tail_ptr_; + size_t length_; + + /** Default constructor */ + ShmHeader() = default; + + /** Copy constructor */ + ShmHeader(const ShmHeader &other) { + strong_copy(other); + } + + /** Copy assignment operator */ + ShmHeader& operator=(const ShmHeader &other) { + if (this != &other) { + strong_copy(other); + } + return *this; + } + + /** Strong copy operation */ + void strong_copy(const ShmHeader &other) { + head_ptr_ = other.head_ptr_; + tail_ptr_ = other.tail_ptr_; + length_ = other.length_; + } + + /** Move constructor */ + ShmHeader(ShmHeader &&other) { + weak_move(other); + } + + /** Move operator */ + ShmHeader& operator=(ShmHeader &&other) { + if (this != &other) { + weak_move(other); + } + return *this; + } + + /** Move operation */ + void weak_move(ShmHeader &other) { + strong_copy(other); + } +}; + +/** + * Doubly linked list implementation + * */ +template +class list : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) + + public: + //////////////////////////// + /// SHM Overrides + //////////////////////////// + + /** Default constructor */ + list() = default; + + /** Initialize list in shared memory */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header); + header_->length_ = 0; + header_->head_ptr_.SetNull(); + header_->tail_ptr_.SetNull(); + } + + /** Copy from std::list */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, std::list &other) { + shm_init_allocator(alloc); + shm_init_header(header); + for (auto &entry : other) { + emplace_back(entry); + } + } + + /** Destroy all shared memory allocated by the list */ + void shm_destroy_main() { + clear(); + } + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, list &other) { + shm_init_allocator(alloc); + shm_init_header(header); + *header_ = *(other.header_); + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const list &other) { + shm_init_allocator(alloc); + shm_init_header(header); + for (auto iter = other.cbegin(); iter != other.cend(); ++iter) { + emplace_back(**iter); + } + } + + //////////////////////////// + /// List Methods + //////////////////////////// + + /** Construct an element at the back of the list */ + template + void emplace_back(Args&&... args) { + emplace(end(), std::forward(args)...); + } + + /** Construct an element at the beginning of the list */ + template + void emplace_front(Args&&... args) { + emplace(begin(), std::forward(args)...); + } + + /** Construct an element at \a pos position in the list */ + template + void emplace(list_iterator pos, Args&&... args) { + OffsetPointer entry_ptr; + auto entry = _create_entry(entry_ptr, std::forward(args)...); + if (size() == 0) { + entry->prior_ptr_.SetNull(); + entry->next_ptr_.SetNull(); + header_->head_ptr_ = entry_ptr; + header_->tail_ptr_ = entry_ptr; + } else if (pos.is_begin()) { + entry->prior_ptr_.SetNull(); + entry->next_ptr_ = header_->head_ptr_; + auto head = alloc_->template + Convert>(header_->tail_ptr_); + head->prior_ptr_ = entry_ptr; + header_->head_ptr_ = entry_ptr; + } else if (pos.is_end()) { + entry->prior_ptr_ = header_->tail_ptr_; + entry->next_ptr_.SetNull(); + auto tail = alloc_->template + Convert>(header_->tail_ptr_); + tail->next_ptr_ = entry_ptr; + header_->tail_ptr_ = entry_ptr; + } else { + auto next = alloc_->template + Convert>(pos.entry_->next_ptr_); + auto prior = alloc_->template + Convert>(pos.entry_->prior_ptr_); + entry->next_ptr_ = pos.entry_->next_ptr_; + entry->prior_ptr_ = pos.entry_->prior_ptr_; + next->prior_ptr_ = entry_ptr; + prior->next_ptr_ = entry_ptr; + } + ++header_->length_; + } + + /** Erase element with ID */ + void erase(const T &entry) { + auto iter = find(entry); + erase(iter); + } + + /** Erase the element at pos */ + void erase(list_iterator pos) { + erase(pos, pos+1); + } + + /** Erase all elements between first and last */ + void erase(list_iterator first, + list_iterator last) { + if (first.is_end()) { return; } + auto first_prior_ptr = first.entry_->prior_ptr_; + auto pos = first; + while (pos != last) { + auto next = pos + 1; + pos.entry_->shm_destroy(alloc_); + Allocator::DestructObj>(*pos.entry_); + alloc_->Free(pos.entry_ptr_); + --header_->length_; + pos = next; + } + + if (first_prior_ptr.IsNull()) { + header_->head_ptr_ = last.entry_ptr_; + } else { + auto first_prior = alloc_->template + Convert>(first_prior_ptr); + first_prior->next_ptr_ = last.entry_ptr_; + } + + if (last.entry_ptr_.IsNull()) { + header_->tail_ptr_ = first_prior_ptr; + } else { + last.entry_->prior_ptr_ = first_prior_ptr; + } + } + + /** Destroy all elements in the list */ + void clear() { + erase(begin(), end()); + } + + /** Get the object at the front of the list */ + ShmRef front() { + return *begin(); + } + + /** Get the object at the back of the list */ + ShmRef back() { + return *end(); + } + + /** Get the number of elements in the list */ + size_t size() const { + if (!IsNull()) { + return header_->length_; + } + return 0; + } + + /** Find an element in this list */ + list_iterator find(const T &entry) { + for (auto iter = begin(); iter != end(); ++iter) { + hipc::ShmRef ref = *iter; + if (*ref == entry) { + return iter; + } + } + return end(); + } + + /** + * ITERATORS + * */ + + /** Forward iterator begin */ + list_iterator begin() { + if (size() == 0) { return end(); } + auto head = alloc_->template + Convert>(header_->head_ptr_); + return list_iterator(GetShmPointer>>(), + head, header_->head_ptr_); + } + + /** Forward iterator end */ + static list_iterator const end() { + return list_iterator::end(); + } + + /** Constant forward iterator begin */ + list_citerator cbegin() const { + if (size() == 0) { return cend(); } + auto head = alloc_->template + Convert>(header_->head_ptr_); + return list_citerator(GetShmPointer>>(), + head, header_->head_ptr_); + } + + /** Constant forward iterator end */ + static list_citerator const cend() { + return list_citerator::end(); + } + + private: + template + list_entry* _create_entry(OffsetPointer &p, Args&& ...args) { + auto entry = alloc_->template + AllocateConstructObjs>( + 1, p, alloc_, std::forward(args)...); + return entry; + } +}; + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif // HERMES_SHM_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h new file mode 100644 index 000000000..80ee70487 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h @@ -0,0 +1,540 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_DATA_STRUCTURES_UNORDERED_MAP_H_ +#define HERMES_SHM_DATA_STRUCTURES_UNORDERED_MAP_H_ + +#include "hermes_shm/thread/thread_manager.h" +#include "hermes_shm/data_structures/thread_unsafe/vector.h" +#include "hermes_shm/data_structures/thread_unsafe/list.h" +#include "hermes_shm/data_structures/pair.h" +#include "hermes_shm/data_structures/data_structure.h" +#include "hermes_shm/types/atomic.h" + +namespace hermes_shm::ipc { + +/** forward pointer for unordered_map */ +template> +class unordered_map; + +/** + * The unordered map iterator (bucket_iter, list_iter) + * */ +template +struct unordered_map_iterator { + public: + using COLLISION_T = hipc::pair; + using BUCKET_T = hipc::list; + + public: + hipc::ShmRef> map_; + vector_iterator bucket_; + list_iterator collision_; + + /** Default constructor */ + unordered_map_iterator() = default; + + /** Construct the iterator */ + explicit unordered_map_iterator(TypedPointer> map) + : map_(map) {} + + /** Copy constructor */ + unordered_map_iterator(const unordered_map_iterator &other) { + shm_strong_copy(other); + } + + /** Assign one iterator into another */ + unordered_map_iterator& + operator=(const unordered_map_iterator &other) { + if (this != &other) { + shm_strong_copy(other); + } + return *this; + } + + /** Copy an iterator */ + void shm_strong_copy(const unordered_map_iterator &other) { + map_ = other.map_; + bucket_ = other.bucket_; + collision_ = other.collision_; + } + + /** Get the pointed object */ + hipc::ShmRef operator*() { + return *collision_; + } + + /** Get the pointed object */ + const hipc::ShmRef operator*() const { + return *collision_; + } + + /** Go to the next object */ + unordered_map_iterator& operator++() { + ++collision_; + make_correct(); + return *this; + } + + /** Return the next iterator */ + unordered_map_iterator operator++(int) const { + unordered_map_iterator next(*this); + ++next; + return next; + } + + /** + * Shifts bucket and collision iterator until there is a valid element. + * Returns true if such an element is found, and false otherwise. + * */ + bool make_correct() { + do { + if (bucket_.is_end()) { + return false; + } + BUCKET_T& bkt = (**bucket_); + list &collisions = bkt; + if (collision_ != collisions.end()) { + return true; + } else { + ++bucket_; + if (bucket_.is_end()) { + return false; + } + BUCKET_T& new_bkt = (**bucket_); + list &new_collisions = new_bkt; + collision_ = collisions.begin(); + } + } while (true); + } + + /** Check if two iterators are equal */ + friend bool operator==(const unordered_map_iterator &a, + const unordered_map_iterator &b) { + if (a.is_end() && b.is_end()) { + return true; + } + return (a.bucket_ == b.bucket_) && (a.collision_ == b.collision_); + } + + /** Check if two iterators are inequal */ + friend bool operator!=(const unordered_map_iterator &a, + const unordered_map_iterator &b) { + if (a.is_end() && b.is_end()) { + return false; + } + return (a.bucket_ != b.bucket_) || (a.collision_ != b.collision_); + } + + /** Determine whether this iterator is the end iterator */ + bool is_end() const { + return bucket_.is_end(); + } + + /** Set this iterator to the end iterator */ + void set_end() { + bucket_.set_end(); + } +}; + +/** + * MACROS to simplify the unordered_map namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ + +#define CLASS_NAME unordered_map +#define TYPED_CLASS unordered_map +#define TYPED_HEADER ShmHeader> + +/** + * The unordered_map shared-memory header + * */ +template +struct ShmHeader : public ShmBaseHeader { + public: + using COLLISION_T = hipc::pair; + using BUCKET_T = hipc::list; + + public: + ShmHeaderOrT> buckets_; + RealNumber max_capacity_; + RealNumber growth_; + hipc::atomic length_; + + /** Default constructor. */ + ShmHeader() = default; + + /** Constructor. Initialize header. */ + explicit ShmHeader(Allocator *alloc, + int num_buckets, + RealNumber max_capacity, + RealNumber growth) : buckets_(alloc, num_buckets) { + max_capacity_ = max_capacity; + growth_ = growth; + length_ = 0; + } + + /** Copy constructor */ + ShmHeader(const ShmHeader &other) = delete; + + /** Move constructor */ + ShmHeader(ShmHeader &&other) = delete; + + /** True move constructor. */ + explicit ShmHeader(Allocator *alloc, + ShmHeader &&other, Allocator *other_alloc) { + (*GetBuckets(alloc)) = std::move(*other.GetBuckets(other_alloc)); + max_capacity_ = other.max_capacity_; + growth_ = other.growth_; + length_ = other.length_.load();/**/ + } + + /** Get a reference to the buckets */ + hipc::ShmRef> GetBuckets(Allocator *alloc) { + return hipc::ShmRef>(buckets_.internal_ref(alloc)); + } +}; + +/** + * The unordered map implementation + * */ +template +class unordered_map : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) + friend unordered_map_iterator; + + public: + using COLLISION_T = hipc::pair; + using BUCKET_T = hipc::list; + + public: + //////////////////////////// + /// SHM Overrides + //////////////////////////// + + /** Default constructor */ + unordered_map() = default; + + /** + * Initialize unordered map + * + * @param alloc the shared-memory allocator + * @param num_buckets the number of buckets to create + * @param max_capacity the maximum number of elements before a growth is + * triggered + * @param growth the multiplier to grow the bucket vector size + * */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, + int num_buckets = 20, + RealNumber max_capacity = RealNumber(4,5), + RealNumber growth = RealNumber(5, 4)) { + shm_init_allocator(alloc); + shm_init_header(header, alloc_, num_buckets, max_capacity, growth); + } + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, unordered_map &other) { + shm_init_allocator(alloc); + shm_init_header(header, + alloc_, + std::move(*other.header_), + other.GetAllocator()); + } + + /** Copy constructor */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const unordered_map &other) { + auto num_buckets = other.get_num_buckets(); + auto max_capacity = other.header_->max_capacity_; + auto growth = other.header_->growth_; + shm_init_allocator(alloc); + shm_init_header(header, alloc_, num_buckets, max_capacity, growth); + for (auto entry : other) { + emplace_templ( + entry->GetKey(), entry->GetVal()); + } + } + + /** Destroy the unordered_map buckets */ + void shm_destroy_main() { + hipc::ShmRef> buckets = GetBuckets(); + buckets->shm_destroy(); + } + + //////////////////////////// + /// Map Operations + //////////////////////////// + + /** + * Construct an object directly in the map. Overrides the object if + * key already exists. + * + * @param key the key to future index the map + * @param args the arguments to construct the object + * @return None + * */ + template + bool emplace(const Key &key, Args&&... args) { + return emplace_templ(key, std::forward(args)...); + } + + /** + * Construct an object directly in the map. Does not modify the key + * if it already exists. + * + * @param key the key to future index the map + * @param args the arguments to construct the object + * @return None + * */ + template + bool try_emplace(const Key &key, Args&&... args) { + return emplace_templ(key, std::forward(args)...); + } + + /** + * Erase an object indexable by \a key key + * */ + void erase(const Key &key) { + if (header_ == nullptr) { shm_init(); } + // Get the bucket the key belongs to + hipc::ShmRef> buckets = GetBuckets(); + size_t bkt_id = Hash{}(key) % buckets->size(); + hipc::ShmRef bkt = (*buckets)[bkt_id]; + + // Find and remove key from collision list + list &collisions = *bkt; + auto iter = find_collision(key, collisions); + if (iter.is_end()) { + return; + } + collisions.erase(iter); + + // Decrement the size of the map + --header_->length_; + } + + /** + * Erase an object at the iterator + * */ + void erase(unordered_map_iterator &iter) { + if (iter == end()) return; + // Acquire the bucket lock for a write (modifying collisions) + hipc::ShmRef bkt = *iter.bucket_; + + // Erase the element from the collision list + list &collisions = bkt; + collisions.erase(iter.collision_); + + // Decrement the size of the map + --header_->length_; + } + + /** + * Erase the entire map + * */ + void clear() { + hipc::ShmRef> buckets = GetBuckets(); + size_t num_buckets = buckets->size(); + buckets->clear(); + buckets->resize(num_buckets); + header_->length_ = 0; + } + + /** + * Locate an entry in the unordered_map + * + * @return the object pointed by key + * @exception UNORDERED_MAP_CANT_FIND the key was not in the map + * */ + ShmRef operator[](const Key &key) { + auto iter = find(key); + if (iter != end()) { + return (*iter)->second_; + } + throw UNORDERED_MAP_CANT_FIND.format(); + } + + /** + * Find an object in the unordered_map + * */ + unordered_map_iterator find(const Key &key) { + unordered_map_iterator iter( + GetShmPointer>>()); + + // Determine the bucket corresponding to the key + hipc::ShmRef> buckets = GetBuckets(); + size_t bkt_id = Hash{}(key) % buckets->size(); + iter.bucket_ = buckets->begin() + bkt_id; + hipc::ShmRef bkt = (*iter.bucket_); + list &collisions = *bkt; + + // Get the specific collision iterator + iter.collision_ = find_collision(key, collisions); + if (iter.collision_.is_end()) { + iter.set_end(); + } + return iter; + } + + /** The number of entries in the map */ + size_t size() const { + if (header_ == nullptr) { + return 0; + } + return header_->length_.load(); + } + + /** The number of buckets in the map */ + size_t get_num_buckets() const { + hipc::ShmRef> buckets = GetBuckets(); + return buckets->size(); + } + + private: + /** + * Find a key in the collision list + * */ + list_iterator + find_collision(const Key &key, list &collisions) { + auto iter = collisions.begin(); + auto iter_end = collisions.end(); + for (; iter != iter_end; ++iter) { + COLLISION_T entry(alloc_, **iter); + if (entry.GetKey() == key) { + return iter; + } + } + return iter_end; + } + + /** + * Construct an object directly in the map + * + * @param key the key to future index the map + * @param args the arguments to construct the object + * @return None + * */ + template + bool emplace_templ(const Key &key, Args&&... args) { + COLLISION_T entry(alloc_, + PiecewiseConstruct(), + make_argpack(key), + make_argpack(std::forward(args)...)); + return insert_templ(entry); + } + + /** + * Insert a serialized (key, value) pair in the map + * + * @param growth whether or not to grow the unordered map on collision + * @param modify_existing whether or not to override an existing entry + * @param entry the (key,value) pair shared-memory serialized + * @return None + * */ + template + bool insert_templ(COLLISION_T &entry) { + if (header_ == nullptr) { shm_init(); } + Key &key = entry.GetKey(); + + // Hash the key to a bucket + hipc::ShmRef> buckets = GetBuckets(); + size_t bkt_id = Hash{}(key) % buckets->size(); + hipc::ShmRef bkt = (*buckets)[bkt_id]; + + // Insert into the map + list &collisions = *bkt; + auto has_key = find_collision(key, collisions); + if (has_key != collisions.end()) { + if constexpr(!modify_existing) { + return false; + } else { + collisions.erase(has_key); + collisions.emplace_back(std::move(entry)); + return true; + } + } + collisions.emplace_back(std::move(entry)); + + // Increment the size of the map + ++header_->length_; + return true; + } + + bool insert_simple(COLLISION_T &&entry, + vector &buckets) { + if (header_ == nullptr) { shm_init(); } + Key &key = entry.GetKey(); + size_t bkt_id = Hash{}(key) % buckets.size(); + hipc::ShmRef bkt = buckets[bkt_id]; + list& collisions = bkt; + collisions.emplace_back(std::move(entry)); + return true; + } + + + public: + //////////////////////////// + /// Iterators + //////////////////////////// + + /** Forward iterator begin */ + inline unordered_map_iterator begin() const { + unordered_map_iterator iter( + GetShmPointer>>()); + hipc::ShmRef> buckets(GetBuckets()); + if (buckets->size() == 0) { + return iter; + } + hipc::ShmRef bkt = (*buckets)[0]; + list &list = *bkt; + iter.bucket_ = buckets->cbegin(); + iter.collision_ = list.begin(); + iter.make_correct(); + return iter; + } + + /** Forward iterator end */ + inline unordered_map_iterator end() const { + unordered_map_iterator iter( + GetShmPointer>>()); + hipc::ShmRef> buckets(GetBuckets()); + iter.bucket_ = buckets->cend(); + return iter; + } + + /** Get the buckets */ + hipc::ShmRef> GetBuckets() { + return header_->GetBuckets(alloc_); + } + + /** Get the buckets (const) */ + hipc::ShmRef> GetBuckets() const { + return header_->GetBuckets(alloc_); + } +}; + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif // HERMES_SHM_DATA_STRUCTURES_UNORDERED_MAP_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h new file mode 100644 index 000000000..38996df27 --- /dev/null +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h @@ -0,0 +1,767 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ +#define HERMES_SHM_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ + +#include "hermes_shm/data_structures/data_structure.h" +#include "hermes_shm/data_structures/internal/shm_archive_or_t.h" + +#include + +namespace hermes_shm::ipc { + +/** forward pointer for vector */ +template +class vector; + +/** + * The vector iterator implementation + * */ +template +struct vector_iterator_templ { + public: + hipc::ShmRef> vec_; + off64_t i_; + + /** Default constructor */ + vector_iterator_templ() = default; + + /** Construct an iterator */ + inline explicit vector_iterator_templ(TypedPointer> vec) + : vec_(vec) {} + + /** Construct end iterator */ + inline explicit vector_iterator_templ(size_t i) + : i_(static_cast(i)) {} + + /** Construct an iterator at \a i offset */ + inline explicit vector_iterator_templ(TypedPointer> vec, size_t i) + : vec_(vec), i_(static_cast(i)) {} + + /** Construct an iterator at \a i offset */ + inline explicit vector_iterator_templ(const hipc::ShmRef> &vec, + size_t i) + : vec_(vec), i_(static_cast(i)) {} + + /** Copy constructor */ + inline vector_iterator_templ(const vector_iterator_templ &other) + : vec_(other.vec_), i_(other.i_) {} + + /** Copy assignment operator */ + inline vector_iterator_templ& + operator=(const vector_iterator_templ &other) { + if (this != &other) { + vec_ = other.vec_; + i_ = other.i_; + } + return *this; + } + + /** Move constructor */ + inline vector_iterator_templ(vector_iterator_templ &&other) { + vec_ = other.vec_; + i_ = other.i_; + } + + /** Move assignment operator */ + inline vector_iterator_templ& + operator=(vector_iterator_templ &&other) { + if (this != &other) { + vec_ = other.vec_; + i_ = other.i_; + } + return *this; + } + + /** Dereference the iterator */ + inline ShmRef operator*() { + return ShmRef(vec_->data_ar()[i_].internal_ref( + vec_->GetAllocator())); + } + + /** Dereference the iterator */ + inline const ShmRef operator*() const { + return ShmRef(vec_->data_ar_const()[i_].internal_ref( + vec_->GetAllocator())); + } + + /** Increment iterator in-place */ + inline vector_iterator_templ& operator++() { + if (is_end()) { return *this; } + if constexpr(FORWARD_ITER) { + ++i_; + if (i_ >= vec_->size()) { + set_end(); + } + } else { + if (i_ == 0) { + set_end(); + } else { + --i_; + } + } + return *this; + } + + /** Decrement iterator in-place */ + inline vector_iterator_templ& operator--() { + if (is_begin() || is_end()) { return *this; } + if constexpr(FORWARD_ITER) { + --i_; + } else { + ++i_; + } + return *this; + } + + /** Create the next iterator */ + inline vector_iterator_templ operator++(int) const { + vector_iterator_templ next_iter(*this); + ++next_iter; + return next_iter; + } + + /** Create the prior iterator */ + inline vector_iterator_templ operator--(int) const { + vector_iterator_templ prior_iter(*this); + --prior_iter; + return prior_iter; + } + + /** Increment iterator by \a count and return */ + inline vector_iterator_templ operator+(size_t count) const { + if (is_end()) { return end(); } + if constexpr(FORWARD_ITER) { + if (i_ + count > vec_->size()) { + return end(); + } + return vector_iterator_templ(vec_, i_ + count); + } else { + if (i_ < count - 1) { + return end(); + } + return vector_iterator_templ(vec_, i_ - count); + } + } + + /** Decrement iterator by \a count and return */ + inline vector_iterator_templ operator-(size_t count) const { + if (is_end()) { return end(); } + if constexpr(FORWARD_ITER) { + if (i_ < count) { + return begin(); + } + return vector_iterator_templ(vec_, i_ - count); + } else { + if (i_ + count > vec_->size() - 1) { + return begin(); + } + return vector_iterator_templ(vec_, i_ + count); + } + } + + /** Increment iterator by \a count in-place */ + inline void operator+=(size_t count) { + if (is_end()) { return end(); } + if constexpr(FORWARD_ITER) { + if (i_ + count > vec_->size()) { + set_end(); + return; + } + i_ += count; + return; + } else { + if (i_ < count - 1) { + set_end(); + return; + } + i_ -= count; + return; + } + } + + /** Decrement iterator by \a count in-place */ + inline void operator-=(size_t count) { + if (is_end()) { return end(); } + if constexpr(FORWARD_ITER) { + if (i_ < count) { + set_begin(); + return; + } + i_ -= count; + return; + } else { + if (i_ + count > vec_->size() - 1) { + set_begin(); + return; + } + i_ += count; + return; + } + } + + /** Check if two iterators are equal */ + inline friend bool operator==(const vector_iterator_templ &a, + const vector_iterator_templ &b) { + return (a.i_ == b.i_); + } + + /** Check if two iterators are inequal */ + inline friend bool operator!=(const vector_iterator_templ &a, + const vector_iterator_templ &b) { + return (a.i_ != b.i_); + } + + /** Create the begin iterator */ + inline vector_iterator_templ const begin() { + if constexpr(FORWARD_ITER) { + return vector_iterator_templ(vec_, 0); + } else { + return vector_iterator_templ(vec_, vec_->size() - 1); + } + } + + /** Create the end iterator */ + inline static vector_iterator_templ const end() { + static vector_iterator_templ end_iter(-1); + return end_iter; + } + + /** Set this iterator to end */ + inline void set_end() { + i_ = -1; + } + + /** Set this iterator to begin */ + inline void set_begin() { + if constexpr(FORWARD_ITER) { + if (vec_->size() > 0) { + i_ = 0; + } else { + set_end(); + } + } else { + i_ = vec_->size() - 1; + } + } + + /** Determine whether this iterator is the begin iterator */ + inline bool is_begin() const { + if constexpr(FORWARD_ITER) { + return (i_ == 0); + } else { + return (i_ == vec_->size() - 1); + } + } + + /** Determine whether this iterator is the end iterator */ + inline bool is_end() const { + return i_ < 0; + } +}; + +/** Forward iterator typedef */ +template +using vector_iterator = vector_iterator_templ; + +/** Backward iterator typedef */ +template +using vector_riterator = vector_iterator_templ; + +/** Constant forward iterator typedef */ +template +using vector_citerator = vector_iterator_templ; + +/** Backward iterator typedef */ +template +using vector_criterator = vector_iterator_templ; + +/** + * MACROS used to simplify the vector namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ +#define CLASS_NAME vector +#define TYPED_CLASS vector +#define TYPED_HEADER ShmHeader> + +/** + * The vector shared-memory header + * */ +template +struct ShmHeader : public ShmBaseHeader { + AtomicPointer vec_ptr_; + size_t max_length_, length_; + + /** Default constructor */ + ShmHeader() = default; + + /** Copy constructor */ + ShmHeader(const ShmHeader &other) { + strong_copy(other); + } + + /** Copy assignment operator */ + ShmHeader& operator=(const ShmHeader &other) { + if (this != &other) { + strong_copy(other); + } + return *this; + } + + /** Strong copy operation */ + void strong_copy(const ShmHeader &other) { + vec_ptr_ = other.vec_ptr_; + max_length_ = other.max_length_; + length_ = other.length_; + } + + /** Move constructor */ + ShmHeader(ShmHeader &&other) { + weak_move(other); + } + + /** Move operator */ + ShmHeader& operator=(ShmHeader &&other) { + if (this != &other) { + weak_move(other); + } + return *this; + } + + /** Move operation */ + void weak_move(ShmHeader &other) { + strong_copy(other); + } +}; + +/** + * The vector class + * */ +template +class vector : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS), (TYPED_HEADER)) + + public: + //////////////////////////// + /// SHM Overrides + //////////////////////////// + + /** Default constructor */ + vector() = default; + + /** Construct the vector in shared memory */ + template + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, size_t length, Args&& ...args) { + shm_init_allocator(alloc); + shm_init_header(header); + resize(length, std::forward(args)...); + } + + /** Construct the vector in shared memory */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header); + header_->length_ = 0; + header_->max_length_ = 0; + header_->vec_ptr_.SetNull(); + } + + /** Copy from std::vector */ + void shm_init_main(TYPED_HEADER *header, + Allocator *alloc, std::vector &other) { + shm_init_allocator(alloc); + shm_init_header(header); + reserve(other.size()); + for (auto &entry : other) { + emplace_back(entry); + } + } + + /** Destroy all shared memory allocated by the vector */ + void shm_destroy_main() { + erase(begin(), end()); + if (!header_->vec_ptr_.IsNull()) { + alloc_->Free(header_->vec_ptr_); + } + } + + /** Store into shared memory */ + void shm_serialize_main() const {} + + /** Load from shared memory */ + void shm_deserialize_main() {} + + /** Move constructor */ + void shm_weak_move_main(TYPED_HEADER *header, + Allocator *alloc, vector &other) { + shm_init_allocator(alloc); + shm_init_header(header); + *header_ = *(other.header_); + other.header_->length_ = 0; + } + + /** Copy a vector */ + void shm_strong_copy_main(TYPED_HEADER *header, + Allocator *alloc, const vector &other) { + shm_init_allocator(alloc); + shm_init_header(header); + reserve(other.size()); + for (auto iter = other.cbegin(); iter != other.cend(); ++iter) { + emplace_back((**iter)); + } + } + + //////////////////////////// + /// Vector Operations + //////////////////////////// + + /** + * Convert to std::vector + * */ + std::vector vec() { + std::vector v; + v.reserve(size()); + for (hipc::ShmRef entry : *this) { + v.emplace_back(*entry); + } + return v; + } + + /** + * Reserve space in the vector to emplace elements. Does not + * change the size of the list. + * + * @param length the maximum size the vector can get before a growth occurs + * @param args the arguments to construct + * */ + template + void reserve(size_t length, Args&& ...args) { + if (IsNull()) { shm_init(); } + if (length == 0) { return; } + grow_vector(data_ar(), length, false, std::forward(args)...); + } + + /** + * Reserve space in the vector to emplace elements. Changes the + * size of the list. + * + * @param length the maximum size the vector can get before a growth occurs + * @param args the arguments used to construct the vector elements + * */ + template + void resize(size_t length, Args&& ...args) { + if (IsNull()) { shm_init(); } + if (length == 0) { return; } + grow_vector(data_ar(), length, true, std::forward(args)...); + header_->length_ = length; + } + + /** Index the vector at position i */ + hipc::ShmRef operator[](const size_t i) { + ShmHeaderOrT *vec = data_ar(); + return hipc::ShmRef(vec[i].internal_ref(alloc_)); + } + + /** Get first element of vector */ + hipc::ShmRef front() { + return (*this)[0]; + } + + /** Get last element of vector */ + hipc::ShmRef back() { + return (*this)[size() - 1]; + } + + /** Index the vector at position i */ + const hipc::ShmRef operator[](const size_t i) const { + ShmHeaderOrT *vec = data_ar_const(); + return hipc::ShmRef(vec[i].internal_ref(alloc_)); + } + + /** Construct an element at the back of the vector */ + template + void emplace_back(Args&& ...args) { + ShmHeaderOrT *vec = data_ar(); + if (header_->length_ == header_->max_length_) { + vec = grow_vector(vec, 0, false); + } + Allocator::ConstructObj>( + *(vec + header_->length_), + alloc_, std::forward(args)...); + ++header_->length_; + } + + /** Construct an element in the front of the vector */ + template + void emplace_front(Args&& ...args) { + emplace(begin(), std::forward(args)...); + } + + /** Construct an element at an arbitrary position in the vector */ + template + void emplace(vector_iterator pos, Args&&... args) { + if (pos.is_end()) { + emplace_back(std::forward(args)...); + return; + } + ShmHeaderOrT *vec = data_ar(); + if (header_->length_ == header_->max_length_) { + vec = grow_vector(vec, 0, false); + } + shift_right(pos); + Allocator::ConstructObj>( + *(vec + pos.i_), + alloc_, std::forward(args)...); + ++header_->length_; + } + + /** Delete the element at \a pos position */ + void erase(vector_iterator pos) { + if (pos.is_end()) return; + shift_left(pos, 1); + header_->length_ -= 1; + } + + /** Delete elements between first and last */ + void erase(vector_iterator first, vector_iterator last) { + size_t last_i; + if (first.is_end()) return; + if (last.is_end()) { + last_i = size(); + } else { + last_i = last.i_; + } + size_t count = last_i - first.i_; + if (count == 0) return; + shift_left(first, count); + header_->length_ -= count; + } + + /** Delete all elements from the vector */ + void clear() { + erase(begin(), end()); + } + + /** Get the size of the vector */ + size_t size() const { + if (header_ == nullptr) { + return 0; + } + return header_->length_; + } + + /** Get the data in the vector */ + void* data() { + if (header_ == nullptr) { + return nullptr; + } + return alloc_->template + Convert(header_->vec_ptr_); + } + + /** Get constant pointer to the data */ + void* data_const() const { + if (header_ == nullptr) { + return nullptr; + } + return alloc_->template + Convert(header_->vec_ptr_); + } + + /** + * Retreives a pointer to the array from the process-independent pointer. + * */ + ShmHeaderOrT* data_ar() { + return alloc_->template + Convert>(header_->vec_ptr_); + } + + /** + * Retreives a pointer to the array from the process-independent pointer. + * */ + ShmHeaderOrT* data_ar_const() const { + return alloc_->template + Convert>(header_->vec_ptr_); + } + + private: + /** + * Grow a vector to a new size. + * + * @param vec the C-style array of elements to grow + * @param max_length the new length of the vector. If 0, the current size + * of the vector will be multiplied by a constant. + * @param args the arguments used to construct the elements of the vector + * */ + template + ShmHeaderOrT* grow_vector(ShmHeaderOrT *vec, size_t max_length, + bool resize, Args&& ...args) { + // Grow vector by 25% + if (max_length == 0) { + max_length = 5 * header_->max_length_ / 4; + if (max_length <= header_->max_length_ + 10) { + max_length += 10; + } + } + if (max_length < header_->max_length_) { + return nullptr; + } + + // Allocate new shared-memory vec + ShmHeaderOrT *new_vec; + if constexpr(std::is_pod() || IS_SHM_ARCHIVEABLE(T)) { + // Use reallocate for well-behaved objects + new_vec = alloc_->template + ReallocateObjs>(header_->vec_ptr_, max_length); + } else { + // Use std::move for unpredictable objects + Pointer new_p; + new_vec = alloc_->template + AllocateObjs>(max_length, new_p); + for (size_t i = 0; i < header_->length_; ++i) { + hipc::ShmRef old = (*this)[i]; + Allocator::ConstructObj>( + *(new_vec + i), + alloc_, std::move(*old)); + } + if (!header_->vec_ptr_.IsNull()) { + alloc_->Free(header_->vec_ptr_); + } + header_->vec_ptr_ = new_p; + } + if (new_vec == nullptr) { + throw OUT_OF_MEMORY.format("vector::emplace_back", + max_length*sizeof(ShmHeaderOrT)); + } + if (resize) { + for (size_t i = header_->length_; i < max_length; ++i) { + Allocator::ConstructObj>( + *(new_vec + i), + alloc_, std::forward(args)...); + } + } + + // Update vector header + header_->max_length_ = max_length; + + return new_vec; + } + + /** + * Shift every element starting at "pos" to the left by count. Any element + * who would be shifted before "pos" will be deleted. + * + * @param pos the starting position + * @param count the amount to shift left by + * */ + void shift_left(const vector_iterator pos, int count = 1) { + ShmHeaderOrT *vec = data_ar(); + for (int i = 0; i < count; ++i) { + auto &vec_i = *(vec + pos.i_ + i); + vec_i.shm_destroy(alloc_); + Allocator::DestructObj>(vec_i); + } + auto dst = vec + pos.i_; + auto src = dst + count; + for (auto i = pos.i_ + count; i < size(); ++i) { + memcpy(dst, src, sizeof(ShmHeaderOrT)); + dst += 1; src += 1; + } + } + + /** + * Shift every element starting at "pos" to the right by count. Increases + * the total number of elements of the vector by "count". Does not modify + * the size parameter of the vector, this is done elsewhere. + * + * @param pos the starting position + * @param count the amount to shift right by + * */ + void shift_right(const vector_iterator pos, int count = 1) { + auto src = data_ar() + size() - 1; + auto dst = src + count; + auto sz = static_cast(size()); + for (auto i = sz - 1; i >= pos.i_; --i) { + memcpy(dst, src, sizeof(ShmHeaderOrT)); + dst -= 1; src -= 1; + } + } + + //////////////////////////// + /// Iterators + //////////////////////////// + + public: + /** Beginning of the forward iterator */ + vector_iterator begin() { + if (size() == 0) { return end(); } + vector_iterator iter(GetShmPointer>>()); + iter.set_begin(); + return iter; + } + + /** End of the forward iterator */ + static vector_iterator const end() { + return vector_iterator::end(); + } + + /** Beginning of the constant forward iterator */ + vector_citerator cbegin() const { + if (size() == 0) { return cend(); } + vector_citerator iter(GetShmPointer>>()); + iter.set_begin(); + return iter; + } + + /** End of the forward iterator */ + static const vector_citerator cend() { + return vector_citerator::end(); + } + + /** Beginning of the reverse iterator */ + vector_riterator rbegin() { + if (size() == 0) { return rend(); } + vector_riterator iter(GetShmPointer>>()); + iter.set_begin(); + return iter; + } + + /** End of the reverse iterator */ + static vector_riterator const rend() { + return vector_riterator::end(); + } + + /** Beginning of the constant reverse iterator */ + vector_criterator crbegin() { + if (size() == 0) { return rend(); } + vector_criterator iter(GetShmPointer>>()); + iter.set_begin(); + return iter; + } + + /** End of the constant reverse iterator */ + static vector_criterator const crend() { + return vector_criterator::end(); + } +}; + +} // namespace hermes_shm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif // HERMES_SHM_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ diff --git a/hermes_shm/include/hermes_shm/introspect/system_info.h b/hermes_shm/include/hermes_shm/introspect/system_info.h new file mode 100644 index 000000000..6e1d86a14 --- /dev/null +++ b/hermes_shm/include/hermes_shm/introspect/system_info.h @@ -0,0 +1,39 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_SYSINFO_INFO_H_ +#define HERMES_SHM_SYSINFO_INFO_H_ + +#include +#include + +namespace hermes_shm { + +struct SystemInfo { + int pid_; + int ncpu_; + int page_size_; + size_t ram_size_; + + SystemInfo() { + pid_ = getpid(); + ncpu_ = get_nprocs_conf(); + page_size_ = getpagesize(); + struct sysinfo info; + sysinfo(&info); + ram_size_ = info.totalram; + } +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_SYSINFO_INFO_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/allocator.h new file mode 100644 index 000000000..8adb8de1b --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/allocator/allocator.h @@ -0,0 +1,496 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_H_ +#define HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_H_ + +#include +#include +#include + +namespace hermes_shm::ipc { + +/** + * The allocator type. + * Used to reconstruct allocator from shared memory + * */ +enum class AllocatorType { + kPageAllocator, + kMultiPageAllocator, + kStackAllocator, + kMallocAllocator, +}; + +/** + * The basic shared-memory allocator header. + * Allocators inherit from this. + * */ +struct AllocatorHeader { + int allocator_type_; + allocator_id_t allocator_id_; + size_t custom_header_size_; + + AllocatorHeader() = default; + + void Configure(allocator_id_t allocator_id, + AllocatorType type, + size_t custom_header_size) { + allocator_type_ = static_cast(type); + allocator_id_ = allocator_id; + custom_header_size_ = custom_header_size; + } +}; + +/** + * The allocator base class. + * */ +class Allocator { + protected: + MemoryBackend *backend_; + char *custom_header_; + + public: + /** + * Constructor + * */ + Allocator() : custom_header_(nullptr) {} + + /** + * Destructor + * */ + virtual ~Allocator() = default; + + /** + * Create the shared-memory allocator with \a id unique allocator id over + * the particular slot of a memory backend. + * + * The shm_init function is required, but cannot be marked virtual as + * each allocator has its own arguments to this method. Though each + * allocator must have "id" as its first argument. + * */ + // virtual void shm_init(MemoryBackend *backend, + // allocator_id_t id, Args ...args) = 0; + + /** + * Attach the allocator to the slot and backend passed in the constructor. + * */ + virtual void shm_deserialize(MemoryBackend *backend) = 0; + + /** + * Allocate a region of memory of \a size size + * */ + virtual OffsetPointer AllocateOffset(size_t size) = 0; + + /** + * Allocate a region of memory to a specific pointer type + * */ + template + POINTER_T Allocate(size_t size) { + return POINTER_T(GetId(), AllocateOffset(size).load()); + } + + /** + * Allocate a region of memory of \a size size + * and \a alignment alignment. Assumes that + * alignment is not 0. + * */ + virtual OffsetPointer AlignedAllocateOffset(size_t size, + size_t alignment) = 0; + + /** + * Allocate a region of memory to a specific pointer type + * */ + template + POINTER_T AlignedAllocate(size_t size, size_t alignment) { + return POINTER_T(GetId(), AlignedAllocateOffset(size, alignment).load()); + } + + /** + * Allocate a region of \a size size and \a alignment + * alignment. Will fall back to regular Allocate if + * alignmnet is 0. + * */ + template + inline POINTER_T Allocate(size_t size, size_t alignment) { + if (alignment == 0) { + return Allocate(size); + } else { + return AlignedAllocate(size, alignment); + } + } + + /** + * Reallocate \a pointer to \a new_size new size + * If p is kNullPointer, will internally call Allocate. + * + * @return true if p was modified. + * */ + template + inline bool Reallocate(POINTER_T &p, size_t new_size) { + if (p.IsNull()) { + p = Allocate(new_size); + return true; + } + auto new_p = ReallocateOffsetNoNullCheck(p.ToOffsetPointer(), + new_size); + bool ret = new_p == p.ToOffsetPointer(); + p.off_ = new_p.load(); + return ret; + } + + /** + * Reallocate \a pointer to \a new_size new size. + * Assumes that p is not kNullPointer. + * + * @return true if p was modified. + * */ + virtual OffsetPointer ReallocateOffsetNoNullCheck(OffsetPointer p, + size_t new_size) = 0; + + /** + * Free the memory pointed to by \a ptr Pointer + * */ + template + inline void FreePtr(T *ptr) { + if (ptr == nullptr) { + throw INVALID_FREE.format(); + } + FreeOffsetNoNullCheck(Convert(ptr)); + } + + /** + * Free the memory pointed to by \a p Pointer + * */ + template + inline void Free(POINTER_T &p) { + if (p.IsNull()) { + throw INVALID_FREE.format(); + } + FreeOffsetNoNullCheck(OffsetPointer(p.off_.load())); + } + + /** + * Free the memory pointed to by \a ptr Pointer + * */ + virtual void FreeOffsetNoNullCheck(OffsetPointer p) = 0; + + /** + * Get the allocator identifier + * */ + virtual allocator_id_t GetId() = 0; + + /** + * Get the amount of memory that was allocated, but not yet freed. + * Useful for memory leak checks. + * */ + virtual size_t GetCurrentlyAllocatedSize() = 0; + + + /////////////////////////////////////// + /////////// POINTER ALLOCATORS + /////////////////////////////////////// + + /** + * Allocate a pointer of \a size size and return \a p process-independent + * pointer and a process-specific pointer. + * */ + template + inline T* AllocatePtr(size_t size, POINTER_T &p, size_t alignment = 0) { + p = Allocate(size, alignment); + if (p.IsNull()) { return nullptr; } + return reinterpret_cast(backend_->data_ + p.off_.load()); + } + + /** + * Allocate a pointer of \a size size + * */ + template + inline T* AllocatePtr(size_t size, size_t alignment = 0) { + POINTER_T p; + return AllocatePtr(size, p, alignment); + } + + /** + * Allocate a pointer of \a size size + * */ + template + inline T* ClearAllocatePtr(size_t size, size_t alignment = 0) { + POINTER_T p; + return ClearAllocatePtr(size, p, alignment); + } + + /** + * Allocate a pointer of \a size size and return \a p process-independent + * pointer and a process-specific pointer. + * */ + template + inline T* ClearAllocatePtr(size_t size, POINTER_T &p, size_t alignment = 0) { + p = Allocate(size, alignment); + if (p.IsNull()) { return nullptr; } + auto ptr = reinterpret_cast(backend_->data_ + p.off_.load()); + if (ptr) { + memset(ptr, 0, size); + } + return ptr; + } + + /** + * Reallocate a pointer to a new size + * + * @param p process-independent pointer (input & output) + * @param new_size the new size to allocate + * @param modified whether or not p was modified (output) + * @return A process-specific pointer + * */ + template + inline T* ReallocatePtr(POINTER_T &p, size_t new_size, bool &modified) { + modified = Reallocate(p, new_size); + return Convert(p); + } + + /** + * Reallocate a pointer to a new size + * + * @param p process-independent pointer (input & output) + * @param new_size the new size to allocate + * @return A process-specific pointer + * */ + template + inline T* ReallocatePtr(POINTER_T &p, size_t new_size) { + Reallocate(p, new_size); + return Convert(p); + } + + /** + * Reallocate a pointer to a new size + * + * @param old_ptr process-specific pointer to reallocate + * @param new_size the new size to allocate + * @return A process-specific pointer + * */ + template + inline T* ReallocatePtr(T *old_ptr, size_t new_size) { + OffsetPointer p = Convert(old_ptr); + return ReallocatePtr(p, new_size); + } + + /////////////////////////////////////// + ///////////OBJECT ALLOCATORS + /////////////////////////////////////// + + /** + * Allocate an array of objects (but don't construct). + * + * @return A process-specific pointer + * */ + template + inline T* AllocateObjs(size_t count) { + POINTER_T p; + return AllocateObjs(count, p); + } + + /** + * Allocate an array of objects (but don't construct). + * + * @param count the number of objects to allocate + * @param p process-independent pointer (output) + * @return A process-specific pointer + * */ + template + inline T* AllocateObjs(size_t count, POINTER_T &p) { + return AllocatePtr(count * sizeof(T), p); + } + + /** + * Allocate an array of objects and memset to 0. + * + * @param count the number of objects to allocate + * @param p process-independent pointer (output) + * @return A process-specific pointer + * */ + template + inline T* ClearAllocateObjs(size_t count, POINTER_T &p) { + return ClearAllocatePtr(count * sizeof(T), p); + } + + /** + * Allocate and construct an array of objects + * + * @param count the number of objects to allocate + * @param p process-independent pointer (output) + * @param args parameters to construct object of type T + * @return A process-specific pointer + * */ + template< + typename T, + typename POINTER_T=Pointer, + typename ...Args> + inline T* AllocateConstructObjs(size_t count, POINTER_T &p, Args&& ...args) { + T *ptr = AllocateObjs(count, p); + ConstructObjs(ptr, 0, count, std::forward(args)...); + return ptr; + } + + /** + * Reallocate a pointer of objects to a new size. + * + * @param p process-independent pointer (input & output) + * @param old_count the original number of objects (avoids reconstruction) + * @param new_count the new number of objects + * + * @return A process-specific pointer + * */ + template + inline T* ReallocateObjs(POINTER_T &p, size_t new_count) { + T *ptr = ReallocatePtr(p, new_count*sizeof(T)); + return ptr; + } + + /** + * Reallocate a pointer of objects to a new size and construct the + * new elements in-place. + * + * @param p process-independent pointer (input & output) + * @param old_count the original number of objects (avoids reconstruction) + * @param new_count the new number of objects + * @param args parameters to construct object of type T + * + * @return A process-specific pointer + * */ + template< + typename T, + typename POINTER_T=Pointer, + typename ...Args> + inline T* ReallocateConstructObjs(POINTER_T &p, + size_t old_count, + size_t new_count, + Args&& ...args) { + T *ptr = ReallocatePtr(p, new_count*sizeof(T)); + ConstructObjs(ptr, old_count, new_count, std::forward(args)...); + return ptr; + } + + /** + * Construct each object in an array of objects. + * + * @param ptr the array of objects (potentially archived) + * @param old_count the original size of the ptr + * @param new_count the new size of the ptr + * @param args parameters to construct object of type T + * @return None + * */ + template< + typename T, + typename ...Args> + inline static void ConstructObjs(T *ptr, + size_t old_count, + size_t new_count, Args&& ...args) { + if (ptr == nullptr) { return; } + for (size_t i = old_count; i < new_count; ++i) { + ConstructObj(*(ptr + i), std::forward(args)...); + } + } + + /** + * Construct an object. + * + * @param ptr the object to construct (potentially archived) + * @param args parameters to construct object of type T + * @return None + * */ + template< + typename T, + typename ...Args> + inline static void ConstructObj(T &obj, Args&& ...args) { + new (&obj) T(std::forward(args)...); + } + + /** + * Destruct an array of objects + * + * @param ptr the object to destruct (potentially archived) + * @param count the length of the object array + * @return None + * */ + template + inline static void DestructObjs(T *ptr, size_t count) { + if (ptr == nullptr) { return; } + for (size_t i = 0; i < count; ++i) { + DestructObj((ptr + i)); + } + } + + /** + * Destruct an object + * + * @param ptr the object to destruct (potentially archived) + * @param count the length of the object array + * @return None + * */ + template + inline static void DestructObj(T &obj) { + obj.~T(); + } + + /** + * Get the custom header of the shared-memory allocator + * + * @return Custom header pointer + * */ + template + inline HEADER_T* GetCustomHeader() { + return reinterpret_cast(custom_header_); + } + + /** + * Convert a process-independent pointer into a process-specific pointer + * + * @param p process-independent pointer + * @return a process-specific pointer + * */ + template + inline T* Convert(const POINTER_T &p) { + if (p.IsNull()) { return nullptr; } + return reinterpret_cast(backend_->data_ + p.off_.load()); + } + + /** + * Convert a process-specific pointer into a process-independent pointer + * + * @param ptr process-specific pointer + * @return a process-independent pointer + * */ + template + inline POINTER_T Convert(T *ptr) { + if (ptr == nullptr) { return POINTER_T::GetNull(); } + return POINTER_T(GetId(), + reinterpret_cast(ptr) - + reinterpret_cast(backend_->data_)); + } + + /** + * Determine whether or not this allocator contains a process-specific + * pointer + * + * @param ptr process-specific pointer + * @return True or false + * */ + template + inline bool ContainsPtr(T *ptr) { + return reinterpret_cast(ptr) >= + reinterpret_cast(backend_->data_); + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h b/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h new file mode 100644 index 000000000..9a4e66927 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h @@ -0,0 +1,79 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ +#define HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ + +#include "allocator.h" +#include "stack_allocator.h" +#include "malloc_allocator.h" + +namespace hermes_shm::ipc { + +class AllocatorFactory { + public: + /** + * Create a new memory allocator + * */ + template + static std::unique_ptr shm_init(MemoryBackend *backend, + allocator_id_t alloc_id, + size_t custom_header_size, + Args&& ...args) { + if constexpr(std::is_same_v) { + // StackAllocator + auto alloc = std::make_unique(); + alloc->shm_init(backend, + alloc_id, + custom_header_size, + std::forward(args)...); + return alloc; + } else if constexpr(std::is_same_v) { + // Malloc Allocator + auto alloc = std::make_unique(); + alloc->shm_init(backend, + alloc_id, + custom_header_size, + std::forward(args)...); + return alloc; + } else { + // Default + throw std::logic_error("Not a valid allocator"); + } + } + + /** + * Deserialize the allocator managing this backend. + * */ + static std::unique_ptr shm_deserialize(MemoryBackend *backend) { + auto header_ = reinterpret_cast(backend->data_); + switch (static_cast(header_->allocator_type_)) { + // Stack Allocator + case AllocatorType::kStackAllocator: { + auto alloc = std::make_unique(); + alloc->shm_deserialize(backend); + return alloc; + } + // Malloc Allocator + case AllocatorType::kMallocAllocator: { + auto alloc = std::make_unique(); + alloc->shm_deserialize(backend); + return alloc; + } + default: return nullptr; + } + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h new file mode 100644 index 000000000..1413025a2 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h @@ -0,0 +1,98 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ +#define HERMES_SHM_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ + +#include "allocator.h" +#include "hermes_shm/thread/lock.h" + +namespace hermes_shm::ipc { + +struct MallocAllocatorHeader : public AllocatorHeader { + std::atomic total_alloc_size_; + + MallocAllocatorHeader() = default; + + void Configure(allocator_id_t alloc_id, + size_t custom_header_size) { + AllocatorHeader::Configure(alloc_id, AllocatorType::kStackAllocator, + custom_header_size); + total_alloc_size_ = 0; + } +}; + +class MallocAllocator : public Allocator { + private: + MallocAllocatorHeader *header_; + + public: + /** + * Allocator constructor + * */ + MallocAllocator() + : header_(nullptr) {} + + /** + * Get the ID of this allocator from shared memory + * */ + allocator_id_t GetId() override { + return header_->allocator_id_; + } + + /** + * Initialize the allocator in shared memory + * */ + void shm_init(MemoryBackend *backend, + allocator_id_t id, + size_t custom_header_size); + + /** + * Attach an existing allocator from shared memory + * */ + void shm_deserialize(MemoryBackend *backend) override; + + /** + * Allocate a memory of \a size size. The page allocator cannot allocate + * memory larger than the page size. + * */ + OffsetPointer AllocateOffset(size_t size) override; + + /** + * Allocate a memory of \a size size, which is aligned to \a + * alignment. + * */ + OffsetPointer AlignedAllocateOffset(size_t size, size_t alignment) override; + + /** + * Reallocate \a p pointer to \a new_size new size. + * + * @return whether or not the pointer p was changed + * */ + OffsetPointer ReallocateOffsetNoNullCheck(OffsetPointer p, + size_t new_size) override; + + /** + * Free \a ptr pointer. Null check is performed elsewhere. + * */ + void FreeOffsetNoNullCheck(OffsetPointer p) override; + + /** + * Get the current amount of data allocated. Can be used for leak + * checking. + * */ + size_t GetCurrentlyAllocatedSize() override; +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h b/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h new file mode 100644 index 000000000..eed6f96c0 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h @@ -0,0 +1,39 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MP_PAGE_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MP_PAGE_H_ + +namespace hermes_shm::ipc { + +struct MpPage { + int flags_; /**< Page flags (e.g., is_allocated?) */ + size_t page_size_; /**< The size of the page allocated */ + uint32_t off_; /**< The offset within the page */ + uint32_t page_idx_; /**< The id of the page in the mp free list */ + + void SetAllocated() { + flags_ = 0x1; + } + + void UnsetAllocated() { + flags_ = 0; + } + + bool IsAllocated() const { + return flags_ & 0x1; + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MP_PAGE_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h new file mode 100644 index 000000000..2f4717623 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h @@ -0,0 +1,104 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ +#define HERMES_SHM_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ + +#include "allocator.h" +#include "hermes_shm/thread/lock.h" + +namespace hermes_shm::ipc { + +struct StackAllocatorHeader : public AllocatorHeader { + std::atomic region_off_; + std::atomic region_size_; + std::atomic total_alloc_; + + StackAllocatorHeader() = default; + + void Configure(allocator_id_t alloc_id, + size_t custom_header_size, + size_t region_off, + size_t region_size) { + AllocatorHeader::Configure(alloc_id, AllocatorType::kStackAllocator, + custom_header_size); + region_off_ = region_off; + region_size_ = region_size; + total_alloc_ = 0; + } +}; + +class StackAllocator : public Allocator { + private: + StackAllocatorHeader *header_; + + public: + /** + * Allocator constructor + * */ + StackAllocator() + : header_(nullptr) {} + + /** + * Get the ID of this allocator from shared memory + * */ + allocator_id_t GetId() override { + return header_->allocator_id_; + } + + /** + * Initialize the allocator in shared memory + * */ + void shm_init(MemoryBackend *backend, + allocator_id_t id, + size_t custom_header_size); + + /** + * Attach an existing allocator from shared memory + * */ + void shm_deserialize(MemoryBackend *backend) override; + + /** + * Allocate a memory of \a size size. The page allocator cannot allocate + * memory larger than the page size. + * */ + OffsetPointer AllocateOffset(size_t size) override; + + /** + * Allocate a memory of \a size size, which is aligned to \a + * alignment. + * */ + OffsetPointer AlignedAllocateOffset(size_t size, size_t alignment) override; + + /** + * Reallocate \a p pointer to \a new_size new size. + * + * @return whether or not the pointer p was changed + * */ + OffsetPointer ReallocateOffsetNoNullCheck( + OffsetPointer p, size_t new_size) override; + + /** + * Free \a ptr pointer. Null check is performed elsewhere. + * */ + void FreeOffsetNoNullCheck(OffsetPointer p) override; + + /** + * Get the current amount of data allocated. Can be used for leak + * checking. + * */ + size_t GetCurrentlyAllocatedSize() override; +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/array_backend.h b/hermes_shm/include/hermes_shm/memory/backend/array_backend.h new file mode 100644 index 000000000..3e14b9831 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/backend/array_backend.h @@ -0,0 +1,65 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_ARRAY_BACKEND_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_ARRAY_BACKEND_H_ + +#include "memory_backend.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace hermes_shm::ipc { + +class ArrayBackend : public MemoryBackend { + public: + ArrayBackend() = default; + + ~ArrayBackend() override {} + + bool shm_init(size_t size, char *region) { + if (size < sizeof(MemoryBackendHeader)) { + throw SHMEM_CREATE_FAILED.format(); + } + SetInitialized(); + Own(); + header_ = reinterpret_cast(region); + header_->data_size_ = size - sizeof(MemoryBackendHeader); + data_size_ = header_->data_size_; + data_ = region + sizeof(MemoryBackendHeader); + return true; + } + + bool shm_deserialize(std::string url) override { + (void) url; + throw SHMEM_NOT_SUPPORTED.format(); + } + + void shm_detach() override {} + + void shm_destroy() override {} +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_ARRAY_BACKEND_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h b/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h new file mode 100644 index 000000000..b96f59872 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h @@ -0,0 +1,90 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_MEMORY_H +#define HERMES_SHM_MEMORY_H + +#include +#include +#include +#include +#include "hermes_shm/constants/macros.h" +#include + +namespace hermes_shm::ipc { + +struct MemoryBackendHeader { + size_t data_size_; +}; + +enum class MemoryBackendType { + kPosixShmMmap, + kNullBackend, + kArrayBackend, + kPosixMmap, +}; + +#define MEMORY_BACKEND_INITIALIZED 0x1 +#define MEMORY_BACKEND_OWNED 0x2 + +class MemoryBackend { + public: + MemoryBackendHeader *header_; + char *data_; + size_t data_size_; + bitfield32_t flags_; + + public: + MemoryBackend() = default; + + virtual ~MemoryBackend() = default; + + /** Mark data as valid */ + void SetInitialized() { + flags_.SetBits(MEMORY_BACKEND_INITIALIZED); + } + + /** Check if data is valid */ + bool IsInitialized() { + return flags_.OrBits(MEMORY_BACKEND_INITIALIZED); + } + + /** Mark data as invalid */ + void UnsetInitialized() { + flags_.UnsetBits(MEMORY_BACKEND_INITIALIZED); + } + + /** This is the process which destroys the backend */ + void Own() { + flags_.SetBits(MEMORY_BACKEND_OWNED); + } + + /** This is owned */ + bool IsOwned() { + return flags_.OrBits(MEMORY_BACKEND_OWNED); + } + + /** This is not the process which destroys the backend */ + void Disown() { + flags_.UnsetBits(MEMORY_BACKEND_OWNED); + } + + /// Each allocator must define its own shm_init. + // virtual bool shm_init(size_t size, ...) = 0; + virtual bool shm_deserialize(std::string url) = 0; + virtual void shm_detach() = 0; + virtual void shm_destroy() = 0; +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_H diff --git a/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h b/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h new file mode 100644 index 000000000..0332502c1 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h @@ -0,0 +1,103 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ +#define HERMES_SHM_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ + +#include "memory_backend.h" +#include "posix_mmap.h" +#include "posix_shm_mmap.h" +#include "null_backend.h" +#include "array_backend.h" + +namespace hermes_shm::ipc { + +class MemoryBackendFactory { + public: + /** Initialize a new backend */ + template + static std::unique_ptr shm_init( + size_t size, const std::string &url, Args ...args) { + if constexpr(std::is_same_v) { + // PosixShmMmap + auto backend = std::make_unique(); + backend->shm_init(size, url, std::forward(args)...); + return backend; + } else if constexpr(std::is_same_v) { + // PosixMmap + auto backend = std::make_unique(); + backend->shm_init(size, url, std::forward(args)...); + return backend; + } else if constexpr(std::is_same_v) { + // NullBackend + auto backend = std::make_unique(); + backend->shm_init(size, url, std::forward(args)...); + return backend; + } else if constexpr(std::is_same_v) { + // ArrayBackend + auto backend = std::make_unique(); + backend->shm_init(size, url, std::forward(args)...); + return backend; + } else { + throw MEMORY_BACKEND_NOT_FOUND.format(); + } + } + + /** Deserialize an existing backend */ + static std::unique_ptr shm_deserialize( + MemoryBackendType type, const std::string &url) { + switch (type) { + // PosixShmMmap + case MemoryBackendType::kPosixShmMmap: { + auto backend = std::make_unique(); + if (!backend->shm_deserialize(url)) { + throw MEMORY_BACKEND_NOT_FOUND.format(); + } + return backend; + } + + // PosixMmap + case MemoryBackendType::kPosixMmap: { + auto backend = std::make_unique(); + if (!backend->shm_deserialize(url)) { + throw MEMORY_BACKEND_NOT_FOUND.format(); + } + return backend; + } + + // NullBackend + case MemoryBackendType::kNullBackend: { + auto backend = std::make_unique(); + if (!backend->shm_deserialize(url)) { + throw MEMORY_BACKEND_NOT_FOUND.format(); + } + return backend; + } + + // ArrayBackend + case MemoryBackendType::kArrayBackend: { + auto backend = std::make_unique(); + if (!backend->shm_deserialize(url)) { + throw MEMORY_BACKEND_NOT_FOUND.format(); + } + return backend; + } + + // Default + default: return nullptr; + } + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/null_backend.h b/hermes_shm/include/hermes_shm/memory/backend/null_backend.h new file mode 100644 index 000000000..33b17329c --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/backend/null_backend.h @@ -0,0 +1,81 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_NULL_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_NULL_H_ + +#include "memory_backend.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace hermes_shm::ipc { + +class NullBackend : public MemoryBackend { + private: + size_t total_size_; + + public: + NullBackend() = default; + + ~NullBackend() override {} + + bool shm_init(size_t size, const std::string &url) { + (void) url; + SetInitialized(); + Own(); + total_size_ = sizeof(MemoryBackendHeader) + size; + char *ptr = (char*)malloc(sizeof(MemoryBackendHeader)); + header_ = reinterpret_cast(ptr); + header_->data_size_ = size; + data_size_ = size; + data_ = nullptr; + return true; + } + + bool shm_deserialize(std::string url) override { + (void) url; + throw SHMEM_NOT_SUPPORTED.format(); + } + + void shm_detach() override { + _Detach(); + } + + void shm_destroy() override { + _Destroy(); + } + + protected: + void _Detach() { + free(header_); + } + + void _Destroy() { + free(header_); + } +}; + +} // namespace hermes_shm::ipc + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_NULL_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h b/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h new file mode 100644 index 000000000..6840cdbc4 --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h @@ -0,0 +1,111 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H +#define HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H + +#include "memory_backend.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace hermes_shm::ipc { + +class PosixMmap : public MemoryBackend { + private: + size_t total_size_; + + public: + /** Constructor */ + PosixMmap() = default; + + /** Destructor */ + ~PosixMmap() override { + if (IsOwned()) { + _Destroy(); + } else { + _Detach(); + } + } + + /** Initialize backend */ + bool shm_init(size_t size) { + SetInitialized(); + Own(); + total_size_ = sizeof(MemoryBackendHeader) + size; + char *ptr = _Map(total_size_); + header_ = reinterpret_cast(ptr); + header_->data_size_ = size; + data_size_ = size; + data_ = reinterpret_cast(header_ + 1); + return true; + } + + /** Deserialize the backend */ + bool shm_deserialize(std::string url) override { + (void) url; + throw SHMEM_NOT_SUPPORTED.format(); + } + + /** Detach the mapped memory */ + void shm_detach() override { + _Detach(); + } + + /** Destroy the mapped memory */ + void shm_destroy() override { + _Destroy(); + } + + protected: + /** Map shared memory */ + template + T* _Map(size_t size) { + T *ptr = reinterpret_cast( + mmap64(nullptr, NextPageSizeMultiple(size), PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); + if (ptr == MAP_FAILED) { + perror("map failed"); + throw SHMEM_CREATE_FAILED.format(); + } + return ptr; + } + + /** Unmap shared memory */ + void _Detach() { + if (!IsInitialized()) { return; } + munmap(reinterpret_cast(header_), total_size_); + UnsetInitialized(); + } + + /** Destroy shared memory */ + void _Destroy() { + if (!IsInitialized()) { return; } + _Detach(); + UnsetInitialized(); + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H diff --git a/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h b/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h new file mode 100644 index 000000000..43f16e10c --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h @@ -0,0 +1,136 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H +#define HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H + +#include "memory_backend.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace hermes_shm::ipc { + +class PosixShmMmap : public MemoryBackend { + private: + std::string url_; + int fd_; + + public: + /** Constructor */ + PosixShmMmap() : fd_(-1) {} + + /** Destructor */ + ~PosixShmMmap() override { + if (IsOwned()) { + _Destroy(); + } else { + _Detach(); + } + } + + /** Initialize backend */ + bool shm_init(size_t size, std::string url) { + SetInitialized(); + Own(); + url_ = std::move(url); + shm_unlink(url_.c_str()); + fd_ = shm_open(url_.c_str(), O_CREAT | O_RDWR, 0666); + if (fd_ < 0) { + return false; + } + _Reserve(size); + header_ = _Map(HERMES_SHM_SYSTEM_INFO->page_size_, 0); + header_->data_size_ = size; + data_size_ = size; + data_ = _Map(size, HERMES_SHM_SYSTEM_INFO->page_size_); + return true; + } + + /** Deserialize the backend */ + bool shm_deserialize(std::string url) override { + SetInitialized(); + Disown(); + url_ = std::move(url); + fd_ = shm_open(url_.c_str(), O_RDWR, 0666); + if (fd_ < 0) { + return false; + } + header_ = _Map(HERMES_SHM_SYSTEM_INFO->page_size_, 0); + data_size_ = header_->data_size_; + data_ = _Map(data_size_, HERMES_SHM_SYSTEM_INFO->page_size_); + return true; + } + + /** Detach the mapped memory */ + void shm_detach() override { + _Detach(); + } + + /** Destroy the mapped memory */ + void shm_destroy() override { + _Destroy(); + } + + protected: + /** Reserve shared memory */ + void _Reserve(size_t size) { + int ret = ftruncate64(fd_, static_cast(size)); + if (ret < 0) { + throw SHMEM_RESERVE_FAILED.format(); + } + } + + /** Map shared memory */ + template + T* _Map(size_t size, off64_t off) { + T *ptr = reinterpret_cast( + mmap64(nullptr, size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd_, off)); + if (ptr == MAP_FAILED) { + throw SHMEM_CREATE_FAILED.format(); + } + return ptr; + } + + /** Unmap shared memory */ + void _Detach() { + if (!IsInitialized()) { return; } + munmap(data_, data_size_); + munmap(header_, HERMES_SHM_SYSTEM_INFO->page_size_); + close(fd_); + UnsetInitialized(); + } + + /** Destroy shared memory */ + void _Destroy() { + if (!IsInitialized()) { return; } + _Detach(); + shm_unlink(url_.c_str()); + UnsetInitialized(); + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H diff --git a/hermes_shm/include/hermes_shm/memory/memory.h b/hermes_shm/include/hermes_shm/memory/memory.h new file mode 100644 index 000000000..35e6ba87d --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/memory.h @@ -0,0 +1,383 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_MEMORY_MEMORY_H_ +#define HERMES_SHM_MEMORY_MEMORY_H_ + +#include +#include +#include +#include +#include + +namespace hermes_shm::ipc { + +/** + * The identifier for an allocator + * */ +union allocator_id_t { + struct { + uint32_t major_; // Typically some sort of process id + uint32_t minor_; // Typically a process-local id + } bits_; + uint64_t int_; + + /** + * Null allocator ID is -1 (for now) + * */ + allocator_id_t() : int_(0) {} + + /** + * Constructor which sets major & minor + * */ + explicit allocator_id_t(uint32_t major, uint32_t minor) { + bits_.major_ = major; + bits_.minor_ = minor; + } + + /** + * Set this allocator to null + * */ + void SetNull() { + int_ = 0; + } + + /** + * Check if this is the null allocator + * */ + bool IsNull() const { return int_ == 0; } + + /** Equality check */ + bool operator==(const allocator_id_t &other) const { + return other.int_ == int_; + } + + /** Inequality check */ + bool operator!=(const allocator_id_t &other) const { + return other.int_ != int_; + } + + /** Get the null allocator */ + static allocator_id_t GetNull() { + static allocator_id_t alloc(0, 0); + return alloc; + } +}; + +typedef uint32_t slot_id_t; // Uniquely ids a MemoryBackend slot + +/** + * Stores an offset into a memory region. Assumes the developer knows + * which allocator the pointer comes from. + * */ +template +struct OffsetPointerBase { + typedef typename std::conditional, nonatomic>::type atomic_t; + atomic_t off_; /**< Offset within the allocator's slot */ + + /** Default constructor */ + OffsetPointerBase() = default; + + /** Full constructor */ + explicit OffsetPointerBase(size_t off) : off_(off) {} + + /** Full constructor */ + explicit OffsetPointerBase(atomic_t off) : off_(off.load()) {} + + /** Pointer constructor */ + explicit OffsetPointerBase(allocator_id_t alloc_id, size_t off) : off_(off) { + (void) alloc_id; + } + + /** Copy constructor */ + OffsetPointerBase(const OffsetPointerBase &other) + : off_(other.off_.load()) {} + + /** Other copy constructor */ + OffsetPointerBase(const OffsetPointerBase &other) + : off_(other.off_.load()) {} + + /** Move constructor */ + OffsetPointerBase(OffsetPointerBase &&other) noexcept + : off_(other.off_.load()) { + other.SetNull(); + } + + /** Get the offset pointer */ + OffsetPointerBase ToOffsetPointer() { + return OffsetPointerBase(off_.load()); + } + + /** Set to null */ + void SetNull() { + off_ = -1; + } + + /** Check if null */ + bool IsNull() const { + return off_ == -1; + } + + /** Get the null pointer */ + static OffsetPointerBase GetNull() { + const static OffsetPointerBase p(-1); + return p; + } + + /** Atomic load wrapper */ + inline size_t load( + std::memory_order order = std::memory_order_seq_cst) const { + return off_.load(order); + } + + /** Atomic exchange wrapper */ + inline void exchange( + size_t count, std::memory_order order = std::memory_order_seq_cst) { + off_.exchange(count, order); + } + + /** Atomic compare exchange weak wrapper */ + inline bool compare_exchange_weak(size_t& expected, size_t desired, + std::memory_order order = + std::memory_order_seq_cst) { + return off_.compare_exchange_weak(expected, desired, order); + } + + /** Atomic compare exchange strong wrapper */ + inline bool compare_exchange_strong(size_t& expected, size_t desired, + std::memory_order order = + std::memory_order_seq_cst) { + return off_.compare_exchange_weak(expected, desired, order); + } + + /** Atomic add operator */ + inline OffsetPointerBase operator+(size_t count) const { + return OffsetPointerBase(off_ + count); + } + + /** Atomic subtract operator */ + inline OffsetPointerBase operator-(size_t count) const { + return OffsetPointerBase(off_ - count); + } + + /** Atomic add assign operator */ + inline OffsetPointerBase& operator+=(size_t count) { + off_ += count; + return *this; + } + + /** Atomic subtract assign operator */ + inline OffsetPointerBase& operator-=(size_t count) { + off_ -= count; + return *this; + } + + /** Atomic assign operator */ + inline OffsetPointerBase& operator=(size_t count) { + off_ = count; + return *this; + } + + /** Atomic copy assign operator */ + inline OffsetPointerBase& operator=(const OffsetPointerBase &count) { + off_ = count.load(); + return *this; + } + + /** Equality check */ + bool operator==(const OffsetPointerBase &other) const { + return off_ == other.off_; + } + + /** Inequality check */ + bool operator!=(const OffsetPointerBase &other) const { + return off_ != other.off_; + } +}; + +/** Non-atomic offset */ +typedef OffsetPointerBase OffsetPointer; + +/** Atomic offset */ +typedef OffsetPointerBase AtomicOffsetPointer; + +/** Typed offset pointer */ +template +using TypedOffsetPointer = OffsetPointer; + +/** Typed atomic pointer */ +template +using TypedAtomicOffsetPointer = AtomicOffsetPointer; + +/** + * A process-independent pointer, which stores both the allocator's + * information and the offset within the allocator's region + * */ +template +struct PointerBase { + allocator_id_t allocator_id_; /// Allocator the pointer comes from + OffsetPointerBase off_; /// Offset within the allocator's slot + + /** Default constructor */ + PointerBase() = default; + + /** Full constructor */ + explicit PointerBase(allocator_id_t id, size_t off) : + allocator_id_(id), off_(off) {} + + /** Full constructor using offset pointer */ + explicit PointerBase(allocator_id_t id, OffsetPointer off) : + allocator_id_(id), off_(off) {} + + /** Copy constructor */ + PointerBase(const PointerBase &other) + : allocator_id_(other.allocator_id_), off_(other.off_) {} + + /** Other copy constructor */ + PointerBase(const PointerBase &other) + : allocator_id_(other.allocator_id_), off_(other.off_.load()) {} + + /** Move constructor */ + PointerBase(PointerBase &&other) noexcept + : allocator_id_(other.allocator_id_), off_(other.off_) { + other.SetNull(); + } + + /** Get the offset pointer */ + OffsetPointerBase ToOffsetPointer() const { + return OffsetPointerBase(off_.load()); + } + + /** Set to null */ + void SetNull() { + allocator_id_.SetNull(); + } + + /** Check if null */ + bool IsNull() const { + return allocator_id_.IsNull(); + } + + /** Get the null pointer */ + static PointerBase GetNull() { + const static PointerBase p(allocator_id_t::GetNull(), + OffsetPointer::GetNull()); + return p; + } + + /** Copy assignment operator */ + PointerBase& operator=(const PointerBase &other) { + if (this != &other) { + allocator_id_ = other.allocator_id_; + off_ = other.off_; + } + return *this; + } + + /** Move assignment operator */ + PointerBase& operator=(PointerBase &&other) { + if (this != &other) { + allocator_id_ = other.allocator_id_; + off_.exchange(other.off_.load()); + other.SetNull(); + } + return *this; + } + + /** Addition operator */ + PointerBase operator+(size_t size) const { + PointerBase p; + p.allocator_id_ = allocator_id_; + p.off_ = off_ + size; + return p; + } + + /** Subtraction operator */ + PointerBase operator-(size_t size) const { + PointerBase p; + p.allocator_id_ = allocator_id_; + p.off_ = off_ - size; + return p; + } + + /** Addition assignment operator */ + PointerBase& operator+=(size_t size) { + off_ += size; + return *this; + } + + /** Subtraction assignment operator */ + PointerBase& operator-=(size_t size) { + off_ -= size; + return *this; + } + + /** Equality check */ + bool operator==(const PointerBase &other) const { + return (other.allocator_id_ == allocator_id_ && other.off_ == off_); + } + + /** Inequality check */ + bool operator!=(const PointerBase &other) const { + return (other.allocator_id_ != allocator_id_ || other.off_ != off_); + } +}; + +/** Non-atomic pointer */ +typedef PointerBase Pointer; + +/** Atomic pointer */ +typedef PointerBase AtomicPointer; + +/** Typed pointer */ +template +using TypedPointer = Pointer; + +/** Typed atomic pointer */ +template +using TypedAtomicPointer = AtomicPointer; + +/** Round up to the nearest multiple of the alignment */ +static size_t NextAlignmentMultiple(size_t alignment, size_t size) { + auto page_size = HERMES_SHM_SYSTEM_INFO->page_size_; + size_t new_size = size; + size_t page_off = size % alignment; + if (page_off) { + new_size = size + page_size - page_off; + } + return new_size; +} + +/** Round up to the nearest multiple of page size */ +static size_t NextPageSizeMultiple(size_t size) { + auto page_size = HERMES_SHM_SYSTEM_INFO->page_size_; + size_t new_size = NextAlignmentMultiple(page_size, size); + return new_size; +} + +} // namespace hermes_shm::ipc + +namespace std { + +/** Allocator ID hash */ +template <> +struct hash { + std::size_t operator()(const hermes_shm::ipc::allocator_id_t &key) const { + return std::hash{}(key.int_); + } +}; + +} // namespace std + + +#endif // HERMES_SHM_MEMORY_MEMORY_H_ diff --git a/hermes_shm/include/hermes_shm/memory/memory_manager.h b/hermes_shm/include/hermes_shm/memory/memory_manager.h new file mode 100644 index 000000000..6e912f57b --- /dev/null +++ b/hermes_shm/include/hermes_shm/memory/memory_manager.h @@ -0,0 +1,204 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_MEMORY_MEMORY_MANAGER_H_ +#define HERMES_SHM_MEMORY_MEMORY_MANAGER_H_ + +#include "hermes_shm/memory/allocator/allocator.h" +#include "backend/memory_backend.h" +#include "hermes_shm/memory/allocator/allocator_factory.h" +#include + +namespace hipc = hermes_shm::ipc; + +namespace hermes_shm::ipc { + +class MemoryManager { + private: + allocator_id_t root_allocator_id_; + PosixMmap root_backend_; + StackAllocator root_allocator_; + std::unordered_map> backends_; + std::unordered_map> allocators_; + Allocator *default_allocator_; + + public: + /** The default amount of memory a single allocator manages */ + static const size_t kDefaultBackendSize = GIGABYTES(64); + + /** + * Constructor. Create the root allocator and backend, which is used + * until the user specifies a new default. The root allocator stores + * only private memory. + * */ + MemoryManager() { + root_allocator_id_.bits_.major_ = 0; + root_allocator_id_.bits_.minor_ = -1; + root_backend_.shm_init(HERMES_SHM_SYSTEM_INFO->ram_size_); + root_backend_.Own(); + root_allocator_.shm_init(&root_backend_, root_allocator_id_, 0); + default_allocator_ = &root_allocator_; + } + + /** + * Create a memory backend. Memory backends are divided into slots. + * Each slot corresponds directly with a single allocator. + * There can be multiple slots per-backend, enabling multiple allocation + * policies over a single memory region. + * */ + template + MemoryBackend* CreateBackend(size_t size, + const std::string &url, + Args&& ...args) { + backends_.emplace(url, + MemoryBackendFactory::shm_init(size, url), + std::forward(args)...); + auto backend = backends_[url].get(); + backend->Own(); + return backend; + } + + /** + * Attaches to an existing memory backend located at \a url url. + * */ + MemoryBackend* AttachBackend(MemoryBackendType type, + const std::string &url) { + backends_.emplace(url, MemoryBackendFactory::shm_deserialize(type, url)); + auto backend = backends_[url].get(); + ScanBackends(); + backend->Disown(); + return backend; + } + + /** + * Returns a pointer to a backend that has already been attached. + * */ + MemoryBackend* GetBackend(const std::string &url); + + /** + * Destroys the memory allocated by the entire backend. + * */ + void DestroyBackend(const std::string &url); + + /** + * Scans all attached backends for new memory allocators. + * */ + void ScanBackends(); + + /** + * Registers an allocator. Used internally by ScanBackends, but may + * also be used externally. + * */ + void RegisterAllocator(std::unique_ptr &alloc); + + /** + * Create and register a memory allocator for a particular backend. + * */ + template + Allocator* CreateAllocator(const std::string &url, + allocator_id_t alloc_id, + size_t custom_header_size, + Args&& ...args) { + auto backend = GetBackend(url); + if (alloc_id.IsNull()) { + alloc_id = allocator_id_t(HERMES_SHM_SYSTEM_INFO->pid_, + allocators_.size()); + } + auto alloc = AllocatorFactory::shm_init( + backend, alloc_id, custom_header_size, std::forward(args)...); + RegisterAllocator(alloc); + return GetAllocator(alloc_id); + } + + /** + * Locates an allocator of a particular id + * */ + Allocator* GetAllocator(allocator_id_t alloc_id) { + if (alloc_id.IsNull()) { return nullptr; } + if (alloc_id == root_allocator_.GetId()) { + return &root_allocator_; + } + auto iter = allocators_.find(alloc_id); + if (iter == allocators_.end()) { + ScanBackends(); + } + return reinterpret_cast(allocators_[alloc_id].get()); + } + + /** + * Gets the allocator used for initializing other allocators. + * */ + Allocator* GetRootAllocator() { + return &root_allocator_; + } + + /** + * Gets the allocator used by default when no allocator is + * used to construct an object. + * */ + Allocator* GetDefaultAllocator() { + return default_allocator_; + } + + /** + * Sets the allocator used by default when no allocator is + * used to construct an object. + * */ + void SetDefaultAllocator(Allocator *alloc) { + default_allocator_ = alloc; + } + + /** + * Convert a process-independent pointer into a process-specific pointer. + * */ + template + T* Convert(const POINTER_T &p) { + if (p.IsNull()) { + return nullptr; + } + return GetAllocator(p.allocator_id_)->template + Convert(p); + } + + /** + * Convert a process-specific pointer into a process-independent pointer + * + * @param allocator_id the allocator the pointer belongs to + * @param ptr the pointer to convert + * */ + template + POINTER_T Convert(allocator_id_t allocator_id, T *ptr) { + return GetAllocator(allocator_id)->template + Convert(ptr); + } + + /** + * Convert a process-specific pointer into a process-independent pointer when + * the allocator is unkown. + * + * @param ptr the pointer to convert + * */ + template + POINTER_T Convert(T *ptr) { + for (auto &[alloc_id, alloc] : allocators_) { + if (alloc->ContainsPtr(ptr)) { + return alloc->template + Convert(ptr); + } + } + return Pointer::GetNull(); + } +}; + +} // namespace hermes_shm::ipc + +#endif // HERMES_SHM_MEMORY_MEMORY_MANAGER_H_ diff --git a/hermes_shm/include/hermes_shm/thread/lock.h b/hermes_shm/include/hermes_shm/thread/lock.h new file mode 100644 index 000000000..61cdfb36f --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/lock.h @@ -0,0 +1,20 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_THREAD_LOCK_H_ +#define HERMES_SHM_THREAD_LOCK_H_ + +#include "lock/mutex.h" +#include "lock/rwlock.h" +#include "thread_manager.h" + +#endif // HERMES_SHM_THREAD_LOCK_H_ diff --git a/hermes_shm/include/hermes_shm/thread/lock/mutex.h b/hermes_shm/include/hermes_shm/thread/lock/mutex.h new file mode 100644 index 000000000..4902d5052 --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/lock/mutex.h @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_THREAD_MUTEX_H_ +#define HERMES_SHM_THREAD_MUTEX_H_ + +#include + +namespace hermes_shm { + +struct Mutex { + std::atomic lock_; + + Mutex() : lock_(0) {} + + void Init() { + lock_ = 0; + } + void Lock(); + bool TryLock(); + void Unlock(); +}; + +struct ScopedMutex { + Mutex &lock_; + bool is_locked_; + + explicit ScopedMutex(Mutex &lock); + ~ScopedMutex(); + + void Lock(); + bool TryLock(); + void Unlock(); +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_THREAD_MUTEX_H_ diff --git a/hermes_shm/include/hermes_shm/thread/lock/rwlock.h b/hermes_shm/include/hermes_shm/thread/lock/rwlock.h new file mode 100644 index 000000000..c7bee4e49 --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/lock/rwlock.h @@ -0,0 +1,99 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_THREAD_RWLOCK_H_ +#define HERMES_SHM_THREAD_RWLOCK_H_ + +#include + +namespace hermes_shm { + +union RwLockPayload { + struct { + uint32_t r_; + uint32_t w_; + } bits_; + uint64_t as_int_; + + RwLockPayload() = default; + + RwLockPayload(const RwLockPayload &other) { + as_int_ = other.as_int_; + } + + RwLockPayload(uint64_t other) { + as_int_ = other; + } + + bool IsWriteLocked() const { + return bits_.w_ > 0; + } + + bool IsReadLocked() const { + return bits_.r_ > 0; + } +}; + +struct RwLock { + std::atomic payload_; + + RwLock() : payload_(0) {} + + void Init() { + payload_ = 0; + } + + RwLock(const RwLock &other) = delete; + + RwLock(RwLock &&other) noexcept + : payload_(other.payload_.load()) {} + + RwLock& operator=(RwLock &&other) { + payload_ = other.payload_.load(); + return (*this); + } + + void ReadLock(); + void ReadUnlock(); + + void WriteLock(); + void WriteUnlock(); + + void assert_r_refcnt(int ref); + void assert_w_refcnt(int ref); +}; + +struct ScopedRwReadLock { + RwLock &lock_; + bool is_locked_; + + explicit ScopedRwReadLock(RwLock &lock); + ~ScopedRwReadLock(); + + void Lock(); + void Unlock(); +}; + +struct ScopedRwWriteLock { + RwLock &lock_; + bool is_locked_; + + explicit ScopedRwWriteLock(RwLock &lock); + ~ScopedRwWriteLock(); + + void Lock(); + void Unlock(); +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_THREAD_RWLOCK_H_ diff --git a/hermes_shm/include/hermes_shm/thread/pthread.h b/hermes_shm/include/hermes_shm/thread/pthread.h new file mode 100644 index 000000000..65d894359 --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/pthread.h @@ -0,0 +1,100 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_THREAD_PTHREAD_H_ +#define HERMES_SHM_THREAD_PTHREAD_H_ + +#include "thread.h" +#include +#include + +namespace hermes_shm { + +template class Pthread; + +template +struct PthreadParams { + BIND bind_; + Pthread *pthread_; + + PthreadParams(Pthread *pthread, BIND bind) : + bind_(bind), + pthread_(pthread) {} +}; + +template +class Pthread : public Thread { + private: + pthread_t pthread_; + + public: + bool started_; + + public: + Pthread() = default; + explicit Pthread(BIND bind) : started_(false), pthread_(-1) { + PthreadParams params(this, bind); + int ret = pthread_create(&pthread_, nullptr, + DoWork, + ¶ms); + if (ret != 0) { + throw PTHREAD_CREATE_FAILED.format(); + } + while (!started_) {} + } + + void Pause() override {} + + void Resume() override {} + + void Join() override { + void *ret; + pthread_join(pthread_, &ret); + } + + void SetAffinity(int cpu_start, int count) override { + /*cpu_set_t cpus[n_cpu_]; + CPU_ZERO(cpus); + CPU_SET(cpu_id, cpus); + pthread_setaffinity_np_safe(n_cpu_, cpus);*/ + } + + private: + static void* DoWork(void *void_params) { + auto params = (*reinterpret_cast*>(void_params)); + params.pthread_->started_ = true; + params.bind_(); + return nullptr; + } + + inline void pthread_setaffinity_np_safe(int n_cpu, cpu_set_t *cpus) { + int ret = pthread_setaffinity_np(pthread_, n_cpu, cpus); + if (ret != 0) { + throw INVALID_AFFINITY.format(strerror(ret)); + } + } +}; + +class PthreadStatic : public ThreadStatic { + public: + void Yield() override { + pthread_yield(); + } + + tid_t GetTid() override { + return static_cast(pthread_self()); + } +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_THREAD_PTHREAD_H_ diff --git a/hermes_shm/include/hermes_shm/thread/thread.h b/hermes_shm/include/hermes_shm/thread/thread.h new file mode 100644 index 000000000..cdf12cfda --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/thread.h @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_THREAD_THREAD_H_ +#define HERMES_SHM_THREAD_THREAD_H_ + +#include +#include +#include +#include + +namespace hermes_shm { + +typedef uint32_t tid_t; + +enum class ThreadType { + kPthread +}; + +class Thread { + public: + virtual void Pause() = 0; + virtual void Resume() = 0; + virtual void Join() = 0; + void SetAffinity(int cpu_id) { SetAffinity(cpu_id, 1); } + virtual void SetAffinity(int cpu_start, int count) = 0; +}; + +class ThreadStatic { + public: + virtual ~ThreadStatic() = default; + virtual void Yield() = 0; + virtual tid_t GetTid() = 0; +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_THREAD_THREAD_H_ diff --git a/hermes_shm/include/hermes_shm/thread/thread_factory.h b/hermes_shm/include/hermes_shm/thread/thread_factory.h new file mode 100644 index 000000000..c10356c99 --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/thread_factory.h @@ -0,0 +1,51 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_THREAD_THREAD_FACTORY_H_ +#define HERMES_SHM_THREAD_THREAD_FACTORY_H_ + +#include "thread.h" +#include "pthread.h" + +namespace hermes_shm { + +template +class ThreadFactory { + private: + ThreadType type_; + BIND bind_; + + public: + explicit ThreadFactory(ThreadType type, BIND bind) + : type_(type), bind_(bind) {} + + std::unique_ptr Get() { + switch (type_) { + case ThreadType::kPthread: return std::make_unique>(bind_); + default: return nullptr; + } + } +}; + +class ThreadStaticFactory { + public: + static std::unique_ptr Get(ThreadType type) { + switch (type) { + case ThreadType::kPthread: return std::make_unique(); + default: return nullptr; + } + } +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_THREAD_THREAD_FACTORY_H_ diff --git a/hermes_shm/include/hermes_shm/thread/thread_manager.h b/hermes_shm/include/hermes_shm/thread/thread_manager.h new file mode 100644 index 000000000..93bdd9660 --- /dev/null +++ b/hermes_shm/include/hermes_shm/thread/thread_manager.h @@ -0,0 +1,43 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_THREAD_THREAD_MANAGER_H_ +#define HERMES_SHM_THREAD_THREAD_MANAGER_H_ + +#include "thread.h" +#include "thread_factory.h" +#include + +namespace hermes_shm { + +class ThreadManager { + public: + ThreadType type_; + std::unique_ptr thread_static_; + + ThreadManager() : type_(ThreadType::kPthread) {} + + void SetThreadType(ThreadType type) { + type_ = type; + } + + ThreadStatic* GetThreadStatic() { + if (!thread_static_) { + thread_static_ = ThreadStaticFactory::Get(type_); + } + return thread_static_.get(); + } +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_THREAD_THREAD_MANAGER_H_ diff --git a/hermes_shm/include/hermes_shm/types/argpack.h b/hermes_shm/include/hermes_shm/types/argpack.h new file mode 100644 index 000000000..9205b73ed --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/argpack.h @@ -0,0 +1,234 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ARGPACK_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ARGPACK_H_ + +#include "basic.h" +#include + +namespace hermes_shm { + +/** Type which indicates that a constructor takes ArgPacks as input */ +struct PiecewiseConstruct {}; + +/** Type which ends template recurrence */ +struct EndTemplateRecurrence {}; + +/** Recurrence used to create argument pack */ +template< + size_t idx, + typename T=EndTemplateRecurrence, + typename ...Args> +struct ArgPackRecur { + constexpr static bool is_rval = std::is_rvalue_reference(); + typedef typename std::conditional::type ElementT; + + ElementT arg_; /**< The element stored */ + ArgPackRecur + recur_; /**< Remaining args */ + + /** Default constructor */ + ArgPackRecur() = default; + + /** Constructor. Rvalue reference. */ + explicit ArgPackRecur(T arg, Args&& ...args) + : arg_(std::forward(arg)), recur_(std::forward(args)...) {} + + /** Forward an rvalue reference (only if argpack) */ + template + constexpr decltype(auto) Forward() const { + if constexpr(i == idx) { + if constexpr(is_rval) { + return std::forward(arg_); + } else { + return arg_; + } + } else { + return recur_.template + Forward(); + } + } +}; + +/** Terminator of the ArgPack recurrence */ +template +struct ArgPackRecur { + /** Default constructor */ + ArgPackRecur() = default; + + /** Forward an rvalue reference (only if argpack) */ + template + constexpr void Forward() const { + throw std::logic_error("(Forward) ArgPack index outside of range"); + } +}; + +/** Used to semantically pack arguments */ +template +struct ArgPack { + /** Variable argument pack */ + ArgPackRecur<0, Args...> recur_; + /** Size of the argpack */ + constexpr const static size_t size_ = sizeof...(Args); + + /** General Constructor. */ + ArgPack(Args&& ...args) + : recur_(std::forward(args)...) {} + + /** Get forward reference */ + template + constexpr decltype(auto) Forward() const { + return recur_.template Forward(); + } + + /** Size */ + constexpr static size_t Size() { + return size_; + } +}; + +/** Make an argpack */ +template +ArgPack make_argpack(Args&& ...args) { + return ArgPack(std::forward(args)...); +} + +/** Get the type + reference of the forward for \a pack pack at \a index i */ +#define FORWARD_ARGPACK_FULL_TYPE(pack, i)\ + decltype(pack.template Forward()) + +/** Get type of the forward for \a pack pack at \a index i */ +#define FORWARD_ARGPACK_BASE_TYPE(pack, i)\ + std::remove_reference + +/** Forward the param for \a pack pack at \a index i */ +#define FORWARD_ARGPACK_PARAM(pack, i)\ + std::forward(\ + pack.template Forward()) + +/** Used to pass an argument pack to a function or class method */ +class PassArgPack { + public: + /** Call function with ArgPack */ + template + constexpr static decltype(auto) Call(ArgPackT &&pack, F &&f) { + return _CallRecur<0, ArgPackT, F>( + std::forward(pack), std::forward(f)); + } + + private: + /** Unpacks the ArgPack and passes it to the function */ + template + constexpr static decltype(auto) _CallRecur(ArgPackT &&pack, + F &&f, + CurArgs&& ...args) { + if constexpr(i < ArgPackT::Size()) { + return _CallRecur( + std::forward(pack), + std::forward(f), + std::forward(args)..., + FORWARD_ARGPACK_PARAM(pack, i)); + } else { + return std::__invoke(f, std::forward(args)...); + } + } +}; + +/** Combine multiple argpacks into a single argpack */ +class MergeArgPacks { + public: + /** Call function with ArgPack */ + template + constexpr static decltype(auto) Merge(ArgPacks&& ...packs) { + return _MergePacksRecur<0>(make_argpack(std::forward(packs)...)); + } + + private: + /** Unpacks the C++ parameter pack of ArgPacks */ + template + constexpr static decltype(auto) _MergePacksRecur(ArgPacksT &&packs, + CurArgs&& ...args) { + if constexpr(cur_pack < ArgPacksT::Size()) { + return _MergeRecur< + cur_pack, ArgPacksT, 0>( + // End template parameters + std::forward(packs), + FORWARD_ARGPACK_PARAM(packs, cur_pack), + std::forward(args)... + ); + } else { + return make_argpack(std::forward(args)...); + } + } + + /** Unpacks the C++ parameter pack of ArgPacks */ + template< + size_t cur_pack, typename ArgPacksT, + size_t i, typename ArgPackT, + typename ...CurArgs> + constexpr static decltype(auto) _MergeRecur(ArgPacksT &&packs, + ArgPackT &&pack, + CurArgs&& ...args) { + if constexpr(i < ArgPackT::Size()) { + return _MergeRecur( + std::forward(packs), + std::forward(pack), + std::forward(args)..., FORWARD_ARGPACK_PARAM(pack, i)); + } else { + return _MergePacksRecur( + std::forward(packs), + std::forward(args)...); + } + } +}; + +/** Insert an argpack at the head of each pack in a set of ArgPacks */ +class ProductArgPacks { + public: + /** The product function */ + template + constexpr static decltype(auto) Product(ProductPackT &&prod_pack, + ArgPacks&& ...packs) { + return _ProductPacksRecur<0>( + std::forward(prod_pack), + make_argpack(std::forward(packs)...)); + } + + private: + /** Prepend \a ArgPack prod_pack to every ArgPack in orig_packs */ + template< + size_t cur_pack, + typename ProductPackT, + typename OrigPacksT, + typename ...NewPacks> + constexpr static decltype(auto) _ProductPacksRecur(ProductPackT &&prod_pack, + OrigPacksT &&orig_packs, + NewPacks&& ...packs) { + if constexpr(cur_pack < OrigPacksT::Size()) { + return _ProductPacksRecur( + std::forward(prod_pack), + std::forward(orig_packs), + std::forward(packs)..., + std::forward(prod_pack), + FORWARD_ARGPACK_PARAM(orig_packs, cur_pack)); + } else { + return make_argpack(std::forward(packs)...); + } + } +}; + +} // namespace hermes_shm + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ARGPACK_H_ diff --git a/hermes_shm/include/hermes_shm/types/atomic.h b/hermes_shm/include/hermes_shm/types/atomic.h new file mode 100644 index 000000000..f39b00eb7 --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/atomic.h @@ -0,0 +1,252 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ATOMIC_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ATOMIC_H_ + +#include + +namespace hermes_shm::ipc { + +/** Provides the API of an atomic, without being atomic */ +template +struct nonatomic { + T x; + + /** Constructor */ + inline nonatomic() = default; + + /** Full constructor */ + inline nonatomic(T def) : x(def) {} + + /** Atomic fetch_add wrapper*/ + inline T fetch_add( + T count, std::memory_order order = std::memory_order_seq_cst) { + (void) order; + x += count; + return x; + } + + /** Atomic fetch_sub wrapper*/ + inline T fetch_sub( + T count, std::memory_order order = std::memory_order_seq_cst) { + (void) order; + x -= count; + return x; + } + + /** Atomic load wrapper */ + inline T load( + std::memory_order order = std::memory_order_seq_cst) const { + (void) order; + return x; + } + + /** Atomic exchange wrapper */ + inline void exchange( + T count, std::memory_order order = std::memory_order_seq_cst) { + (void) order; + x = count; + } + + /** Atomic compare exchange weak wrapper */ + inline bool compare_exchange_weak(T& expected, T desired, + std::memory_order order = + std::memory_order_seq_cst) { + (void) expected; (void) order; + x = desired; + return true; + } + + /** Atomic compare exchange strong wrapper */ + inline bool compare_exchange_strong(T& expected, T desired, + std::memory_order order = + std::memory_order_seq_cst) { + (void) expected; (void) order; + x = desired; + return true; + } + + /** Atomic pre-increment operator */ + inline nonatomic& operator++() { + ++x; + return *this; + } + + /** Atomic post-increment operator */ + inline nonatomic operator++(int) { + return atomic(x+1); + } + + /** Atomic pre-decrement operator */ + inline nonatomic& operator--() { + --x; + return *this; + } + + /** Atomic post-decrement operator */ + inline nonatomic operator--(int) { + return atomic(x-1); + } + + /** Atomic add operator */ + inline nonatomic operator+(T count) const { + return nonatomic(x + count); + } + + /** Atomic subtract operator */ + inline nonatomic operator-(T count) const { + return nonatomic(x - count); + } + + /** Atomic add assign operator */ + inline nonatomic& operator+=(T count) { + x += count; + return *this; + } + + /** Atomic subtract assign operator */ + inline nonatomic& operator-=(T count) { + x -= count; + return *this; + } + + /** Atomic assign operator */ + inline nonatomic& operator=(T count) { + x = count; + return *this; + } + + /** Equality check */ + inline bool operator==(const nonatomic &other) const { + return (other.x == x); + } + + /** Inequality check */ + inline bool operator!=(const nonatomic &other) const { + return (other.x != x); + } +}; + +/** A wrapper around std::atomic */ +template +struct atomic { + std::atomic x; + + /** Constructor */ + inline atomic() = default; + + /** Full constructor */ + inline atomic(T def) : x(def) {} + + /** Atomic fetch_add wrapper*/ + inline T fetch_add( + T count, std::memory_order order = std::memory_order_seq_cst) { + return x.fetch_add(count, order); + } + + /** Atomic fetch_sub wrapper*/ + inline T fetch_sub( + T count, std::memory_order order = std::memory_order_seq_cst) { + return x.fetch_sub(count, order); + } + + /** Atomic load wrapper */ + inline T load( + std::memory_order order = std::memory_order_seq_cst) const { + return x.load(order); + } + + /** Atomic exchange wrapper */ + inline void exchange( + T count, std::memory_order order = std::memory_order_seq_cst) { + x.exchange(count, order); + } + + /** Atomic compare exchange weak wrapper */ + inline bool compare_exchange_weak(T& expected, T desired, + std::memory_order order = + std::memory_order_seq_cst) { + return x.compare_exchange_weak(expected, desired, order); + } + + /** Atomic compare exchange strong wrapper */ + inline bool compare_exchange_strong(T& expected, T desired, + std::memory_order order = + std::memory_order_seq_cst) { + return x.compare_exchange_strong(expected, desired, order); + } + + /** Atomic pre-increment operator */ + inline atomic& operator++() { + ++x; + return *this; + } + + /** Atomic post-increment operator */ + inline atomic operator++(int) { + return atomic(x+1); + } + + /** Atomic pre-decrement operator */ + inline atomic& operator--() { + --x; + return *this; + } + + /** Atomic post-decrement operator */ + inline atomic operator--(int) { + return atomic(x-1); + } + + /** Atomic add operator */ + inline atomic operator+(T count) const { + return x + count; + } + + /** Atomic subtract operator */ + inline atomic operator-(T count) const { + return x - count; + } + + /** Atomic add assign operator */ + inline atomic& operator+=(T count) { + x += count; + return *this; + } + + /** Atomic subtract assign operator */ + inline atomic& operator-=(T count) { + x -= count; + return *this; + } + + /** Atomic assign operator */ + inline atomic& operator=(T count) { + x.exchange(count); + return *this; + } + + /** Equality check */ + inline bool operator==(const atomic &other) const { + return (other.x == x); + } + + /** Inequality check */ + inline bool operator!=(const atomic &other) const { + return (other.x != x); + } +}; + +} + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ATOMIC_H_ diff --git a/hermes_shm/include/hermes_shm/types/basic.h b/hermes_shm/include/hermes_shm/types/basic.h new file mode 100644 index 000000000..bd02abe18 --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/basic.h @@ -0,0 +1,139 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_BASICS_H +#define HERMES_SHM_BASICS_H + +#define MODULE_KEY_SIZE 32 + +#include +using std::size_t; + +#include +#include +#include +#include +#include + +namespace hermes_shm { + +/** + * decimal + (numerator/65536) + * */ +struct RealNumber { + uint64_t decimal_; + uint32_t numerator_; + static const uint32_t precision = 65536; + + RealNumber() = default; + + /** + * Converts numerator / denomintor -> + * decimal + (numerator / 65536); + * + * For example, + * 4/5 = (4 * 65536 / 5) / 65536 + * */ + explicit RealNumber(uint64_t numerator, uint64_t denominator) { + decimal_ = numerator / denominator; + uint64_t rem = numerator % denominator; + numerator_ = rem * precision / denominator; + } + + /** + * (d1 + n1/p) * d2 = + * d1 * d2 + d2 * n1 / p + * */ + RealNumber operator*(size_t other) const { + RealNumber res; + res.decimal_ = other * decimal_; + uint64_t frac = other * numerator_; + res.decimal_ += frac / precision; + res.numerator_ = frac % precision; + return res; + } + + /** + * (d1 + n1/p) * (d2 + n2/p) = + * (d1 * d2) + (d1 * n2)/p + (d2 * n1) / p + (n1 * n2 / p) / p = + * (d1 * d2) + [(d1 * n2) + (d2 * n1) + (n1 * n2)/p] / p + * */ + RealNumber operator*(const RealNumber &other) const { + RealNumber res; + // d1 * d2 + res.decimal_ = other.decimal_ * decimal_; + uint64_t frac = + (decimal_ * other.numerator_) + // d1 * n2 + (other.decimal_ * numerator_) + // d2 * n1 + (numerator_ * other.numerator_) / precision; // n1 * n2 / p + res.decimal_ += frac / precision; + res.numerator_ = frac % precision; + return res; + } + + RealNumber operator*=(size_t other) { + (*this) = (*this) * other; + return *this; + } + + RealNumber operator*=(const RealNumber &other) { + (*this) = (*this) * other; + return *this; + } + + size_t as_int() const { + return decimal_ + numerator_ / precision; + } +}; + +struct id { + char key_[MODULE_KEY_SIZE]; + id() = default; + ~id() = default; + explicit id(const std::string &key_str) { + snprintf(key_, MODULE_KEY_SIZE, "%s", key_str.c_str()); + } + explicit id(const char* key_str) { + snprintf(key_, MODULE_KEY_SIZE, "%s", key_str); + } + bool operator==(const id &other) const { + return strncmp(key_, other.key_, MODULE_KEY_SIZE) == 0; + } + void copy(const std::string &str) { + memcpy(key_, str.c_str(), str.size()); + key_[str.size()] = 0; + } + const char& operator[](int i) { + return key_[i]; + } +}; + +typedef int32_t off_t; + +} // namespace hermes_shm + +namespace std { +template<> +struct hash { + size_t operator()(const hermes_shm::id &id) const { + size_t sum = 0; + int len = strnlen(id.key_, MODULE_KEY_SIZE); + for (int i = 0; i < len; ++i) { + if (id.key_[i] == 0) { break; } + sum += id.key_[i] << (i % 8); + } + return sum; + } +}; +} // namespace std + +#endif // HERMES_SHM_BASICS_H diff --git a/hermes_shm/include/hermes_shm/types/bitfield.h b/hermes_shm/include/hermes_shm/types/bitfield.h new file mode 100644 index 000000000..b0a5346a7 --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/bitfield.h @@ -0,0 +1,75 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_BITFIELD_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_BITFIELD_H_ + +#include + +namespace hermes_shm { + +#define BIT_OPT(T, n) (((T)1) << n) + +/** + * A generic bitfield template + * */ +template +struct bitfield { + T bits_; + + bitfield() : bits_(0) {} + + inline void SetBits(T mask) { + bits_ |= mask; + } + + inline void UnsetBits(T mask) { + bits_ &= ~mask; + } + + inline bool OrBits(T mask) const { + return bits_ & mask; + } + + inline void CopyBits(bitfield field, T mask) { + bits_ &= (field.bits_ & mask); + } + + inline void Clear() { + bits_ = 0; + } +} __attribute__((packed)); +typedef bitfield bitfield8_t; +typedef bitfield bitfield16_t; +typedef bitfield bitfield32_t; + +#define INHERIT_BITFIELD_OPS(BITFIELD_VAR, MASK_T)\ + inline void SetBits(MASK_T mask) {\ + BITFIELD_VAR.SetBits(mask);\ + }\ + inline void UnsetBits(MASK_T mask) {\ + BITFIELD_VAR.UnsetBits(mask);\ + }\ + inline bool OrBits(MASK_T mask) const {\ + return BITFIELD_VAR.OrBits(mask);\ + }\ + inline void Clear() {\ + BITFIELD_VAR.Clear();\ + }\ + template\ + inline void CopyBits(BITFIELD_T field, MASK_T mask) {\ + BITFIELD_VAR.CopyBits(field, mask);\ + } + +} // namespace hermes_shm + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_BITFIELD_H_ diff --git a/hermes_shm/include/hermes_shm/types/charbuf.h b/hermes_shm/include/hermes_shm/types/charbuf.h new file mode 100644 index 000000000..155a5b1aa --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/charbuf.h @@ -0,0 +1,204 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_CHARBUF_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_CHARBUF_H_ + +#include "basic.h" +#include "hermes_shm/memory/memory_manager.h" +#include + +namespace hermes_shm { + +/** An uninterpreted array of bytes */ +struct charbuf { + hipc::Allocator *alloc_; /**< The allocator used to allocate data */ + char *data_; /**< The pointer to data */ + size_t size_; /**< The size of data */ + bool destructable_; /**< Whether or not this container owns data */ + + /** Default constructor */ + charbuf() : alloc_(nullptr), data_(nullptr), size_(0), destructable_(false) {} + + /** Destructor */ + ~charbuf() { Free(); } + + /** Size-based constructor */ + explicit charbuf(size_t size) { + Allocate(HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(), size); + } + + /** String-based constructor */ + explicit charbuf(const std::string &data) { + Allocate(HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(), data.size()); + memcpy(data_, data.data(), data.size()); + } + + /** Pointer-based constructor */ + explicit charbuf(char *data, size_t size) + : alloc_(nullptr), data_(data), size_(size), destructable_(false) {} + + /** + * Pointer-based constructor + * This should only be used when Blob itself is const. + * */ + explicit charbuf(const char *data, size_t size) + : alloc_(nullptr), data_(const_cast(data)), + size_(size), destructable_(false) {} + + + /** Copy constructor */ + charbuf(const charbuf &other) { + if (!Allocate(HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(), + other.size())) { + return; + } + memcpy(data_, other.data(), size()); + } + + /** Copy assignment operator */ + charbuf& operator=(const charbuf &other) { + if (this != &other) { + Free(); + if (!Allocate(HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(), + other.size())) { + return *this; + } + memcpy(data_, other.data(), size()); + } + return *this; + } + + /** Move constructor */ + charbuf(charbuf &&other) { + alloc_ = other.alloc_; + data_ = other.data_; + size_ = other.size_; + destructable_ = other.destructable_; + other.size_ = 0; + other.destructable_ = false; + } + + /** Move assignment operator */ + charbuf& operator=(charbuf &other) { + if (this != &other) { + Free(); + alloc_ = other.alloc_; + data_ = other.data_; + size_ = other.size_; + destructable_ = other.destructable_; + other.size_ = 0; + other.destructable_ = false; + } + return *this; + } + + /** Destroy and resize */ + void resize(size_t new_size) { + if (new_size <= size()) { + size_ = new_size; + return; + } + if (alloc_ == nullptr) { + alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + } + if (destructable_) { + data_ = alloc_->ReallocatePtr(data_, new_size); + } else { + data_ = alloc_->AllocatePtr(new_size); + } + destructable_ = true; + size_ = new_size; + } + + /** Reference data */ + char* data() { + return data_; + } + + /** Reference data */ + char* data() const { + return data_; + } + + /** Reference size */ + size_t size() const { + return size_; + } + + /** + * Comparison operators + * */ + + int _strncmp(const char *a, size_t len_a, + const char *b, size_t len_b) const { + if (len_a != len_b) { + return int((int64_t)len_a - (int64_t)len_b); + } + int sum = 0; + for (size_t i = 0; i < len_a; ++i) { + sum += a[i] - b[i]; + } + return sum; + } + +#define HERMES_SHM_STR_CMP_OPERATOR(op) \ + bool operator op(const char *other) const { \ + return _strncmp(data(), size(), other, strlen(other)) op 0; \ + } \ + bool operator op(const std::string &other) const { \ + return _strncmp(data(), size(), other.data(), other.size()) op 0; \ + } \ + bool operator op(const charbuf &other) const { \ + return _strncmp(data(), size(), other.data(), other.size()) op 0; \ + } + + HERMES_SHM_STR_CMP_OPERATOR(==) + HERMES_SHM_STR_CMP_OPERATOR(!=) + HERMES_SHM_STR_CMP_OPERATOR(<) + HERMES_SHM_STR_CMP_OPERATOR(>) + HERMES_SHM_STR_CMP_OPERATOR(<=) + HERMES_SHM_STR_CMP_OPERATOR(>=) + +#undef HERMES_SHM_STR_CMP_OPERATOR + + private: + /** Allocate charbuf */ + bool Allocate(hipc::Allocator *alloc, size_t size) { + hipc::OffsetPointer p; + if (size == 0) { + alloc_ = nullptr; + data_ = nullptr; + size_ = 0; + destructable_ = false; + return false; + } + alloc_ = alloc; + data_ = alloc->AllocatePtr(size, p); + size_ = size; + destructable_ = true; + return true; + } + + /** Explicitly free the charbuf */ + void Free() { + if (destructable_ && data_ && size_) { + alloc_->FreePtr(data_); + } + } +}; + +typedef charbuf string; + +} // namespace hermes_shm + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_CHARBUF_H_ diff --git a/hermes_shm/include/hermes_shm/types/messages.h b/hermes_shm/include/hermes_shm/types/messages.h new file mode 100644 index 000000000..11b87e230 --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/messages.h @@ -0,0 +1,49 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_MESSAGES_H +#define HERMES_SHM_MESSAGES_H + +namespace hermes_shm { + +enum { + HERMES_SHM_ADMIN_REGISTER_QP +}; + +struct admin_request { + int op_; + admin_request() {} + explicit admin_request(int op) : op_(op) {} +}; + +struct admin_reply { + int code_; + admin_reply() {} + explicit admin_reply(int code) : code_(code) {} +}; + +struct setup_reply : public admin_reply { + uint32_t region_id_; + uint32_t region_size_; + uint32_t request_region_size_; + uint32_t request_unit_; + uint32_t queue_region_size_; + uint32_t queue_depth_; + uint32_t num_queues_; + uint32_t namespace_region_id_; + uint32_t namespace_region_size_; + uint32_t namespace_max_entries_; +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_MESSAGES_H diff --git a/hermes_shm/include/hermes_shm/types/tuple_base.h b/hermes_shm/include/hermes_shm/types/tuple_base.h new file mode 100644 index 000000000..c24aeca93 --- /dev/null +++ b/hermes_shm/include/hermes_shm/types/tuple_base.h @@ -0,0 +1,247 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_TupleBase_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_TupleBase_H_ + +#include +#include "basic.h" +#include "argpack.h" + +namespace hermes_shm { + +/** The null container wrapper */ +template +using NullWrap = T; + +/** Recurrence used to create argument pack */ +template< + template typename Wrap, + size_t idx, + typename T=EndTemplateRecurrence, + typename ...Args> +struct TupleBaseRecur { + Wrap arg_; /**< The element stored */ + TupleBaseRecur + recur_; /**< Remaining args */ + + /** Default constructor */ + TupleBaseRecur() = default; + + /** Constructor. Const reference. */ + explicit TupleBaseRecur(const T &arg, Args&& ...args) + : arg_(std::forward(arg)), recur_(std::forward(args)...) {} + + /** Constructor. Lvalue reference. */ + explicit TupleBaseRecur(T& arg, Args&& ...args) + : arg_(std::forward(arg)), recur_(std::forward(args)...) {} + + /** Constructor. Rvalue reference. */ + explicit TupleBaseRecur(T&& arg, Args&& ...args) + : arg_(std::forward(arg)), recur_(std::forward(args)...) {} + + /** Move constructor */ + TupleBaseRecur(TupleBaseRecur &&other) noexcept + : arg_(std::move(other.arg_)), recur_(std::move(other.recur_)) {} + + /** Move assignment operator */ + TupleBaseRecur& operator=(TupleBaseRecur &&other) { + if (this != &other) { + arg_ = std::move(other.arg_); + recur_ = std::move(other.recur_); + } + return *this; + } + + /** Copy constructor */ + TupleBaseRecur(const TupleBaseRecur &other) + : arg_(other.arg_), recur_(other.recur_) {} + + /** Copy assignment operator */ + TupleBaseRecur& operator=(const TupleBaseRecur &other) { + if (this != &other) { + arg_ = other.arg_; + recur_ = other.recur_; + } + return *this; + } + + /** Solidification constructor */ + template + explicit TupleBaseRecur(ArgPack &&other) + : arg_(other.template Forward()), + recur_(std::forward>(other)) {} + + /** Get reference to internal variable (only if tuple) */ + template + constexpr auto& Get() { + if constexpr(i == idx) { + return arg_; + } else { + return recur_.template + Get(); + } + } + + /** Get reference to internal variable (only if tuple, const) */ + template + constexpr auto& Get() const { + if constexpr(i == idx) { + return arg_; + } else { + return recur_.template + Get(); + } + } +}; + +/** Terminator of the TupleBase recurrence */ +template< + template typename Wrap, + size_t idx> +struct TupleBaseRecur { + /** Default constructor */ + TupleBaseRecur() = default; + + /** Solidification constructor */ + template + explicit TupleBaseRecur(ArgPack &&other) {} + + /** Getter */ + template + void Get() { + throw std::logic_error("(Get) TupleBase index outside of range"); + } + + /** Getter */ + template + void Get() const { + throw std::logic_error("(Get) TupleBase index outside of range"); + } +}; + +/** Used to semantically pack arguments */ +template< + bool is_argpack, + template typename Wrap, + typename ...Args> +struct TupleBase { + /** Variable argument pack */ + TupleBaseRecur recur_; + + /** Default constructor */ + TupleBase() = default; + + /** General Constructor. */ + template + explicit TupleBase(Args&& ...args) + : recur_(std::forward(args)...) {} + + /** Move constructor */ + TupleBase(TupleBase &&other) noexcept + : recur_(std::move(other.recur_)) {} + + /** Move assignment operator */ + TupleBase& operator=(TupleBase &&other) noexcept { + if (this != &other) { + recur_ = std::move(other.recur_); + } + return *this; + } + + /** Copy constructor */ + TupleBase(const TupleBase &other) + : recur_(other.recur_) {} + + /** Copy assignment operator */ + TupleBase& operator=(const TupleBase &other) { + if (this != &other) { + recur_ = other.recur_; + } + return *this; + } + + /** Solidification constructor */ + template + explicit TupleBase(ArgPack &&other) + : recur_(std::forward>(other)) {} + + /** Getter */ + template + constexpr auto& Get() { + return recur_.template Get(); + } + + /** Getter (const) */ + template + constexpr auto& Get() const { + return recur_.template Get(); + } + + /** Size */ + constexpr static size_t Size() { + return sizeof...(Args); + } +}; + +/** Tuple definition */ +template +using tuple = TupleBase; + +/** Tuple Wrapper Definition */ +template typename Wrap, typename ...Containers> +using tuple_wrap = TupleBase; + +/** Used to emulate constexpr to lambda */ +template +struct MakeConstexpr { + constexpr static T val_ = Val; + constexpr static T Get() { + return val_; + } +}; + +/** Apply a function over an entire TupleBase / tuple */ +template +class IterateTuple { + public: + /** Apply a function to every element of a tuple */ + template + constexpr static void Apply(TupleT &pack, F &&f) { + _Apply<0, TupleT, F>(pack, std::forward(f)); + } + + private: + /** Apply the function recursively */ + template + constexpr static void _Apply(TupleT &pack, F &&f) { + if constexpr(i < TupleT::Size()) { + if constexpr(reverse) { + _Apply(pack, std::forward(f)); + f(MakeConstexpr(), pack.template Get()); + } else { + f(MakeConstexpr(), pack.template Get()); + _Apply(pack, std::forward(f)); + } + } + } +}; + +/** Forward iterate over tuple and apply function */ +using ForwardIterateTuple = IterateTuple; + +/** Reverse iterate over tuple and apply function */ +using ReverseIterateTuple = IterateTuple; + +} // namespace hermes_shm + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_TupleBase_H_ diff --git a/hermes_shm/include/hermes_shm/util/auto_trace.h b/hermes_shm/include/hermes_shm/util/auto_trace.h new file mode 100644 index 000000000..614bc3085 --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/auto_trace.h @@ -0,0 +1,52 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_UTIL_AUTO_TRACE_H_ +#define HERMES_SHM_INCLUDE_HERMES_SHM_UTIL_AUTO_TRACE_H_ + +#include "formatter.h" +#include "timer.h" + +namespace hermes_shm { + +#define AUTO_TRACE() AutoTrace(__PRETTY_FUNCTION__); + +/** An in-memory log of trace times */ +class AutoTraceLog { + public: + std::stringstream ss_; + void emplace_back(const std::string &fname, Timer timer) { + ss_ << fname << "," << timer.GetUsec() << "," << std::endl; + } +}; + +/** Trace function execution times */ +class AutoTrace { + private: + HighResMonotonicTimer timer_; + std::string fname_; + static AutoTraceLog log_; + + public: + AutoTrace(const std::string &fname) : fname_(fname) { + timer_.Resume(); + } + + ~AutoTrace() { + timer_.Pause(); + log_.emplace_back(fname_, timer_); + } +}; + +} // namespace hermes_shm + +#endif //HERMES_SHM_INCLUDE_HERMES_SHM_UTIL_AUTO_TRACE_H_ diff --git a/hermes_shm/include/hermes_shm/util/debug.h b/hermes_shm/include/hermes_shm/util/debug.h new file mode 100644 index 000000000..68bf7e504 --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/debug.h @@ -0,0 +1,77 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_DEBUG_H +#define HERMES_SHM_DEBUG_H + +#if defined(HERMES_SHM_DEBUG) && defined(__cplusplus) +#define AUTO_TRACE(...) \ + hermes_shm::AutoTrace auto_tracer(false, __PRETTY_FUNCTION__, __VA_ARGS__); +#define TRACEPOINT(...) \ + hermes_shm::AutoTrace(true, __PRETTY_FUNCTION__, __VA_ARGS__); +#elif defined(KERNEL_BUILD) && defined(DEBUG) +#define AUTO_TRACE(...) pr_info(__VA_ARGS__); +#define TRACEPOINT(...) pr_info(__VA_ARGS__); +#else +#define AUTO_TRACE(...) +#define TRACEPOINT(...) +#endif + +#ifdef __cplusplus + +#include "stdio.h" +#include "hermes_shm/util/timer.h" +#include "hermes_shm/util/formatter.h" +#include +#include + +namespace hermes_shm { + +class AutoTrace { + private: + std::string base_text_; + bool tracepoint_; + hermes_shm::HighResCpuTimer t_cpu_; + hermes_shm::HighResMonotonicTimer t_total_; + + public: + template + AutoTrace(bool tracepoint, Args&& ...args) : tracepoint_(tracepoint) { + // TODO(llogan): Redo with good argpack + std::stringstream ss; + base_text_ = ss.str(); + t_cpu_.Resume(); + t_total_.Resume(); + if (!tracepoint) { + printf("%s\n", (base_text_ + "start").c_str()); + } else { + printf("%d;%s\n", gettid(), (base_text_).c_str()); + } + } + + ~AutoTrace() { + if (!tracepoint_) { + t_cpu_.Pause(); + t_total_.Pause(); + base_text_ += "cpu-time-us;" + + std::to_string(t_cpu_.GetUsec()) + ";total-time-us;" + + std::to_string(t_total_.GetUsec()) + ";"; + printf("%s\n", (base_text_ + "end").c_str()); + } + } +}; + +} // namespace hermes_shm + +#endif + +#endif // HERMES_SHM_DEBUG_H diff --git a/hermes_shm/include/hermes_shm/util/error.h b/hermes_shm/include/hermes_shm/util/error.h new file mode 100644 index 000000000..027bbfbff --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/error.h @@ -0,0 +1,60 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_ERROR_H +#define HERMES_SHM_ERROR_H + +// #ifdef __cplusplus + +#include +#include +#include +#include +#include + +#define HERMES_SHM_ERROR_TYPE std::shared_ptr +#define HERMES_SHM_ERROR_HANDLE_START() try { +#define HERMES_SHM_ERROR_HANDLE_END() \ + } catch(HERMES_SHM_ERROR_TYPE &err) { err->print(); exit(-1024); } +#define HERMES_SHM_ERROR_HANDLE_TRY try +#define HERMES_SHM_ERROR_PTR err +#define HERMES_SHM_ERROR_HANDLE_CATCH catch(HERMES_SHM_ERROR_TYPE &HERMES_SHM_ERROR_PTR) +#define HERMES_SHM_ERROR_IS(err, check) (err->get_code() == check.get_code()) + +namespace hermes_shm { + +class Error { + private: + std::string fmt_; + std::string msg_; + public: + Error() : fmt_() {} + explicit Error(std::string fmt) : fmt_(std::move(fmt)) {} + ~Error() = default; + + template + std::shared_ptr format(Args&& ...args) const { + std::shared_ptr err = std::make_shared(fmt_); + err->msg_ = Formatter::format(fmt_, std::forward(args)...); + return err; + } + + void print() { + std::cout << msg_ << std::endl; + } +}; + +} // namespace hermes_shm + +// #endif + +#endif // HERMES_SHM_ERROR_H diff --git a/hermes_shm/include/hermes_shm/util/errors.h b/hermes_shm/include/hermes_shm/util/errors.h new file mode 100644 index 000000000..9ae0e6f8f --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/errors.h @@ -0,0 +1,62 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_ERRORS_H +#define HERMES_SHM_ERRORS_H + +#ifdef __cplusplus + +#include + +namespace hermes_shm { + const Error FILE_NOT_FOUND("File not found at {}"); + const Error INVALID_STORAGE_TYPE("{} is not a valid storage method"); + const Error INVALID_SERIALIZER_TYPE("{} is not a valid serializer type"); + const Error INVALID_TRANSPORT_TYPE("{} is not a valid transport type"); + const Error INVALID_AFFINITY("Could not set CPU affinity of thread: {}"); + const Error MMAP_FAILED("Could not mmap file: {}"); + const Error LAZY_ERROR("Error in function {}"); + const Error PTHREAD_CREATE_FAILED("Failed to create a pthread"); + const Error NOT_IMPLEMENTED("{} not implemented"); + + const Error DLSYM_MODULE_NOT_FOUND("Module {} was not loaded; error {}"); + const Error DLSYM_MODULE_NO_CONSTRUCTOR("Module {} has no constructor"); + + const Error UNIX_SOCKET_FAILED("Failed to create socket: {}"); + const Error UNIX_BIND_FAILED("Failed to bind socket: {}"); + const Error UNIX_CONNECT_FAILED("Failed to connect over socket: {}"); + const Error UNIX_SENDMSG_FAILED("Failed to send message over socket: {}"); + const Error UNIX_RECVMSG_FAILED("Failed to receive message over socket: {}"); + const Error UNIX_SETSOCKOPT_FAILED("Failed to set socket options: {}"); + const Error UNIX_GETSOCKOPT_FAILED("Failed to acquire user credentials: {}"); + const Error UNIX_LISTEN_FAILED("Failed to listen for connections: {}"); + const Error UNIX_ACCEPT_FAILED("Failed accept connections: {}"); + + const Error ARRAY_OUT_OF_BOUNDS("Exceeded the bounds of array in {}"); + + const Error SHMEM_CREATE_FAILED("Failed to allocate SHMEM"); + const Error SHMEM_RESERVE_FAILED("Failed to reserve SHMEM"); + const Error SHMEM_NOT_SUPPORTED("Attempting to deserialize a non-shm backend"); + const Error MEMORY_BACKEND_NOT_FOUND("Failed to find the memory backend"); + const Error NOT_ENOUGH_CONCURRENT_SPACE("{}: Failed to divide memory slot {} among {} devices"); + const Error ALIGNED_ALLOC_NOT_SUPPORTED("Allocator does not support aligned allocations"); + const Error PAGE_SIZE_UNSUPPORTED("Allocator does not support size: {}"); + const Error OUT_OF_MEMORY("{}: could not allocate memory of size {}"); + const Error INVALID_FREE("{}: could not free memory of size {}"); + const Error DOUBLE_FREE("Freeing the same memory twice!"); + + const Error UNORDERED_MAP_CANT_FIND("Could not find key in unordered_map"); +} // namespace hermes_shm + +#endif + +#endif // HERMES_SHM_ERRORS_H diff --git a/hermes_shm/include/hermes_shm/util/formatter.h b/hermes_shm/include/hermes_shm/util/formatter.h new file mode 100644 index 000000000..a5b9c7d8d --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/formatter.h @@ -0,0 +1,100 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_ERROR_SERIALIZER_H +#define HERMES_SHM_ERROR_SERIALIZER_H + +#include +#include +#include +#include +#include +#include +#include + +#define NUMBER_SERIAL(type) \ + return std::to_string(num_.type); + +namespace hermes_shm { + +class Formattable { + public: + virtual std::string ToString() = 0; +}; + +class SizeType : public Formattable { + public: + double num_; + size_t unit_; + + static const size_t + BYTES = 1, + KB = (1ul << 10), + MB = (1ul << 20), + GB = (1ul << 30), + TB = (1ul << 40); + + std::string unit_to_str(size_t unit) { + switch (unit) { + case BYTES: return "BYTES"; + case KB: return "KB"; + case MB: return "MB"; + case GB: return "GB"; + case TB: return "TB"; + } + return ""; + } + + SizeType() : num_(0), unit_(0) {} + SizeType(const SizeType &old_obj) { + num_ = old_obj.num_; + unit_ = old_obj.unit_; + } + + SizeType(int8_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(int16_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(int32_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(int64_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(uint8_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(uint16_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(uint32_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(uint64_t bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(float bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + SizeType(double bytes, size_t unit) : + num_(((double)bytes)/unit), unit_(unit) {} + + std::string ToString() { + return std::to_string(num_) + unit_to_str(unit_); + } +}; + +class Formatter { + public: + template + static std::string format(std::string fmt, Args&& ...args) { + // make_argpack(std::forward(args)...); + return fmt; + } +}; + +} // namespace hermes_shm + +#endif //HERMES_SHM_ERROR_SERIALIZER_H diff --git a/hermes_shm/include/hermes_shm/util/partitioner.h b/hermes_shm/include/hermes_shm/util/partitioner.h new file mode 100644 index 000000000..e1122cd06 --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/partitioner.h @@ -0,0 +1,156 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_PARTITIONER_H +#define HERMES_SHM_PARTITIONER_H + +// Reference: https://stackoverflow.com/questions/63372288/getting-list-of-pids-from-proc-in-linux + +#include +#include +#include +#include +#include + +namespace hermes_shm { + +class ProcessAffiner { + private: + int n_cpu_; + cpu_set_t *cpus_; + + public: + ProcessAffiner() { + n_cpu_ = get_nprocs_conf(); + cpus_ = new cpu_set_t[n_cpu_]; + CPU_ZERO(cpus_); + } + + ~ProcessAffiner() { + delete cpus_; + } + + inline bool isdigit(char digit) { + return ('0' <= digit && digit <= '9'); + } + + inline int GetNumCPU() { + return n_cpu_; + } + + inline void SetCpu(int cpu) { + CPU_SET(cpu, cpus_); + } + + inline void SetCpus(int off, int len) { + for (int i = 0; i < len; ++i) { + SetCpu(off + i); + } + } + + inline void ClearCpu(int cpu) { + CPU_CLR(cpu, cpus_); + } + + inline void ClearCpus(int off, int len) { + for (int i = 0; i < len; ++i) { + ClearCpu(off + i); + } + } + + inline void Clear() { + CPU_ZERO(cpus_); + } + + int AffineAll(void) { + DIR *procdir; + struct dirent *entry; + int count = 0; + + // Open /proc directory. + procdir = opendir("/proc"); + if (!procdir) { + perror("opendir failed"); + return 0; + } + + // Iterate through all files and folders of /proc. + while ((entry = readdir(procdir))) { + // Skip anything that is not a PID folder. + if (!is_pid_folder(entry)) + continue; + // Get the PID of the running process + int proc_pid = atoi(entry->d_name); + // Set the affinity of all running process to this mask + count += Affine(proc_pid); + } + closedir(procdir); + return count; + } + int Affine(std::vector &&pids) { + return Affine(pids); + } + int Affine(std::vector &pids) { + // Set the affinity of all running process to this mask + int count = 0; + for (pid_t &pid : pids) { + count += Affine(pid); + } + return count; + } + int Affine(int pid) { + return SetAffinitySafe(pid, n_cpu_, cpus_); + } + + void PrintAffinity(int pid) { + PrintAffinity("", pid); + } + void PrintAffinity(std::string prefix, int pid) { + std::vector cpus(n_cpu_); + sched_getaffinity(pid, n_cpu_, cpus.data()); + PrintAffinity(prefix, pid, cpus.data()); + } + + void PrintAffinity(std::string prefix, int pid, cpu_set_t *cpus) { + std::string affinity = ""; + for (int i = 0; i < n_cpu_; ++i) { + if (CPU_ISSET(i, cpus)) { + affinity += std::to_string(i) + ", "; + } + } + printf("%s: CPU affinity[pid=%d]: %s\n", prefix.c_str(), + pid, affinity.c_str()); + } + + private: + int SetAffinitySafe(int pid, int n_cpu, cpu_set_t *cpus) { + int ret = sched_setaffinity(pid, n_cpu, cpus); + if (ret == -1) { + return 0; + } + return 1; + } + + // Helper function to check if a struct dirent from /proc is a PID folder. + int is_pid_folder(const struct dirent *entry) { + const char *p; + for (p = entry->d_name; *p; p++) { + if (!isdigit(*p)) + return false; + } + return true; + } +}; + +} // namespace hermes_shm + +#endif // HERMES_SHM_PARTITIONER_H diff --git a/hermes_shm/include/hermes_shm/util/path_parser.h b/hermes_shm/include/hermes_shm/util/path_parser.h new file mode 100644 index 000000000..eaff1531f --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/path_parser.h @@ -0,0 +1,50 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_PATH_PARSER_H +#define HERMES_SHM_PATH_PARSER_H + +#include +#include +#include +#include + +namespace scs { + +std::string path_parser(std::string path) { + std::smatch env_names; + std::regex expr("\\$\\{[^\\}]+\\}"); + if (!std::regex_search(path, env_names, expr)) { + return path; + } + for (auto &env_name_re : env_names) { + std::string to_replace = std::string(env_name_re); + std::string env_name = to_replace.substr(2, to_replace.size()-3); + std::string env_val = env_name; + try { + char *ret = getenv(env_name.c_str()); + if (ret) { + env_val = ret; + } else { + continue; + } + } catch(...) { + } + std::regex replace_expr("\\$\\{" + env_name + "\\}"); + path = std::regex_replace(path, replace_expr, env_val); + } + return path; +} + +} // namespace scs + +#endif // HERMES_SHM_PATH_PARSER_H diff --git a/hermes_shm/include/hermes_shm/util/singleton.h b/hermes_shm/include/hermes_shm/util/singleton.h new file mode 100644 index 000000000..bbfb063fe --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/singleton.h @@ -0,0 +1,34 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef SCS_SINGLETON_H +#define SCS_SINGLETON_H + +#include +#include "hermes_shm/thread/lock/mutex.h" + +namespace scs { + +template +class Singleton { + private: + static T obj_; + public: + Singleton() = default; + static T* GetInstance() { + return &obj_; + } +}; + +} // namespace scs + +#endif // SCS_SINGLETON_H diff --git a/hermes_shm/include/hermes_shm/util/timer.h b/hermes_shm/include/hermes_shm/util/timer.h new file mode 100644 index 000000000..3561c5d18 --- /dev/null +++ b/hermes_shm/include/hermes_shm/util/timer.h @@ -0,0 +1,96 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_TIMER_H +#define HERMES_SHM_TIMER_H + +#include +#include +#include + +namespace hermes_shm { + +template +class TimerBase { + private: + std::chrono::time_point start_, end_; + double time_ns_; + + public: + TimerBase() : time_ns_(0) {} + + void Resume() { + start_ = T::now(); + } + double Pause() { + time_ns_ += GetNsecFromStart(); + return time_ns_; + } + double Pause(double &dt) { + dt = GetNsecFromStart(); + time_ns_ += dt; + return time_ns_; + } + void Reset() { + time_ns_ = 0; + } + + double GetNsecFromStart() { + end_ = T::now(); + double elapsed = std::chrono::duration_cast( + end_ - start_).count(); + return elapsed; + } + double GetUsecFromStart() { + end_ = T::now(); + return std::chrono::duration_cast( + end_ - start_).count(); + } + double GetMsecFromStart() { + end_ = T::now(); + return std::chrono::duration_cast( + end_ - start_).count(); + } + double GetSecFromStart() { + end_ = T::now(); + return std::chrono::duration_cast( + end_ - start_).count(); + } + + double GetNsec() const { + return time_ns_; + } + double GetUsec() const { + return time_ns_/1000; + } + double GetMsec() const { + return time_ns_/1000000; + } + double GetSec() const { + return time_ns_/1000000000; + } + + double GetUsFromEpoch() const { + std::chrono::time_point point = + std::chrono::system_clock::now(); + return std::chrono::duration_cast( + point.time_since_epoch()).count(); + } +}; + +typedef TimerBase HighResCpuTimer; +typedef TimerBase HighResMonotonicTimer; +typedef HighResMonotonicTimer Timer; + +} // namespace hermes_shm + +#endif // HERMES_SHM_TIMER_H diff --git a/hermes_shm/src/CMakeLists.txt b/hermes_shm/src/CMakeLists.txt new file mode 100644 index 000000000..10de1020a --- /dev/null +++ b/hermes_shm/src/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +##################Build HermesShm main packages +add_library(hermes_shm_data_structures + ${CMAKE_CURRENT_SOURCE_DIR}/thread/mutex.cc + ${CMAKE_CURRENT_SOURCE_DIR}/thread/rwlock.cc + ${CMAKE_CURRENT_SOURCE_DIR}/memory/malloc_allocator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/memory/stack_allocator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/memory/memory_manager.cc + ${CMAKE_CURRENT_SOURCE_DIR}/data_structure_singleton.cc) +target_link_libraries(hermes_shm_data_structures + yaml-cpp pthread -lrt -ldl) + +##################Install HermesShm +install(TARGETS + hermes_shm_data_structures + EXPORT + ${HERMES_EXPORTED_TARGETS} + LIBRARY DESTINATION ${HERMES_INSTALL_LIB_DIR} + ARCHIVE DESTINATION ${HERMES_INSTALL_LIB_DIR} + RUNTIME DESTINATION ${HERMES_INSTALL_BIN_DIR}) + +##################COVERAGE +if(HERMES_ENABLE_COVERAGE) + set_coverage_flags(hermes_shm_data_structures) +endif() + +#----------------------------------------------------------------------------- +# Export all exported targets to the build tree for use by parent project +#----------------------------------------------------------------------------- +set(HERMES_EXPORTED_LIBS + hermes_shm_data_structures + ${HERMES_EXPORTED_LIBS}) +if(NOT HERMES_EXTERNALLY_CONFIGURED) + EXPORT ( + TARGETS + ${HERMES_EXPORTED_LIBS} + FILE + ${HERMES_EXPORTED_TARGETS}.cmake + ) +endif() \ No newline at end of file diff --git a/hermes_shm/src/data_structure_singleton.cc b/hermes_shm/src/data_structure_singleton.cc new file mode 100644 index 000000000..309f96b0c --- /dev/null +++ b/hermes_shm/src/data_structure_singleton.cc @@ -0,0 +1,23 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include +#include + +#include +template<> hermes_shm::SystemInfo scs::Singleton::obj_ = hermes_shm::SystemInfo(); +#include +template<> hermes_shm::ipc::MemoryManager scs::Singleton::obj_ = hermes_shm::ipc::MemoryManager(); +#include +template<> hermes_shm::ThreadManager scs::Singleton::obj_ = hermes_shm::ThreadManager(); diff --git a/hermes_shm/src/memory/malloc_allocator.cc b/hermes_shm/src/memory/malloc_allocator.cc new file mode 100644 index 000000000..313e5c5d2 --- /dev/null +++ b/hermes_shm/src/memory/malloc_allocator.cc @@ -0,0 +1,79 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +namespace hermes_shm::ipc { + +struct MallocPage { + size_t page_size_; +}; + +void MallocAllocator::shm_init(MemoryBackend *backend, + allocator_id_t id, + size_t custom_header_size) { + backend_ = backend; + header_ = reinterpret_cast( + malloc(sizeof(MallocAllocatorHeader) + custom_header_size)); + custom_header_ = reinterpret_cast(header_ + 1); + header_->Configure(id, custom_header_size); +} + +void MallocAllocator::shm_deserialize(MemoryBackend *backend) { + throw NOT_IMPLEMENTED.format("MallocAllocator::shm_deserialize"); +} + +size_t MallocAllocator::GetCurrentlyAllocatedSize() { + return header_->total_alloc_size_; +} + +OffsetPointer MallocAllocator::AllocateOffset(size_t size) { + auto page = reinterpret_cast( + malloc(sizeof(MallocPage) + size)); + page->page_size_ = size; + header_->total_alloc_size_ += size; + return OffsetPointer(size_t(page + 1)); +} + +OffsetPointer MallocAllocator::AlignedAllocateOffset(size_t size, + size_t alignment) { + auto page = reinterpret_cast( + aligned_alloc(alignment, sizeof(MallocPage) + size)); + page->page_size_ = size; + header_->total_alloc_size_ += size; + return OffsetPointer(size_t(page + 1)); +} + +OffsetPointer MallocAllocator::ReallocateOffsetNoNullCheck(OffsetPointer p, + size_t new_size) { + // Get the input page + auto page = reinterpret_cast( + p.off_.load() - sizeof(MallocPage)); + header_->total_alloc_size_ += new_size - page->page_size_; + + // Reallocate the input page + auto new_page = reinterpret_cast( + realloc(page, sizeof(MallocPage) + new_size)); + new_page->page_size_ = new_size; + + // Create the pointer + return OffsetPointer(size_t(new_page + 1)); +} + +void MallocAllocator::FreeOffsetNoNullCheck(OffsetPointer p) { + auto page = reinterpret_cast( + p.off_.load() - sizeof(MallocPage)); + header_->total_alloc_size_ -= page->page_size_; + free(page); +} + +} // namespace hermes_shm::ipc diff --git a/hermes_shm/src/memory/memory_intercept.cc b/hermes_shm/src/memory/memory_intercept.cc new file mode 100644 index 000000000..c8109e4fc --- /dev/null +++ b/hermes_shm/src/memory/memory_intercept.cc @@ -0,0 +1,93 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include "hermes_shm/memory/memory_manager.h" + +using hermes_shm::ipc::Pointer; +using hermes_shm::ipc::Allocator; + +/** Allocate SIZE bytes of memory. */ +void* malloc(size_t size) { + auto alloc = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + return alloc->AllocatePtr(size); +} + +/** Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ +void* calloc(size_t nmemb, size_t size) { + auto alloc = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + return alloc->ClearAllocatePtr(nmemb * size); +} + +/** + * Re-allocate the previously allocated block in ptr, making the new + * block SIZE bytes long. + * */ +void* realloc(void *ptr, size_t size) { + Pointer p = HERMES_SHM_MEMORY_MANAGER->Convert(ptr); + auto alloc = HERMES_SHM_MEMORY_MANAGER->GetAllocator(p.allocator_id_); + return alloc->AllocatePtr(size); +} + +/** + * Re-allocate the previously allocated block in PTR, making the new + * block large enough for NMEMB elements of SIZE bytes each. + * */ +void* reallocarray(void *ptr, size_t nmemb, size_t size) { + return realloc(ptr, nmemb * size); +} + +/** Free a block allocated by `malloc', `realloc' or `calloc'. */ +void free(void *ptr) { + Pointer p = HERMES_SHM_MEMORY_MANAGER->Convert(ptr); + auto alloc = HERMES_SHM_MEMORY_MANAGER->GetAllocator(p.allocator_id_); + alloc->Free(p); +} + +/** Allocate SIZE bytes allocated to ALIGNMENT bytes. */ +void* memalign(size_t alignment, size_t size) { + // TODO(llogan): need to add an aligned allocator + return malloc(size); +} + +/** Allocate SIZE bytes on a page boundary. */ +void* valloc(size_t size) { + return memalign(HERMES_SHM_SYSTEM_INFO->page_size_, size); +} + +/** + * Equivalent to valloc(minimum-page-that-holds(n)), + * that is, round up size to nearest pagesize. + * */ +void* pvalloc(size_t size) { + size_t new_size = hermes_shm::ipc::NextPageSizeMultiple(size); + return valloc(new_size); +} + +/** + * Allocates size bytes and places the address of the + * allocated memory in *memptr. The address of the allocated memory + * will be a multiple of alignment, which must be a power of two and a multiple + * of sizeof(void *). Returns NULL if size is 0. */ +int posix_memalign(void **memptr, size_t alignment, size_t size) { + (*memptr) = memalign(alignment, size); + return 0; +} + +/** + * Aligned to an alignment with a size that is a multiple of the + * alignment + * */ +void *aligned_alloc(size_t alignment, size_t size) { + return memalign(alignment, hermes_shm::ipc::NextAlignmentMultiple(alignment, size)); +} diff --git a/hermes_shm/src/memory/memory_intercept.h b/hermes_shm/src/memory/memory_intercept.h new file mode 100644 index 000000000..6c86ac713 --- /dev/null +++ b/hermes_shm/src/memory/memory_intercept.h @@ -0,0 +1,18 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_SRC_MEMORY_MEMORY_INTERCEPT_H_ +#define HERMES_SHM_SRC_MEMORY_MEMORY_INTERCEPT_H_ + + + +#endif //HERMES_SHM_SRC_MEMORY_MEMORY_INTERCEPT_H_ diff --git a/hermes_shm/src/memory/memory_manager.cc b/hermes_shm/src/memory/memory_manager.cc new file mode 100644 index 000000000..2ce79e735 --- /dev/null +++ b/hermes_shm/src/memory/memory_manager.cc @@ -0,0 +1,45 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include "hermes_shm/memory/backend/memory_backend_factory.h" +#include "hermes_shm/memory/allocator/allocator_factory.h" +#include + +namespace hermes_shm::ipc { + +MemoryBackend* MemoryManager::GetBackend(const std::string &url) { + return backends_[url].get(); +} + +void MemoryManager::DestroyBackend(const std::string &url) { + auto backend = GetBackend(url); + backend->shm_destroy(); + backends_.erase(url); +} + +void MemoryManager::ScanBackends() { + for (auto &[url, backend] : backends_) { + auto alloc = AllocatorFactory::shm_deserialize(backend.get()); + RegisterAllocator(alloc); + } +} + +void MemoryManager::RegisterAllocator(std::unique_ptr &alloc) { + if (default_allocator_ == nullptr || + default_allocator_ == &root_allocator_) { + default_allocator_ = alloc.get(); + } + allocators_.emplace(alloc->GetId(), std::move(alloc)); +} + +} // namespace hermes_shm::ipc diff --git a/hermes_shm/src/memory/stack_allocator.cc b/hermes_shm/src/memory/stack_allocator.cc new file mode 100644 index 000000000..622323187 --- /dev/null +++ b/hermes_shm/src/memory/stack_allocator.cc @@ -0,0 +1,76 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include + +namespace hermes_shm::ipc { + +void StackAllocator::shm_init(MemoryBackend *backend, + allocator_id_t id, + size_t custom_header_size) { + backend_ = backend; + header_ = reinterpret_cast(backend_->data_); + custom_header_ = reinterpret_cast(header_ + 1); + size_t region_off = (custom_header_ - backend_->data_) + custom_header_size; + size_t region_size = backend_->data_size_ - region_off; + header_->Configure(id, custom_header_size, region_off, region_size); +} + +void StackAllocator::shm_deserialize(MemoryBackend *backend) { + backend_ = backend; + header_ = reinterpret_cast(backend_->data_); + custom_header_ = reinterpret_cast(header_ + 1); +} + +size_t StackAllocator::GetCurrentlyAllocatedSize() { + return header_->total_alloc_; +} + +OffsetPointer StackAllocator::AllocateOffset(size_t size) { + size += sizeof(MpPage); + OffsetPointer p(header_->region_off_.fetch_add(size)); + auto hdr = Convert(p); + hdr->SetAllocated(); + hdr->page_size_ = size; + header_->region_size_.fetch_sub(hdr->page_size_); + header_->total_alloc_.fetch_add(hdr->page_size_); + return p + sizeof(MpPage); +} + +OffsetPointer StackAllocator::AlignedAllocateOffset(size_t size, + size_t alignment) { + throw ALIGNED_ALLOC_NOT_SUPPORTED.format(); +} + +OffsetPointer StackAllocator::ReallocateOffsetNoNullCheck(OffsetPointer p, + size_t new_size) { + OffsetPointer new_p; + void *src = Convert(p); + auto hdr = Convert(p - sizeof(MpPage)); + size_t old_size = hdr->page_size_ - sizeof(MpPage); + void *dst = AllocatePtr(new_size, new_p); + memcpy(dst, src, old_size); + Free(p); + return new_p; +} + +void StackAllocator::FreeOffsetNoNullCheck(OffsetPointer p) { + auto hdr = Convert(p - sizeof(MpPage)); + if (!hdr->IsAllocated()) { + throw DOUBLE_FREE.format(); + } + hdr->UnsetAllocated(); + header_->total_alloc_.fetch_sub(hdr->page_size_); +} + +} // namespace hermes_shm::ipc diff --git a/hermes_shm/src/thread/mutex.cc b/hermes_shm/src/thread/mutex.cc new file mode 100644 index 000000000..4f0ef3b60 --- /dev/null +++ b/hermes_shm/src/thread/mutex.cc @@ -0,0 +1,96 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "hermes_shm/thread/lock.h" +#include "hermes_shm/thread/thread_manager.h" + +namespace hermes_shm { + +/** + * Acquire the mutex + * */ +void Mutex::Lock() { + auto thread_info = HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + while (!TryLock()) { + thread_info->Yield(); + } +} + +/** + * Attempt to acquire the mutex + * */ +bool Mutex::TryLock() { + if (lock_.load() != 0) return false; + uint32_t tkt = lock_.fetch_add(1); + if (tkt != 0) { + lock_.fetch_sub(1); + return false; + } + return true; +} + +/** + * Release the mutex + * */ +void Mutex::Unlock() { + lock_.fetch_sub(1); +} + +/** + * SCOPED MUTEX + * */ + +/** + * Constructor + * */ +ScopedMutex::ScopedMutex(Mutex &lock) +: lock_(lock), is_locked_(false) { +} + +/** + * Release the mutex + * */ +ScopedMutex::~ScopedMutex() { + Unlock(); +} + +/** + * Acquire the mutex + * */ +void ScopedMutex::Lock() { + if (!is_locked_) { + lock_.Lock(); + is_locked_ = true; + } +} + +/** + * Attempt to acquire the mutex + * */ +bool ScopedMutex::TryLock() { + if (!is_locked_) { + is_locked_ = lock_.TryLock(); + } + return is_locked_; +} + +/** + * Acquire the mutex + * */ +void ScopedMutex::Unlock() { + if (is_locked_) { + lock_.Unlock(); + is_locked_ = false; + } +} + +} // namespace hermes_shm diff --git a/hermes_shm/src/thread/rwlock.cc b/hermes_shm/src/thread/rwlock.cc new file mode 100644 index 000000000..5554d7c4a --- /dev/null +++ b/hermes_shm/src/thread/rwlock.cc @@ -0,0 +1,192 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "hermes_shm/thread/lock/rwlock.h" +#include "hermes_shm/thread/thread_manager.h" + +namespace hermes_shm { + +/** + * Acquire the read lock + * */ +void RwLock::ReadLock() { + bool ret = false; + RwLockPayload expected, desired; + auto thread_info = HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + do { + expected.as_int_ = payload_.load(); + if (expected.IsWriteLocked()) { + thread_info->Yield(); + continue; + } + desired = expected; + desired.bits_.r_ += 1; + ret = payload_.compare_exchange_weak( + expected.as_int_, + desired.as_int_); + } while (!ret); +} + +/** + * Release the read lock + * */ +void RwLock::ReadUnlock() { + bool ret; + RwLockPayload expected, desired; + do { + expected.as_int_ = payload_.load(); + desired = expected; + desired.bits_.r_ -= 1; + ret = payload_.compare_exchange_weak( + expected.as_int_, + desired.as_int_); + } while (!ret); +} + +/** + * Acquire the write lock + * */ +void RwLock::WriteLock() { + bool ret = false; + RwLockPayload expected, desired; + auto thread_info = HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + do { + expected.as_int_ = payload_.load(); + if (expected.IsReadLocked()) { + thread_info->Yield(); + continue; + } + if (expected.IsWriteLocked()) { + thread_info->Yield(); + continue; + } + desired = expected; + desired.bits_.w_ += 1; + ret = payload_.compare_exchange_weak( + expected.as_int_, + desired.as_int_); + } while (!ret); +} + +/** + * Release the write lock + * */ +void RwLock::WriteUnlock() { + bool ret; + RwLockPayload expected, desired; + do { + expected.as_int_ = payload_.load(); + desired = expected; + desired.bits_.w_ -= 1; + ret = payload_.compare_exchange_weak( + expected.as_int_, + desired.as_int_); + } while (!ret); +} + +/** + * Verify the reference count for reads (for debugging) + * */ +void RwLock::assert_r_refcnt(int ref) { + if (RwLockPayload(payload_).bits_.r_ != ref) { + throw 1; + } +} + +/** + * Verify the reference count for writes (for debugging) + * */ +void RwLock::assert_w_refcnt(int ref) { + if (RwLockPayload(payload_).bits_.w_ > 1) { + throw 1; + } +} + +/** + * SCOPED R/W READ LOCK + * */ + +/** + * Constructor + * */ +ScopedRwReadLock::ScopedRwReadLock(RwLock &lock) +: lock_(lock), is_locked_(false) { + Lock(); +} + +/** + * Release the read lock + * */ +ScopedRwReadLock::~ScopedRwReadLock() { + Unlock(); +} + +/** + * Acquire the read lock + * */ +void ScopedRwReadLock::Lock() { + if (!is_locked_) { + lock_.ReadLock(); + is_locked_ = true; + } +} + +/** + * Release the read lock + * */ +void ScopedRwReadLock::Unlock() { + if (is_locked_) { + lock_.ReadUnlock(); + is_locked_ = false; + } +} + +/** + * SCOPED R/W WRITE LOCK + * */ + +/** + * Constructor + * */ +ScopedRwWriteLock::ScopedRwWriteLock(RwLock &lock) +: lock_(lock), is_locked_(false) { + Lock(); +} + +/** + * Release the write lock + * */ +ScopedRwWriteLock::~ScopedRwWriteLock() { + Unlock(); +} + +/** + * Acquire the write lock + * */ +void ScopedRwWriteLock::Lock() { + if (!is_locked_) { + lock_.WriteLock(); + is_locked_ = true; + } +} + +/** + * Release the write lock + * */ +void ScopedRwWriteLock::Unlock() { + if (is_locked_) { + lock_.WriteUnlock(); + is_locked_ = false; + } +} + +} // namespace hermes_shm diff --git a/hermes_shm/test/CMakeLists.txt b/hermes_shm/test/CMakeLists.txt new file mode 100644 index 000000000..81aad4158 --- /dev/null +++ b/hermes_shm/test/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_subdirectory(unit) \ No newline at end of file diff --git a/hermes_shm/test/unit/CMakeLists.txt b/hermes_shm/test/unit/CMakeLists.txt new file mode 100644 index 000000000..d14daaa58 --- /dev/null +++ b/hermes_shm/test/unit/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +set(TEST_MAIN ${CMAKE_CURRENT_SOURCE_DIR}) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +add_subdirectory(data_structures) +add_subdirectory(allocators) +add_subdirectory(types) \ No newline at end of file diff --git a/hermes_shm/test/unit/allocators/CMakeLists.txt b/hermes_shm/test/unit/allocators/CMakeLists.txt new file mode 100644 index 000000000..b6328e0c2 --- /dev/null +++ b/hermes_shm/test/unit/allocators/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(test_allocator_exec + ${TEST_MAIN}/main.cc + test_init.cc + allocator.cc + allocator_thread.cc) +add_dependencies(test_allocator_exec hermes_shm_data_structures) +target_link_libraries(test_allocator_exec + hermes_shm_data_structures Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) + +# PAGE ALLOCATOR TESTS +add_test(NAME test_page_allocator COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_allocator_exec "StackAllocator") +add_test(NAME test_page_allocator_4t COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_allocator_exec "StackAllocatorMultithreaded") diff --git a/hermes_shm/test/unit/allocators/allocator.cc b/hermes_shm/test/unit/allocators/allocator.cc new file mode 100644 index 000000000..5218f35f2 --- /dev/null +++ b/hermes_shm/test/unit/allocators/allocator.cc @@ -0,0 +1,135 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "test_init.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" + +void PageAllocationTest(Allocator *alloc) { + int count = 1024; + size_t page_size = KILOBYTES(4); + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + + // Allocate pages + std::vector ps(count); + void *ptrs[count]; + for (int i = 0; i < count; ++i) { + ptrs[i] = alloc->AllocatePtr(page_size, ps[i]); + memset(ptrs[i], i, page_size); + REQUIRE(ps[i].off_.load() != 0); + REQUIRE(!ps[i].IsNull()); + REQUIRE(ptrs[i] != nullptr); + } + + // Convert process pointers into independent pointers + for (int i = 0; i < count; ++i) { + Pointer p = mem_mngr->Convert(ptrs[i]); + REQUIRE(p == ps[i]); + REQUIRE(VerifyBuffer((char*)ptrs[i], page_size, i)); + } + + // Check the custom header + auto hdr = alloc->GetCustomHeader(); + REQUIRE(hdr->checksum_ == HEADER_CHECKSUM); + + // Free pages + for (int i = 0; i < count; ++i) { + alloc->Free(ps[i]); + } + + // Reallocate pages + for (int i = 0; i < count; ++i) { + ptrs[i] = alloc->AllocatePtr(page_size, ps[i]); + REQUIRE(ps[i].off_.load() != 0); + REQUIRE(!ps[i].IsNull()); + } + + // Free again + for (int i = 0; i < count; ++i) { + alloc->Free(ps[i]); + } +} + +void MultiPageAllocationTest(Allocator *alloc) { + size_t alloc_sizes[] = { + 64, 128, 256, + KILOBYTES(1), KILOBYTES(4), KILOBYTES(64), + MEGABYTES(1), MEGABYTES(16), MEGABYTES(32) + }; + + // Allocate and free pages between 64 bytes and 1MB + { + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + for (size_t r = 0; r < 10; ++r) { + for (size_t i = 0; i < 1000; ++i) { + Pointer ps[4]; + for (size_t j = 0; j < 4; ++j) { + ps[j] = alloc->Allocate(alloc_sizes[i % 9]); + } + for (size_t j = 0; j < 4; ++j) { + alloc->Free(ps[j]); + } + } + } + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + } + + // Aligned allocate 4KB pages + { + for (size_t i = 0; i < 1024; ++i) { + Pointer p = alloc->AlignedAllocate(KILOBYTES(4), KILOBYTES(4)); + memset(alloc->Convert(p), 0, KILOBYTES(4)); + alloc->Free(p); + } + } + + // Reallocate a 4KB page to 16KB + { + Pointer p = alloc->Allocate(KILOBYTES(4)); + alloc->Reallocate(p, KILOBYTES(16)); + memset(alloc->Convert(p), 0, KILOBYTES(16)); + alloc->Free(p); + } +} + +TEST_CASE("StackAllocator") { + auto alloc = Pretest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + PageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + Posttest(); +} + +TEST_CASE("MultiPageAllocator") { + auto alloc = Pretest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + PageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + MultiPageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + + Posttest(); +} + +TEST_CASE("MallocAllocator") { + auto alloc = Pretest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + PageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + MultiPageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + + Posttest(); +} diff --git a/hermes_shm/test/unit/allocators/allocator_thread.cc b/hermes_shm/test/unit/allocators/allocator_thread.cc new file mode 100644 index 000000000..b76762f63 --- /dev/null +++ b/hermes_shm/test/unit/allocators/allocator_thread.cc @@ -0,0 +1,42 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "test_init.h" + +void MultiThreadedPageAllocationTest(Allocator *alloc) { + int nthreads = 8; + HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + + omp_set_dynamic(0); +#pragma omp parallel shared(alloc) num_threads(nthreads) + { +#pragma omp barrier + PageAllocationTest(alloc); +#pragma omp barrier + } +} + +TEST_CASE("StackAllocatorMultithreaded") { + auto alloc = Pretest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + MultiThreadedPageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + Posttest(); +} + +TEST_CASE("MultiPageAllocatorMultithreaded") { + auto alloc = Pretest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + MultiThreadedPageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + Posttest(); +} diff --git a/hermes_shm/test/unit/allocators/test_init.cc b/hermes_shm/test/unit/allocators/test_init.cc new file mode 100644 index 000000000..4b0042a82 --- /dev/null +++ b/hermes_shm/test/unit/allocators/test_init.cc @@ -0,0 +1,23 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "test_init.h" + +void Posttest() { + std::string shm_url = "test_allocators"; + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + mem_mngr->DestroyBackend(shm_url); +} + +void MainPretest() {} + +void MainPosttest() {} diff --git a/hermes_shm/test/unit/allocators/test_init.h b/hermes_shm/test/unit/allocators/test_init.h new file mode 100644 index 000000000..53e532efd --- /dev/null +++ b/hermes_shm/test/unit/allocators/test_init.h @@ -0,0 +1,52 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ +#define HERMES_SHM_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ + +#include "basic_test.h" +#include "omp.h" +#include "hermes_shm/memory/memory_manager.h" + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::MemoryManager; +using hermes_shm::ipc::Pointer; + +#define HEADER_CHECKSUM 8482942 + +struct SimpleAllocatorHeader { + int checksum_; +}; + +template +Allocator* Pretest() { + std::string shm_url = "test_allocators"; + allocator_id_t alloc_id(0, 1); + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + mem_mngr->CreateBackend( + MemoryManager::kDefaultBackendSize, shm_url); + mem_mngr->CreateAllocator( + shm_url, alloc_id, sizeof(SimpleAllocatorHeader)); + auto alloc = mem_mngr->GetAllocator(alloc_id); + auto hdr = alloc->GetCustomHeader(); + hdr->checksum_ = HEADER_CHECKSUM; + return alloc; +} + +void Posttest(); +void PageAllocationTest(Allocator *alloc); + +#endif // HERMES_SHM_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ diff --git a/hermes_shm/test/unit/basic_test.h b/hermes_shm/test/unit/basic_test.h new file mode 100644 index 000000000..e669ed34e --- /dev/null +++ b/hermes_shm/test/unit/basic_test.h @@ -0,0 +1,68 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ +#define HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ + +#define CATCH_CONFIG_RUNNER +#include + +namespace cl = Catch::Clara; +cl::Parser define_options(); + +#include +#include + +static bool VerifyBuffer(char *ptr, size_t size, char nonce) { + for (size_t i = 0; i < size; ++i) { + if (ptr[i] != nonce) { + std::cout << (int)ptr[i] << std::endl; + return false; + } + } + return true; +} + +/** var = TYPE(val) */ +#define SET_VAR_TO_INT_OR_STRING(TYPE, VAR, VAL)\ + if constexpr(std::is_same_v) {\ + VAR = hipc::string(std::to_string(VAL));\ + } else if constexpr(std::is_same_v) {\ + VAR = std::string(std::to_string(VAL));\ + } else {\ + VAR = VAL;\ + } + +/** TYPE VAR = TYPE(VAL) */ +#define CREATE_SET_VAR_TO_INT_OR_STRING(TYPE, VAR, VAL)\ + TYPE VAR;\ + SET_VAR_TO_INT_OR_STRING(TYPE, VAR, VAL); + +/** RET = int(TYPE(VAR)); */ +#define GET_INT_FROM_VAR(TYPE, RET, VAR)\ + if constexpr(std::is_same_v) {\ + RET = atoi((VAR).str().c_str());\ + } else if constexpr(std::is_same_v) {\ + RET = atoi((VAR).c_str());\ + } else {\ + RET = VAR;\ + } + +/** int RET = int(TYPE(VAR)); */ +#define CREATE_GET_INT_FROM_VAR(TYPE, RET, VAR)\ + int RET;\ + GET_INT_FROM_VAR(TYPE, RET, VAR) + +void MainPretest(); +void MainPosttest(); + +#endif // HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ diff --git a/hermes_shm/test/unit/data_structures/CMakeLists.txt b/hermes_shm/test/unit/data_structures/CMakeLists.txt new file mode 100644 index 000000000..0db1dd7ff --- /dev/null +++ b/hermes_shm/test/unit/data_structures/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +include_directories(${CMAKE_SOURCE_DIR}/test/unit) +add_subdirectory(backend) +add_subdirectory(containers) +add_subdirectory(containers_mpi) +add_subdirectory(lock) \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/backend/CMakeLists.txt b/hermes_shm/test/unit/data_structures/backend/CMakeLists.txt new file mode 100644 index 000000000..fb2b751eb --- /dev/null +++ b/hermes_shm/test/unit/data_structures/backend/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(test_memory_exec + ${TEST_MAIN}/main_mpi.cc + test_init.cc + backend.cc + memory_slots.cc + memory_manager.cc) +add_dependencies(test_memory_exec hermes_shm_data_structures) +target_link_libraries(test_memory_exec + hermes_shm_data_structures Catch2::Catch2 MPI::MPI_CXX) + +# TESTS +add_test(NAME test_memory_slots COMMAND + mpirun -n 2 ${CMAKE_CURRENT_BINARY_DIR}/test_memory_exec "MemorySlot") +add_test(NAME test_reserve COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_memory_exec "BackendReserve") +add_test(NAME test_memory_manager COMMAND + mpirun -n 2 ${CMAKE_CURRENT_BINARY_DIR}/test_memory_exec "MemoryManager") \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/backend/backend.cc b/hermes_shm/test/unit/data_structures/backend/backend.cc new file mode 100644 index 000000000..fa7b8a53a --- /dev/null +++ b/hermes_shm/test/unit/data_structures/backend/backend.cc @@ -0,0 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" + +#include "hermes_shm/memory/backend/posix_shm_mmap.h" + +using hermes_shm::ipc::PosixShmMmap; + +TEST_CASE("BackendReserve") { + PosixShmMmap b1; + + // Reserve + Map 8GB of memory + b1.shm_init(GIGABYTES(8), "shmem_test"); + + // Set 2GB of SHMEM + memset(b1.data_, 0, GIGABYTES(2)); + + // Destroy SHMEM + b1.shm_destroy(); +} diff --git a/hermes_shm/test/unit/data_structures/backend/memory_manager.cc b/hermes_shm/test/unit/data_structures/backend/memory_manager.cc new file mode 100644 index 000000000..e6d6a6742 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/backend/memory_manager.cc @@ -0,0 +1,78 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" + +#include +#include "hermes_shm/memory/memory_manager.h" + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::MemoryManager; + +struct SimpleHeader { + hermes_shm::ipc::Pointer p_; +}; + +TEST_CASE("MemoryManager") { + int rank; + char nonce = 8; + size_t page_size = KILOBYTES(4); + std::string shm_url = "test_mem_backend"; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + allocator_id_t alloc_id(0, 1); + + HERMES_SHM_ERROR_HANDLE_START() + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + + if (rank == 0) { + std::cout << "Creating SHMEM (rank 0): " << shm_url << std::endl; + mem_mngr->CreateBackend( + MemoryManager::kDefaultBackendSize, shm_url); + mem_mngr->CreateAllocator( + shm_url, alloc_id, 0); + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank != 0) { + std::cout << "Attaching SHMEM (rank 1): " << shm_url << std::endl; + mem_mngr->AttachBackend(MemoryBackendType::kPosixShmMmap, shm_url); + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank == 0) { + std::cout << "Allocating pages (rank 0)" << std::endl; + hipc::Allocator *alloc = mem_mngr->GetAllocator(alloc_id); + char *page = alloc->AllocatePtr(page_size); + memset(page, nonce, page_size); + auto header = alloc->GetCustomHeader(); + hipc::Pointer p1 = mem_mngr->Convert(alloc_id, page); + hipc::Pointer p2 = mem_mngr->Convert(page); + header->p_ = p1; + REQUIRE(p1 == p2); + REQUIRE(VerifyBuffer(page, page_size, nonce)); + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank != 0) { + std::cout << "Finding and checking pages (rank 1)" << std::endl; + hipc::Allocator *alloc = mem_mngr->GetAllocator(alloc_id); + SimpleHeader *header = alloc->GetCustomHeader(); + char *page = alloc->Convert(header->p_); + REQUIRE(VerifyBuffer(page, page_size, nonce)); + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank == 0) { + mem_mngr->DestroyBackend(shm_url); + } + + HERMES_SHM_ERROR_HANDLE_END() +} diff --git a/hermes_shm/test/unit/data_structures/backend/memory_slots.cc b/hermes_shm/test/unit/data_structures/backend/memory_slots.cc new file mode 100644 index 000000000..f5df1a526 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/backend/memory_slots.cc @@ -0,0 +1,53 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" + +#include +#include +#include "hermes_shm/memory/backend/posix_shm_mmap.h" + +using hermes_shm::ipc::PosixShmMmap; + +TEST_CASE("MemorySlot") { + int rank; + char nonce = 8; + std::string shm_url = "test_mem_backend"; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + HERMES_SHM_ERROR_HANDLE_START() + + PosixShmMmap backend; + if (rank == 0) { + std::cout << "HERE?" << std::endl; + SECTION("Creating SHMEM (rank 0)") { + backend.shm_init(MEGABYTES(1), shm_url); + memset(backend.data_, nonce, backend.data_size_); + } + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank != 0) { + SECTION("Attaching SHMEM (rank 1)") { + backend.shm_deserialize(shm_url); + char *ptr = backend.data_; + REQUIRE(VerifyBuffer(ptr, backend.data_size_, nonce)); + } + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank == 0) { + SECTION("Destroying shmem (rank 1)") { + backend.shm_destroy(); + } + } + + HERMES_SHM_ERROR_HANDLE_END() +} diff --git a/hermes_shm/test/unit/data_structures/backend/test_init.cc b/hermes_shm/test/unit/data_structures/backend/test_init.cc new file mode 100644 index 000000000..7590f5764 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/backend/test_init.cc @@ -0,0 +1,17 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" + +void MainPretest() {} + +void MainPosttest() {} diff --git a/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt b/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt new file mode 100644 index 000000000..6b6cda3a6 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt @@ -0,0 +1,55 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(test_data_structure_exec + ${TEST_MAIN}/main.cc + test_init.cc + string.cc + pair.cc + list.cc + vector.cc + manual_ptr.cc + unordered_map.cc +) + +add_dependencies(test_data_structure_exec hermes_shm_data_structures) +target_link_libraries(test_data_structure_exec + hermes_shm_data_structures Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) + +# STRING TESTS +add_test(NAME test_string COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "String") + +# VECTOR TESTS +add_test(NAME test_vector_of_int COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "VectorOfInt") +add_test(NAME test_vector_of_string COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "VectorOfString") +add_test(NAME test_vector_of_list_of_string COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "VectorOfListOfString") + +# LIST TESTS +add_test(NAME test_list_of_int COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "ListOfInt") +add_test(NAME test_list_of_string COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "ListOfString") + +# MANUAL PTR TESTS +add_test(NAME test_manual_ptr_of_string COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "ManualPtrOfString") + +# UNIQUE PTR TESTS +add_test(NAME test_unique_ptr_of_string COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "UniquePtrOfString") + +# UNORDERED_MAP TESTS +add_test(NAME test_unordered_map_of_int_int COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "UnorderedMapOfIntInt") +add_test(NAME test_unordered_map_of_int_str COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "UnorderedMapOfIntString") +add_test(NAME test_unordered_map_of_str_int COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "UnorderedMapOfStringInt") +add_test(NAME test_unordered_map_of_str_str COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_exec "UnorderedMapOfStringString") diff --git a/hermes_shm/test/unit/data_structures/containers/list.cc b/hermes_shm/test/unit/data_structures/containers/list.cc new file mode 100644 index 000000000..e13939ed9 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/list.cc @@ -0,0 +1,60 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include "test_init.h" +#include "list.h" +#include "hermes_shm/data_structures/thread_unsafe/list.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" + +using hermes_shm::ipc::list; + +template +void ListTest() { + Allocator *alloc = alloc_g; + list lp(alloc); + ListTestSuite> test(lp, alloc); + + test.EmplaceTest(30); + test.ForwardIteratorTest(); + test.ConstForwardIteratorTest(); + test.CopyConstructorTest(); + test.CopyAssignmentTest(); + test.MoveConstructorTest(); + test.MoveAssignmentTest(); + test.EmplaceFrontTest(); + test.ModifyEntryCopyIntoTest(); + test.ModifyEntryMoveIntoTest(); + test.EraseTest(); +} + +TEST_CASE("ListOfInt") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + ListTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("ListOfString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + ListTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("ListOfStdString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + ListTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} diff --git a/hermes_shm/test/unit/data_structures/containers/list.h b/hermes_shm/test/unit/data_structures/containers/list.h new file mode 100644 index 000000000..b5819eabb --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/list.h @@ -0,0 +1,192 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ +#define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ + +#include "basic_test.h" +#include "test_init.h" +#include + +template +class ListTestSuite { + public: + Container &obj_; + Allocator *alloc_; + + /// Constructor + ListTestSuite(Container &obj, Allocator *alloc) + : obj_(obj), alloc_(alloc) {} + + /// Emplace elements + void EmplaceTest(int count = 30) { + for (int i = 0; i < count; ++i) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, var, i); + obj_.emplace_back(var); + } + REQUIRE(obj_.size() == count); + } + + /// Forward iterator + void ForwardIteratorTest(int count = 30) { + int fcur = 0; + for (auto num : obj_) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, fcur_conv, fcur); + REQUIRE(*num == fcur_conv); + ++fcur; + } + } + + /// Constant Forward iterator + void ConstForwardIteratorTest(int count = 30) { + const Container &obj = obj_; + int fcur = 0; + for (auto iter = obj.cbegin(); iter != obj.cend(); ++iter) { + hipc::ShmRef num = *iter; + CREATE_SET_VAR_TO_INT_OR_STRING(T, fcur_conv, fcur); + REQUIRE(*num == fcur_conv); + ++fcur; + } + } + + /// Copy constructor + void CopyConstructorTest() { + int count = obj_.size(); + Container cpy(obj_); + VerifyCopy(obj_, cpy, count); + } + + /// Copy assignment + void CopyAssignmentTest() { + int count = obj_.size(); + Container cpy; + cpy = obj_; + VerifyCopy(obj_, cpy, count); + } + + /// Move constructor + void MoveConstructorTest() { + int count = obj_.size(); + Container cpy(std::move(obj_)); + VerifyMove(obj_, cpy, count); + obj_ = std::move(cpy); + VerifyMove(cpy, obj_, count); + } + + /// Move assignment + void MoveAssignmentTest() { + int count = obj_.size(); + Container cpy; + cpy = std::move(obj_); + VerifyMove(obj_, cpy, count); + obj_ = std::move(cpy); + VerifyMove(cpy, obj_, count); + } + + /// Emplace and erase front + void EmplaceFrontTest() { + CREATE_SET_VAR_TO_INT_OR_STRING(T, i0, 100); + int old_size = obj_.size(); + obj_.emplace_front(i0); + REQUIRE(*obj_.front() == i0); + REQUIRE(obj_.size() == old_size + 1); + obj_.erase(obj_.begin(), obj_.begin() + 1); + } + + /// Copy an object into the container + void ModifyEntryCopyIntoTest() { + // Modify the fourth list entry + { + CREATE_SET_VAR_TO_INT_OR_STRING(T, i4, 25); + auto iter = obj_.begin() + 4; + (**iter) = i4; + } + + // Verify the modification took place + { + CREATE_SET_VAR_TO_INT_OR_STRING(T, i4, 25); + auto iter = obj_.begin() + 4; + REQUIRE((**iter) == i4); + } + } + + /// Move an object into the container + void ModifyEntryMoveIntoTest() { + // Modify the fourth list entry + { + CREATE_SET_VAR_TO_INT_OR_STRING(T, i4, 25); + auto iter = obj_.begin() + 4; + (**iter) = std::move(i4); + } + + // Verify the modification took place + { + CREATE_SET_VAR_TO_INT_OR_STRING(T, i4, 25); + auto iter = obj_.begin() + 4; + REQUIRE((**iter) == i4); + } + } + + /// Verify erase + void EraseTest() { + obj_.clear(); + REQUIRE(obj_.size() == 0); + } + + private: + /// Verify copy construct/assign worked + void VerifyCopy(Container &obj, + Container &cpy, + int count) { + REQUIRE(obj_.size() == count); + REQUIRE(cpy.size() == count); + + // Verify obj + { + int fcur = 0; + for (auto num : obj_) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, fcur_conv, fcur); + REQUIRE(*num == fcur_conv); + ++fcur; + } + } + + // Verify copy + { + int fcur = 0; + for (auto num : cpy) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, fcur_conv, fcur); + REQUIRE(*num == fcur_conv); + ++fcur; + } + } + } + + /// Verify move worked + void VerifyMove(Container &orig_obj, + Container &new_obj, + int count) { + // Verify move into cpy worked + { + int fcur = 0; + REQUIRE(orig_obj.size() == 0); + REQUIRE(new_obj.size() == count); + for (auto num : new_obj) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, fcur_conv, fcur); + REQUIRE(*num == fcur_conv); + ++fcur; + } + } + } +}; + +#endif //HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ diff --git a/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc b/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc new file mode 100644 index 000000000..49f1a2d2a --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "hermes_shm/data_structures/smart_ptr/manual_ptr.h" +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" +#include "smart_ptr.h" + +using hermes_shm::ipc::string; +using hermes_shm::ipc::mptr; +using hermes_shm::ipc::mptr; +using hermes_shm::ipc::make_mptr; +using hermes_shm::ipc::TypedPointer; + +template +void ManualPtrTest() { + Allocator *alloc = alloc_g; + hipc::SmartPtrTestSuite> test; + CREATE_SET_VAR_TO_INT_OR_STRING(T, num, 25); + test.ptr_ = make_mptr(num); + test.DereferenceTest(num); + test.MoveConstructorTest(num); + test.MoveAssignmentTest(num); + test.CopyConstructorTest(num); + test.CopyAssignmentTest(num); + test.SerializeationConstructorTest(num); + test.SerializeationOperatorTest(num); + test.ptr_.shm_destroy(); +} + +TEST_CASE("ManualPtrOfString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + ManualPtrTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} diff --git a/hermes_shm/test/unit/data_structures/containers/pair.cc b/hermes_shm/test/unit/data_structures/containers/pair.cc new file mode 100644 index 000000000..aa047f447 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/pair.cc @@ -0,0 +1,64 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/pair.h" +#include "hermes_shm/data_structures/string.h" + +template +void PairTest() { + Allocator *alloc = alloc_g; + + // Construct test + { + CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); + CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); + hipc::pair data(alloc, first, second); + REQUIRE(*data.first_ == first); + REQUIRE(*data.second_ == second); + } + + // Copy test + { + CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); + CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); + hipc::pair data(alloc, first, second); + hipc::pair cpy(data); + REQUIRE(*cpy.first_ == first); + REQUIRE(*cpy.second_ == second); + } + + // Move test + { + CREATE_SET_VAR_TO_INT_OR_STRING(FirstT, first, 124); + CREATE_SET_VAR_TO_INT_OR_STRING(SecondT, second, 130); + hipc::pair data(alloc, first, second); + hipc::pair cpy(std::move(data)); + REQUIRE(*cpy.first_ == first); + REQUIRE(*cpy.second_ == second); + } +} + +TEST_CASE("PairOfIntInt") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + PairTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("PairOfIntString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + PairTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} diff --git a/hermes_shm/test/unit/data_structures/containers/smart_ptr.h b/hermes_shm/test/unit/data_structures/containers/smart_ptr.h new file mode 100644 index 000000000..3f56ed4a8 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/smart_ptr.h @@ -0,0 +1,84 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ +#define HERMES_SHM_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ + +#include "basic_test.h" +#include "test_init.h" + +namespace hermes_shm::ipc { + +template +class SmartPtrTestSuite { + public: + PointerT ptr_; + + public: + // Test dereference + void DereferenceTest(T &num) { + REQUIRE(ptr_.get_ref() == num); + REQUIRE(ptr_.get_ref_const() == num); + REQUIRE(*ptr_ == num); + } + + // Test move constructor + void MoveConstructorTest(T &num) { + PointerT ptr2(std::move(ptr_)); + REQUIRE(ptr_.IsNull()); + REQUIRE(std::hash{}(ptr2) == std::hash{}(num)); + ptr_ = std::move(ptr2); + } + + // Test move assignment operator + void MoveAssignmentTest(T &num) { + PointerT ptr2 = std::move(ptr_); + REQUIRE(ptr_.IsNull()); + REQUIRE(std::hash{}(ptr2) == std::hash{}(num)); + ptr_ = std::move(ptr2); + } + + // Test copy constructor + void CopyConstructorTest(T &num) { + PointerT ptr2(ptr_); + REQUIRE(*ptr_ == num); + REQUIRE(*ptr2 == num); + } + + // Test copy assignment + void CopyAssignmentTest(T &num) { + PointerT ptr2 = ptr_; + REQUIRE(*ptr_ == num); + REQUIRE(*ptr2 == num); + } + + // Test serialization + deserialization (constructor) + void SerializeationConstructorTest(T &num) { + TypedPointer ar; + ptr_ >> ar; + PointerT from_ar(ar); + REQUIRE(*from_ar == num); + } + + // Test serialization + deserialization (operator) + void SerializeationOperatorTest(T &num) { + TypedPointer ar; + ptr_ >> ar; + PointerT from_ar; + from_ar << ar; + REQUIRE(*from_ar == num); + } +}; + +} // namespace hermes_shm::ipc + +#endif //HERMES_SHM_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ diff --git a/hermes_shm/test/unit/data_structures/containers/string.cc b/hermes_shm/test/unit/data_structures/containers/string.cc new file mode 100644 index 000000000..104c198ea --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/string.cc @@ -0,0 +1,51 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" + +using hermes_shm::ipc::string; + +void TestString() { + Allocator *alloc = alloc_g; + + auto text1 = string("hello1"); + REQUIRE(text1 == "hello1"); + REQUIRE(text1 != "h"); + REQUIRE(text1 != "asdfklaf"); + + auto text2 = string("hello2"); + REQUIRE(text2 == "hello2"); + + string text3 = text1 + text2; + REQUIRE(text3 == "hello1hello2"); + + string text4(6); + memcpy(text4.data_mutable(), "hello4", strlen("hello4")); + + string text5 = text4; + REQUIRE(text5 == "hello4"); + REQUIRE(text5.header_ != text4.header_); + + string text6 = std::move(text5); + REQUIRE(text6 == "hello4"); +} + +TEST_CASE("String") { + Allocator *alloc = alloc_g; + REQUIRE(IS_SHM_ARCHIVEABLE(string)); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + TestString(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} diff --git a/hermes_shm/test/unit/data_structures/containers/test_init.cc b/hermes_shm/test/unit/data_structures/containers/test_init.cc new file mode 100644 index 000000000..df4498908 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/test_init.cc @@ -0,0 +1,34 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include "test_init.h" +#include + +#include "hermes_shm/memory/allocator/stack_allocator.h" + +Allocator *alloc_g = nullptr; + +void Posttest() { + std::string shm_url = "test_allocators"; + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + mem_mngr->DestroyBackend(shm_url); + alloc_g = nullptr; +} + +void MainPretest() { + Pretest(); +} + +void MainPosttest() { + Posttest(); +} diff --git a/hermes_shm/test/unit/data_structures/containers/test_init.h b/hermes_shm/test/unit/data_structures/containers/test_init.h new file mode 100644 index 000000000..041560218 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/test_init.h @@ -0,0 +1,49 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ +#define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ + +#include "hermes_shm/data_structures/data_structure.h" + +using hermes_shm::ipc::PosixShmMmap; +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::Pointer; + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::MemoryManager; +using hermes_shm::ipc::Pointer; + +extern Allocator *alloc_g; + +template +void Pretest() { + std::string shm_url = "test_allocators"; + allocator_id_t alloc_id(0, 1); + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + mem_mngr->CreateBackend( + MemoryManager::kDefaultBackendSize, shm_url); + mem_mngr->CreateAllocator(shm_url, alloc_id, 0); + alloc_g = mem_mngr->GetAllocator(alloc_id); +} + +void Posttest(); + +#endif // HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ diff --git a/hermes_shm/test/unit/data_structures/containers/unordered_map.cc b/hermes_shm/test/unit/data_structures/containers/unordered_map.cc new file mode 100644 index 000000000..afef50f08 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/unordered_map.cc @@ -0,0 +1,226 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/thread_unsafe/unordered_map.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::MemoryManager; +using hermes_shm::ipc::Pointer; +using hermes_shm::ipc::unordered_map; +using hermes_shm::ipc::string; + +#define GET_INT_FROM_KEY(VAR) CREATE_GET_INT_FROM_VAR(Key, key_ret, VAR) +#define GET_INT_FROM_VAL(VAR) CREATE_GET_INT_FROM_VAR(Val, val_ret, VAR) + +#define CREATE_KV_PAIR(KEY_NAME, KEY, VAL_NAME, VAL)\ + CREATE_SET_VAR_TO_INT_OR_STRING(Key, KEY_NAME, KEY); \ + CREATE_SET_VAR_TO_INT_OR_STRING(Val, VAL_NAME, VAL); + +template +void UnorderedMapOpTest() { + Allocator *alloc = alloc_g; + unordered_map map(alloc); + + // Insert 20 entries into the map (no growth trigger) + { + for (int i = 0; i < 20; ++i) { + CREATE_KV_PAIR(key, i, val, i); + map.emplace(key, val); + } + } + + // Check if the 20 entries are indexable + { + for (int i = 0; i < 20; ++i) { + CREATE_KV_PAIR(key, i, val, i); + REQUIRE(*(map[key]) == val); + } + } + + // Check if 20 entries are findable + { + for (int i = 0; i < 20; ++i) { + CREATE_KV_PAIR(key, i, val, i); + auto iter = map.find(key); + REQUIRE((*iter)->GetVal() == val); + } + } + + // Iterate over the map + { + // auto prep = map.iter_prep(); + // prep.Lock(); + int i = 0; + for (auto entry : map) { + GET_INT_FROM_KEY(entry->GetKey()); + GET_INT_FROM_VAL(entry->GetVal()); + REQUIRE((0 <= key_ret && key_ret < 20)); + REQUIRE((0 <= val_ret && val_ret < 20)); + ++i; + } + REQUIRE(i == 20); + } + + // Re-emplace elements + { + for (int i = 0; i < 20; ++i) { + CREATE_KV_PAIR(key, i, val, i + 100); + map.emplace(key, val); + REQUIRE(*(map[key]) == val); + } + } + + // Modify the fourth map entry (move assignment) + { + CREATE_KV_PAIR(key, 4, val, 25); + auto iter = map.find(key); + (*iter)->GetVal() = std::move(val); + REQUIRE((*iter)->GetVal() == val); + } + + // Verify the modification took place + { + CREATE_KV_PAIR(key, 4, val, 25); + REQUIRE(*(map[key]) == val); + } + + // Modify the fourth map entry (copy assignment) + { + CREATE_KV_PAIR(key, 4, val, 50); + auto iter = map.find(key); + (*iter)->GetVal() = val; + REQUIRE((*iter)->GetVal() == val); + } + + // Verify the modification took place + { + CREATE_KV_PAIR(key, 4, val, 50); + REQUIRE(*(map[key]) == val); + } + + // Modify the fourth map entry (copy assignment) + { + CREATE_KV_PAIR(key, 4, val, 100); + auto x = map[key]; + (*x) = val; + } + + // Verify the modification took place + { + CREATE_KV_PAIR(key, 4, val, 100); + REQUIRE(*map[key] == val); + } + + // Remove 15 entries from the map + { + for (int i = 0; i < 15; ++i) { + CREATE_KV_PAIR(key, i, val, i); + map.erase(key); + } + REQUIRE(map.size() == 5); + for (int i = 0; i < 15; ++i) { + CREATE_KV_PAIR(key, i, val, i); + REQUIRE(map.find(key) == map.end()); + } + } + + // Attempt to replace an existing key + { + for (int i = 15; i < 20; ++i) { + CREATE_KV_PAIR(key, i, val, 100); + REQUIRE(map.try_emplace(key, val) == false); + } + for (int i = 15; i < 20; ++i) { + CREATE_KV_PAIR(key, i, val, 100); + REQUIRE(*map[key] != val); + } + } + + // Erase the entire map + { + map.clear(); + REQUIRE(map.size() == 0); + } + + // Add 100 entries to the map (should force a growth) + { + for (int i = 0; i < 100; ++i) { + CREATE_KV_PAIR(key, i, val, i); + map.emplace(key, val); + REQUIRE(map.find(key) != map.end()); + } + for (int i = 0; i < 100; ++i) { + CREATE_KV_PAIR(key, i, val, i); + REQUIRE(map.find(key) != map.end()); + } + } + + // Copy the unordered_map + { + unordered_map cpy(map); + for (int i = 0; i < 100; ++i) { + CREATE_KV_PAIR(key, i, val, i); + REQUIRE(map.find(key) != map.end()); + REQUIRE(cpy.find(key) != cpy.end()); + } + } + + // Move the unordered_map + { + unordered_map cpy = std::move(map); + for (int i = 0; i < 100; ++i) { + CREATE_KV_PAIR(key, i, val, i); + REQUIRE(cpy.find(key) != cpy.end()); + } + map = std::move(cpy); + } + + // Emplace a move entry into the map + +} + +TEST_CASE("UnorderedMapOfIntInt") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + UnorderedMapOpTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("UnorderedMapOfIntString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + UnorderedMapOpTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + + +TEST_CASE("UnorderedMapOfStringInt") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + UnorderedMapOpTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("UnorderedMapOfStringString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + UnorderedMapOpTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} diff --git a/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc b/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc new file mode 100644 index 000000000..88e6bce50 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc @@ -0,0 +1,85 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "omp.h" +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/thread_safe/unordered_map.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" +#include "hermes_shm/util/errors.h" +#include + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::MemoryManager; +using hermes_shm::ipc::Pointer; +using hermes_shm::ipc::unordered_map; +using hermes_shm::ipc::string; + +void UnorderedMapParallelInsert() { + Allocator *alloc = alloc_g; + unordered_map map(alloc); + + int entries_per_thread = 50; + int nthreads = 4; + int total_entries = nthreads * entries_per_thread; + HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + + omp_set_dynamic(0); +#pragma omp parallel shared(alloc, map) num_threads(nthreads) + { + int rank = omp_get_thread_num(); + int off = rank*entries_per_thread; +#pragma omp barrier + // Insert entries into the map (no growth trigger) + { + for (int i = 0; i < entries_per_thread; ++i) { + int key = off + i; + int val = 2 * key; + auto t1 = string(std::to_string(key)); + auto t2 = string(std::to_string(val)); + + { + std::stringstream ss; + ss << "Emplace start: " << t1.str() << std::endl; + std::cout << ss.str(); + } + map.emplace(t1, t2); + { + std::stringstream ss; + ss << "Emplace end: " << t1.str() << std::endl; + std::cout << ss.str(); + } + } + } +#pragma omp barrier + } + REQUIRE(map.size() == total_entries); + + // Verify the map has all entries + for (int i = 0; i < total_entries; ++i) { + auto key = string(std::to_string(i)); + auto val = string(std::to_string(2*i)); + REQUIRE(*(map[key]) == val); + } +} + +TEST_CASE("UnorderedMapParallelInsert") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + UnorderedMapParallelInsert(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} diff --git a/hermes_shm/test/unit/data_structures/containers/vector.cc b/hermes_shm/test/unit/data_structures/containers/vector.cc new file mode 100644 index 000000000..66adca8ce --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/vector.cc @@ -0,0 +1,81 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/thread_unsafe/vector.h" +#include "hermes_shm/data_structures/thread_unsafe/list.h" +#include "hermes_shm/data_structures/string.h" +#include "vector.h" + +using hermes_shm::ipc::vector; +using hermes_shm::ipc::list; +using hermes_shm::ipc::string; + +template +void VectorTest() { + Allocator *alloc = alloc_g; + vector vec(alloc); + VectorTestSuite> test(vec, alloc); + + test.EmplaceTest(15); + test.IndexTest(); + test.ForwardIteratorTest(); + test.ConstForwardIteratorTest(); + test.CopyConstructorTest(); + test.CopyAssignmentTest(); + test.MoveConstructorTest(); + test.MoveAssignmentTest(); + test.EmplaceFrontTest(); + test.ModifyEntryCopyIntoTest(); + test.ModifyEntryMoveIntoTest(); + test.EraseTest(); +} + +void VectorOfListOfStringTest() { + Allocator *alloc = alloc_g; + vector> vec(alloc); + + vec.resize(10); + for (auto bkt : vec) { + (*bkt).emplace_back("hello"); + } + vec.clear(); +} + +TEST_CASE("VectorOfInt") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + VectorTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("VectorOfString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + VectorTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("VectorOfStdString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + VectorTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} + +TEST_CASE("VectorOfListOfString") { + Allocator *alloc = alloc_g; + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + VectorOfListOfStringTest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); +} diff --git a/hermes_shm/test/unit/data_structures/containers/vector.h b/hermes_shm/test/unit/data_structures/containers/vector.h new file mode 100644 index 000000000..9a1158164 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers/vector.h @@ -0,0 +1,37 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ +#define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ + +#include "list.h" + +template +class VectorTestSuite : public ListTestSuite { + public: + using ListTestSuite::obj_; + + public: + /// Constructor + VectorTestSuite(Container &obj, Allocator *alloc) + : ListTestSuite(obj, alloc) {} + + /// Test vector index operator + void IndexTest() { + for (int i = 0; i < obj_.size(); ++i) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, var, i); + REQUIRE(*obj_[i] == var); + } + } +}; + +#endif //HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/CMakeLists.txt b/hermes_shm/test/unit/data_structures/containers_mpi/CMakeLists.txt new file mode 100644 index 000000000..32e29ea53 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers_mpi/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(test_data_structure_mpi_exec + ${TEST_MAIN}/main_mpi.cc + test_init.cc + list_vec_mpi.cc +) + +add_dependencies(test_data_structure_mpi_exec hermes_shm_data_structures) +target_link_libraries(test_data_structure_mpi_exec + hermes_shm_data_structures Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) + +# VECTOR TESTS +add_test(NAME test_vector_of_int_mpi COMMAND + mpirun -n 4 ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_mpi_exec "VectorOfIntMpi") +add_test(NAME test_vector_of_string_mpi COMMAND + mpirun -n 1 ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_mpi_exec "VectorOfStringMpi") + +# LIST TESTS +add_test(NAME test_list_of_int_mpi COMMAND + mpirun -n 4 ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_mpi_exec "ListOfIntMpi") +add_test(NAME test_list_of_string_mpi COMMAND + mpirun -n 2 ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_mpi_exec "ListOfStringMpi") + +message("mpirun -n 1 ${CMAKE_CURRENT_BINARY_DIR}/test_data_structure_mpi_exec ListOfStringMpi") \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc b/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc new file mode 100644 index 000000000..73a2bc64e --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc @@ -0,0 +1,110 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include "test_init.h" +#include "hermes_shm/data_structures/string.h" +#include "hermes_shm/data_structures/thread_unsafe/list.h" +#include "hermes_shm/data_structures/thread_unsafe/vector.h" +#include "hermes_shm/util/error.h" + +template +void ListVecTest(size_t count) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + Allocator *alloc = alloc_g; + Pointer *header = alloc->GetCustomHeader(); + ContainerT obj; + + try { + if (rank == 0) { + obj.shm_init(alloc); + obj >> (*header); + } + MPI_Barrier(MPI_COMM_WORLD); + obj.shm_deserialize(*header); + MPI_Barrier(MPI_COMM_WORLD); + + // Write 100 objects from rank 0 + { + if (rank == 0) { + for (int i = 0; i < count; ++i) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, var, i); + obj.emplace_back(var); + } + } + MPI_Barrier(MPI_COMM_WORLD); + } + + // Read 100 objects from every rank + { + REQUIRE(obj.size() == count); + int i = 0; + for (hipc::ShmRef var : obj) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, orig, i); + REQUIRE(*var == orig); + ++i; + } + MPI_Barrier(MPI_COMM_WORLD); + } + + // Modify an object in rank 0 + { + if (rank == 0) { + CREATE_SET_VAR_TO_INT_OR_STRING(T, update, count); + hipc::ShmRef first = *obj.begin(); + (*first) = update; + } + MPI_Barrier(MPI_COMM_WORLD); + } + + // Check if modification received + { + CREATE_SET_VAR_TO_INT_OR_STRING(T, update, count); + hipc::ShmRef first = *obj.begin(); + REQUIRE((*first) == update); + MPI_Barrier(MPI_COMM_WORLD); + MPI_Barrier(MPI_COMM_WORLD); + } + + } catch(HERMES_SHM_ERROR_TYPE &HERMES_SHM_ERROR_PTR) { + std::cout << "HERE0" << std::endl; + err->print(); + } catch(hermes_shm::Error &err) { + std::cout << "HERE1" << std::endl; + err.print(); + } catch(int err) { + std::cout << "HERE2" << std::endl; + } catch(std::runtime_error &err) { + std::cout << "HERE3" << std::endl; + } catch(std::logic_error &err) { + std::cout << "HERE4" << std::endl; + } catch(...) { + std::cout << "HERE5" << std::endl; + } +} + +TEST_CASE("ListOfIntMpi") { + ListVecTest>(100); +} + +TEST_CASE("ListOfStringMpi") { + ListVecTest>(100); +} + +TEST_CASE("VectorOfIntMpi") { + ListVecTest>(100); +} + +TEST_CASE("VectorOfStringMpi") { + ListVecTest>(100); +} diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc new file mode 100644 index 000000000..b74bb31f3 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc @@ -0,0 +1,52 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include "test_init.h" + +#include "hermes_shm/memory/allocator/stack_allocator.h" + +Allocator *alloc_g = nullptr; + +template +void PretestRank0() { + std::string shm_url = "test_allocators"; + allocator_id_t alloc_id(0, 1); + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + mem_mngr->CreateBackend( + MemoryManager::kDefaultBackendSize, shm_url); + mem_mngr->CreateAllocator(shm_url, alloc_id, sizeof(Pointer)); + alloc_g = mem_mngr->GetAllocator(alloc_id); +} + +void PretestRankN() { + std::string shm_url = "test_allocators"; + allocator_id_t alloc_id(0, 1); + auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + mem_mngr->AttachBackend(MemoryBackendType::kPosixShmMmap, shm_url); + alloc_g = mem_mngr->GetAllocator(alloc_id); +} + +void MainPretest() { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) { + PretestRank0(); + } + MPI_Barrier(MPI_COMM_WORLD); + if (rank != 0) { + PretestRankN(); + } +} + +void MainPosttest() { +} diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h new file mode 100644 index 000000000..77a20a365 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h @@ -0,0 +1,39 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ +#define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ + +#include "hermes_shm/data_structures/data_structure.h" +#include + +using hermes_shm::ipc::PosixShmMmap; +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::Pointer; + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::MemoryManager; +using hermes_shm::ipc::Pointer; + +extern Allocator *alloc_g; + +void Posttest(); + +#endif // HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ diff --git a/hermes_shm/test/unit/data_structures/lock/CMakeLists.txt b/hermes_shm/test/unit/data_structures/lock/CMakeLists.txt new file mode 100644 index 000000000..8962fb4fc --- /dev/null +++ b/hermes_shm/test/unit/data_structures/lock/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(test_lock_exec + ${TEST_MAIN}/main.cc + test_init.cc + lock.cc) +add_dependencies(test_lock_exec hermes_shm_data_structures) +target_link_libraries(test_lock_exec + hermes_shm_data_structures Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) + +add_test(NAME test_mutex COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_lock_exec "Mutex") + +add_test(NAME test_rw_lock COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/test_lock_exec "RwLock") + diff --git a/hermes_shm/test/unit/data_structures/lock/lock.cc b/hermes_shm/test/unit/data_structures/lock/lock.cc new file mode 100644 index 000000000..db6b9204a --- /dev/null +++ b/hermes_shm/test/unit/data_structures/lock/lock.cc @@ -0,0 +1,111 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include "omp.h" +#include "hermes_shm/thread/lock.h" + +using hermes_shm::Mutex; +using hermes_shm::RwLock; + +void MutexTest() { + int nthreads = 8; + int loop_count = 10000; + int count = 0; + Mutex lock; + + HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + + omp_set_dynamic(0); +#pragma omp parallel shared(lock) num_threads(nthreads) + { + // Support parallel write +#pragma omp barrier + for (int i = 0; i < loop_count; ++i) { + lock.Lock(); + count += 1; + lock.Unlock(); + } +#pragma omp barrier + REQUIRE(count == loop_count * nthreads); +#pragma omp barrier + } +} + +void barrier_for_reads(std::vector &tid_start, int left) { + int count; + do { + count = 0; + for (int i = 0; i < left; ++i) { + count += tid_start[i]; + } + } while (count < left); +} + +void RwLockTest() { + int nthreads = 8; + int left = nthreads / 2; + std::vector tid_start(left, 0); + int loop_count = 100000; + int count = 0; + RwLock lock; + + HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + + omp_set_dynamic(0); +#pragma omp parallel \ + shared(lock, nthreads, left, loop_count, count, tid_start) \ + num_threads(nthreads) + { + int tid = omp_get_thread_num(); + + // Support parallel write +#pragma omp barrier + for (int i = 0; i < loop_count; ++i) { + lock.WriteLock(); + count += 1; + lock.WriteUnlock(); + } +#pragma omp barrier + REQUIRE(count == loop_count * nthreads); +#pragma omp barrier + + // Support for parallel read and write +#pragma omp barrier + + int cur_count = count; + if (tid < left) { + lock.ReadLock(); + tid_start[tid] = 1; + barrier_for_reads(tid_start, left); + for (int i = 0; i < loop_count; ++i) { + REQUIRE(count == cur_count); + } + lock.ReadUnlock(); + } else { + barrier_for_reads(tid_start, left); + lock.WriteLock(); + for (int i = 0; i < loop_count; ++i) { + count += 1; + } + lock.WriteUnlock(); + } + } +} + +TEST_CASE("Mutex") { + MutexTest(); +} + +TEST_CASE("RwLock") { + RwLockTest(); +} diff --git a/hermes_shm/test/unit/data_structures/lock/test_init.cc b/hermes_shm/test/unit/data_structures/lock/test_init.cc new file mode 100644 index 000000000..7590f5764 --- /dev/null +++ b/hermes_shm/test/unit/data_structures/lock/test_init.cc @@ -0,0 +1,17 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" + +void MainPretest() {} + +void MainPosttest() {} diff --git a/hermes_shm/test/unit/main.cc b/hermes_shm/test/unit/main.cc new file mode 100644 index 000000000..da1e76728 --- /dev/null +++ b/hermes_shm/test/unit/main.cc @@ -0,0 +1,28 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include + +int main(int argc, char **argv) { + int rc; + Catch::Session session; + auto cli = session.cli(); + session.cli(cli); + rc = session.applyCommandLine(argc, argv); + if (rc != 0) return rc; + MainPretest(); + rc = session.run(); + MainPosttest(); + if (rc != 0) return rc; + return rc; +} diff --git a/hermes_shm/test/unit/main_mpi.cc b/hermes_shm/test/unit/main_mpi.cc new file mode 100644 index 000000000..c34f81eca --- /dev/null +++ b/hermes_shm/test/unit/main_mpi.cc @@ -0,0 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include + +int main(int argc, char **argv) { + int rc; + MPI_Init(&argc, &argv); + Catch::Session session; + auto cli = session.cli(); + session.cli(cli); + rc = session.applyCommandLine(argc, argv); + if (rc != 0) return rc; + MainPretest(); + rc = session.run(); + MainPosttest(); + if (rc != 0) return rc; + MPI_Finalize(); + return rc; +} diff --git a/hermes_shm/test/unit/types/CMakeLists.txt b/hermes_shm/test/unit/types/CMakeLists.txt new file mode 100644 index 000000000..1437ed150 --- /dev/null +++ b/hermes_shm/test/unit/types/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +add_executable(test_types + ${TEST_MAIN}/main.cc + test_init.cc + test_argpack.cc) +target_link_libraries(test_types + Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) \ No newline at end of file diff --git a/hermes_shm/test/unit/types/test_argpack.cc b/hermes_shm/test/unit/types/test_argpack.cc new file mode 100644 index 000000000..5a38f72fd --- /dev/null +++ b/hermes_shm/test/unit/types/test_argpack.cc @@ -0,0 +1,180 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include +#include + +void test_argpack0_pass() { + std::cout << "HERE0" << std::endl; +} + +void test_argpack0() { + hermes_shm::PassArgPack::Call(hermes_shm::ArgPack<>(), test_argpack0_pass); +} + +template +void test_argpack3_pass(T1 x, T2 y, T3 z) { + REQUIRE(x == 0); + REQUIRE(y == 1); + REQUIRE(z == 0); + std::cout << "HERE3" << std::endl; +} + +void test_product1(int b, int c) { + REQUIRE(b == 1); + REQUIRE(c == 2); +} + +void test_product2(double d, double e) { + REQUIRE(d == 3); + REQUIRE(e == 4); +} + +template +void test_product(int a, Pack1 &&pack1, int a2, Pack2 &&pack2) { + REQUIRE(a == 0); + REQUIRE(a2 == 0); + hermes_shm::PassArgPack::Call( + std::forward(pack1), + test_product1); + hermes_shm::PassArgPack::Call( + std::forward(pack2), + test_product2); +} + +template +void verify_tuple3(hermes_shm::tuple &x) { + REQUIRE(x.Size() == 3); + REQUIRE(x.template Get<0>() == 0); + REQUIRE(x.template Get<1>() == 1); + REQUIRE(x.template Get<2>() == 0); +#ifdef TEST_COMPILER_ERROR + std::cout << x.Get<3>() << std::endl; +#endif +} + +template +void test_argpack3() { + // Pass an argpack to a function + { + hermes_shm::PassArgPack::Call( + hermes_shm::make_argpack(T1(0), T2(1), T3(0)), + test_argpack3_pass); + } + + // Pass an argpack containing references to a function + { + T2 y = 1; + hermes_shm::PassArgPack::Call( + hermes_shm::make_argpack(0, y, 0), + test_argpack3_pass); + } + + // Create a 3-tuple + { + hermes_shm::tuple x(0, 1, 0); + verify_tuple3(x); + } + + // Copy a tuple + { + hermes_shm::tuple y(0, 1, 0); + hermes_shm::tuple x(y); + verify_tuple3(x); + } + + // Copy assign tuple + { + hermes_shm::tuple y(0, 1, 0); + hermes_shm::tuple x; + x = y; + verify_tuple3(x); + } + + // Move tuple + { + hermes_shm::tuple y(0, 1, 0); + hermes_shm::tuple x(std::move(y)); + verify_tuple3(x); + } + + // Move assign tuple + { + hermes_shm::tuple y(0, 1, 0); + hermes_shm::tuple x; + x = std::move(y); + verify_tuple3(x); + } + + // Iterate over a tuple + { + hermes_shm::tuple x(0, 1, 0); + hermes_shm::ForwardIterateTuple::Apply( + x, + [](auto i, auto &arg) constexpr { + std::cout << "lambda: " << i.Get() << std::endl; + }); + } + + // Merge two argpacks into a single pack + { + size_t y = hermes_shm::MergeArgPacks::Merge( + hermes_shm::make_argpack(T1(0)), + hermes_shm::make_argpack(T2(1), T2(0))).Size(); + REQUIRE(y == 3); + } + + // Pass a merged argpack to a function + { + hermes_shm::PassArgPack::Call( + hermes_shm::MergeArgPacks::Merge( + hermes_shm::make_argpack(0), + hermes_shm::make_argpack(1, 0)), + test_argpack3_pass); + } + + // Construct tuple from argpack + { + hermes_shm::tuple x( + hermes_shm::make_argpack(10, 11, 12)); + REQUIRE(x.Get<0>() == 10); + REQUIRE(x.Get<1>() == 11); + REQUIRE(x.Get<2>() == 12); + } + + // Product an argpack + { + auto&& pack = hermes_shm::ProductArgPacks::Product( + 0, + hermes_shm::make_argpack(1, 2), + hermes_shm::make_argpack(3, 4)); + REQUIRE(pack.Size() == 4); + } + + // Product an argpack + { + hermes_shm::PassArgPack::Call( + hermes_shm::ProductArgPacks::Product( + 0, + hermes_shm::make_argpack(1, 2), + hermes_shm::make_argpack(3.0, 4.0)), + test_product< + hermes_shm::ArgPack, + hermes_shm::ArgPack>); + } +} + +TEST_CASE("TestArgpack") { + test_argpack0(); + test_argpack3(); +} diff --git a/hermes_shm/test/unit/types/test_init.cc b/hermes_shm/test/unit/types/test_init.cc new file mode 100644 index 000000000..7590f5764 --- /dev/null +++ b/hermes_shm/test/unit/types/test_init.cc @@ -0,0 +1,17 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" + +void MainPretest() {} + +void MainPosttest() {} From b7bb71ff87235b308ee5b824ed13befaf17305b9 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 11:22:30 -0600 Subject: [PATCH 145/511] Disable OpenMP --- hermes_shm/CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hermes_shm/CMakeLists.txt b/hermes_shm/CMakeLists.txt index 31484fb5f..39f5ff857 100644 --- a/hermes_shm/CMakeLists.txt +++ b/hermes_shm/CMakeLists.txt @@ -47,17 +47,17 @@ if(BUILD_MPI_TESTS) endif() # OpenMP -if(BUILD_OpenMP_TESTS) - find_package(OpenMP REQUIRED COMPONENTS C CXX) - message(STATUS "found omp.h at ${OpenMP_CXX_INCLUDE_DIRS}") -endif() +#if(BUILD_OpenMP_TESTS) +# find_package(OpenMP REQUIRED COMPONENTS C CXX) +# message(STATUS "found omp.h at ${OpenMP_CXX_INCLUDE_DIRS}") +#endif() ##################Build HermesShm main packages add_subdirectory(src) ##################MODULES & TESTS set(TEST_MAIN ${CMAKE_SOURCE_DIR}/test/unit) -if (BUILD_TESTS) - enable_testing() - add_subdirectory(test) -endif() \ No newline at end of file +#if (BUILD_TESTS) +# enable_testing() +# add_subdirectory(test) +#endif() \ No newline at end of file From 884853baa430af3f57e70751779eea4728571ce2 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 6 Feb 2023 11:29:46 -0600 Subject: [PATCH 146/511] Remove all pkg-config --- hermes_shm/CMakeLists.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/hermes_shm/CMakeLists.txt b/hermes_shm/CMakeLists.txt index 39f5ff857..7f4f812af 100644 --- a/hermes_shm/CMakeLists.txt +++ b/hermes_shm/CMakeLists.txt @@ -32,19 +32,19 @@ endfunction() ##################REQUIRED EXTERNAL LIBRARIES -# YAML-CPP -find_package(yaml-cpp REQUIRED) -message(STATUS "found yaml-cpp at ${yaml-cpp_DIR}") - -# Catch2 -find_package(Catch2 3.0.1 REQUIRED) -message(STATUS "found catch2.h at ${Catch2_CXX_INCLUDE_DIRS}") - -# MPICH -if(BUILD_MPI_TESTS) - find_package(MPI REQUIRED COMPONENTS C CXX) - message(STATUS "found mpi.h at ${MPI_CXX_INCLUDE_DIRS}") -endif() +## YAML-CPP +#find_package(yaml-cpp REQUIRED) +#message(STATUS "found yaml-cpp at ${yaml-cpp_DIR}") +# +## Catch2 +#find_package(Catch2 3.0.1 REQUIRED) +#message(STATUS "found catch2.h at ${Catch2_CXX_INCLUDE_DIRS}") +# +## MPICH +#if(BUILD_MPI_TESTS) +# find_package(MPI REQUIRED COMPONENTS C CXX) +# message(STATUS "found mpi.h at ${MPI_CXX_INCLUDE_DIRS}") +#endif() # OpenMP #if(BUILD_OpenMP_TESTS) From ab79562a084dd8419b028574ec2e66473504d5fc Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 15 Feb 2023 23:08:55 -0600 Subject: [PATCH 147/511] Begin clang for RPCgen --- .gitignore | 2 + CMakeLists.txt | 12 +- .../code_generators/rpc/clang_doc.py | 145 ++++++++++++++++++ code_generators/code_generators/rpc/empty.cc | 2 + code_generators/code_generators/rpc/rpcgen.sh | 14 ++ src/CMakeLists.txt | 2 +- src/api/hermes_singleton.cc | 1 + src/metadata_types.h | 8 + 8 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 code_generators/code_generators/rpc/clang_doc.py create mode 100644 code_generators/code_generators/rpc/empty.cc create mode 100644 code_generators/code_generators/rpc/rpcgen.sh diff --git a/.gitignore b/.gitignore index 6071cf4d7..5f7007002 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ GPATH GRTAGS GTAGS +/compiler_data + .gdb_history /cmake-build-* diff --git a/CMakeLists.txt b/CMakeLists.txt index cc56516ed..d824d257a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,8 @@ set(HERMES_PACKAGE_VERSION_MINOR "${HERMES_VERSION_PATCH}") set(HERMES_PACKAGE_STRING "${HERMES_PACKAGE_NAME} ${HERMES_PACKAGE_VERSION}") set(HERMES_PACKAGE_TARNAME "${HERMES_PACKAGE}") +#set( CMAKE_VERBOSE_MAKEFILE on ) + #------------------------------------------------------------------------------ # Setup install and output Directories #------------------------------------------------------------------------------ @@ -59,6 +61,8 @@ endif() #------------------------------------------------------------------------------ # Setup CMake Environment #------------------------------------------------------------------------------ +# Export compile commands for autocode generation with CLANG +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(APPLE) # We are doing a unix-style install i.e. everything will be installed in # CMAKE_INSTALL_PREFIX/bin and CMAKE_INSTALL_PREFIX/lib etc. as on other unix @@ -149,7 +153,7 @@ option(HERMES_INTERCEPT_IO "Use GOTCHA as IO interception tool" OFF) option(HERMES_COMMUNICATION_MPI "Use MPI as the communication layer." ON) option(HERMES_ENABLE_DOXYGEN "Enable hermes documentation." OFF) option(HERMES_BUILD_BUFFER_POOL_VISUALIZER "Build the BufferPool visualizer" OFF) -option(HERMES_USE_ADDRESS_SANITIZER "Enable -fsanitize=address in Debug builds" ON) +option(HERMES_USE_ADDRESS_SANITIZER "Enable -fsanitize=address in Debug builds" OFF) option(HERMES_USE_THREAD_SANITIZER "Enable -fsanitize=thread in Debug builds" OFF) option(HERMES_RPC_THALLIUM "Use Thallium as the RPC library." ON) option(HERMES_MDM_STORAGE_STBDS @@ -166,6 +170,7 @@ option(HERMES_ENABLE_VFD "Build the Hermes HDF5 Virtual File Driver" OFF) option(HERMES_ENABLE_WRAPPER "Enable hermes C API wrapper." ON) option(HERMES_ENABLE_GFLAGS "Enable GFLAGS support." ON) option(HERMES_INSTALL_TESTS "Enable installation of tests." OFF) + # Calculate code coverage with debug mode if(HERMES_ENABLE_COVERAGE) if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") @@ -403,6 +408,11 @@ include_directories(${CMAKE_SOURCE_DIR}/hermes_shm/include) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src) add_subdirectory(${CMAKE_SOURCE_DIR}/hermes_shm) +add_custom_target(rpc COMMAND bash + ${CMAKE_SOURCE_DIR}/code_generators/code_generators/rpc/rpcgen.sh + "${CMAKE_SOURCE_DIR}" + "${CMAKE_BINARY_DIR}") + # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/data_stager) #----------------------------------------------------------------------------- diff --git a/code_generators/code_generators/rpc/clang_doc.py b/code_generators/code_generators/rpc/clang_doc.py new file mode 100644 index 000000000..0636f81b4 --- /dev/null +++ b/code_generators/code_generators/rpc/clang_doc.py @@ -0,0 +1,145 @@ +import pprint +import sys +import clang.cindex +from clang.cindex import CursorKind, TokenKind +import os, sys +import json +from enum import Enum +import inspect + + +class OpType: + COMMENT = "COMMENT" + METHOD = "METHOD" + + +def parse_compiler_includes(COMPILER_INCLUDES): + with open(COMPILER_INCLUDES) as fp: + lines = fp.read().splitlines() + cmd = " ".join(lines[4:]) + toks = cmd.split() + args = [] + for i, tok in enumerate(toks): + if "-I" in tok: + tok = tok.replace('"', '') + args.append(tok) + elif "-internal-isystem" in tok: + tok = toks[i+1] + tok = tok.replace('"', '') + args.append(f"-I{tok}") + return args + + +def parse_compile_commands(COMPILER_COMMANDS, CMAKE_CURRENT_BINARY_DIR, + includes): + sources = [] + with open(COMPILER_COMMANDS) as fp: + compile_commands = json.load(fp) + for cmd_info in compile_commands: + dir = cmd_info['directory'] + if not os.path.samefile(dir, CMAKE_CURRENT_BINARY_DIR): + continue + arg_str = cmd_info['command'] + toks = arg_str.split()[1:] + args = [] + for i, tok in enumerate(toks): + if "-I" in tok: + tok = tok.replace('"', '') + args.append(tok) + elif "-isystem" in tok: + tok = toks[i+1] + tok = tok.replace('"', '') + args.append(f"-I{tok}") + elif "-internal-isystem" in tok: + tok = toks[i+1] + tok = tok.replace('"', '') + args.append(f"-I{tok}") + elif "-D" in tok: + tok = tok.replace('"', '') + args.append(tok) + sources.append({ + 'source': cmd_info['file'], + 'args': args + includes + }) + return sources + + +def find_comments(cursor, info=None): + if info is None: + info = {} + for x in cursor.get_tokens(): + if x.kind == TokenKind.COMMENT: + path = x.start.file + if path not in info: + info[path] = [] + info[path].append((OpType.COMMENT, + x.start.line, + x.start.column, + x.spelling)) + children = list(cursor.get_children()) + for child in children: + find_comments(child) + return info + + +def find_functions(cursor, info=None, cur_ns=[]): + if info is None: + info = {} + children = list(cursor.get_children()) + ns_types = { + CursorKind.NAMESPACE, + CursorKind.STRUCT_DECL, + CursorKind.UNION_DECL, + CursorKind.CLASS_DECL + } + function_types = { + CursorKind.FUNCTION_DECL, + CursorKind.CXX_METHOD + } + for x in children: + if x.kind in ns_types: + cur_ns += [x.displayname] + find_functions(x, info, cur_ns) + elif x.kind in function_types: + path = x.start.file + exit() + if path not in info: + info[path] = [] + info[path].append((OpType.METHOD, + x.start.line, + x.start.column, + cur_ns, + x.displayname)) + find_functions(x, info) + return info + + +### MAIN START +CMAKE_SOURCE_DIR = sys.argv[1] +CMAKE_BINARY_DIR = sys.argv[2] +COMPILER_INCLUDES = sys.argv[3] +COMPILER_COMMANDS = sys.argv[4] +CMAKE_CURRENT_SOURCE_DIR = os.path.join(CMAKE_SOURCE_DIR, 'src') +CMAKE_CURRENT_BINARY_DIR = os.path.join(CMAKE_BINARY_DIR, 'src') + +# Load the CLANG commands from YAML +includes = parse_compiler_includes(COMPILER_INCLUDES) +sources = parse_compile_commands(COMPILER_COMMANDS, CMAKE_CURRENT_BINARY_DIR, includes) + +# Call Clang +for source in sources: + print(f"Parsing {source['source']}") + extra_args = ["-fparse-all-comments"] + index = clang.cindex.Index.create() + tu = index.parse(source['source'], args=extra_args + source['args']) + diagnostics = list(tu.diagnostics) + if len(diagnostics) > 0: + print(f'There were {len(diagnostics)} parse errors') + for err in diagnostics: + if err.severity > 3: + pprint.pprint(err) + exit() + #info = find_comments(tu.cursor) + info = find_functions(tu.cursor) + pprint.pprint(info) + exit() diff --git a/code_generators/code_generators/rpc/empty.cc b/code_generators/code_generators/rpc/empty.cc new file mode 100644 index 000000000..e1e8e9fc5 --- /dev/null +++ b/code_generators/code_generators/rpc/empty.cc @@ -0,0 +1,2 @@ +int main() { +} \ No newline at end of file diff --git a/code_generators/code_generators/rpc/rpcgen.sh b/code_generators/code_generators/rpc/rpcgen.sh new file mode 100644 index 000000000..bd06f3ad1 --- /dev/null +++ b/code_generators/code_generators/rpc/rpcgen.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +CMAKE_SOURCE_DIR=$1 +CMAKE_BINARY_DIR=$2 +COMPILER_INCLUDES=${PWD}/compile_includes.txt +COMPILER_COMMANDS=${PWD}/compile_commands.json +RPC_GEN_DIR=${CMAKE_SOURCE_DIR}/code_generators/code_generators/rpc + +clang -### "${RPC_GEN_DIR}/empty.cc" &> ${COMPILER_INCLUDES} +python3 "${CMAKE_SOURCE_DIR}/code_generators/code_generators/rpc/clang_doc.py" \ + "${CMAKE_SOURCE_DIR}" \ + "${CMAKE_BINARY_DIR}" \ + "${COMPILER_INCLUDES}" \ + "${COMPILER_COMMANDS}" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5dd7f8d42..ef0cc6b98 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -90,7 +90,7 @@ target_link_libraries(hermes PUBLIC ${CMAKE_HERMES_RPC_TYPE_LIB} PUBLIC glog::glog PUBLIC yaml-cpp - PUBLIC labstor_client hermes_shm_data_structures + PUBLIC hermes_shm_data_structures PUBLIC "$<$:${GOTCHA_MODULE_LIBS}>" ) diff --git a/src/api/hermes_singleton.cc b/src/api/hermes_singleton.cc index 1326ed620..f9b1aa9dd 100644 --- a/src/api/hermes_singleton.cc +++ b/src/api/hermes_singleton.cc @@ -16,6 +16,7 @@ template<> hermes::api::Hermes hermes::GlobalSingleton< hermes::api::Hermes>::obj_ = hermes::api::Hermes(); +/** Finalize hermes when program exits */ void Finalize() { HERMES->Finalize(); } diff --git a/src/metadata_types.h b/src/metadata_types.h index 77a82edfc..5d1fd6313 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -19,6 +19,14 @@ namespace hermes { +#define TEXT_HASH(text) \ + std::hash{}(text); +#define ID_HASH(id) \ + id.bits_.node_id_ +#define BUCKET_HASH TEXT_HASH(bkt_name) +#define BLOB_HASH TEXT_HASH(blob_name) +#define VBUCKET_HASH TEXT_HASH(vbkt_name) + using adapter::GlobalIoClientState; using api::Blob; /**< Namespace simplification for blob */ struct BucketInfo; /**< Forward declaration of BucketInfo */ From 09cbb002a9bfa548e679a6812e125472ec4d1dea Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Wed, 15 Feb 2023 23:17:21 -0600 Subject: [PATCH 148/511] Add fstat as LD_PRELOAD option to posix --- adapter/posix/posix_api.cc | 38 ++++++++++++++++++++++++++++++++++++++ adapter/posix/posix_api.h | 11 ++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/adapter/posix/posix_api.cc b/adapter/posix/posix_api.cc index 3944919be..df1427a5f 100644 --- a/adapter/posix/posix_api.cc +++ b/adapter/posix/posix_api.cc @@ -283,6 +283,44 @@ int HERMES_DECL(__fxstat)(int __ver, int fd, struct stat *buf) { return result; } +int HERMES_DECL(fstat)(int fd, struct stat *buf) { + int result = 0; + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; + if (fs_api->IsFdTracked(fd)) { + File f; f.hermes_fd_ = fd; + LOG(INFO) << "Intercepted fstat." << std::endl; + auto mdm = HERMES_FS_METADATA_MANAGER; + auto existing = mdm->Find(f); + if (existing) { + AdapterStat &astat = *existing; + // TODO(chogan): st_dev and st_ino need to be assigned by us, but + // currently we get them by calling the real fstat on open. + buf->st_dev = 0; + buf->st_ino = 0; + buf->st_mode = astat.st_mode_; + buf->st_nlink = 0; + buf->st_uid = astat.st_uid_; + buf->st_gid = astat.st_gid_; + buf->st_rdev = 0; + buf->st_size = fs_api->GetSize(f, astat); + // buf->st_blksize = astat.st_blksize_; + buf->st_blocks = 0; + buf->st_atime = astat.st_atim_.tv_sec; + buf->st_mtime = astat.st_mtim_.tv_sec; + buf->st_ctime = astat.st_ctim_.tv_sec; + } else { + result = -1; + errno = EBADF; + LOG(ERROR) << "File with descriptor " << fd + << " does not exist in Hermes\n"; + } + } else { + result = real_api->fstat(fd, buf); + } + return result; +} + int HERMES_DECL(fsync)(int fd) { bool stat_exists; auto real_api = HERMES_POSIX_API; diff --git a/adapter/posix/posix_api.h b/adapter/posix/posix_api.h index 070e15eff..1f3b1819b 100644 --- a/adapter/posix/posix_api.h +++ b/adapter/posix/posix_api.h @@ -43,6 +43,7 @@ typedef ssize_t (*pwrite64_t)(int fd, const void * buf, size_t count, off64_t of typedef off_t (*lseek_t)(int fd, off_t offset, int whence); typedef off64_t (*lseek64_t)(int fd, off64_t offset, int whence); typedef int (*__fxstat_t)(int __ver, int __filedesc, struct stat * __stat_buf); +typedef int (*fstat_t)(int __filedesc, struct stat * __stat_buf); typedef int (*fsync_t)(int fd); typedef int (*close_t)(int fd); } @@ -80,6 +81,8 @@ class PosixApi { lseek64_t lseek64 = nullptr; /** __fxstat */ __fxstat_t __fxstat = nullptr; + /** fstat */ + fstat_t fstat = nullptr; /** fsync */ fsync_t fsync = nullptr; /** close */ @@ -170,7 +173,13 @@ class PosixApi { } else { __fxstat = (__fxstat_t)dlsym(RTLD_DEFAULT, "__fxstat"); } - REQUIRE_API(__fxstat) + // REQUIRE_API(__fxstat) + if (is_intercepted) { + fstat = (fstat_t)dlsym(RTLD_NEXT, "fstat"); + } else { + fstat = (fstat_t)dlsym(RTLD_DEFAULT, "fstat"); + } + // REQUIRE_API(fstat) if (is_intercepted) { fsync = (fsync_t)dlsym(RTLD_NEXT, "fsync"); } else { From be1f7ba257f6def860801650597bf4b859f5c26e Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 20 Feb 2023 06:38:09 -0600 Subject: [PATCH 149/511] Use fstat instead of __fxstat. --- adapter/posix/posix_api.h | 16 ++++++++++++++++ adapter/posix/posix_io_client.cc | 2 +- adapter/test/posix/CMakeLists.txt | 1 + adapter/test/posix/posix_adapter_basic_test.cpp | 2 +- adapter/test/posix/simple_io.cc | 2 +- 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/adapter/posix/posix_api.h b/adapter/posix/posix_api.h index 1f3b1819b..568c8ad63 100644 --- a/adapter/posix/posix_api.h +++ b/adapter/posix/posix_api.h @@ -50,6 +50,9 @@ typedef int (*close_t)(int fd); namespace hermes::adapter::fs { +/** Used for compatability with older kernel versions */ +static int fxstat_to_fstat(int fd, struct stat * stbuf); + /** Pointers to the real posix API */ class PosixApi { public: @@ -179,6 +182,9 @@ class PosixApi { } else { fstat = (fstat_t)dlsym(RTLD_DEFAULT, "fstat"); } + if (fstat == nullptr) { + fstat = fxstat_to_fstat; + } // REQUIRE_API(fstat) if (is_intercepted) { fsync = (fsync_t)dlsym(RTLD_NEXT, "fsync"); @@ -194,6 +200,7 @@ class PosixApi { REQUIRE_API(close) } }; + } // namespace hermes::adapter::fs // Singleton macros @@ -205,4 +212,13 @@ class PosixApi { #undef REQUIRE_API +namespace hermes::adapter::fs { +/** Used for compatability with older kernel versions */ +static int fxstat_to_fstat(int fd, struct stat *stbuf) { +#ifdef _STAT_VER + return HERMES_POSIX_API->__fxstat(_STAT_VER, fd, stbuf); +#endif +} +} // namespace hermes::adapter::fs + #endif // HERMES_ADAPTER_POSIX_H diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 6cfabce7b..5dcad0e5d 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -76,7 +76,7 @@ void PosixIoClient::InitBucketState(const hipc::charbuf &bkt_name, int fd = real_api->open(filename.c_str(), O_RDONLY); if (fd < 0) { return; } struct stat buf; - real_api->__fxstat(_STAT_VER, fd, &buf); + real_api->fstat(fd, &buf); stat.true_size_ = buf.st_size; real_api->close(fd); } diff --git a/adapter/test/posix/CMakeLists.txt b/adapter/test/posix/CMakeLists.txt index ecece0379..a223dcbb1 100644 --- a/adapter/test/posix/CMakeLists.txt +++ b/adapter/test/posix/CMakeLists.txt @@ -24,6 +24,7 @@ mpi_daemon(hermes_posix_adapter_mpi_test 2 "[request_size=range-large]" "large" include_directories(${CMAKE_SOURCE_DIR}/adapter) add_executable(posix_simple_io simple_io.cc) +target_link_libraries(posix_simple_io hermes_posix) set(POSIX_TESTS posix_adapter_test diff --git a/adapter/test/posix/posix_adapter_basic_test.cpp b/adapter/test/posix/posix_adapter_basic_test.cpp index ef66c577e..ee8ef163c 100644 --- a/adapter/test/posix/posix_adapter_basic_test.cpp +++ b/adapter/test/posix/posix_adapter_basic_test.cpp @@ -1466,7 +1466,7 @@ TEST_CASE("fstat") { REQUIRE(test::size_written_orig == args.request_size); struct stat buf = {}; - int result = __fxstat(_STAT_VER, test::fh_orig, &buf); + int result = fstat(test::fh_orig, &buf); REQUIRE(result == 0); REQUIRE(buf.st_size == (off_t)test::size_written_orig); diff --git a/adapter/test/posix/simple_io.cc b/adapter/test/posix/simple_io.cc index 8aafd89b2..eaf1f97fa 100644 --- a/adapter/test/posix/simple_io.cc +++ b/adapter/test/posix/simple_io.cc @@ -80,7 +80,7 @@ int main(int argc, char **argv) { lseek(fd, off, SEEK_SET); struct stat st; - __fxstat(_STAT_VER, fd, &st); + fstat(fd, &st); if (do_read && (st.st_size - total_size) > 3) { if (rank == 0) { std::cout << "File sizes aren't equivalent: " From 820445b86621f9dd308fbeaa0b3c0c72c1fffd03 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 26 Feb 2023 07:21:07 -0600 Subject: [PATCH 150/511] Blob stats --- src/metadata_types.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/metadata_types.h b/src/metadata_types.h index 5d1fd6313..cfb53bc0f 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -122,6 +122,13 @@ struct ShmHeader : public hipc::ShmBaseHeader { buffers_ar_; /**< SHM pointer to BufferInfo vector */ size_t blob_size_; /**< The overall size of the blob */ RwLock lock_[2]; /**< Ensures BlobInfo access is synchronized */ + time_t update_time_; /**< Last time statistics updated */ + int access_count_; /**< The number of times blob accessed */ + /** + * Estimate when blob will be accessed next (ns) + * 0 indicates unknown + * */ + size_t next_access_time_ns_; /** Default constructor */ ShmHeader() = default; From 9f71f7d642baae20383d7122b15c7a89dcc32832 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 26 Feb 2023 07:40:42 -0600 Subject: [PATCH 151/511] Use separate hermes_shm git repo. Clone when needed. --- hermes_shm/CMakeLists.txt | 105 ++++++++-- .../data_structure_singleton_macros.h | 19 +- .../include/hermes_shm/constants/macros.h | 6 +- .../data_structures/data_structure.h | 19 +- .../data_structures/internal/shm_archive.h | 8 +- .../internal/shm_archive_or_t.h | 158 +++++--------- .../data_structures/internal/shm_container.h | 9 +- .../internal/shm_container_extend_macro.h | 30 +-- .../internal/shm_container_macro.h | 51 +++-- .../internal/shm_deserialize.h | 10 +- .../data_structures/internal/shm_macros.h | 11 +- .../internal/shm_null_container.h | 6 +- .../data_structures/internal/shm_ref.h | 14 +- .../data_structures/internal/shm_smart_ptr.h | 9 +- .../template/shm_container_base_example.h | 27 ++- .../template/shm_container_base_template.h | 23 ++- .../template/shm_container_extend_example.h | 6 +- .../include/hermes_shm/data_structures/pair.h | 41 ++-- .../data_structures/smart_ptr/manual_ptr.h | 11 +- .../hermes_shm/data_structures/string.h | 25 +-- .../data_structures/thread_unsafe/list.h | 27 ++- .../thread_unsafe/unordered_map.h | 16 +- .../data_structures/thread_unsafe/vector.h | 193 +++++++----------- .../hermes_shm/introspect/system_info.h | 6 +- .../hermes_shm/memory/allocator/allocator.h | 33 +-- .../memory/allocator/allocator_factory.h | 78 ++++--- .../memory/allocator/malloc_allocator.h | 17 +- .../hermes_shm/memory/allocator/mp_page.h | 12 +- .../memory/allocator/stack_allocator.h | 17 +- .../hermes_shm/memory/backend/array_backend.h | 6 +- .../memory/backend/memory_backend.h | 6 +- .../memory/backend/memory_backend_factory.h | 7 +- .../hermes_shm/memory/backend/null_backend.h | 6 +- .../hermes_shm/memory/backend/posix_mmap.h | 6 +- .../memory/backend/posix_shm_mmap.h | 18 +- hermes_shm/include/hermes_shm/memory/memory.h | 11 +- .../hermes_shm/memory/memory_manager.h | 92 ++++----- hermes_shm/include/hermes_shm/thread/lock.h | 7 +- .../include/hermes_shm/thread/lock/mutex.h | 7 +- .../include/hermes_shm/thread/lock/rwlock.h | 7 +- .../include/hermes_shm/thread/pthread.h | 10 +- hermes_shm/include/hermes_shm/thread/thread.h | 6 +- .../hermes_shm/thread/thread_factory.h | 6 +- .../hermes_shm/thread/thread_manager.h | 29 ++- hermes_shm/include/hermes_shm/types/argpack.h | 14 +- hermes_shm/include/hermes_shm/types/atomic.h | 6 +- hermes_shm/include/hermes_shm/types/basic.h | 32 ++- .../include/hermes_shm/types/bitfield.h | 6 +- hermes_shm/include/hermes_shm/types/charbuf.h | 34 +-- .../include/hermes_shm/types/messages.h | 8 +- .../include/hermes_shm/types/tuple_base.h | 6 +- .../include/hermes_shm/util/auto_trace.h | 6 +- hermes_shm/include/hermes_shm/util/debug.h | 8 +- hermes_shm/include/hermes_shm/util/error.h | 22 +- hermes_shm/include/hermes_shm/util/errors.h | 6 +- .../include/hermes_shm/util/formatter.h | 6 +- .../include/hermes_shm/util/partitioner.h | 6 +- .../include/hermes_shm/util/path_parser.h | 6 +- hermes_shm/include/hermes_shm/util/timer.h | 6 +- hermes_shm/src/CMakeLists.txt | 31 +-- hermes_shm/src/data_structure_singleton.cc | 2 + hermes_shm/src/memory/malloc_allocator.cc | 14 +- hermes_shm/src/memory/memory_intercept.cc | 14 +- hermes_shm/src/memory/memory_intercept.h | 6 +- hermes_shm/src/memory/memory_manager.cc | 22 +- hermes_shm/src/memory/stack_allocator.cc | 29 ++- hermes_shm/src/thread/mutex.cc | 9 +- hermes_shm/src/thread/rwlock.cc | 55 ++--- hermes_shm/test/unit/allocators/allocator.cc | 48 +++-- .../test/unit/allocators/allocator_thread.cc | 9 +- hermes_shm/test/unit/allocators/test_init.cc | 4 +- hermes_shm/test/unit/allocators/test_init.h | 10 +- hermes_shm/test/unit/basic_test.h | 6 +- .../test/unit/data_structures/CMakeLists.txt | 4 +- .../data_structures/backend/memory_manager.cc | 10 +- .../data_structures/backend/memory_slots.cc | 21 +- .../unit/data_structures/backend/test_init.cc | 1 + .../data_structures/containers/CMakeLists.txt | 5 + .../unit/data_structures/containers/list.cc | 1 - .../unit/data_structures/containers/list.h | 6 +- .../data_structures/containers/manual_ptr.cc | 3 +- .../data_structures/containers/smart_ptr.h | 6 +- .../unit/data_structures/containers/string.cc | 1 - .../data_structures/containers/test_init.cc | 6 +- .../data_structures/containers/test_init.h | 9 +- .../containers/unordered_map.cc | 1 - .../containers/unordered_map_thread.cc | 3 +- .../unit/data_structures/containers/vector.h | 6 +- .../containers_mpi/list_vec_mpi.cc | 2 +- .../containers_mpi/test_init.cc | 7 +- .../containers_mpi/test_init.h | 7 +- .../test/unit/data_structures/lock/lock.cc | 5 +- .../unit/data_structures/lock/test_init.cc | 1 + hermes_shm/test/unit/main.cc | 1 + hermes_shm/test/unit/main_mpi.cc | 1 + hermes_shm/test/unit/types/CMakeLists.txt | 8 +- hermes_shm/test/unit/types/test_init.cc | 1 + src/api/hermes.cc | 4 +- src/data_structures.h | 2 + 99 files changed, 965 insertions(+), 799 deletions(-) diff --git a/hermes_shm/CMakeLists.txt b/hermes_shm/CMakeLists.txt index 31484fb5f..13b15871a 100644 --- a/hermes_shm/CMakeLists.txt +++ b/hermes_shm/CMakeLists.txt @@ -3,14 +3,35 @@ project(hermes_shm) set(CMAKE_CXX_STANDARD 17) -include_directories(${CMAKE_SOURCE_DIR}/include) +###################GLOBAL VARIABLES +set(HERMES_SHM_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${HERMES_SHM_ROOT}/include) ###################OPTIONS option(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" ON) -option(BUILD_TESTS "Wether or not to build unit tests" OFF) -option(BUILD_MPI_TESTS "Build tests which depend on MPI" OFF) -option(BUILD_OpenMP_TESTS "Build tests which depend on OpenMP" OFF) -option(BUILD_Boost_TESTS "Build tests which depend on libboost" OFF) +option(BUILD_MPI_TESTS "Build tests which depend on MPI" ON) +option(BUILD_OpenMP_TESTS "Build tests which depend on OpenMP" ON) +option(BUILD_Boost_TESTS "Build tests which depend on libboost" ON) +option(HERMES_RPC_THALLIUM "Enable compatability for mochi" ON) +option(HERMES_ENABLE_COVERAGE "Check how well tests cover code" ON) +option(HERMES_ENABLE_DOXYGEN "Check how well the code is documented" ON) +option(HERMES_CXX_PROFILE "Generate profiling data from benchmarks" OFF) + +#------------------------------------------------------------------------------ +# Setup install and output Directories +#------------------------------------------------------------------------------ +if(NOT HERMES_INSTALL_BIN_DIR) + set(HERMES_INSTALL_BIN_DIR ${CMAKE_INSTALL_PREFIX}/bin) +endif() +if(NOT HERMES_INSTALL_LIB_DIR) + set(HERMES_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib) +endif() +if(NOT HERMES_INSTALL_INCLUDE_DIR) + set(HERMES_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_PREFIX}/include) +endif() +if(NOT HERMES_INSTALL_DATA_DIR) + set(HERMES_INSTALL_DATA_DIR ${CMAKE_INSTALL_PREFIX}/share) +endif() ##################CMAKE MODULES set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake) @@ -23,6 +44,10 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Release") message("IN RELEASE MODE") set(CMAKE_CXX_FLAGS "-g -O3") endif() +if(HERMES_CXX_PROFILE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") + message("CXX PROFILER IS ON") +endif() function(make_gprof exec_name exec_dir) message("gprof -b -A -p -q ${exec_dir}/${exec_name} gmon.out > gprof_out.txt") add_custom_target( @@ -47,17 +72,69 @@ if(BUILD_MPI_TESTS) endif() # OpenMP -if(BUILD_OpenMP_TESTS) - find_package(OpenMP REQUIRED COMPONENTS C CXX) - message(STATUS "found omp.h at ${OpenMP_CXX_INCLUDE_DIRS}") +#if(BUILD_OpenMP_TESTS) +find_package(OpenMP REQUIRED COMPONENTS C CXX) +message(STATUS "found omp.h at ${OpenMP_CXX_INCLUDE_DIRS}") +#endif() + +# thallium +if(HERMES_RPC_THALLIUM) + find_package(thallium CONFIG REQUIRED) + if(thallium_FOUND) + message(STATUS "found thallium at ${thallium_DIR}") + endif() +endif() + +# Boost +if(BUILD_Boost_TESTS) + find_package(Boost REQUIRED) + message(STATUS "found boost.h at ${Boost_INCLUDE_DIRS}") endif() -##################Build HermesShm main packages +##################CODE COVERAGE +if(HERMES_ENABLE_COVERAGE) + set(COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage" CACHE STRING + "Flags to the coverage program to perform coverage inspection") + mark_as_advanced(COVERAGE_FLAGS) + + macro(set_coverage_flags target) + set_target_properties(${target} + PROPERTIES + COMPILE_FLAGS ${COVERAGE_FLAGS} + LINK_FLAGS ${COVERAGE_FLAGS} + ) + endmacro() +endif() + +##################DOCUMENTATION +if(HERMES_ENABLE_DOXYGEN) + include(UseDoxygenDoc) + + add_doxygen_doc( + BUILD_DIR + ${CMAKE_CURRENT_BINARY_DIR}/_build + DOXY_FILE + ${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in + TARGET_NAME + dox + COMMENT + "HTML documentation" + ) +endif() + +##################Build hermes main packages + add_subdirectory(src) +add_custom_target(shm_lint COMMAND bash ${HERMES_SHM_ROOT}/scripts/lint.sh ${HERMES_SHM_ROOT}) +add_custom_target(shm_preamble COMMAND python3 ${HERMES_SHM_ROOT}/scripts/preamble.py ${HERMES_SHM_ROOT}) + ##################MODULES & TESTS -set(TEST_MAIN ${CMAKE_SOURCE_DIR}/test/unit) -if (BUILD_TESTS) - enable_testing() - add_subdirectory(test) -endif() \ No newline at end of file +set(TEST_MAIN ${HERMES_SHM_ROOT}/test/unit) +enable_testing() +add_subdirectory(test) +add_subdirectory(benchmark) +add_subdirectory(example) + +##################Install hermes +install(DIRECTORY include DESTINATION ${CMAKE_INSTALL_PREFIX}) diff --git a/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h b/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h index 3f1519c23..775577c7c 100644 --- a/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h +++ b/hermes_shm/include/hermes_shm/constants/data_structure_singleton_macros.h @@ -10,18 +10,21 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_CONSTANTS_DATA_STRUCTURE_SINGLETON_MACROS_H_H -#define HERMES_SHM_INCLUDE_HERMES_SHM_CONSTANTS_DATA_STRUCTURE_SINGLETON_MACROS_H_H +#ifndef HERMES_INCLUDE_HERMES_CONSTANTS_DATA_STRUCTURE_SINGLETON_MACROS_H_H +#define HERMES_INCLUDE_HERMES_CONSTANTS_DATA_STRUCTURE_SINGLETON_MACROS_H_H #include -#define HERMES_SHM_SYSTEM_INFO scs::Singleton::GetInstance() -#define HERMES_SHM_SYSTEM_INFO_T hermes_shm::SystemInfo* +#define HERMES_SYSTEM_INFO scs::Singleton::GetInstance() +#define HERMES_SYSTEM_INFO_T hermes_shm::SystemInfo* -#define HERMES_SHM_MEMORY_MANAGER scs::Singleton::GetInstance() -#define HERMES_SHM_MEMORY_MANAGER_T hermes_shm::ipc::MemoryManager* +#define HERMES_MEMORY_REGISTRY scs::Singleton::GetInstance() +#define HERMES_MEMORY_REGISTRY_T hermes_shm::ipc::MemoryRegistry* -#define HERMES_SHM_THREAD_MANAGER scs::Singleton::GetInstance() -#define HERMES_SHM_THREAD_MANAGER_T hermes_shm::ThreadManager* +#define HERMES_MEMORY_MANAGER scs::Singleton::GetInstance() +#define HERMES_MEMORY_MANAGER_T hermes_shm::ipc::MemoryManager* + +#define HERMES_THREAD_MANAGER scs::Singleton::GetInstance() +#define HERMES_THREAD_MANAGER_T hermes_shm::ThreadManager* #endif // include_labstor_constants_data_structure_singleton_macros_h diff --git a/hermes_shm/include/hermes_shm/constants/macros.h b/hermes_shm/include/hermes_shm/constants/macros.h index 884527725..9d5b2388c 100644 --- a/hermes_shm/include/hermes_shm/constants/macros.h +++ b/hermes_shm/include/hermes_shm/constants/macros.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_MACROS_H -#define HERMES_SHM_MACROS_H +#ifndef HERMES_MACROS_H +#define HERMES_MACROS_H #define KILOBYTES(n) ((size_t)(n) * (1<<10)) #define MEGABYTES(n) ((size_t)(n) * (1<<20)) @@ -27,4 +27,4 @@ #define ESC_(...) VAN ## __VA_ARGS__ #define VANISH -#endif // HERMES_SHM_MACROS_H +#endif // HERMES_MACROS_H diff --git a/hermes_shm/include/hermes_shm/data_structures/data_structure.h b/hermes_shm/include/hermes_shm/data_structures/data_structure.h index ce21574c3..c8c112204 100644 --- a/hermes_shm/include/hermes_shm/data_structures/data_structure.h +++ b/hermes_shm/include/hermes_shm/data_structures/data_structure.h @@ -10,13 +10,16 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_DATA_STRUCTURES_DATA_STRUCTURE_H_ -#define HERMES_SHM_DATA_STRUCTURES_DATA_STRUCTURE_H_ -#include "internal/shm_archive.h" -#include "internal/shm_container.h" -#include "internal/shm_smart_ptr.h" -#include "internal/shm_macros.h" -#include "internal/shm_container.h" +#ifndef HERMES_DATA_STRUCTURES_DATA_STRUCTURE_H_ +#define HERMES_DATA_STRUCTURES_DATA_STRUCTURE_H_ -#endif // HERMES_SHM_DATA_STRUCTURES_DATA_STRUCTURE_H_ +#include "hermes_shm/data_structures/internal/shm_internal.h" +#include "hermes_shm/memory/memory_manager.h" +// #include "pair.h" +// #include "string.h" +// #include "thread_unsafe/list.h" +// #include "thread_unsafe/vector.h" +// #include "thread_unsafe/unordered_map.h" + +#endif // HERMES_DATA_STRUCTURES_DATA_STRUCTURE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h index d0f12ca10..2544213ba 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive.h @@ -10,10 +10,10 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_DATA_STRUCTURES_SHM_ARCHIVE_H_ -#define HERMES_SHM_DATA_STRUCTURES_SHM_ARCHIVE_H_ -#include "hermes_shm/memory/memory_manager.h" +#ifndef HERMES_DATA_STRUCTURES_SHM_ARCHIVE_H_ +#define HERMES_DATA_STRUCTURES_SHM_ARCHIVE_H_ + #include "shm_macros.h" namespace hermes_shm::ipc { @@ -102,4 +102,4 @@ class ShmArchiveable : public ShmPredictable { } // namespace hermes_shm::ipc -#endif // HERMES_SHM_DATA_STRUCTURES_SHM_ARCHIVE_H_ +#endif // HERMES_DATA_STRUCTURES_SHM_ARCHIVE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h index 52b4e9ae4..0b51fba02 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h @@ -10,12 +10,11 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_DATA_STRUCTURES_SHM_AR_H_ -#define HERMES_SHM_DATA_STRUCTURES_SHM_AR_H_ + +#ifndef HERMES_DATA_STRUCTURES_SHM_AR_H_ +#define HERMES_DATA_STRUCTURES_SHM_AR_H_ #include "hermes_shm/memory/memory.h" -#include "hermes_shm/data_structures/data_structure.h" -#include "hermes_shm/types/tuple_base.h" namespace hermes_shm::ipc { @@ -23,28 +22,33 @@ namespace hermes_shm::ipc { * Constructs a TypedPointer in-place * */ template -class _ShmHeaderOrT_Header { +class _ShmArchiveOrT_Header { public: typedef typename T::header_t header_t; - header_t obj_hdr_; + char obj_hdr_[sizeof(header_t)]; public: /** Default constructor */ - _ShmHeaderOrT_Header() = default; + _ShmArchiveOrT_Header() = default; + + /** Destructor */ + ~_ShmArchiveOrT_Header() = default; - /** Construct + store object */ + /** SHM Construct + store object */ template - explicit _ShmHeaderOrT_Header(Allocator *alloc, Args&& ...args) { - T(obj_hdr_, alloc, std::forward(args)...).UnsetDestructable(); + void shm_init(Allocator *alloc, Args&& ...args) { + T(reinterpret_cast(obj_hdr_), + alloc, std::forward(args)...).UnsetDestructable(); } - /** Construct + store object (hermes_shm rval argpack) */ + /** SHM Construct + store object (hermes rval argpack) */ template - void PiecewiseInit(Allocator *alloc, - ArgPackT &&args) { + void shm_init_piecewise(Allocator *alloc, ArgPackT &&args) { T obj; PassArgPack::Call( - MergeArgPacks::Merge(make_argpack(obj, obj_hdr_, alloc), + MergeArgPacks::Merge(make_argpack(obj, + reinterpret_cast(obj_hdr_), + alloc), std::forward(args)), [](auto&& ...Args) constexpr { Allocator::ConstructObj(std::forward(Args)...); @@ -52,10 +56,7 @@ class _ShmHeaderOrT_Header { obj.UnsetDestructable(); } - /** Destructor */ - ~_ShmHeaderOrT_Header() = default; - - /** Shm destructor */ + /** SHM destructor */ void shm_destroy(Allocator *alloc) { auto ar = internal_ref(alloc); T obj; @@ -64,33 +65,13 @@ class _ShmHeaderOrT_Header { } /** Returns a reference to the internal object */ - TypedPointer internal_ref(Allocator *alloc) { - return TypedPointer(alloc->Convert(&obj_hdr_)); + ShmDeserialize internal_ref(Allocator *alloc) { + return ShmDeserialize(alloc, reinterpret_cast(obj_hdr_)); } /** Returns a reference to the internal object */ - TypedPointer internal_ref(Allocator *alloc) const { - return TypedPointer(alloc->Convert(&obj_hdr_)); - } - - /** Move constructor */ - _ShmHeaderOrT_Header(_ShmHeaderOrT_Header &&other) noexcept - : obj_hdr_(std::move(other.obj_hdr_)) {} - - /** Move assignment operator */ - _ShmHeaderOrT_Header& operator=(_ShmHeaderOrT_Header &&other) noexcept { - obj_hdr_ = std::move(other.obj_hdr_); - return *this; - } - - /** Copy constructor */ - _ShmHeaderOrT_Header(const _ShmHeaderOrT_Header &other) - : obj_hdr_(other.obj_hdr_) { - } - - /** Copy assignment operator */ - _ShmHeaderOrT_Header& operator=(const _ShmHeaderOrT_Header &other) { - obj_hdr_ = other.obj_hdr_; + ShmDeserialize internal_ref(Allocator *alloc) const { + return ShmDeserialize(alloc, reinterpret_cast(obj_hdr_)); } }; @@ -98,27 +79,27 @@ class _ShmHeaderOrT_Header { * Constructs an object in-place * */ template -class _ShmHeaderOrT_T { +class _ShmArchiveOrT_T { public: char obj_[sizeof(T)]; /**< Store object without constructing */ public: - /** Default constructor */ - _ShmHeaderOrT_T() { - Allocator::ConstructObj(internal_ref(nullptr)); - } + /** Default constructor. */ + _ShmArchiveOrT_T() = default; + + /** Destructor. Does nothing. */ + ~_ShmArchiveOrT_T() = default; /** Construct + store object (C++ argpack) */ template - explicit _ShmHeaderOrT_T(Allocator *alloc, Args&& ...args) { + void shm_init(Allocator *alloc, Args&& ...args) { Allocator::ConstructObj( internal_ref(alloc), std::forward(args)...); } - /** Construct + store object (hermes_shm rval argpack) */ + /** Construct + store object (hermes rval argpack) */ template - void PiecewiseInit(Allocator *alloc, - ArgPackT &&args) { + void shm_init_piecewise(Allocator *alloc, ArgPackT &&args) { hermes_shm::PassArgPack::Call( MergeArgPacks::Merge( make_argpack(internal_ref(alloc)), @@ -129,10 +110,9 @@ class _ShmHeaderOrT_T { } /** Shm destructor */ - void shm_destroy(Allocator *alloc) {} - - /** Destructor. Does nothing. */ - ~_ShmHeaderOrT_T() = default; + void shm_destroy(Allocator *alloc) { + Allocator::DestructObj(internal_ref(alloc)); + } /** Returns a reference to the internal object */ T& internal_ref(Allocator *alloc) { @@ -145,37 +125,13 @@ class _ShmHeaderOrT_T { (void) alloc; return reinterpret_cast(obj_); } - - /** Move constructor */ - _ShmHeaderOrT_T(_ShmHeaderOrT_T &&other) noexcept { - Allocator::ConstructObj<_ShmHeaderOrT_T>( - obj_, std::move(other.internal_ref())); - } - - /** Move assignment operator */ - _ShmHeaderOrT_T& operator=(_ShmHeaderOrT_T &&other) noexcept { - internal_ref() = std::move(other.internal_ref()); - return *this; - } - - /** Copy constructor */ - _ShmHeaderOrT_T(const _ShmHeaderOrT_T &other) { - Allocator::ConstructObj<_ShmHeaderOrT_T>( - obj_, other); - } - - /** Copy assignment operator */ - _ShmHeaderOrT_T& operator=(const _ShmHeaderOrT_T &other) { - internal_ref() = other.internal_ref(); - return *this; - } }; /** - * Whether or not to use _ShmHeaderOrT or _ShmHeaderOrT_T + * Whether or not to use _ShmArchiveOrT or _ShmArchiveOrT_T * */ #define SHM_MAKE_HEADER_OR_T(T) \ - SHM_X_OR_Y(T, _ShmHeaderOrT_Header, _ShmHeaderOrT_T) + SHM_X_OR_Y(T, _ShmArchiveOrT_Header, _ShmArchiveOrT_T) /** * Used for data structures which intend to store: @@ -186,28 +142,29 @@ class _ShmHeaderOrT_T { * E.g., used in a list for storing list entries. * */ template -class ShmHeaderOrT { +class ShmArchiveOrT { public: typedef SHM_ARCHIVE_OR_REF(T) T_Ar; typedef SHM_MAKE_HEADER_OR_T(T) T_Hdr; T_Hdr obj_; /** Default constructor */ - ShmHeaderOrT() = default; + ShmArchiveOrT() = default; - /** Construct + store object */ + /** Construct object */ template - explicit ShmHeaderOrT(Args&& ...args) - : obj_(std::forward(args)...) {} + void shm_init(Args&& ...args) { + obj_.shm_init(std::forward(args)...); + } - /** Construct + store object (hermes_shm rval argpack) */ + /** Construct + store object (hermes rval argpack) */ template - void PiecewiseInit(Allocator *alloc, ArgPackT &&args) { - obj_.PiecewiseInit(alloc, std::forward(args)); + void shm_init_piecewise(Allocator *alloc, ArgPackT &&args) { + obj_.shm_init_piecewise(alloc, std::forward(args)); } /** Destructor */ - ~ShmHeaderOrT() = default; + ~ShmArchiveOrT() = default; /** Returns a reference to the internal object */ T_Ar internal_ref(Allocator *alloc) { @@ -223,27 +180,8 @@ class ShmHeaderOrT { void shm_destroy(Allocator *alloc) { obj_.shm_destroy(alloc); } - - /** Move constructor */ - ShmHeaderOrT(ShmHeaderOrT &&other) noexcept - : obj_(std::move(other.obj_)) {} - - /** Move assignment operator */ - ShmHeaderOrT& operator=(ShmHeaderOrT &&other) noexcept { - obj_ = std::move(other.obj_); - return *this; - } - - /** Copy constructor */ - ShmHeaderOrT(const ShmHeaderOrT &other) - : obj_(other.obj_) {} - - /** Copy assignment operator */ - ShmHeaderOrT& operator=(const ShmHeaderOrT &other) { - obj_ = other.obj_; - } }; } // namespace hermes_shm::ipc -#endif // HERMES_SHM_DATA_STRUCTURES_SHM_AR_H_ +#endif // HERMES_DATA_STRUCTURES_SHM_AR_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h index 3df01401f..7b2b9c420 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container.h @@ -10,10 +10,11 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_SHM_CONTAINER_H_ -#define HERMES_SHM_SHM_CONTAINER_H_ -#include "hermes_shm/memory/memory_manager.h" +#ifndef HERMES_SHM_CONTAINER_H_ +#define HERMES_SHM_CONTAINER_H_ + +#include "hermes_shm/memory/memory_registry.h" #include "hermes_shm/constants/macros.h" #include "shm_container_macro.h" #include "shm_macros.h" @@ -81,4 +82,4 @@ static inline T* typed_nullptr() { } // namespace hermes_shm::ipc -#endif // HERMES_SHM_SHM_CONTAINER_H_ +#endif // HERMES_SHM_CONTAINER_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h index 8cf120288..b67bfec68 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_extend_macro.h @@ -1,18 +1,18 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ -#define HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ +#ifndef HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ +#define HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ #define SHM_CONTAINER_EXTEND_TEMPLATE(CLASS_NAME,TYPED_CLASS,TYPED_HEADER)\ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ + * Distributed under BSD 3-Clause license. *\ + * Copyright by The HDF Group. *\ + * Copyright by the Illinois Institute of Technology. *\ + * All rights reserved. *\ + * *\ + * This file is part of Hermes. The full Hermes copyright notice, including *\ + * terms governing use, modification, and redistribution, is contained in *\ + * the COPYING file, which can be found at the top directory. If you do not *\ + * have access to the file, you may request a copy from help@hdfgroup.org. *\ + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\ +\ public:\ /**====================================\ * Variables & Types\ @@ -252,4 +252,4 @@ allocator_id_t GetAllocatorId() const {\ return GetAllocator()->GetId();\ }\ -#endif // HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ +#endif // HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h index 20b285082..0fa3eccf9 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h @@ -1,18 +1,18 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ -#define HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ +#ifndef HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ +#define HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ #define SHM_CONTAINER_TEMPLATE(CLASS_NAME,TYPED_CLASS,TYPED_HEADER)\ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ + * Distributed under BSD 3-Clause license. *\ + * Copyright by The HDF Group. *\ + * Copyright by the Illinois Institute of Technology. *\ + * All rights reserved. *\ + * *\ + * This file is part of Hermes. The full Hermes copyright notice, including *\ + * terms governing use, modification, and redistribution, is contained in *\ + * the COPYING file, which can be found at the top directory. If you do not *\ + * have access to the file, you may request a copy from help@hdfgroup.org. *\ + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\ +\ public:\ /**====================================\ * Variables & Types\ @@ -23,7 +23,6 @@ header_t *header_; /**< Header of the shared-memory data structure */\ hipc::Allocator *alloc_; /**< hipc::Allocator used for this data structure */\ hermes_shm::bitfield32_t flags_; /**< Flags used data structure status */\ \ -public:\ /**====================================\ * Constructors\ * ===================================*/\ @@ -64,7 +63,7 @@ void shm_init(TYPE_UNWRAP(TYPED_HEADER) &header,\ inline void shm_init_allocator(hipc::Allocator *alloc) {\ if (IsValid()) { return; }\ if (alloc == nullptr) {\ - alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator();\ + alloc_ = HERMES_MEMORY_REGISTRY->GetDefaultAllocator();\ } else {\ alloc_ = alloc;\ }\ @@ -132,7 +131,7 @@ SHM_SERIALIZE_OPS((TYPE_UNWRAP(TYPED_CLASS)))\ /** Deserialize object from a raw pointer */\ bool shm_deserialize(const hipc::TypedPointer &ar) {\ return shm_deserialize(\ - HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_),\ + HERMES_MEMORY_REGISTRY->GetAllocator(ar.allocator_id_),\ ar.ToOffsetPointer()\ );\ }\ @@ -152,6 +151,11 @@ bool shm_deserialize(const TYPE_UNWRAP(CLASS_NAME) &other) {\ return shm_deserialize(other.GetAllocator(), other.header_);\ }\ \ +/** Deserialize object from "Deserialize" object */\ +bool shm_deserialize(hipc::ShmDeserialize other) {\ + return shm_deserialize(other.alloc_, other.header_);\ +}\ +\ /** Deserialize object from allocator + header */\ bool shm_deserialize(hipc::Allocator *alloc,\ TYPE_UNWRAP(TYPED_HEADER) *header) {\ @@ -169,6 +173,12 @@ void shm_init(hipc::ShmRef &obj) {\ shm_deserialize(obj->GetAllocator(), obj->header_);\ }\ \ +/** Constructor. Deserialize the object deserialize reference. */\ +template\ +void shm_init(hipc::ShmDeserialize other) {\ + shm_deserialize(other);\ +}\ +\ /** Override >> operators */\ SHM_DESERIALIZE_OPS((TYPE_UNWRAP(TYPED_CLASS)))\ \ @@ -338,6 +348,11 @@ POINTER_T GetShmPointer() const {\ return alloc_->Convert(header_);\ }\ \ +/** Get a ShmDeserialize object */\ +hipc::ShmDeserialize GetShmDeserialize() const {\ + return hipc::ShmDeserialize(alloc_, header_);\ +}\ +\ /**====================================\ * Query Operations\ * ===================================*/\ @@ -357,4 +372,4 @@ hipc::allocator_id_t GetAllocatorId() const {\ return alloc_->GetId();\ }\ -#endif // HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ +#endif // HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h index e674177d9..173d8c93c 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h @@ -10,10 +10,10 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ +#ifndef HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ +#define HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ -#include "hermes_shm/memory/memory_manager.h" +#include "hermes_shm/memory/memory_registry.h" namespace hermes_shm::ipc { @@ -33,7 +33,7 @@ struct ShmDeserialize { /** Construct from TypedPointer */ ShmDeserialize(const TypedPointer &ar) { - alloc_ = HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_); + alloc_ = HERMES_MEMORY_REGISTRY->GetAllocator(ar.allocator_id_); header_ = alloc_->Convert< TypedPointer, OffsetPointer>(ar.ToOffsetPointer()); @@ -89,4 +89,4 @@ struct ShmDeserialize { } // namespace hermes_shm::ipc -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ +#endif //HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_DESERIALIZE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h index 179785009..e50dc8b10 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_macros.h @@ -10,8 +10,9 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_MEMORY_SHM_MACROS_H_ -#define HERMES_SHM_MEMORY_SHM_MACROS_H_ + +#ifndef HERMES_MEMORY_SHM_MACROS_H_ +#define HERMES_MEMORY_SHM_MACROS_H_ #include @@ -45,7 +46,7 @@ SHM_X_OR_Y(T, T, T*) /** - * ShmHeaderOrT: Returns TypedPointer if SHM_ARCHIVEABLE, and T + * ShmArchiveOrT: Returns TypedPointer if SHM_ARCHIVEABLE, and T * otherwise. Used to construct an hipc::ShmRef. * * @param T The type being stored in the shmem data structure @@ -75,6 +76,6 @@ * SHM_ARCHIVE_OR_REF: Return value of shm_ar::internal_ref(). * */ #define SHM_ARCHIVE_OR_REF(T)\ - SHM_X_OR_Y(T, TypedPointer, T&) + SHM_X_OR_Y(T, ShmDeserialize, T&) -#endif // HERMES_SHM_MEMORY_SHM_MACROS_H_ +#endif // HERMES_MEMORY_SHM_MACROS_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h index dba9ce461..1caaa1ea5 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_null_container.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ +#ifndef HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ +#define HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ #include "shm_container.h" #include @@ -124,4 +124,4 @@ namespace std { #undef TYPED_CLASS #undef TYPED_HEADER -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ +#endif //HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_SHM_NULL_CONTAINER_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h index 2bbf3a9fd..8c41638e3 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_ref.h @@ -10,12 +10,13 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ +#ifndef HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ +#define HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ #include "hermes_shm/constants/macros.h" #include "shm_macros.h" #include "shm_archive.h" +#include "shm_deserialize.h" namespace hermes_shm::ipc { @@ -34,11 +35,16 @@ struct _ShmRefShm { obj_.UnsetDestructable(); } - /** Constructor. */ + /** Constructor. From TypedPointer. */ explicit _ShmRefShm(TypedPointer other) { obj_.shm_deserialize(other); } + /** Constructor. From ShmDeserialize. */ + explicit _ShmRefShm(ShmDeserialize other) { + obj_.shm_deserialize(other); + } + /** Copy constructor */ _ShmRefShm(const _ShmRefShm &other) { obj_.shm_deserialize(other.obj_); @@ -198,4 +204,4 @@ struct ShmRef { } // namespace hermes_shm::ipc -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ +#endif //HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_SHM_ShmRef_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h index 4db23e2ae..8de6b6e20 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_smart_ptr.h @@ -10,12 +10,13 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ -#define HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ + +#ifndef HERMES_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ +#define HERMES_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ #include "hermes_shm/memory/memory.h" #include "hermes_shm/memory/allocator/allocator.h" -#include "hermes_shm/memory/memory_manager.h" +#include "hermes_shm/memory/memory_registry.h" #include "hermes_shm/data_structures/internal/shm_macros.h" #include @@ -159,4 +160,4 @@ class ShmSmartPtr : public ShmSmartPointer { SHM_SERIALIZE_WRAPPER(AR_TYPE)\ SHM_DESERIALIZE_WRAPPER(AR_TYPE) -#endif // HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ +#endif // HERMES_DATA_STRUCTURES_INTERNAL_SHM_DATA_STRUCTURE_POINTER_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h index bb5b8c96b..aeb7e08dd 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h @@ -10,10 +10,11 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ +#ifndef HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ +#define HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ #include "hermes_shm/data_structures/internal/shm_container.h" +#include "hermes_shm/data_structures/internal/shm_deserialize.h" namespace honey { @@ -119,7 +120,7 @@ class ShmContainerExample { inline void shm_init_allocator(hipc::Allocator *alloc) { if (IsValid()) { return; } if (alloc == nullptr) { - alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + alloc_ = HERMES_MEMORY_REGISTRY->GetDefaultAllocator(); } else { alloc_ = alloc; } @@ -187,7 +188,7 @@ class ShmContainerExample { /** Deserialize object from a raw pointer */ bool shm_deserialize(const hipc::TypedPointer &ar) { return shm_deserialize( - HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_), + HERMES_MEMORY_REGISTRY->GetAllocator(ar.allocator_id_), ar.ToOffsetPointer() ); } @@ -207,6 +208,11 @@ class ShmContainerExample { return shm_deserialize(other.GetAllocator(), other.header_); } + /** Deserialize object from "Deserialize" object */ + bool shm_deserialize(hipc::ShmDeserialize other) { + return shm_deserialize(other.alloc_, other.header_); + } + /** Deserialize object from allocator + header */ bool shm_deserialize(hipc::Allocator *alloc, TYPED_HEADER *header) { @@ -224,6 +230,12 @@ class ShmContainerExample { shm_deserialize(obj->GetAllocator(), obj->header_); } + /** Constructor. Deserialize the object deserialize reference. */ + template + void shm_init(hipc::ShmDeserialize other) { + shm_deserialize(other); + } + /** Override >> operators */ SHM_DESERIALIZE_OPS((TYPED_CLASS)) @@ -393,6 +405,11 @@ class ShmContainerExample { return alloc_->Convert(header_); } + /** Get a ShmDeserialize object */ + hipc::ShmDeserialize GetShmDeserialize() const { + return hipc::ShmDeserialize(alloc_, header_); + } + /**==================================== * Query Operations * ===================================*/ @@ -419,4 +436,4 @@ class ShmContainerExample { #undef TYPED_CLASS #undef TYPED_HEADER -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ +#endif //HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXAMPLE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h index e6aff6dd9..2a0c85097 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h @@ -20,7 +20,6 @@ header_t *header_; /**< Header of the shared-memory data structure */ hipc::Allocator *alloc_; /**< hipc::Allocator used for this data structure */ hermes_shm::bitfield32_t flags_; /**< Flags used data structure status */ -public: /**==================================== * Constructors * ===================================*/ @@ -61,7 +60,7 @@ void shm_init(TYPED_HEADER &header, inline void shm_init_allocator(hipc::Allocator *alloc) { if (IsValid()) { return; } if (alloc == nullptr) { - alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + alloc_ = HERMES_MEMORY_REGISTRY->GetDefaultAllocator(); } else { alloc_ = alloc; } @@ -129,7 +128,7 @@ SHM_SERIALIZE_OPS((TYPED_CLASS)) /** Deserialize object from a raw pointer */ bool shm_deserialize(const hipc::TypedPointer &ar) { return shm_deserialize( - HERMES_SHM_MEMORY_MANAGER->GetAllocator(ar.allocator_id_), + HERMES_MEMORY_REGISTRY->GetAllocator(ar.allocator_id_), ar.ToOffsetPointer() ); } @@ -149,6 +148,11 @@ bool shm_deserialize(const CLASS_NAME &other) { return shm_deserialize(other.GetAllocator(), other.header_); } +/** Deserialize object from "Deserialize" object */ +bool shm_deserialize(hipc::ShmDeserialize other) { + return shm_deserialize(other.alloc_, other.header_); +} + /** Deserialize object from allocator + header */ bool shm_deserialize(hipc::Allocator *alloc, TYPED_HEADER *header) { @@ -166,6 +170,12 @@ void shm_init(hipc::ShmRef &obj) { shm_deserialize(obj->GetAllocator(), obj->header_); } +/** Constructor. Deserialize the object deserialize reference. */ +template +void shm_init(hipc::ShmDeserialize other) { + shm_deserialize(other); +} + /** Override >> operators */ SHM_DESERIALIZE_OPS((TYPED_CLASS)) @@ -335,6 +345,11 @@ POINTER_T GetShmPointer() const { return alloc_->Convert(header_); } +/** Get a ShmDeserialize object */ +hipc::ShmDeserialize GetShmDeserialize() const { + return hipc::ShmDeserialize(alloc_, header_); +} + /**==================================== * Query Operations * ===================================*/ @@ -352,4 +367,4 @@ hipc::Allocator* GetAllocator() const { /** Get the shared-memory allocator id */ hipc::allocator_id_t GetAllocatorId() const { return alloc_->GetId(); -} +} \ No newline at end of file diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h index 9f98382ff..6fe500ea3 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_extend_example.h @@ -14,8 +14,8 @@ * Let's say we want a data structure * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_INHERIT_EXAMPLE_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_INHERIT_EXAMPLE_H_ +#ifndef HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_INHERIT_EXAMPLE_H_ +#define HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_INHERIT_EXAMPLE_H_ #define CLASS_NAME ShmContainerExtendExample #define TYPED_CLASS ShmContainerExtendExample @@ -313,4 +313,4 @@ class ShmContainerExtendExample : public ShmContainer { #undef TYPED_CLASS #undef TYPED_HEADER -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_INHERIT_EXAMPLE_H_ +#endif //HERMES_INCLUDE_HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_INHERIT_EXAMPLE_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/pair.h b/hermes_shm/include/hermes_shm/data_structures/pair.h index 035854acf..9f4d46a80 100644 --- a/hermes_shm/include/hermes_shm/data_structures/pair.h +++ b/hermes_shm/include/hermes_shm/data_structures/pair.h @@ -10,11 +10,10 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_PAIR_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_PAIR_H_ +#ifndef HERMES_INCLUDE_HERMES_DATA_STRUCTURES_PAIR_H_ +#define HERMES_INCLUDE_HERMES_DATA_STRUCTURES_PAIR_H_ -#include "data_structure.h" -#include "internal/shm_archive_or_t.h" +#include "internal/shm_internal.h" namespace hermes_shm::ipc { @@ -33,15 +32,20 @@ class pair; /** pair shared-memory header */ template struct ShmHeader : public ShmBaseHeader { - ShmHeaderOrT first_; - ShmHeaderOrT second_; + ShmArchiveOrT first_; + ShmArchiveOrT second_; /** Default constructor */ - ShmHeader() = default; + ShmHeader() { + first_.shm_init(); + second_.shm_init(); + } /** Constructor. Default shm allocate. */ - explicit ShmHeader(Allocator *alloc) - : first_(alloc), second_(alloc) {} + explicit ShmHeader(Allocator *alloc) { + first_.shm_init(alloc); + second_.shm_init(alloc); + } /** Piecewise constructor. */ template @@ -50,22 +54,25 @@ struct ShmHeader : public ShmBaseHeader { FirstArgPackT &&first, SecondArgPackT &&second) { (void) hint; - first_.PiecewiseInit(alloc, std::forward(first)); - second_.PiecewiseInit(alloc, std::forward(second)); + first_.shm_init_piecewise(alloc, std::forward(first)); + second_.shm_init_piecewise(alloc, std::forward(second)); } /** Move constructor. */ explicit ShmHeader(Allocator *alloc, FirstT &&first, - SecondT &&second) - : first_(alloc, std::forward(first)), - second_(alloc, std::forward(second)) {} + SecondT &&second) { + first_.shm_init(alloc, std::forward(first)); + second_.shm_init(alloc, std::forward(second)); + } /** Copy constructor. */ explicit ShmHeader(Allocator *alloc, const FirstT &first, - const SecondT &second) - : first_(alloc, first), second_(alloc, second) {} + const SecondT &second) { + first_.shm_init(alloc, first); + second_.shm_init(alloc, second); + } /** Shm destructor */ void shm_destroy(Allocator *alloc) { @@ -200,4 +207,4 @@ class pair : public ShmContainer { } // namespace hermes_shm::ipc -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_PAIR_H_ +#endif //HERMES_INCLUDE_HERMES_DATA_STRUCTURES_PAIR_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h b/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h index 892bbfe9f..49d7e95ae 100644 --- a/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h +++ b/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h @@ -10,12 +10,13 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_DATA_STRUCTURES_PTR_H_ -#define HERMES_SHM_DATA_STRUCTURES_PTR_H_ + +#ifndef HERMES_DATA_STRUCTURES_PTR_H_ +#define HERMES_DATA_STRUCTURES_PTR_H_ #include "hermes_shm/memory/memory.h" -#include "hermes_shm/data_structures/data_structure.h" -#include "hermes_shm/data_structures/internal/shm_archive_or_t.h" +#include "unique_ptr.h" +#include "hermes_shm/data_structures/internal/shm_internal.h" namespace hermes_shm::ipc { @@ -109,4 +110,4 @@ struct hash> { } // namespace std -#endif // HERMES_SHM_DATA_STRUCTURES_PTR_H_ +#endif // HERMES_DATA_STRUCTURES_PTR_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/string.h b/hermes_shm/include/hermes_shm/data_structures/string.h index e5d968eb9..9966a90bd 100644 --- a/hermes_shm/include/hermes_shm/data_structures/string.h +++ b/hermes_shm/include/hermes_shm/data_structures/string.h @@ -10,10 +10,11 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_DATA_STRUCTURES_LOCKLESS_STRING_H_ -#define HERMES_SHM_DATA_STRUCTURES_LOCKLESS_STRING_H_ -#include "data_structure.h" +#ifndef HERMES_DATA_STRUCTURES_LOCKLESS_STRING_H_ +#define HERMES_DATA_STRUCTURES_LOCKLESS_STRING_H_ + +#include "internal/shm_internal.h" #include namespace hermes_shm::ipc { @@ -244,7 +245,7 @@ class string : public ShmContainer { return sum; } -#define HERMES_SHM_STR_CMP_OPERATOR(op) \ +#define HERMES_STR_CMP_OPERATOR(op) \ bool operator op(const char *other) const { \ return _strncmp(data(), size(), other, strlen(other)) op 0; \ } \ @@ -255,14 +256,14 @@ class string : public ShmContainer { return _strncmp(data(), size(), other.data(), other.size()) op 0; \ } - HERMES_SHM_STR_CMP_OPERATOR(==) - HERMES_SHM_STR_CMP_OPERATOR(!=) - HERMES_SHM_STR_CMP_OPERATOR(<) - HERMES_SHM_STR_CMP_OPERATOR(>) - HERMES_SHM_STR_CMP_OPERATOR(<=) - HERMES_SHM_STR_CMP_OPERATOR(>=) + HERMES_STR_CMP_OPERATOR(==) + HERMES_STR_CMP_OPERATOR(!=) + HERMES_STR_CMP_OPERATOR(<) + HERMES_STR_CMP_OPERATOR(>) + HERMES_STR_CMP_OPERATOR(<=) + HERMES_STR_CMP_OPERATOR(>=) -#undef HERMES_SHM_STR_CMP_OPERATOR +#undef HERMES_STR_CMP_OPERATOR private: inline void _create_str(const char *text, size_t length) { @@ -298,4 +299,4 @@ struct hash { #undef TYPED_CLASS #undef TYPED_HEADER -#endif // HERMES_SHM_DATA_STRUCTURES_LOCKLESS_STRING_H_ +#endif // HERMES_DATA_STRUCTURES_LOCKLESS_STRING_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h index e80ce4b3e..d55330cac 100644 --- a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/list.h @@ -10,11 +10,11 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ -#define HERMES_SHM_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ -#include "hermes_shm/data_structures/data_structure.h" -#include "hermes_shm/data_structures/internal/shm_archive_or_t.h" +#ifndef HERMES_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ +#define HERMES_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ + +#include "hermes_shm/data_structures/internal/shm_internal.h" #include @@ -29,12 +29,13 @@ template struct list_entry { public: OffsetPointer next_ptr_, prior_ptr_; - ShmHeaderOrT data_; + ShmArchiveOrT data_; /** Constructor */ template - explicit list_entry(Allocator *alloc, Args ...args) - : data_(alloc, std::forward(args)...) {} + explicit list_entry(Allocator *alloc, Args&& ...args) { + data_.shm_init(alloc, std::forward(args)...); + } /** Destructor */ void shm_destroy(Allocator *alloc) { @@ -73,11 +74,7 @@ struct list_iterator_templ { : entry_(nullptr), entry_ptr_(OffsetPointer::GetNull()) {} /** Construct an iterator */ - explicit list_iterator_templ(TypedPointer> list) - : list_(list), entry_(nullptr), entry_ptr_(OffsetPointer::GetNull()) {} - - /** Construct an iterator */ - explicit list_iterator_templ(TypedPointer> list, + explicit list_iterator_templ(ShmDeserialize> list, list_entry *entry, OffsetPointer entry_ptr) : list_(list), entry_(entry), entry_ptr_(entry_ptr) {} @@ -475,7 +472,7 @@ class list : public ShmContainer { if (size() == 0) { return end(); } auto head = alloc_->template Convert>(header_->head_ptr_); - return list_iterator(GetShmPointer>>(), + return list_iterator(GetShmDeserialize(), head, header_->head_ptr_); } @@ -489,7 +486,7 @@ class list : public ShmContainer { if (size() == 0) { return cend(); } auto head = alloc_->template Convert>(header_->head_ptr_); - return list_citerator(GetShmPointer>>(), + return list_citerator(GetShmDeserialize(), head, header_->head_ptr_); } @@ -514,4 +511,4 @@ class list : public ShmContainer { #undef TYPED_CLASS #undef TYPED_HEADER -#endif // HERMES_SHM_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ +#endif // HERMES_DATA_STRUCTURES_THREAD_UNSAFE_LIST_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h index 80ee70487..ca0c5dee4 100644 --- a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/unordered_map.h @@ -10,15 +10,16 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_DATA_STRUCTURES_UNORDERED_MAP_H_ -#define HERMES_SHM_DATA_STRUCTURES_UNORDERED_MAP_H_ + +#ifndef HERMES_DATA_STRUCTURES_UNORDERED_MAP_H_ +#define HERMES_DATA_STRUCTURES_UNORDERED_MAP_H_ #include "hermes_shm/thread/thread_manager.h" #include "hermes_shm/data_structures/thread_unsafe/vector.h" #include "hermes_shm/data_structures/thread_unsafe/list.h" #include "hermes_shm/data_structures/pair.h" -#include "hermes_shm/data_structures/data_structure.h" #include "hermes_shm/types/atomic.h" +#include "hermes_shm/data_structures/internal/shm_internal.h" namespace hermes_shm::ipc { @@ -165,7 +166,7 @@ struct ShmHeader : public ShmBaseHeader { using BUCKET_T = hipc::list; public: - ShmHeaderOrT> buckets_; + ShmArchiveOrT> buckets_; RealNumber max_capacity_; RealNumber growth_; hipc::atomic length_; @@ -177,7 +178,8 @@ struct ShmHeader : public ShmBaseHeader { explicit ShmHeader(Allocator *alloc, int num_buckets, RealNumber max_capacity, - RealNumber growth) : buckets_(alloc, num_buckets) { + RealNumber growth) { + buckets_.shm_init(alloc, num_buckets); max_capacity_ = max_capacity; growth_ = growth; length_ = 0; @@ -195,7 +197,7 @@ struct ShmHeader : public ShmBaseHeader { (*GetBuckets(alloc)) = std::move(*other.GetBuckets(other_alloc)); max_capacity_ = other.max_capacity_; growth_ = other.growth_; - length_ = other.length_.load();/**/ + length_ = other.length_.load(); } /** Get a reference to the buckets */ @@ -537,4 +539,4 @@ class unordered_map : public ShmContainer { #undef TYPED_CLASS #undef TYPED_HEADER -#endif // HERMES_SHM_DATA_STRUCTURES_UNORDERED_MAP_H_ +#endif // HERMES_DATA_STRUCTURES_UNORDERED_MAP_H_ diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h index 38996df27..1c043137a 100644 --- a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h @@ -10,11 +10,11 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ -#define HERMES_SHM_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ -#include "hermes_shm/data_structures/data_structure.h" -#include "hermes_shm/data_structures/internal/shm_archive_or_t.h" +#ifndef HERMES_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ +#define HERMES_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ + +#include "hermes_shm/data_structures/internal/shm_internal.h" #include @@ -37,17 +37,9 @@ struct vector_iterator_templ { vector_iterator_templ() = default; /** Construct an iterator */ - inline explicit vector_iterator_templ(TypedPointer> vec) + inline explicit vector_iterator_templ(ShmDeserialize> &&vec) : vec_(vec) {} - /** Construct end iterator */ - inline explicit vector_iterator_templ(size_t i) - : i_(static_cast(i)) {} - - /** Construct an iterator at \a i offset */ - inline explicit vector_iterator_templ(TypedPointer> vec, size_t i) - : vec_(vec), i_(static_cast(i)) {} - /** Construct an iterator at \a i offset */ inline explicit vector_iterator_templ(const hipc::ShmRef> &vec, size_t i) @@ -97,18 +89,10 @@ struct vector_iterator_templ { /** Increment iterator in-place */ inline vector_iterator_templ& operator++() { - if (is_end()) { return *this; } if constexpr(FORWARD_ITER) { ++i_; - if (i_ >= vec_->size()) { - set_end(); - } } else { - if (i_ == 0) { - set_end(); - } else { - --i_; - } + --i_; } return *this; } @@ -140,73 +124,37 @@ struct vector_iterator_templ { /** Increment iterator by \a count and return */ inline vector_iterator_templ operator+(size_t count) const { - if (is_end()) { return end(); } if constexpr(FORWARD_ITER) { - if (i_ + count > vec_->size()) { - return end(); - } return vector_iterator_templ(vec_, i_ + count); } else { - if (i_ < count - 1) { - return end(); - } return vector_iterator_templ(vec_, i_ - count); } } /** Decrement iterator by \a count and return */ inline vector_iterator_templ operator-(size_t count) const { - if (is_end()) { return end(); } if constexpr(FORWARD_ITER) { - if (i_ < count) { - return begin(); - } return vector_iterator_templ(vec_, i_ - count); } else { - if (i_ + count > vec_->size() - 1) { - return begin(); - } return vector_iterator_templ(vec_, i_ + count); } } /** Increment iterator by \a count in-place */ inline void operator+=(size_t count) { - if (is_end()) { return end(); } if constexpr(FORWARD_ITER) { - if (i_ + count > vec_->size()) { - set_end(); - return; - } i_ += count; - return; } else { - if (i_ < count - 1) { - set_end(); - return; - } i_ -= count; - return; } } /** Decrement iterator by \a count in-place */ inline void operator-=(size_t count) { - if (is_end()) { return end(); } if constexpr(FORWARD_ITER) { - if (i_ < count) { - set_begin(); - return; - } i_ -= count; - return; } else { - if (i_ + count > vec_->size() - 1) { - set_begin(); - return; - } i_ += count; - return; } } @@ -232,24 +180,27 @@ struct vector_iterator_templ { } /** Create the end iterator */ - inline static vector_iterator_templ const end() { - static vector_iterator_templ end_iter(-1); - return end_iter; + inline vector_iterator_templ const end() { + if constexpr(FORWARD_ITER) { + return vector_iterator_templ(vec_, vec_->size()); + } else { + return vector_iterator_templ(vec_, -1); + } } /** Set this iterator to end */ inline void set_end() { - i_ = -1; + if constexpr(FORWARD_ITER) { + i_ = vec_->size(); + } else { + i_ = -1; + } } /** Set this iterator to begin */ inline void set_begin() { if constexpr(FORWARD_ITER) { - if (vec_->size() > 0) { - i_ = 0; - } else { - set_end(); - } + i_ = 0; } else { i_ = vec_->size() - 1; } @@ -266,7 +217,11 @@ struct vector_iterator_templ { /** Determine whether this iterator is the end iterator */ inline bool is_end() const { - return i_ < 0; + if constexpr(FORWARD_ITER) { + return i_ == vec_->size(); + } else { + return i_ == -1; + } } }; @@ -419,8 +374,14 @@ class vector : public ShmContainer { shm_init_allocator(alloc); shm_init_header(header); reserve(other.size()); - for (auto iter = other.cbegin(); iter != other.cend(); ++iter) { - emplace_back((**iter)); + if constexpr(std::is_pod()) { + memcpy(data_ar(), other.data_ar_const(), + other.size() * sizeof(T)); + header_->length_ = other.size(); + } else { + for (auto iter = other.cbegin(); iter != other.cend(); ++iter) { + emplace_back((**iter)); + } } } @@ -471,7 +432,7 @@ class vector : public ShmContainer { /** Index the vector at position i */ hipc::ShmRef operator[](const size_t i) { - ShmHeaderOrT *vec = data_ar(); + ShmArchiveOrT *vec = data_ar(); return hipc::ShmRef(vec[i].internal_ref(alloc_)); } @@ -487,20 +448,18 @@ class vector : public ShmContainer { /** Index the vector at position i */ const hipc::ShmRef operator[](const size_t i) const { - ShmHeaderOrT *vec = data_ar_const(); + ShmArchiveOrT *vec = data_ar_const(); return hipc::ShmRef(vec[i].internal_ref(alloc_)); } /** Construct an element at the back of the vector */ template void emplace_back(Args&& ...args) { - ShmHeaderOrT *vec = data_ar(); + ShmArchiveOrT *vec = data_ar(); if (header_->length_ == header_->max_length_) { vec = grow_vector(vec, 0, false); } - Allocator::ConstructObj>( - *(vec + header_->length_), - alloc_, std::forward(args)...); + vec[header_->length_].shm_init(alloc_, std::forward(args)...); ++header_->length_; } @@ -517,14 +476,12 @@ class vector : public ShmContainer { emplace_back(std::forward(args)...); return; } - ShmHeaderOrT *vec = data_ar(); + ShmArchiveOrT *vec = data_ar(); if (header_->length_ == header_->max_length_) { vec = grow_vector(vec, 0, false); } shift_right(pos); - Allocator::ConstructObj>( - *(vec + pos.i_), - alloc_, std::forward(args)...); + vec[pos.i_].shm_init(alloc_, std::forward(args)...); ++header_->length_; } @@ -584,17 +541,17 @@ class vector : public ShmContainer { /** * Retreives a pointer to the array from the process-independent pointer. * */ - ShmHeaderOrT* data_ar() { + ShmArchiveOrT* data_ar() { return alloc_->template - Convert>(header_->vec_ptr_); + Convert>(header_->vec_ptr_); } /** * Retreives a pointer to the array from the process-independent pointer. * */ - ShmHeaderOrT* data_ar_const() const { + ShmArchiveOrT* data_ar_const() const { return alloc_->template - Convert>(header_->vec_ptr_); + Convert>(header_->vec_ptr_); } private: @@ -607,7 +564,7 @@ class vector : public ShmContainer { * @param args the arguments used to construct the elements of the vector * */ template - ShmHeaderOrT* grow_vector(ShmHeaderOrT *vec, size_t max_length, + ShmArchiveOrT* grow_vector(ShmArchiveOrT *vec, size_t max_length, bool resize, Args&& ...args) { // Grow vector by 25% if (max_length == 0) { @@ -621,21 +578,19 @@ class vector : public ShmContainer { } // Allocate new shared-memory vec - ShmHeaderOrT *new_vec; + ShmArchiveOrT *new_vec; if constexpr(std::is_pod() || IS_SHM_ARCHIVEABLE(T)) { // Use reallocate for well-behaved objects new_vec = alloc_->template - ReallocateObjs>(header_->vec_ptr_, max_length); + ReallocateObjs>(header_->vec_ptr_, max_length); } else { // Use std::move for unpredictable objects Pointer new_p; new_vec = alloc_->template - AllocateObjs>(max_length, new_p); + AllocateObjs>(max_length, new_p); for (size_t i = 0; i < header_->length_; ++i) { hipc::ShmRef old = (*this)[i]; - Allocator::ConstructObj>( - *(new_vec + i), - alloc_, std::move(*old)); + new_vec[i].shm_init(alloc_, std::move(*old)); } if (!header_->vec_ptr_.IsNull()) { alloc_->Free(header_->vec_ptr_); @@ -644,13 +599,11 @@ class vector : public ShmContainer { } if (new_vec == nullptr) { throw OUT_OF_MEMORY.format("vector::emplace_back", - max_length*sizeof(ShmHeaderOrT)); + max_length*sizeof(ShmArchiveOrT)); } if (resize) { for (size_t i = header_->length_; i < max_length; ++i) { - Allocator::ConstructObj>( - *(new_vec + i), - alloc_, std::forward(args)...); + new_vec[i].shm_init(alloc_, std::forward(args)...); } } @@ -668,16 +621,14 @@ class vector : public ShmContainer { * @param count the amount to shift left by * */ void shift_left(const vector_iterator pos, int count = 1) { - ShmHeaderOrT *vec = data_ar(); + ShmArchiveOrT *vec = data_ar(); for (int i = 0; i < count; ++i) { - auto &vec_i = *(vec + pos.i_ + i); - vec_i.shm_destroy(alloc_); - Allocator::DestructObj>(vec_i); + vec[pos.i_ + i].shm_destroy(alloc_); } auto dst = vec + pos.i_; auto src = dst + count; for (auto i = pos.i_ + count; i < size(); ++i) { - memcpy(dst, src, sizeof(ShmHeaderOrT)); + memcpy(dst, src, sizeof(ShmArchiveOrT)); dst += 1; src += 1; } } @@ -695,7 +646,7 @@ class vector : public ShmContainer { auto dst = src + count; auto sz = static_cast(size()); for (auto i = sz - 1; i >= pos.i_; --i) { - memcpy(dst, src, sizeof(ShmHeaderOrT)); + memcpy(dst, src, sizeof(ShmArchiveOrT)); dst -= 1; src -= 1; } } @@ -707,54 +658,58 @@ class vector : public ShmContainer { public: /** Beginning of the forward iterator */ vector_iterator begin() { - if (size() == 0) { return end(); } - vector_iterator iter(GetShmPointer>>()); + vector_iterator iter(ShmDeserialize>(alloc_, header_)); iter.set_begin(); return iter; } /** End of the forward iterator */ - static vector_iterator const end() { - return vector_iterator::end(); + vector_iterator const end() { + vector_iterator iter(ShmDeserialize>(alloc_, header_)); + iter.set_end(); + return iter; } /** Beginning of the constant forward iterator */ vector_citerator cbegin() const { - if (size() == 0) { return cend(); } - vector_citerator iter(GetShmPointer>>()); + vector_citerator iter(ShmDeserialize>(alloc_, header_)); iter.set_begin(); return iter; } /** End of the forward iterator */ - static const vector_citerator cend() { - return vector_citerator::end(); + vector_citerator cend() const { + vector_citerator iter(ShmDeserialize>(alloc_, header_)); + iter.set_end(); + return iter; } /** Beginning of the reverse iterator */ vector_riterator rbegin() { - if (size() == 0) { return rend(); } - vector_riterator iter(GetShmPointer>>()); + vector_riterator iter(ShmDeserialize>(alloc_, header_)); iter.set_begin(); return iter; } /** End of the reverse iterator */ - static vector_riterator const rend() { - return vector_riterator::end(); + vector_riterator rend() { + vector_citerator iter(ShmDeserialize>(alloc_, header_)); + iter.set_end(); + return iter; } /** Beginning of the constant reverse iterator */ - vector_criterator crbegin() { - if (size() == 0) { return rend(); } - vector_criterator iter(GetShmPointer>>()); + vector_criterator crbegin() const { + vector_criterator iter(ShmDeserialize(alloc_, header_)); iter.set_begin(); return iter; } /** End of the constant reverse iterator */ - static vector_criterator const crend() { - return vector_criterator::end(); + vector_criterator crend() const { + vector_criterator iter(ShmDeserialize(alloc_, header_)); + iter.set_end(); + return iter; } }; @@ -764,4 +719,4 @@ class vector : public ShmContainer { #undef TYPED_CLASS #undef TYPED_HEADER -#endif // HERMES_SHM_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ +#endif // HERMES_DATA_STRUCTURES_LOCKLESS_VECTOR_H_ diff --git a/hermes_shm/include/hermes_shm/introspect/system_info.h b/hermes_shm/include/hermes_shm/introspect/system_info.h index 6e1d86a14..c344c3cb4 100644 --- a/hermes_shm/include/hermes_shm/introspect/system_info.h +++ b/hermes_shm/include/hermes_shm/introspect/system_info.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_SYSINFO_INFO_H_ -#define HERMES_SHM_SYSINFO_INFO_H_ +#ifndef HERMES_SYSINFO_INFO_H_ +#define HERMES_SYSINFO_INFO_H_ #include #include @@ -36,4 +36,4 @@ struct SystemInfo { } // namespace hermes_shm -#endif // HERMES_SHM_SYSINFO_INFO_H_ +#endif // HERMES_SYSINFO_INFO_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/allocator.h index 8adb8de1b..9a9cc555b 100644 --- a/hermes_shm/include/hermes_shm/memory/allocator/allocator.h +++ b/hermes_shm/include/hermes_shm/memory/allocator/allocator.h @@ -10,12 +10,12 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_H_ -#define HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_H_ +#ifndef HERMES_MEMORY_ALLOCATOR_ALLOCATOR_H_ +#define HERMES_MEMORY_ALLOCATOR_ALLOCATOR_H_ #include -#include #include +#include namespace hermes_shm::ipc { @@ -24,10 +24,10 @@ namespace hermes_shm::ipc { * Used to reconstruct allocator from shared memory * */ enum class AllocatorType { - kPageAllocator, - kMultiPageAllocator, kStackAllocator, kMallocAllocator, + kFixedPageAllocator, + kScalablePageAllocator, }; /** @@ -55,7 +55,8 @@ struct AllocatorHeader { * */ class Allocator { protected: - MemoryBackend *backend_; + char *buffer_; + size_t buffer_size_; char *custom_header_; public: @@ -77,13 +78,13 @@ class Allocator { * each allocator has its own arguments to this method. Though each * allocator must have "id" as its first argument. * */ - // virtual void shm_init(MemoryBackend *backend, - // allocator_id_t id, Args ...args) = 0; + // virtual void shm_init(allocator_id_t id, Args ...args) = 0; /** - * Attach the allocator to the slot and backend passed in the constructor. + * Deserialize allocator from a buffer. * */ - virtual void shm_deserialize(MemoryBackend *backend) = 0; + virtual void shm_deserialize(char *buffer, + size_t buffer_size) = 0; /** * Allocate a region of memory of \a size size @@ -207,7 +208,7 @@ class Allocator { inline T* AllocatePtr(size_t size, POINTER_T &p, size_t alignment = 0) { p = Allocate(size, alignment); if (p.IsNull()) { return nullptr; } - return reinterpret_cast(backend_->data_ + p.off_.load()); + return reinterpret_cast(buffer_ + p.off_.load()); } /** @@ -236,7 +237,7 @@ class Allocator { inline T* ClearAllocatePtr(size_t size, POINTER_T &p, size_t alignment = 0) { p = Allocate(size, alignment); if (p.IsNull()) { return nullptr; } - auto ptr = reinterpret_cast(backend_->data_ + p.off_.load()); + auto ptr = reinterpret_cast(buffer_ + p.off_.load()); if (ptr) { memset(ptr, 0, size); } @@ -460,7 +461,7 @@ class Allocator { template inline T* Convert(const POINTER_T &p) { if (p.IsNull()) { return nullptr; } - return reinterpret_cast(backend_->data_ + p.off_.load()); + return reinterpret_cast(buffer_ + p.off_.load()); } /** @@ -474,7 +475,7 @@ class Allocator { if (ptr == nullptr) { return POINTER_T::GetNull(); } return POINTER_T(GetId(), reinterpret_cast(ptr) - - reinterpret_cast(backend_->data_)); + reinterpret_cast(buffer_)); } /** @@ -487,10 +488,10 @@ class Allocator { template inline bool ContainsPtr(T *ptr) { return reinterpret_cast(ptr) >= - reinterpret_cast(backend_->data_); + reinterpret_cast(buffer_); } }; } // namespace hermes_shm::ipc -#endif // HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_H_ +#endif // HERMES_MEMORY_ALLOCATOR_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h b/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h index f14da3ca4..0b244f513 100644 --- a/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h +++ b/hermes_shm/include/hermes_shm/memory/allocator/allocator_factory.h @@ -10,13 +10,15 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ -#define HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ + +#ifndef HERMES_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ +#define HERMES_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ #include "allocator.h" #include "stack_allocator.h" -#include "multi_page_allocator.h" #include "malloc_allocator.h" +#include "fixed_page_allocator.h" +#include "scalable_page_allocator.h" namespace hermes_shm::ipc { @@ -26,32 +28,44 @@ class AllocatorFactory { * Create a new memory allocator * */ template - static std::unique_ptr shm_init(MemoryBackend *backend, - allocator_id_t alloc_id, + static std::unique_ptr shm_init(allocator_id_t alloc_id, size_t custom_header_size, + MemoryBackend *backend, Args&& ...args) { - if constexpr(std::is_same_v) { - // MultiPageAllocator - auto alloc = std::make_unique(); - alloc->shm_init(backend, - alloc_id, - custom_header_size, - std::forward(args)...); - return alloc; - } else if constexpr(std::is_same_v) { + if constexpr(std::is_same_v) { // StackAllocator auto alloc = std::make_unique(); - alloc->shm_init(backend, - alloc_id, + alloc->shm_init(alloc_id, custom_header_size, + backend->data_, + backend->data_size_, std::forward(args)...); return alloc; } else if constexpr(std::is_same_v) { // Malloc Allocator auto alloc = std::make_unique(); - alloc->shm_init(backend, - alloc_id, + alloc->shm_init(alloc_id, + custom_header_size, + backend->data_, + backend->data_size_, + std::forward(args)...); + return alloc; + } else if constexpr(std::is_same_v) { + // Fixed Page Allocator + auto alloc = std::make_unique(); + alloc->shm_init(alloc_id, + custom_header_size, + backend->data_, + backend->data_size_, + std::forward(args)...); + return alloc; + } else if constexpr(std::is_same_v) { + // Scalable Page Allocator + auto alloc = std::make_unique(); + alloc->shm_init(alloc_id, custom_header_size, + backend->data_, + backend->data_size_, std::forward(args)...); return alloc; } else { @@ -66,22 +80,32 @@ class AllocatorFactory { static std::unique_ptr shm_deserialize(MemoryBackend *backend) { auto header_ = reinterpret_cast(backend->data_); switch (static_cast(header_->allocator_type_)) { - // MultiPageAllocator - case AllocatorType::kMultiPageAllocator: { - auto alloc = std::make_unique(); - alloc->shm_deserialize(backend); - return alloc; - } // Stack Allocator case AllocatorType::kStackAllocator: { auto alloc = std::make_unique(); - alloc->shm_deserialize(backend); + alloc->shm_deserialize(backend->data_, + backend->data_size_); return alloc; } // Malloc Allocator case AllocatorType::kMallocAllocator: { auto alloc = std::make_unique(); - alloc->shm_deserialize(backend); + alloc->shm_deserialize(backend->data_, + backend->data_size_); + return alloc; + } + // Fixed Page Allocator + case AllocatorType::kFixedPageAllocator: { + auto alloc = std::make_unique(); + alloc->shm_deserialize(backend->data_, + backend->data_size_); + return alloc; + } + // Scalable Page Allocator + case AllocatorType::kScalablePageAllocator: { + auto alloc = std::make_unique(); + alloc->shm_deserialize(backend->data_, + backend->data_size_); return alloc; } default: return nullptr; @@ -91,4 +115,4 @@ class AllocatorFactory { } // namespace hermes_shm::ipc -#endif // HERMES_SHM_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ +#endif // HERMES_MEMORY_ALLOCATOR_ALLOCATOR_FACTORY_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h index 1413025a2..25fcf8d91 100644 --- a/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h +++ b/hermes_shm/include/hermes_shm/memory/allocator/malloc_allocator.h @@ -10,8 +10,9 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ -#define HERMES_SHM_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ + +#ifndef HERMES_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ +#define HERMES_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ #include "allocator.h" #include "hermes_shm/thread/lock.h" @@ -52,14 +53,16 @@ class MallocAllocator : public Allocator { /** * Initialize the allocator in shared memory * */ - void shm_init(MemoryBackend *backend, - allocator_id_t id, - size_t custom_header_size); + void shm_init(allocator_id_t id, + size_t custom_header_size, + char *buffer, + size_t buffer_size); /** * Attach an existing allocator from shared memory * */ - void shm_deserialize(MemoryBackend *backend) override; + void shm_deserialize(char *buffer, + size_t buffer_size) override; /** * Allocate a memory of \a size size. The page allocator cannot allocate @@ -95,4 +98,4 @@ class MallocAllocator : public Allocator { } // namespace hermes_shm::ipc -#endif // HERMES_SHM_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ +#endif // HERMES_MEMORY_ALLOCATOR_MALLOC_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h b/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h index eed6f96c0..79008f1be 100644 --- a/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h +++ b/hermes_shm/include/hermes_shm/memory/allocator/mp_page.h @@ -10,16 +10,18 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MP_PAGE_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MP_PAGE_H_ +#ifndef HERMES_INCLUDE_HERMES_MEMORY_ALLOCATOR_MP_PAGE_H_ +#define HERMES_INCLUDE_HERMES_MEMORY_ALLOCATOR_MP_PAGE_H_ + +#include "hermes_shm/data_structures/thread_unsafe/iqueue.h" namespace hermes_shm::ipc { struct MpPage { - int flags_; /**< Page flags (e.g., is_allocated?) */ + iqueue_entry entry_; /**< Position of page in free list */ size_t page_size_; /**< The size of the page allocated */ + int flags_; /**< Page flags (e.g., is_allocated?) */ uint32_t off_; /**< The offset within the page */ - uint32_t page_idx_; /**< The id of the page in the mp free list */ void SetAllocated() { flags_ = 0x1; @@ -36,4 +38,4 @@ struct MpPage { } // namespace hermes_shm::ipc -#endif // HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MP_PAGE_H_ +#endif // HERMES_INCLUDE_HERMES_MEMORY_ALLOCATOR_MP_PAGE_H_ diff --git a/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h index 2f4717623..465895d5f 100644 --- a/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h +++ b/hermes_shm/include/hermes_shm/memory/allocator/stack_allocator.h @@ -10,8 +10,9 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ -#define HERMES_SHM_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ + +#ifndef HERMES_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ +#define HERMES_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ #include "allocator.h" #include "hermes_shm/thread/lock.h" @@ -58,14 +59,16 @@ class StackAllocator : public Allocator { /** * Initialize the allocator in shared memory * */ - void shm_init(MemoryBackend *backend, - allocator_id_t id, - size_t custom_header_size); + void shm_init(allocator_id_t id, + size_t custom_header_size, + char *buffer, + size_t buffer_size); /** * Attach an existing allocator from shared memory * */ - void shm_deserialize(MemoryBackend *backend) override; + void shm_deserialize(char *buffer, + size_t buffer_size) override; /** * Allocate a memory of \a size size. The page allocator cannot allocate @@ -101,4 +104,4 @@ class StackAllocator : public Allocator { } // namespace hermes_shm::ipc -#endif // HERMES_SHM_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ +#endif // HERMES_MEMORY_ALLOCATOR_STACK_ALLOCATOR_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/array_backend.h b/hermes_shm/include/hermes_shm/memory/backend/array_backend.h index 3e14b9831..7bcb3216f 100644 --- a/hermes_shm/include/hermes_shm/memory/backend/array_backend.h +++ b/hermes_shm/include/hermes_shm/memory/backend/array_backend.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_ARRAY_BACKEND_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_ARRAY_BACKEND_H_ +#ifndef HERMES_INCLUDE_HERMES_MEMORY_BACKEND_ARRAY_BACKEND_H_ +#define HERMES_INCLUDE_HERMES_MEMORY_BACKEND_ARRAY_BACKEND_H_ #include "memory_backend.h" #include @@ -62,4 +62,4 @@ class ArrayBackend : public MemoryBackend { } // namespace hermes_shm::ipc -#endif // HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_ARRAY_BACKEND_H_ +#endif // HERMES_INCLUDE_HERMES_MEMORY_BACKEND_ARRAY_BACKEND_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h b/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h index b96f59872..193ebe15b 100644 --- a/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h +++ b/hermes_shm/include/hermes_shm/memory/backend/memory_backend.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_MEMORY_H -#define HERMES_SHM_MEMORY_H +#ifndef HERMES_MEMORY_H +#define HERMES_MEMORY_H #include #include @@ -87,4 +87,4 @@ class MemoryBackend { } // namespace hermes_shm::ipc -#endif // HERMES_SHM_MEMORY_H +#endif // HERMES_MEMORY_H diff --git a/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h b/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h index 0332502c1..775340cbc 100644 --- a/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h +++ b/hermes_shm/include/hermes_shm/memory/backend/memory_backend_factory.h @@ -10,8 +10,9 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ -#define HERMES_SHM_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ + +#ifndef HERMES_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ +#define HERMES_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ #include "memory_backend.h" #include "posix_mmap.h" @@ -100,4 +101,4 @@ class MemoryBackendFactory { } // namespace hermes_shm::ipc -#endif // HERMES_SHM_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ +#endif // HERMES_MEMORY_BACKEND_MEMORY_BACKEND_FACTORY_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/null_backend.h b/hermes_shm/include/hermes_shm/memory/backend/null_backend.h index 33b17329c..8246398af 100644 --- a/hermes_shm/include/hermes_shm/memory/backend/null_backend.h +++ b/hermes_shm/include/hermes_shm/memory/backend/null_backend.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_NULL_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_NULL_H_ +#ifndef HERMES_INCLUDE_HERMES_MEMORY_BACKEND_NULL_H_ +#define HERMES_INCLUDE_HERMES_MEMORY_BACKEND_NULL_H_ #include "memory_backend.h" #include @@ -78,4 +78,4 @@ class NullBackend : public MemoryBackend { } // namespace hermes_shm::ipc -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_BACKEND_NULL_H_ +#endif //HERMES_INCLUDE_HERMES_MEMORY_BACKEND_NULL_H_ diff --git a/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h b/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h index 6840cdbc4..ccc0410fa 100644 --- a/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h +++ b/hermes_shm/include/hermes_shm/memory/backend/posix_mmap.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H -#define HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H +#ifndef HERMES_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H +#define HERMES_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H #include "memory_backend.h" #include @@ -108,4 +108,4 @@ class PosixMmap : public MemoryBackend { } // namespace hermes_shm::ipc -#endif // HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H +#endif // HERMES_INCLUDE_MEMORY_BACKEND_POSIX_MMAP_H diff --git a/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h b/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h index 43f16e10c..335d5bd86 100644 --- a/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h +++ b/hermes_shm/include/hermes_shm/memory/backend/posix_shm_mmap.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H -#define HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H +#ifndef HERMES_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H +#define HERMES_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H #include "memory_backend.h" #include @@ -59,11 +59,11 @@ class PosixShmMmap : public MemoryBackend { if (fd_ < 0) { return false; } - _Reserve(size); - header_ = _Map(HERMES_SHM_SYSTEM_INFO->page_size_, 0); + _Reserve(size + HERMES_SYSTEM_INFO->page_size_); + header_ = _Map(HERMES_SYSTEM_INFO->page_size_, 0); header_->data_size_ = size; data_size_ = size; - data_ = _Map(size, HERMES_SHM_SYSTEM_INFO->page_size_); + data_ = _Map(size, HERMES_SYSTEM_INFO->page_size_); return true; } @@ -76,9 +76,9 @@ class PosixShmMmap : public MemoryBackend { if (fd_ < 0) { return false; } - header_ = _Map(HERMES_SHM_SYSTEM_INFO->page_size_, 0); + header_ = _Map(HERMES_SYSTEM_INFO->page_size_, 0); data_size_ = header_->data_size_; - data_ = _Map(data_size_, HERMES_SHM_SYSTEM_INFO->page_size_); + data_ = _Map(data_size_, HERMES_SYSTEM_INFO->page_size_); return true; } @@ -117,7 +117,7 @@ class PosixShmMmap : public MemoryBackend { void _Detach() { if (!IsInitialized()) { return; } munmap(data_, data_size_); - munmap(header_, HERMES_SHM_SYSTEM_INFO->page_size_); + munmap(header_, HERMES_SYSTEM_INFO->page_size_); close(fd_); UnsetInitialized(); } @@ -133,4 +133,4 @@ class PosixShmMmap : public MemoryBackend { } // namespace hermes_shm::ipc -#endif // HERMES_SHM_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H +#endif // HERMES_INCLUDE_MEMORY_BACKEND_POSIX_SHM_MMAP_H diff --git a/hermes_shm/include/hermes_shm/memory/memory.h b/hermes_shm/include/hermes_shm/memory/memory.h index 35e6ba87d..12446f328 100644 --- a/hermes_shm/include/hermes_shm/memory/memory.h +++ b/hermes_shm/include/hermes_shm/memory/memory.h @@ -10,8 +10,9 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_MEMORY_MEMORY_H_ -#define HERMES_SHM_MEMORY_MEMORY_H_ + +#ifndef HERMES_MEMORY_MEMORY_H_ +#define HERMES_MEMORY_MEMORY_H_ #include #include @@ -349,7 +350,7 @@ using TypedAtomicPointer = AtomicPointer; /** Round up to the nearest multiple of the alignment */ static size_t NextAlignmentMultiple(size_t alignment, size_t size) { - auto page_size = HERMES_SHM_SYSTEM_INFO->page_size_; + auto page_size = HERMES_SYSTEM_INFO->page_size_; size_t new_size = size; size_t page_off = size % alignment; if (page_off) { @@ -360,7 +361,7 @@ static size_t NextAlignmentMultiple(size_t alignment, size_t size) { /** Round up to the nearest multiple of page size */ static size_t NextPageSizeMultiple(size_t size) { - auto page_size = HERMES_SHM_SYSTEM_INFO->page_size_; + auto page_size = HERMES_SYSTEM_INFO->page_size_; size_t new_size = NextAlignmentMultiple(page_size, size); return new_size; } @@ -380,4 +381,4 @@ struct hash { } // namespace std -#endif // HERMES_SHM_MEMORY_MEMORY_H_ +#endif // HERMES_MEMORY_MEMORY_H_ diff --git a/hermes_shm/include/hermes_shm/memory/memory_manager.h b/hermes_shm/include/hermes_shm/memory/memory_manager.h index 6e912f57b..72f4844e6 100644 --- a/hermes_shm/include/hermes_shm/memory/memory_manager.h +++ b/hermes_shm/include/hermes_shm/memory/memory_manager.h @@ -10,12 +10,13 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_MEMORY_MEMORY_MANAGER_H_ -#define HERMES_SHM_MEMORY_MEMORY_MANAGER_H_ +#ifndef HERMES_MEMORY_MEMORY_MANAGER_H_ +#define HERMES_MEMORY_MEMORY_MANAGER_H_ -#include "hermes_shm/memory/allocator/allocator.h" -#include "backend/memory_backend.h" +#include "hermes_shm/memory/backend/memory_backend_factory.h" #include "hermes_shm/memory/allocator/allocator_factory.h" +#include "hermes_shm/memory/memory_registry.h" +#include "hermes_shm/constants/macros.h" #include namespace hipc = hermes_shm::ipc; @@ -23,31 +24,12 @@ namespace hipc = hermes_shm::ipc; namespace hermes_shm::ipc { class MemoryManager { - private: - allocator_id_t root_allocator_id_; - PosixMmap root_backend_; - StackAllocator root_allocator_; - std::unordered_map> backends_; - std::unordered_map> allocators_; - Allocator *default_allocator_; - public: /** The default amount of memory a single allocator manages */ static const size_t kDefaultBackendSize = GIGABYTES(64); - /** - * Constructor. Create the root allocator and backend, which is used - * until the user specifies a new default. The root allocator stores - * only private memory. - * */ - MemoryManager() { - root_allocator_id_.bits_.major_ = 0; - root_allocator_id_.bits_.minor_ = -1; - root_backend_.shm_init(HERMES_SHM_SYSTEM_INFO->ram_size_); - root_backend_.Own(); - root_allocator_.shm_init(&root_backend_, root_allocator_id_, 0); - default_allocator_ = &root_allocator_; - } + /** Default constructor. */ + MemoryManager() = default; /** * Create a memory backend. Memory backends are divided into slots. @@ -59,10 +41,9 @@ class MemoryManager { MemoryBackend* CreateBackend(size_t size, const std::string &url, Args&& ...args) { - backends_.emplace(url, - MemoryBackendFactory::shm_init(size, url), - std::forward(args)...); - auto backend = backends_[url].get(); + auto backend_u = MemoryBackendFactory::shm_init( + size, url, std::forward(args)...); + auto backend = HERMES_MEMORY_REGISTRY->RegisterBackend(url, backend_u); backend->Own(); return backend; } @@ -72,8 +53,8 @@ class MemoryManager { * */ MemoryBackend* AttachBackend(MemoryBackendType type, const std::string &url) { - backends_.emplace(url, MemoryBackendFactory::shm_deserialize(type, url)); - auto backend = backends_[url].get(); + auto backend_u = MemoryBackendFactory::shm_deserialize(type, url); + auto backend = HERMES_MEMORY_REGISTRY->RegisterBackend(url, backend_u); ScanBackends(); backend->Disown(); return backend; @@ -82,12 +63,25 @@ class MemoryManager { /** * Returns a pointer to a backend that has already been attached. * */ - MemoryBackend* GetBackend(const std::string &url); + MemoryBackend* GetBackend(const std::string &url) { + return HERMES_MEMORY_REGISTRY->GetBackend(url); + } + + /** + * Unregister backend + * */ + void UnregisterBackend(const std::string &url) { + HERMES_MEMORY_REGISTRY->UnregisterBackend(url); + } /** - * Destroys the memory allocated by the entire backend. + * Destroy backend * */ - void DestroyBackend(const std::string &url); + void DestroyBackend(const std::string &url) { + auto backend = GetBackend(url); + backend->Own(); + UnregisterBackend(url); + } /** * Scans all attached backends for new memory allocators. @@ -98,7 +92,9 @@ class MemoryManager { * Registers an allocator. Used internally by ScanBackends, but may * also be used externally. * */ - void RegisterAllocator(std::unique_ptr &alloc); + void RegisterAllocator(std::unique_ptr &alloc) { + HERMES_MEMORY_REGISTRY->RegisterAllocator(alloc); + } /** * Create and register a memory allocator for a particular backend. @@ -110,11 +106,11 @@ class MemoryManager { Args&& ...args) { auto backend = GetBackend(url); if (alloc_id.IsNull()) { - alloc_id = allocator_id_t(HERMES_SHM_SYSTEM_INFO->pid_, - allocators_.size()); + alloc_id = allocator_id_t(HERMES_SYSTEM_INFO->pid_, + HERMES_MEMORY_REGISTRY->allocators_.size()); } auto alloc = AllocatorFactory::shm_init( - backend, alloc_id, custom_header_size, std::forward(args)...); + alloc_id, custom_header_size, backend, std::forward(args)...); RegisterAllocator(alloc); return GetAllocator(alloc_id); } @@ -123,22 +119,18 @@ class MemoryManager { * Locates an allocator of a particular id * */ Allocator* GetAllocator(allocator_id_t alloc_id) { - if (alloc_id.IsNull()) { return nullptr; } - if (alloc_id == root_allocator_.GetId()) { - return &root_allocator_; - } - auto iter = allocators_.find(alloc_id); - if (iter == allocators_.end()) { + auto alloc = HERMES_MEMORY_REGISTRY->GetAllocator(alloc_id); + if (!alloc) { ScanBackends(); } - return reinterpret_cast(allocators_[alloc_id].get()); + return HERMES_MEMORY_REGISTRY->GetAllocator(alloc_id); } /** * Gets the allocator used for initializing other allocators. * */ Allocator* GetRootAllocator() { - return &root_allocator_; + return HERMES_MEMORY_REGISTRY->GetRootAllocator(); } /** @@ -146,7 +138,7 @@ class MemoryManager { * used to construct an object. * */ Allocator* GetDefaultAllocator() { - return default_allocator_; + return HERMES_MEMORY_REGISTRY->GetDefaultAllocator(); } /** @@ -154,7 +146,7 @@ class MemoryManager { * used to construct an object. * */ void SetDefaultAllocator(Allocator *alloc) { - default_allocator_ = alloc; + HERMES_MEMORY_REGISTRY->SetDefaultAllocator(alloc); } /** @@ -189,7 +181,7 @@ class MemoryManager { * */ template POINTER_T Convert(T *ptr) { - for (auto &[alloc_id, alloc] : allocators_) { + for (auto &[alloc_id, alloc] : HERMES_MEMORY_REGISTRY->allocators_) { if (alloc->ContainsPtr(ptr)) { return alloc->template Convert(ptr); @@ -201,4 +193,4 @@ class MemoryManager { } // namespace hermes_shm::ipc -#endif // HERMES_SHM_MEMORY_MEMORY_MANAGER_H_ +#endif // HERMES_MEMORY_MEMORY_MANAGER_H_ diff --git a/hermes_shm/include/hermes_shm/thread/lock.h b/hermes_shm/include/hermes_shm/thread/lock.h index 61cdfb36f..12ca4fde8 100644 --- a/hermes_shm/include/hermes_shm/thread/lock.h +++ b/hermes_shm/include/hermes_shm/thread/lock.h @@ -10,11 +10,12 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_THREAD_LOCK_H_ -#define HERMES_SHM_THREAD_LOCK_H_ + +#ifndef HERMES_THREAD_LOCK_H_ +#define HERMES_THREAD_LOCK_H_ #include "lock/mutex.h" #include "lock/rwlock.h" #include "thread_manager.h" -#endif // HERMES_SHM_THREAD_LOCK_H_ +#endif // HERMES_THREAD_LOCK_H_ diff --git a/hermes_shm/include/hermes_shm/thread/lock/mutex.h b/hermes_shm/include/hermes_shm/thread/lock/mutex.h index 4902d5052..b405ad75c 100644 --- a/hermes_shm/include/hermes_shm/thread/lock/mutex.h +++ b/hermes_shm/include/hermes_shm/thread/lock/mutex.h @@ -10,8 +10,9 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_THREAD_MUTEX_H_ -#define HERMES_SHM_THREAD_MUTEX_H_ + +#ifndef HERMES_THREAD_MUTEX_H_ +#define HERMES_THREAD_MUTEX_H_ #include @@ -44,4 +45,4 @@ struct ScopedMutex { } // namespace hermes_shm -#endif // HERMES_SHM_THREAD_MUTEX_H_ +#endif // HERMES_THREAD_MUTEX_H_ diff --git a/hermes_shm/include/hermes_shm/thread/lock/rwlock.h b/hermes_shm/include/hermes_shm/thread/lock/rwlock.h index c7bee4e49..de37b631c 100644 --- a/hermes_shm/include/hermes_shm/thread/lock/rwlock.h +++ b/hermes_shm/include/hermes_shm/thread/lock/rwlock.h @@ -10,8 +10,9 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_THREAD_RWLOCK_H_ -#define HERMES_SHM_THREAD_RWLOCK_H_ + +#ifndef HERMES_THREAD_RWLOCK_H_ +#define HERMES_THREAD_RWLOCK_H_ #include @@ -96,4 +97,4 @@ struct ScopedRwWriteLock { } // namespace hermes_shm -#endif // HERMES_SHM_THREAD_RWLOCK_H_ +#endif // HERMES_THREAD_RWLOCK_H_ diff --git a/hermes_shm/include/hermes_shm/thread/pthread.h b/hermes_shm/include/hermes_shm/thread/pthread.h index 65d894359..ddb9d4d08 100644 --- a/hermes_shm/include/hermes_shm/thread/pthread.h +++ b/hermes_shm/include/hermes_shm/thread/pthread.h @@ -10,12 +10,13 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_THREAD_PTHREAD_H_ -#define HERMES_SHM_THREAD_PTHREAD_H_ +#ifndef HERMES_THREAD_PTHREAD_H_ +#define HERMES_THREAD_PTHREAD_H_ #include "thread.h" #include #include +#include namespace hermes_shm { @@ -91,10 +92,11 @@ class PthreadStatic : public ThreadStatic { } tid_t GetTid() override { - return static_cast(pthread_self()); + return omp_get_thread_num(); + // return static_cast(pthread_self()); } }; } // namespace hermes_shm -#endif // HERMES_SHM_THREAD_PTHREAD_H_ +#endif // HERMES_THREAD_PTHREAD_H_ diff --git a/hermes_shm/include/hermes_shm/thread/thread.h b/hermes_shm/include/hermes_shm/thread/thread.h index cdf12cfda..6d52a2bde 100644 --- a/hermes_shm/include/hermes_shm/thread/thread.h +++ b/hermes_shm/include/hermes_shm/thread/thread.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_THREAD_THREAD_H_ -#define HERMES_SHM_THREAD_THREAD_H_ +#ifndef HERMES_THREAD_THREAD_H_ +#define HERMES_THREAD_THREAD_H_ #include #include @@ -44,4 +44,4 @@ class ThreadStatic { } // namespace hermes_shm -#endif // HERMES_SHM_THREAD_THREAD_H_ +#endif // HERMES_THREAD_THREAD_H_ diff --git a/hermes_shm/include/hermes_shm/thread/thread_factory.h b/hermes_shm/include/hermes_shm/thread/thread_factory.h index c10356c99..d889ff129 100644 --- a/hermes_shm/include/hermes_shm/thread/thread_factory.h +++ b/hermes_shm/include/hermes_shm/thread/thread_factory.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_THREAD_THREAD_FACTORY_H_ -#define HERMES_SHM_THREAD_THREAD_FACTORY_H_ +#ifndef HERMES_THREAD_THREAD_FACTORY_H_ +#define HERMES_THREAD_THREAD_FACTORY_H_ #include "thread.h" #include "pthread.h" @@ -48,4 +48,4 @@ class ThreadStaticFactory { } // namespace hermes_shm -#endif // HERMES_SHM_THREAD_THREAD_FACTORY_H_ +#endif // HERMES_THREAD_THREAD_FACTORY_H_ diff --git a/hermes_shm/include/hermes_shm/thread/thread_manager.h b/hermes_shm/include/hermes_shm/thread/thread_manager.h index 93bdd9660..4aca415fb 100644 --- a/hermes_shm/include/hermes_shm/thread/thread_manager.h +++ b/hermes_shm/include/hermes_shm/thread/thread_manager.h @@ -10,15 +10,21 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_THREAD_THREAD_MANAGER_H_ -#define HERMES_SHM_THREAD_THREAD_MANAGER_H_ + +#ifndef HERMES_THREAD_THREAD_MANAGER_H_ +#define HERMES_THREAD_THREAD_MANAGER_H_ #include "thread.h" #include "thread_factory.h" #include +#include + +#define US_TO_CLOCKS(x) (x * 56) namespace hermes_shm { +union NodeThreadId; + class ThreadManager { public: ThreadType type_; @@ -38,6 +44,23 @@ class ThreadManager { } }; +union NodeThreadId { + struct { + uint32_t tid_; + uint32_t pid_; + } bits_; + uint64_t as_int_; + + NodeThreadId() { + bits_.tid_ = HERMES_THREAD_MANAGER->GetThreadStatic()->GetTid(); + bits_.pid_ = HERMES_SYSTEM_INFO->pid_; + } + + uint32_t hash() { + return as_int_; + } +}; + } // namespace hermes_shm -#endif // HERMES_SHM_THREAD_THREAD_MANAGER_H_ +#endif // HERMES_THREAD_THREAD_MANAGER_H_ diff --git a/hermes_shm/include/hermes_shm/types/argpack.h b/hermes_shm/include/hermes_shm/types/argpack.h index 9205b73ed..9e25a90db 100644 --- a/hermes_shm/include/hermes_shm/types/argpack.h +++ b/hermes_shm/include/hermes_shm/types/argpack.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ARGPACK_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ARGPACK_H_ +#ifndef HERMES_INCLUDE_HERMES_TYPES_ARGPACK_H_ +#define HERMES_INCLUDE_HERMES_TYPES_ARGPACK_H_ #include "basic.h" #include @@ -107,15 +107,15 @@ ArgPack make_argpack(Args&& ...args) { #define FORWARD_ARGPACK_FULL_TYPE(pack, i)\ decltype(pack.template Forward()) -/** Get type of the forward for \a pack pack at \a index i */ -#define FORWARD_ARGPACK_BASE_TYPE(pack, i)\ - std::remove_reference - /** Forward the param for \a pack pack at \a index i */ #define FORWARD_ARGPACK_PARAM(pack, i)\ std::forward(\ pack.template Forward()) +/** Forward an argpack */ +#define FORWARD_ARGPACK(pack) \ + std::forward(pack) + /** Used to pass an argument pack to a function or class method */ class PassArgPack { public: @@ -231,4 +231,4 @@ class ProductArgPacks { } // namespace hermes_shm -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ARGPACK_H_ +#endif //HERMES_INCLUDE_HERMES_TYPES_ARGPACK_H_ diff --git a/hermes_shm/include/hermes_shm/types/atomic.h b/hermes_shm/include/hermes_shm/types/atomic.h index f39b00eb7..9b1b24a48 100644 --- a/hermes_shm/include/hermes_shm/types/atomic.h +++ b/hermes_shm/include/hermes_shm/types/atomic.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ATOMIC_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ATOMIC_H_ +#ifndef HERMES_INCLUDE_HERMES_TYPES_ATOMIC_H_ +#define HERMES_INCLUDE_HERMES_TYPES_ATOMIC_H_ #include @@ -249,4 +249,4 @@ struct atomic { } -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_ATOMIC_H_ +#endif //HERMES_INCLUDE_HERMES_TYPES_ATOMIC_H_ diff --git a/hermes_shm/include/hermes_shm/types/basic.h b/hermes_shm/include/hermes_shm/types/basic.h index bd02abe18..0649ad82c 100644 --- a/hermes_shm/include/hermes_shm/types/basic.h +++ b/hermes_shm/include/hermes_shm/types/basic.h @@ -10,22 +10,44 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_BASICS_H -#define HERMES_SHM_BASICS_H +#ifndef HERMES_BASICS_H +#define HERMES_BASICS_H #define MODULE_KEY_SIZE 32 #include using std::size_t; +#ifdef KERNEL_BUILD +#include +#elif __cplusplus #include #include #include #include #include +#endif + +typedef uint32_t labstor_runtime_id_t; +typedef int32_t labstor_off_t; + +struct labstor_id { + char key_[MODULE_KEY_SIZE]; +}; + +struct labstor_credentials { + int pid_; + int uid_; + int gid_; + int priority_; +}; + +#ifdef __cplusplus namespace hermes_shm { +typedef labstor_credentials UserCredentials; + /** * decimal + (numerator/65536) * */ @@ -136,4 +158,8 @@ struct hash { }; } // namespace std -#endif // HERMES_SHM_BASICS_H +#endif + + + +#endif // HERMES_BASICS_H diff --git a/hermes_shm/include/hermes_shm/types/bitfield.h b/hermes_shm/include/hermes_shm/types/bitfield.h index b0a5346a7..26403250b 100644 --- a/hermes_shm/include/hermes_shm/types/bitfield.h +++ b/hermes_shm/include/hermes_shm/types/bitfield.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_BITFIELD_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_BITFIELD_H_ +#ifndef HERMES_INCLUDE_HERMES_TYPES_BITFIELD_H_ +#define HERMES_INCLUDE_HERMES_TYPES_BITFIELD_H_ #include @@ -72,4 +72,4 @@ typedef bitfield bitfield32_t; } // namespace hermes_shm -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_BITFIELD_H_ +#endif //HERMES_INCLUDE_HERMES_TYPES_BITFIELD_H_ diff --git a/hermes_shm/include/hermes_shm/types/charbuf.h b/hermes_shm/include/hermes_shm/types/charbuf.h index 155a5b1aa..db08992a3 100644 --- a/hermes_shm/include/hermes_shm/types/charbuf.h +++ b/hermes_shm/include/hermes_shm/types/charbuf.h @@ -10,11 +10,11 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_CHARBUF_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_CHARBUF_H_ +#ifndef HERMES_INCLUDE_HERMES_TYPES_CHARBUF_H_ +#define HERMES_INCLUDE_HERMES_TYPES_CHARBUF_H_ #include "basic.h" -#include "hermes_shm/memory/memory_manager.h" +#include "hermes_shm/memory/memory_registry.h" #include namespace hermes_shm { @@ -34,12 +34,12 @@ struct charbuf { /** Size-based constructor */ explicit charbuf(size_t size) { - Allocate(HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(), size); + Allocate(HERMES_MEMORY_REGISTRY->GetDefaultAllocator(), size); } /** String-based constructor */ explicit charbuf(const std::string &data) { - Allocate(HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(), data.size()); + Allocate(HERMES_MEMORY_REGISTRY->GetDefaultAllocator(), data.size()); memcpy(data_, data.data(), data.size()); } @@ -58,7 +58,7 @@ struct charbuf { /** Copy constructor */ charbuf(const charbuf &other) { - if (!Allocate(HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(), + if (!Allocate(HERMES_MEMORY_REGISTRY->GetDefaultAllocator(), other.size())) { return; } @@ -69,7 +69,7 @@ struct charbuf { charbuf& operator=(const charbuf &other) { if (this != &other) { Free(); - if (!Allocate(HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(), + if (!Allocate(HERMES_MEMORY_REGISTRY->GetDefaultAllocator(), other.size())) { return *this; } @@ -109,7 +109,7 @@ struct charbuf { return; } if (alloc_ == nullptr) { - alloc_ = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + alloc_ = HERMES_MEMORY_REGISTRY->GetDefaultAllocator(); } if (destructable_) { data_ = alloc_->ReallocatePtr(data_, new_size); @@ -151,7 +151,7 @@ struct charbuf { return sum; } -#define HERMES_SHM_STR_CMP_OPERATOR(op) \ +#define HERMES_STR_CMP_OPERATOR(op) \ bool operator op(const char *other) const { \ return _strncmp(data(), size(), other, strlen(other)) op 0; \ } \ @@ -162,14 +162,14 @@ struct charbuf { return _strncmp(data(), size(), other.data(), other.size()) op 0; \ } - HERMES_SHM_STR_CMP_OPERATOR(==) - HERMES_SHM_STR_CMP_OPERATOR(!=) - HERMES_SHM_STR_CMP_OPERATOR(<) - HERMES_SHM_STR_CMP_OPERATOR(>) - HERMES_SHM_STR_CMP_OPERATOR(<=) - HERMES_SHM_STR_CMP_OPERATOR(>=) + HERMES_STR_CMP_OPERATOR(==) + HERMES_STR_CMP_OPERATOR(!=) + HERMES_STR_CMP_OPERATOR(<) + HERMES_STR_CMP_OPERATOR(>) + HERMES_STR_CMP_OPERATOR(<=) + HERMES_STR_CMP_OPERATOR(>=) -#undef HERMES_SHM_STR_CMP_OPERATOR +#undef HERMES_STR_CMP_OPERATOR private: /** Allocate charbuf */ @@ -201,4 +201,4 @@ typedef charbuf string; } // namespace hermes_shm -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_TYPES_CHARBUF_H_ +#endif //HERMES_INCLUDE_HERMES_TYPES_CHARBUF_H_ diff --git a/hermes_shm/include/hermes_shm/types/messages.h b/hermes_shm/include/hermes_shm/types/messages.h index 11b87e230..0d805b789 100644 --- a/hermes_shm/include/hermes_shm/types/messages.h +++ b/hermes_shm/include/hermes_shm/types/messages.h @@ -10,13 +10,13 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_MESSAGES_H -#define HERMES_SHM_MESSAGES_H +#ifndef HERMES_MESSAGES_H +#define HERMES_MESSAGES_H namespace hermes_shm { enum { - HERMES_SHM_ADMIN_REGISTER_QP + HERMES_ADMIN_REGISTER_QP }; struct admin_request { @@ -46,4 +46,4 @@ struct setup_reply : public admin_reply { } // namespace hermes_shm -#endif // HERMES_SHM_MESSAGES_H +#endif // HERMES_MESSAGES_H diff --git a/hermes_shm/include/hermes_shm/types/tuple_base.h b/hermes_shm/include/hermes_shm/types/tuple_base.h index c24aeca93..49ba27268 100644 --- a/hermes_shm/include/hermes_shm/types/tuple_base.h +++ b/hermes_shm/include/hermes_shm/types/tuple_base.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_TupleBase_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_TupleBase_H_ +#ifndef HERMES_INCLUDE_HERMES_DATA_STRUCTURES_TupleBase_H_ +#define HERMES_INCLUDE_HERMES_DATA_STRUCTURES_TupleBase_H_ #include #include "basic.h" @@ -244,4 +244,4 @@ using ReverseIterateTuple = IterateTuple; } // namespace hermes_shm -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_DATA_STRUCTURES_TupleBase_H_ +#endif //HERMES_INCLUDE_HERMES_DATA_STRUCTURES_TupleBase_H_ diff --git a/hermes_shm/include/hermes_shm/util/auto_trace.h b/hermes_shm/include/hermes_shm/util/auto_trace.h index 614bc3085..91246a31f 100644 --- a/hermes_shm/include/hermes_shm/util/auto_trace.h +++ b/hermes_shm/include/hermes_shm/util/auto_trace.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_UTIL_AUTO_TRACE_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_UTIL_AUTO_TRACE_H_ +#ifndef HERMES_INCLUDE_HERMES_UTIL_AUTO_TRACE_H_ +#define HERMES_INCLUDE_HERMES_UTIL_AUTO_TRACE_H_ #include "formatter.h" #include "timer.h" @@ -49,4 +49,4 @@ class AutoTrace { } // namespace hermes_shm -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_UTIL_AUTO_TRACE_H_ +#endif //HERMES_INCLUDE_HERMES_UTIL_AUTO_TRACE_H_ diff --git a/hermes_shm/include/hermes_shm/util/debug.h b/hermes_shm/include/hermes_shm/util/debug.h index 68bf7e504..4c5bb774b 100644 --- a/hermes_shm/include/hermes_shm/util/debug.h +++ b/hermes_shm/include/hermes_shm/util/debug.h @@ -10,10 +10,10 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_DEBUG_H -#define HERMES_SHM_DEBUG_H +#ifndef HERMES_DEBUG_H +#define HERMES_DEBUG_H -#if defined(HERMES_SHM_DEBUG) && defined(__cplusplus) +#if defined(HERMES_DEBUG) && defined(__cplusplus) #define AUTO_TRACE(...) \ hermes_shm::AutoTrace auto_tracer(false, __PRETTY_FUNCTION__, __VA_ARGS__); #define TRACEPOINT(...) \ @@ -74,4 +74,4 @@ class AutoTrace { #endif -#endif // HERMES_SHM_DEBUG_H +#endif // HERMES_DEBUG_H diff --git a/hermes_shm/include/hermes_shm/util/error.h b/hermes_shm/include/hermes_shm/util/error.h index 027bbfbff..3e31830af 100644 --- a/hermes_shm/include/hermes_shm/util/error.h +++ b/hermes_shm/include/hermes_shm/util/error.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_ERROR_H -#define HERMES_SHM_ERROR_H +#ifndef HERMES_ERROR_H +#define HERMES_ERROR_H // #ifdef __cplusplus @@ -21,14 +21,14 @@ #include #include -#define HERMES_SHM_ERROR_TYPE std::shared_ptr -#define HERMES_SHM_ERROR_HANDLE_START() try { -#define HERMES_SHM_ERROR_HANDLE_END() \ - } catch(HERMES_SHM_ERROR_TYPE &err) { err->print(); exit(-1024); } -#define HERMES_SHM_ERROR_HANDLE_TRY try -#define HERMES_SHM_ERROR_PTR err -#define HERMES_SHM_ERROR_HANDLE_CATCH catch(HERMES_SHM_ERROR_TYPE &HERMES_SHM_ERROR_PTR) -#define HERMES_SHM_ERROR_IS(err, check) (err->get_code() == check.get_code()) +#define HERMES_ERROR_TYPE std::shared_ptr +#define HERMES_ERROR_HANDLE_START() try { +#define HERMES_ERROR_HANDLE_END() \ + } catch(HERMES_ERROR_TYPE &err) { err->print(); exit(-1024); } +#define HERMES_ERROR_HANDLE_TRY try +#define HERMES_ERROR_PTR err +#define HERMES_ERROR_HANDLE_CATCH catch(HERMES_ERROR_TYPE &HERMES_ERROR_PTR) +#define HERMES_ERROR_IS(err, check) (err->get_code() == check.get_code()) namespace hermes_shm { @@ -57,4 +57,4 @@ class Error { // #endif -#endif // HERMES_SHM_ERROR_H +#endif // HERMES_ERROR_H diff --git a/hermes_shm/include/hermes_shm/util/errors.h b/hermes_shm/include/hermes_shm/util/errors.h index 9ae0e6f8f..f5331a4e4 100644 --- a/hermes_shm/include/hermes_shm/util/errors.h +++ b/hermes_shm/include/hermes_shm/util/errors.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_ERRORS_H -#define HERMES_SHM_ERRORS_H +#ifndef HERMES_ERRORS_H +#define HERMES_ERRORS_H #ifdef __cplusplus @@ -59,4 +59,4 @@ namespace hermes_shm { #endif -#endif // HERMES_SHM_ERRORS_H +#endif // HERMES_ERRORS_H diff --git a/hermes_shm/include/hermes_shm/util/formatter.h b/hermes_shm/include/hermes_shm/util/formatter.h index a5b9c7d8d..4b96ef7bb 100644 --- a/hermes_shm/include/hermes_shm/util/formatter.h +++ b/hermes_shm/include/hermes_shm/util/formatter.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_ERROR_SERIALIZER_H -#define HERMES_SHM_ERROR_SERIALIZER_H +#ifndef HERMES_ERROR_SERIALIZER_H +#define HERMES_ERROR_SERIALIZER_H #include #include @@ -97,4 +97,4 @@ class Formatter { } // namespace hermes_shm -#endif //HERMES_SHM_ERROR_SERIALIZER_H +#endif //HERMES_ERROR_SERIALIZER_H diff --git a/hermes_shm/include/hermes_shm/util/partitioner.h b/hermes_shm/include/hermes_shm/util/partitioner.h index e1122cd06..5799bcf82 100644 --- a/hermes_shm/include/hermes_shm/util/partitioner.h +++ b/hermes_shm/include/hermes_shm/util/partitioner.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_PARTITIONER_H -#define HERMES_SHM_PARTITIONER_H +#ifndef HERMES_PARTITIONER_H +#define HERMES_PARTITIONER_H // Reference: https://stackoverflow.com/questions/63372288/getting-list-of-pids-from-proc-in-linux @@ -153,4 +153,4 @@ class ProcessAffiner { } // namespace hermes_shm -#endif // HERMES_SHM_PARTITIONER_H +#endif // HERMES_PARTITIONER_H diff --git a/hermes_shm/include/hermes_shm/util/path_parser.h b/hermes_shm/include/hermes_shm/util/path_parser.h index eaff1531f..c10a921ce 100644 --- a/hermes_shm/include/hermes_shm/util/path_parser.h +++ b/hermes_shm/include/hermes_shm/util/path_parser.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_PATH_PARSER_H -#define HERMES_SHM_PATH_PARSER_H +#ifndef HERMES_PATH_PARSER_H +#define HERMES_PATH_PARSER_H #include #include @@ -47,4 +47,4 @@ std::string path_parser(std::string path) { } // namespace scs -#endif // HERMES_SHM_PATH_PARSER_H +#endif // HERMES_PATH_PARSER_H diff --git a/hermes_shm/include/hermes_shm/util/timer.h b/hermes_shm/include/hermes_shm/util/timer.h index 3561c5d18..ba0275e49 100644 --- a/hermes_shm/include/hermes_shm/util/timer.h +++ b/hermes_shm/include/hermes_shm/util/timer.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_TIMER_H -#define HERMES_SHM_TIMER_H +#ifndef HERMES_TIMER_H +#define HERMES_TIMER_H #include #include @@ -93,4 +93,4 @@ typedef HighResMonotonicTimer Timer; } // namespace hermes_shm -#endif // HERMES_SHM_TIMER_H +#endif // HERMES_TIMER_H diff --git a/hermes_shm/src/CMakeLists.txt b/hermes_shm/src/CMakeLists.txt index fa5030a67..5c75e9855 100644 --- a/hermes_shm/src/CMakeLists.txt +++ b/hermes_shm/src/CMakeLists.txt @@ -3,19 +3,22 @@ project(hermes_shm) set(CMAKE_CXX_STANDARD 17) -##################Build HermesShm main packages +##################Build hermes main packages + add_library(hermes_shm_data_structures - ${CMAKE_CURRENT_SOURCE_DIR}/thread/mutex.cc - ${CMAKE_CURRENT_SOURCE_DIR}/thread/rwlock.cc - ${CMAKE_CURRENT_SOURCE_DIR}/memory/malloc_allocator.cc - ${CMAKE_CURRENT_SOURCE_DIR}/memory/stack_allocator.cc - ${CMAKE_CURRENT_SOURCE_DIR}/memory/multi_page_allocator.cc - ${CMAKE_CURRENT_SOURCE_DIR}/memory/memory_manager.cc - ${CMAKE_CURRENT_SOURCE_DIR}/data_structure_singleton.cc) + thread/mutex.cc + thread/rwlock.cc + memory/malloc_allocator.cc + memory/stack_allocator.cc + memory/fixed_page_allocator.cc + memory/scalable_page_allocator.cc + memory/memory_registry.cc + memory/memory_manager.cc + data_structure_singleton.cc) target_link_libraries(hermes_shm_data_structures - yaml-cpp pthread -lrt -ldl) + yaml-cpp pthread -lrt -ldl OpenMP::OpenMP_CXX) -##################Install HermesShm +##################Install hermes install(TARGETS hermes_shm_data_structures EXPORT @@ -37,9 +40,9 @@ set(HERMES_EXPORTED_LIBS ${HERMES_EXPORTED_LIBS}) if(NOT HERMES_EXTERNALLY_CONFIGURED) EXPORT ( - TARGETS - ${HERMES_EXPORTED_LIBS} - FILE - ${HERMES_EXPORTED_TARGETS}.cmake + TARGETS + ${HERMES_EXPORTED_LIBS} + FILE + ${HERMES_EXPORTED_TARGETS}.cmake ) endif() \ No newline at end of file diff --git a/hermes_shm/src/data_structure_singleton.cc b/hermes_shm/src/data_structure_singleton.cc index 309f96b0c..7b5cc25d6 100644 --- a/hermes_shm/src/data_structure_singleton.cc +++ b/hermes_shm/src/data_structure_singleton.cc @@ -17,6 +17,8 @@ #include template<> hermes_shm::SystemInfo scs::Singleton::obj_ = hermes_shm::SystemInfo(); +#include +template<> hermes_shm::ipc::MemoryRegistry scs::Singleton::obj_ = hermes_shm::ipc::MemoryRegistry(); #include template<> hermes_shm::ipc::MemoryManager scs::Singleton::obj_ = hermes_shm::ipc::MemoryManager(); #include diff --git a/hermes_shm/src/memory/malloc_allocator.cc b/hermes_shm/src/memory/malloc_allocator.cc index 313e5c5d2..0e073e78f 100644 --- a/hermes_shm/src/memory/malloc_allocator.cc +++ b/hermes_shm/src/memory/malloc_allocator.cc @@ -10,6 +10,7 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include namespace hermes_shm::ipc { @@ -18,17 +19,20 @@ struct MallocPage { size_t page_size_; }; -void MallocAllocator::shm_init(MemoryBackend *backend, - allocator_id_t id, - size_t custom_header_size) { - backend_ = backend; +void MallocAllocator::shm_init(allocator_id_t id, + size_t custom_header_size, + char *buffer, + size_t buffer_size) { + buffer_ = buffer; + buffer_size_ = buffer_size; header_ = reinterpret_cast( malloc(sizeof(MallocAllocatorHeader) + custom_header_size)); custom_header_ = reinterpret_cast(header_ + 1); header_->Configure(id, custom_header_size); } -void MallocAllocator::shm_deserialize(MemoryBackend *backend) { +void MallocAllocator::shm_deserialize(char *buffer, + size_t buffer_size) { throw NOT_IMPLEMENTED.format("MallocAllocator::shm_deserialize"); } diff --git a/hermes_shm/src/memory/memory_intercept.cc b/hermes_shm/src/memory/memory_intercept.cc index c8109e4fc..ee150ace4 100644 --- a/hermes_shm/src/memory/memory_intercept.cc +++ b/hermes_shm/src/memory/memory_intercept.cc @@ -19,13 +19,13 @@ using hermes_shm::ipc::Allocator; /** Allocate SIZE bytes of memory. */ void* malloc(size_t size) { - auto alloc = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + auto alloc = HERMES_MEMORY_MANAGER->GetDefaultAllocator(); return alloc->AllocatePtr(size); } /** Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ void* calloc(size_t nmemb, size_t size) { - auto alloc = HERMES_SHM_MEMORY_MANAGER->GetDefaultAllocator(); + auto alloc = HERMES_MEMORY_MANAGER->GetDefaultAllocator(); return alloc->ClearAllocatePtr(nmemb * size); } @@ -34,8 +34,8 @@ void* calloc(size_t nmemb, size_t size) { * block SIZE bytes long. * */ void* realloc(void *ptr, size_t size) { - Pointer p = HERMES_SHM_MEMORY_MANAGER->Convert(ptr); - auto alloc = HERMES_SHM_MEMORY_MANAGER->GetAllocator(p.allocator_id_); + Pointer p = HERMES_MEMORY_MANAGER->Convert(ptr); + auto alloc = HERMES_MEMORY_MANAGER->GetAllocator(p.allocator_id_); return alloc->AllocatePtr(size); } @@ -49,8 +49,8 @@ void* reallocarray(void *ptr, size_t nmemb, size_t size) { /** Free a block allocated by `malloc', `realloc' or `calloc'. */ void free(void *ptr) { - Pointer p = HERMES_SHM_MEMORY_MANAGER->Convert(ptr); - auto alloc = HERMES_SHM_MEMORY_MANAGER->GetAllocator(p.allocator_id_); + Pointer p = HERMES_MEMORY_MANAGER->Convert(ptr); + auto alloc = HERMES_MEMORY_MANAGER->GetAllocator(p.allocator_id_); alloc->Free(p); } @@ -62,7 +62,7 @@ void* memalign(size_t alignment, size_t size) { /** Allocate SIZE bytes on a page boundary. */ void* valloc(size_t size) { - return memalign(HERMES_SHM_SYSTEM_INFO->page_size_, size); + return memalign(HERMES_SYSTEM_INFO->page_size_, size); } /** diff --git a/hermes_shm/src/memory/memory_intercept.h b/hermes_shm/src/memory/memory_intercept.h index 6c86ac713..ae45f9248 100644 --- a/hermes_shm/src/memory/memory_intercept.h +++ b/hermes_shm/src/memory/memory_intercept.h @@ -10,9 +10,9 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_SRC_MEMORY_MEMORY_INTERCEPT_H_ -#define HERMES_SHM_SRC_MEMORY_MEMORY_INTERCEPT_H_ +#ifndef HERMES_SRC_MEMORY_MEMORY_INTERCEPT_H_ +#define HERMES_SRC_MEMORY_MEMORY_INTERCEPT_H_ -#endif //HERMES_SHM_SRC_MEMORY_MEMORY_INTERCEPT_H_ +#endif //HERMES_SRC_MEMORY_MEMORY_INTERCEPT_H_ diff --git a/hermes_shm/src/memory/memory_manager.cc b/hermes_shm/src/memory/memory_manager.cc index 2ce79e735..15b683b7f 100644 --- a/hermes_shm/src/memory/memory_manager.cc +++ b/hermes_shm/src/memory/memory_manager.cc @@ -10,36 +10,20 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include #include "hermes_shm/memory/backend/memory_backend_factory.h" #include "hermes_shm/memory/allocator/allocator_factory.h" #include +#include namespace hermes_shm::ipc { -MemoryBackend* MemoryManager::GetBackend(const std::string &url) { - return backends_[url].get(); -} - -void MemoryManager::DestroyBackend(const std::string &url) { - auto backend = GetBackend(url); - backend->shm_destroy(); - backends_.erase(url); -} - void MemoryManager::ScanBackends() { - for (auto &[url, backend] : backends_) { + for (auto &[url, backend] : HERMES_MEMORY_REGISTRY->backends_) { auto alloc = AllocatorFactory::shm_deserialize(backend.get()); RegisterAllocator(alloc); } } -void MemoryManager::RegisterAllocator(std::unique_ptr &alloc) { - if (default_allocator_ == nullptr || - default_allocator_ == &root_allocator_) { - default_allocator_ = alloc.get(); - } - allocators_.emplace(alloc->GetId(), std::move(alloc)); -} - } // namespace hermes_shm::ipc diff --git a/hermes_shm/src/memory/stack_allocator.cc b/hermes_shm/src/memory/stack_allocator.cc index 622323187..7b722f30d 100644 --- a/hermes_shm/src/memory/stack_allocator.cc +++ b/hermes_shm/src/memory/stack_allocator.cc @@ -10,25 +10,30 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include #include namespace hermes_shm::ipc { -void StackAllocator::shm_init(MemoryBackend *backend, - allocator_id_t id, - size_t custom_header_size) { - backend_ = backend; - header_ = reinterpret_cast(backend_->data_); +void StackAllocator::shm_init(allocator_id_t id, + size_t custom_header_size, + char *buffer, + size_t buffer_size) { + buffer_ = buffer; + buffer_size_ = buffer_size; + header_ = reinterpret_cast(buffer_); custom_header_ = reinterpret_cast(header_ + 1); - size_t region_off = (custom_header_ - backend_->data_) + custom_header_size; - size_t region_size = backend_->data_size_ - region_off; + size_t region_off = (custom_header_ - buffer_) + custom_header_size; + size_t region_size = buffer_size_ - region_off; header_->Configure(id, custom_header_size, region_off, region_size); } -void StackAllocator::shm_deserialize(MemoryBackend *backend) { - backend_ = backend; - header_ = reinterpret_cast(backend_->data_); +void StackAllocator::shm_deserialize(char *buffer, + size_t buffer_size) { + buffer_ = buffer; + buffer_size_ = buffer_size; + header_ = reinterpret_cast(buffer_); custom_header_ = reinterpret_cast(header_ + 1); } @@ -38,10 +43,14 @@ size_t StackAllocator::GetCurrentlyAllocatedSize() { OffsetPointer StackAllocator::AllocateOffset(size_t size) { size += sizeof(MpPage); + if (header_->region_size_ < size) { + return OffsetPointer::GetNull(); + } OffsetPointer p(header_->region_off_.fetch_add(size)); auto hdr = Convert(p); hdr->SetAllocated(); hdr->page_size_ = size; + hdr->off_ = 0; header_->region_size_.fetch_sub(hdr->page_size_); header_->total_alloc_.fetch_add(hdr->page_size_); return p + sizeof(MpPage); diff --git a/hermes_shm/src/thread/mutex.cc b/hermes_shm/src/thread/mutex.cc index 4f0ef3b60..e19ef3e94 100644 --- a/hermes_shm/src/thread/mutex.cc +++ b/hermes_shm/src/thread/mutex.cc @@ -10,6 +10,7 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "hermes_shm/thread/lock.h" #include "hermes_shm/thread/thread_manager.h" @@ -19,10 +20,11 @@ namespace hermes_shm { * Acquire the mutex * */ void Mutex::Lock() { - auto thread_info = HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); - while (!TryLock()) { - thread_info->Yield(); + auto thread_info = HERMES_THREAD_MANAGER->GetThreadStatic(); + for (int i = 0; i < US_TO_CLOCKS(16); ++i) { + if (TryLock()) { return; } } + thread_info->Yield(); } /** @@ -54,6 +56,7 @@ void Mutex::Unlock() { * */ ScopedMutex::ScopedMutex(Mutex &lock) : lock_(lock), is_locked_(false) { + Lock(); } /** diff --git a/hermes_shm/src/thread/rwlock.cc b/hermes_shm/src/thread/rwlock.cc index 5554d7c4a..9ecda46de 100644 --- a/hermes_shm/src/thread/rwlock.cc +++ b/hermes_shm/src/thread/rwlock.cc @@ -10,6 +10,7 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "hermes_shm/thread/lock/rwlock.h" #include "hermes_shm/thread/thread_manager.h" @@ -21,19 +22,22 @@ namespace hermes_shm { void RwLock::ReadLock() { bool ret = false; RwLockPayload expected, desired; - auto thread_info = HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + auto thread_info = HERMES_THREAD_MANAGER->GetThreadStatic(); do { - expected.as_int_ = payload_.load(); - if (expected.IsWriteLocked()) { - thread_info->Yield(); - continue; + for (int i = 0; i < US_TO_CLOCKS(8); ++i) { + expected.as_int_ = payload_.load(); + if (expected.IsWriteLocked()) { + continue; + } + desired = expected; + desired.bits_.r_ += 1; + ret = payload_.compare_exchange_weak( + expected.as_int_, + desired.as_int_); + if (ret) { return; } } - desired = expected; - desired.bits_.r_ += 1; - ret = payload_.compare_exchange_weak( - expected.as_int_, - desired.as_int_); - } while (!ret); + thread_info->Yield(); + } while (true); } /** @@ -58,23 +62,22 @@ void RwLock::ReadUnlock() { void RwLock::WriteLock() { bool ret = false; RwLockPayload expected, desired; - auto thread_info = HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + auto thread_info = HERMES_THREAD_MANAGER->GetThreadStatic(); do { - expected.as_int_ = payload_.load(); - if (expected.IsReadLocked()) { - thread_info->Yield(); - continue; - } - if (expected.IsWriteLocked()) { - thread_info->Yield(); - continue; + for (int i = 0; i < US_TO_CLOCKS(8); ++i) { + expected.as_int_ = payload_.load(); + if (expected.IsReadLocked() || expected.IsWriteLocked()) { + continue; + } + desired = expected; + desired.bits_.w_ += 1; + ret = payload_.compare_exchange_weak( + expected.as_int_, + desired.as_int_); + if (ret) { return; } } - desired = expected; - desired.bits_.w_ += 1; - ret = payload_.compare_exchange_weak( - expected.as_int_, - desired.as_int_); - } while (!ret); + thread_info->Yield(); + } while (true); } /** diff --git a/hermes_shm/test/unit/allocators/allocator.cc b/hermes_shm/test/unit/allocators/allocator.cc index 9cf4c3271..a25a0bfc1 100644 --- a/hermes_shm/test/unit/allocators/allocator.cc +++ b/hermes_shm/test/unit/allocators/allocator.cc @@ -10,14 +10,13 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "test_init.h" -#include "hermes_shm/memory/allocator/stack_allocator.h" -#include "hermes_shm/memory/allocator/multi_page_allocator.h" void PageAllocationTest(Allocator *alloc) { int count = 1024; size_t page_size = KILOBYTES(4); - auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + auto mem_mngr = HERMES_MEMORY_MANAGER; // Allocate pages std::vector ps(count); @@ -60,29 +59,29 @@ void PageAllocationTest(Allocator *alloc) { } void MultiPageAllocationTest(Allocator *alloc) { - size_t alloc_sizes[] = { + std::vector alloc_sizes = { 64, 128, 256, KILOBYTES(1), KILOBYTES(4), KILOBYTES(64), - MEGABYTES(1), MEGABYTES(16), MEGABYTES(32) + MEGABYTES(1) }; - // Allocate and free pages between 64 bytes and 1MB + // Allocate and free pages between 64 bytes and 32MB { - REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); - for (size_t r = 0; r < 10; ++r) { - for (size_t i = 0; i < 1000; ++i) { - Pointer ps[4]; - for (size_t j = 0; j < 4; ++j) { - ps[j] = alloc->Allocate(alloc_sizes[i % 9]); + for (size_t r = 0; r < 16; ++r) { + for (size_t i = 0; i < alloc_sizes.size(); ++i) { + Pointer ps[16]; + for (size_t j = 0; j < 16; ++j) { + ps[j] = alloc->Allocate(alloc_sizes[i]); } - for (size_t j = 0; j < 4; ++j) { + for (size_t j = 0; j < 16; ++j) { alloc->Free(ps[j]); } } } - REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); } +} +void ReallocationTest(Allocator *alloc) { // Aligned allocate 4KB pages { for (size_t i = 0; i < 1024; ++i) { @@ -109,8 +108,8 @@ TEST_CASE("StackAllocator") { Posttest(); } -TEST_CASE("MultiPageAllocator") { - auto alloc = Pretest(); +TEST_CASE("MallocAllocator") { + auto alloc = Pretest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); PageAllocationTest(alloc); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); @@ -122,8 +121,8 @@ TEST_CASE("MultiPageAllocator") { Posttest(); } -TEST_CASE("MallocAllocator") { - auto alloc = Pretest(); +TEST_CASE("FixedPageAllocator") { + auto alloc = Pretest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); PageAllocationTest(alloc); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); @@ -134,3 +133,16 @@ TEST_CASE("MallocAllocator") { Posttest(); } + +TEST_CASE("ScalablePageAllocator") { + auto alloc = Pretest(); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + // PageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + MultiPageAllocationTest(alloc); + REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); + + Posttest(); +} \ No newline at end of file diff --git a/hermes_shm/test/unit/allocators/allocator_thread.cc b/hermes_shm/test/unit/allocators/allocator_thread.cc index b76762f63..e5cdd4af2 100644 --- a/hermes_shm/test/unit/allocators/allocator_thread.cc +++ b/hermes_shm/test/unit/allocators/allocator_thread.cc @@ -10,17 +10,20 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "test_init.h" void MultiThreadedPageAllocationTest(Allocator *alloc) { int nthreads = 8; - HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + HERMES_THREAD_MANAGER->GetThreadStatic(); omp_set_dynamic(0); #pragma omp parallel shared(alloc) num_threads(nthreads) { #pragma omp barrier PageAllocationTest(alloc); +#pragma omp barrier + // MultiPageAllocationTest(alloc); #pragma omp barrier } } @@ -33,8 +36,8 @@ TEST_CASE("StackAllocatorMultithreaded") { Posttest(); } -TEST_CASE("MultiPageAllocatorMultithreaded") { - auto alloc = Pretest(); +TEST_CASE("ScalablePageAllocatorMultithreaded") { + auto alloc = Pretest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); MultiThreadedPageAllocationTest(alloc); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); diff --git a/hermes_shm/test/unit/allocators/test_init.cc b/hermes_shm/test/unit/allocators/test_init.cc index 4b0042a82..5ada4b16f 100644 --- a/hermes_shm/test/unit/allocators/test_init.cc +++ b/hermes_shm/test/unit/allocators/test_init.cc @@ -10,12 +10,12 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "test_init.h" void Posttest() { std::string shm_url = "test_allocators"; - auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; - mem_mngr->DestroyBackend(shm_url); + auto mem_mngr = HERMES_MEMORY_MANAGER; } void MainPretest() {} diff --git a/hermes_shm/test/unit/allocators/test_init.h b/hermes_shm/test/unit/allocators/test_init.h index 53e532efd..fcad30a58 100644 --- a/hermes_shm/test/unit/allocators/test_init.h +++ b/hermes_shm/test/unit/allocators/test_init.h @@ -10,8 +10,9 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ -#define HERMES_SHM_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ + +#ifndef HERMES_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ +#define HERMES_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ #include "basic_test.h" #include "omp.h" @@ -35,7 +36,7 @@ template Allocator* Pretest() { std::string shm_url = "test_allocators"; allocator_id_t alloc_id(0, 1); - auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + auto mem_mngr = HERMES_MEMORY_MANAGER; mem_mngr->CreateBackend( MemoryManager::kDefaultBackendSize, shm_url); mem_mngr->CreateAllocator( @@ -48,5 +49,6 @@ Allocator* Pretest() { void Posttest(); void PageAllocationTest(Allocator *alloc); +void MultiPageAllocationTest(Allocator *alloc); -#endif // HERMES_SHM_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ +#endif // HERMES_TEST_UNIT_ALLOCATORS_TEST_INIT_H_ diff --git a/hermes_shm/test/unit/basic_test.h b/hermes_shm/test/unit/basic_test.h index e669ed34e..3fd61159d 100644 --- a/hermes_shm/test/unit/basic_test.h +++ b/hermes_shm/test/unit/basic_test.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ -#define HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ +#ifndef HERMES_TEST_UNIT_BASIC_TEST_H_ +#define HERMES_TEST_UNIT_BASIC_TEST_H_ #define CATCH_CONFIG_RUNNER #include @@ -65,4 +65,4 @@ static bool VerifyBuffer(char *ptr, size_t size, char nonce) { void MainPretest(); void MainPosttest(); -#endif // HERMES_SHM_TEST_UNIT_BASIC_TEST_H_ +#endif // HERMES_TEST_UNIT_BASIC_TEST_H_ diff --git a/hermes_shm/test/unit/data_structures/CMakeLists.txt b/hermes_shm/test/unit/data_structures/CMakeLists.txt index 0db1dd7ff..969fd6cfe 100644 --- a/hermes_shm/test/unit/data_structures/CMakeLists.txt +++ b/hermes_shm/test/unit/data_structures/CMakeLists.txt @@ -3,8 +3,8 @@ project(hermes_shm) set(CMAKE_CXX_STANDARD 17) -include_directories(${CMAKE_SOURCE_DIR}/test/unit) +include_directories(${HERMES_SHM_ROOT}/test/unit) add_subdirectory(backend) add_subdirectory(containers) -add_subdirectory(containers_mpi) +#add_subdirectory(containers_mpi) add_subdirectory(lock) \ No newline at end of file diff --git a/hermes_shm/test/unit/data_structures/backend/memory_manager.cc b/hermes_shm/test/unit/data_structures/backend/memory_manager.cc index e6d6a6742..03f224d3d 100644 --- a/hermes_shm/test/unit/data_structures/backend/memory_manager.cc +++ b/hermes_shm/test/unit/data_structures/backend/memory_manager.cc @@ -10,6 +10,7 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "basic_test.h" #include @@ -33,8 +34,8 @@ TEST_CASE("MemoryManager") { MPI_Comm_rank(MPI_COMM_WORLD, &rank); allocator_id_t alloc_id(0, 1); - HERMES_SHM_ERROR_HANDLE_START() - auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + HERMES_ERROR_HANDLE_START() + auto mem_mngr = HERMES_MEMORY_MANAGER; if (rank == 0) { std::cout << "Creating SHMEM (rank 0): " << shm_url << std::endl; @@ -70,9 +71,6 @@ TEST_CASE("MemoryManager") { REQUIRE(VerifyBuffer(page, page_size, nonce)); } MPI_Barrier(MPI_COMM_WORLD); - if (rank == 0) { - mem_mngr->DestroyBackend(shm_url); - } - HERMES_SHM_ERROR_HANDLE_END() + HERMES_ERROR_HANDLE_END() } diff --git a/hermes_shm/test/unit/data_structures/backend/memory_slots.cc b/hermes_shm/test/unit/data_structures/backend/memory_slots.cc index f5df1a526..462ff5949 100644 --- a/hermes_shm/test/unit/data_structures/backend/memory_slots.cc +++ b/hermes_shm/test/unit/data_structures/backend/memory_slots.cc @@ -24,19 +24,25 @@ TEST_CASE("MemorySlot") { std::string shm_url = "test_mem_backend"; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - HERMES_SHM_ERROR_HANDLE_START() + HERMES_ERROR_HANDLE_START() PosixShmMmap backend; if (rank == 0) { - std::cout << "HERE?" << std::endl; - SECTION("Creating SHMEM (rank 0)") { - backend.shm_init(MEGABYTES(1), shm_url); + { + std::cout << "Creating SHMEM (rank 0)" << std::endl; + if(!backend.shm_init(MEGABYTES(1), shm_url)) { + throw std::runtime_error("Couldn't create backend"); + } + std::cout << "Backend data: " << (void*)backend.data_ << std::endl; + std::cout << "Backend sz: " << backend.data_size_ << std::endl; memset(backend.data_, nonce, backend.data_size_); + std::cout << "Wrote backend data" << std::endl; } } MPI_Barrier(MPI_COMM_WORLD); if (rank != 0) { - SECTION("Attaching SHMEM (rank 1)") { + { + std::cout << "Attaching SHMEM (rank 1)" << std::endl; backend.shm_deserialize(shm_url); char *ptr = backend.data_; REQUIRE(VerifyBuffer(ptr, backend.data_size_, nonce)); @@ -44,10 +50,11 @@ TEST_CASE("MemorySlot") { } MPI_Barrier(MPI_COMM_WORLD); if (rank == 0) { - SECTION("Destroying shmem (rank 1)") { + { + std::cout << "Destroying shmem (rank 1)" << std::endl; backend.shm_destroy(); } } - HERMES_SHM_ERROR_HANDLE_END() + HERMES_ERROR_HANDLE_END() } diff --git a/hermes_shm/test/unit/data_structures/backend/test_init.cc b/hermes_shm/test/unit/data_structures/backend/test_init.cc index 7590f5764..82bac123b 100644 --- a/hermes_shm/test/unit/data_structures/backend/test_init.cc +++ b/hermes_shm/test/unit/data_structures/backend/test_init.cc @@ -10,6 +10,7 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "basic_test.h" void MainPretest() {} diff --git a/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt b/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt index 6b6cda3a6..07b0b1181 100644 --- a/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt +++ b/hermes_shm/test/unit/data_structures/containers/CMakeLists.txt @@ -8,10 +8,15 @@ add_executable(test_data_structure_exec test_init.cc string.cc pair.cc + #tuple.cc list.cc + slist.cc vector.cc + iqueue.cc manual_ptr.cc + unique_ptr.cc unordered_map.cc + #unordered_map_thread.cc ) add_dependencies(test_data_structure_exec hermes_shm_data_structures) diff --git a/hermes_shm/test/unit/data_structures/containers/list.cc b/hermes_shm/test/unit/data_structures/containers/list.cc index e13939ed9..157cdf112 100644 --- a/hermes_shm/test/unit/data_structures/containers/list.cc +++ b/hermes_shm/test/unit/data_structures/containers/list.cc @@ -15,7 +15,6 @@ #include "list.h" #include "hermes_shm/data_structures/thread_unsafe/list.h" #include "hermes_shm/data_structures/string.h" -#include "hermes_shm/memory/allocator/stack_allocator.h" using hermes_shm::ipc::list; diff --git a/hermes_shm/test/unit/data_structures/containers/list.h b/hermes_shm/test/unit/data_structures/containers/list.h index b5819eabb..990e43114 100644 --- a/hermes_shm/test/unit/data_structures/containers/list.h +++ b/hermes_shm/test/unit/data_structures/containers/list.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ -#define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ +#ifndef HERMES_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ +#define HERMES_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ #include "basic_test.h" #include "test_init.h" @@ -189,4 +189,4 @@ class ListTestSuite { } }; -#endif //HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ +#endif //HERMES_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_LIST_H_ diff --git a/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc b/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc index 49f1a2d2a..4d870493e 100644 --- a/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc +++ b/hermes_shm/test/unit/data_structures/containers/manual_ptr.cc @@ -10,15 +10,16 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "hermes_shm/data_structures/smart_ptr/manual_ptr.h" #include "basic_test.h" #include "test_init.h" #include "hermes_shm/data_structures/string.h" -#include "hermes_shm/memory/allocator/stack_allocator.h" #include "smart_ptr.h" using hermes_shm::ipc::string; using hermes_shm::ipc::mptr; +using hermes_shm::ipc::uptr; using hermes_shm::ipc::mptr; using hermes_shm::ipc::make_mptr; using hermes_shm::ipc::TypedPointer; diff --git a/hermes_shm/test/unit/data_structures/containers/smart_ptr.h b/hermes_shm/test/unit/data_structures/containers/smart_ptr.h index 3f56ed4a8..6e9fc0a6e 100644 --- a/hermes_shm/test/unit/data_structures/containers/smart_ptr.h +++ b/hermes_shm/test/unit/data_structures/containers/smart_ptr.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ -#define HERMES_SHM_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ +#ifndef HERMES_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ +#define HERMES_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ #include "basic_test.h" #include "test_init.h" @@ -81,4 +81,4 @@ class SmartPtrTestSuite { } // namespace hermes_shm::ipc -#endif //HERMES_SHM_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ +#endif //HERMES_TEST_UNIT_ptr__STRUCTURES_CONTAINERS_SMART_PTR_H_ diff --git a/hermes_shm/test/unit/data_structures/containers/string.cc b/hermes_shm/test/unit/data_structures/containers/string.cc index 104c198ea..b3a6d51a6 100644 --- a/hermes_shm/test/unit/data_structures/containers/string.cc +++ b/hermes_shm/test/unit/data_structures/containers/string.cc @@ -13,7 +13,6 @@ #include "basic_test.h" #include "test_init.h" #include "hermes_shm/data_structures/string.h" -#include "hermes_shm/memory/allocator/stack_allocator.h" using hermes_shm::ipc::string; diff --git a/hermes_shm/test/unit/data_structures/containers/test_init.cc b/hermes_shm/test/unit/data_structures/containers/test_init.cc index df4498908..d8e74d57f 100644 --- a/hermes_shm/test/unit/data_structures/containers/test_init.cc +++ b/hermes_shm/test/unit/data_structures/containers/test_init.cc @@ -10,18 +10,16 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "basic_test.h" #include "test_init.h" #include -#include "hermes_shm/memory/allocator/stack_allocator.h" - Allocator *alloc_g = nullptr; void Posttest() { std::string shm_url = "test_allocators"; - auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; - mem_mngr->DestroyBackend(shm_url); + auto mem_mngr = HERMES_MEMORY_MANAGER; alloc_g = nullptr; } diff --git a/hermes_shm/test/unit/data_structures/containers/test_init.h b/hermes_shm/test/unit/data_structures/containers/test_init.h index 041560218..e85e26e70 100644 --- a/hermes_shm/test/unit/data_structures/containers/test_init.h +++ b/hermes_shm/test/unit/data_structures/containers/test_init.h @@ -10,8 +10,9 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ -#define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ + +#ifndef HERMES_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ +#define HERMES_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ #include "hermes_shm/data_structures/data_structure.h" @@ -37,7 +38,7 @@ template void Pretest() { std::string shm_url = "test_allocators"; allocator_id_t alloc_id(0, 1); - auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + auto mem_mngr = HERMES_MEMORY_MANAGER; mem_mngr->CreateBackend( MemoryManager::kDefaultBackendSize, shm_url); mem_mngr->CreateAllocator(shm_url, alloc_id, 0); @@ -46,4 +47,4 @@ void Pretest() { void Posttest(); -#endif // HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ +#endif // HERMES_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ diff --git a/hermes_shm/test/unit/data_structures/containers/unordered_map.cc b/hermes_shm/test/unit/data_structures/containers/unordered_map.cc index afef50f08..c461d2ddb 100644 --- a/hermes_shm/test/unit/data_structures/containers/unordered_map.cc +++ b/hermes_shm/test/unit/data_structures/containers/unordered_map.cc @@ -14,7 +14,6 @@ #include "test_init.h" #include "hermes_shm/data_structures/thread_unsafe/unordered_map.h" #include "hermes_shm/data_structures/string.h" -#include "hermes_shm/memory/allocator/stack_allocator.h" using hermes_shm::ipc::MemoryBackendType; using hermes_shm::ipc::MemoryBackend; diff --git a/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc b/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc index 88e6bce50..b4d5b8714 100644 --- a/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc +++ b/hermes_shm/test/unit/data_structures/containers/unordered_map_thread.cc @@ -15,7 +15,6 @@ #include "test_init.h" #include "hermes_shm/data_structures/thread_safe/unordered_map.h" #include "hermes_shm/data_structures/string.h" -#include "hermes_shm/memory/allocator/stack_allocator.h" #include "hermes_shm/util/errors.h" #include @@ -36,7 +35,7 @@ void UnorderedMapParallelInsert() { int entries_per_thread = 50; int nthreads = 4; int total_entries = nthreads * entries_per_thread; - HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + HERMES_THREAD_MANAGER->GetThreadStatic(); omp_set_dynamic(0); #pragma omp parallel shared(alloc, map) num_threads(nthreads) diff --git a/hermes_shm/test/unit/data_structures/containers/vector.h b/hermes_shm/test/unit/data_structures/containers/vector.h index 9a1158164..00256a8d5 100644 --- a/hermes_shm/test/unit/data_structures/containers/vector.h +++ b/hermes_shm/test/unit/data_structures/containers/vector.h @@ -10,8 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ -#define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ +#ifndef HERMES_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ +#define HERMES_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ #include "list.h" @@ -34,4 +34,4 @@ class VectorTestSuite : public ListTestSuite { } }; -#endif //HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ +#endif //HERMES_TEST_UNIT_DATA_STRUCTURES_CONTAINERS_VECTOR_H_ diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc b/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc index 73a2bc64e..22498b2b3 100644 --- a/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc +++ b/hermes_shm/test/unit/data_structures/containers_mpi/list_vec_mpi.cc @@ -76,7 +76,7 @@ void ListVecTest(size_t count) { MPI_Barrier(MPI_COMM_WORLD); } - } catch(HERMES_SHM_ERROR_TYPE &HERMES_SHM_ERROR_PTR) { + } catch(HERMES_ERROR_TYPE &HERMES_ERROR_PTR) { std::cout << "HERE0" << std::endl; err->print(); } catch(hermes_shm::Error &err) { diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc index b74bb31f3..0e0c2e3b3 100644 --- a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc +++ b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.cc @@ -10,18 +10,17 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "basic_test.h" #include "test_init.h" -#include "hermes_shm/memory/allocator/stack_allocator.h" - Allocator *alloc_g = nullptr; template void PretestRank0() { std::string shm_url = "test_allocators"; allocator_id_t alloc_id(0, 1); - auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + auto mem_mngr = HERMES_MEMORY_MANAGER; mem_mngr->CreateBackend( MemoryManager::kDefaultBackendSize, shm_url); mem_mngr->CreateAllocator(shm_url, alloc_id, sizeof(Pointer)); @@ -31,7 +30,7 @@ void PretestRank0() { void PretestRankN() { std::string shm_url = "test_allocators"; allocator_id_t alloc_id(0, 1); - auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + auto mem_mngr = HERMES_MEMORY_MANAGER; mem_mngr->AttachBackend(MemoryBackendType::kPosixShmMmap, shm_url); alloc_g = mem_mngr->GetAllocator(alloc_id); } diff --git a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h index 77a20a365..fc012b3e5 100644 --- a/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h +++ b/hermes_shm/test/unit/data_structures/containers_mpi/test_init.h @@ -10,8 +10,9 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ -#define HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ + +#ifndef HERMES_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ +#define HERMES_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ #include "hermes_shm/data_structures/data_structure.h" #include @@ -36,4 +37,4 @@ extern Allocator *alloc_g; void Posttest(); -#endif // HERMES_SHM_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ +#endif // HERMES_TEST_UNIT_DATA_STRUCTURES_TEST_INIT_H_ diff --git a/hermes_shm/test/unit/data_structures/lock/lock.cc b/hermes_shm/test/unit/data_structures/lock/lock.cc index db6b9204a..7ba4e52bb 100644 --- a/hermes_shm/test/unit/data_structures/lock/lock.cc +++ b/hermes_shm/test/unit/data_structures/lock/lock.cc @@ -10,6 +10,7 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "basic_test.h" #include "omp.h" #include "hermes_shm/thread/lock.h" @@ -23,7 +24,7 @@ void MutexTest() { int count = 0; Mutex lock; - HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + HERMES_THREAD_MANAGER->GetThreadStatic(); omp_set_dynamic(0); #pragma omp parallel shared(lock) num_threads(nthreads) @@ -59,7 +60,7 @@ void RwLockTest() { int count = 0; RwLock lock; - HERMES_SHM_THREAD_MANAGER->GetThreadStatic(); + HERMES_THREAD_MANAGER->GetThreadStatic(); omp_set_dynamic(0); #pragma omp parallel \ diff --git a/hermes_shm/test/unit/data_structures/lock/test_init.cc b/hermes_shm/test/unit/data_structures/lock/test_init.cc index 7590f5764..82bac123b 100644 --- a/hermes_shm/test/unit/data_structures/lock/test_init.cc +++ b/hermes_shm/test/unit/data_structures/lock/test_init.cc @@ -10,6 +10,7 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "basic_test.h" void MainPretest() {} diff --git a/hermes_shm/test/unit/main.cc b/hermes_shm/test/unit/main.cc index da1e76728..bd480daba 100644 --- a/hermes_shm/test/unit/main.cc +++ b/hermes_shm/test/unit/main.cc @@ -10,6 +10,7 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "basic_test.h" #include diff --git a/hermes_shm/test/unit/main_mpi.cc b/hermes_shm/test/unit/main_mpi.cc index c34f81eca..c2a3249a6 100644 --- a/hermes_shm/test/unit/main_mpi.cc +++ b/hermes_shm/test/unit/main_mpi.cc @@ -10,6 +10,7 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "basic_test.h" #include diff --git a/hermes_shm/test/unit/types/CMakeLists.txt b/hermes_shm/test/unit/types/CMakeLists.txt index 1437ed150..fc2a975e0 100644 --- a/hermes_shm/test/unit/types/CMakeLists.txt +++ b/hermes_shm/test/unit/types/CMakeLists.txt @@ -8,4 +8,10 @@ add_executable(test_types test_init.cc test_argpack.cc) target_link_libraries(test_types - Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) \ No newline at end of file + Catch2::Catch2 MPI::MPI_CXX OpenMP::OpenMP_CXX) + +#add_test(NAME test_connect COMMAND +# bash ${CMAKE_CURRENT_SOURCE_DIR}/test_connect.sh +# ${CMAKE_BINARY_DIR}/labstor_runtime +# ${CMAKE_CURRENT_BINARY_DIR}/test_connect_exec +# ${HERMES_SHM_ROOT}/config/config.yaml) \ No newline at end of file diff --git a/hermes_shm/test/unit/types/test_init.cc b/hermes_shm/test/unit/types/test_init.cc index 7590f5764..82bac123b 100644 --- a/hermes_shm/test/unit/types/test_init.cc +++ b/hermes_shm/test/unit/types/test_init.cc @@ -10,6 +10,7 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "basic_test.h" void MainPretest() {} diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 81489a31a..89ba7d120 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -120,7 +120,7 @@ void Hermes::LoadClientConfig(std::string config_path) { void Hermes::InitSharedMemory() { // Create shared-memory allocator - auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + auto mem_mngr = HERMES_MEMORY_MANAGER; mem_mngr->CreateBackend( hipc::MemoryManager::kDefaultBackendSize, server_config_.shmem_name_); @@ -134,7 +134,7 @@ void Hermes::InitSharedMemory() { void Hermes::LoadSharedMemory() { // Load shared-memory allocator - auto mem_mngr = HERMES_SHM_MEMORY_MANAGER; + auto mem_mngr = HERMES_MEMORY_MANAGER; mem_mngr->AttachBackend(hipc::MemoryBackendType::kPosixShmMmap, server_config_.shmem_name_); main_alloc_ = mem_mngr->GetAllocator(main_alloc_id); diff --git a/src/data_structures.h b/src/data_structures.h index 122f25b4f..cd0f3d184 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -16,8 +16,10 @@ #include #include #include +#include #include #include +#include #include #include From 71a16d1c37675f42e7edb9fed035d56175689441 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Sun, 26 Feb 2023 08:52:42 -0600 Subject: [PATCH 152/511] Use ScalablePageAllocator --- .../memory/allocator/multi_page_allocator.h | 212 ------------------ hermes_shm/src/memory/multi_page_allocator.cc | 112 --------- hermes_shm/test/unit/allocators/allocator.cc | 4 +- .../test/unit/allocators/allocator_thread.cc | 7 +- src/api/hermes.cc | 2 +- 5 files changed, 9 insertions(+), 328 deletions(-) delete mode 100644 hermes_shm/include/hermes_shm/memory/allocator/multi_page_allocator.h delete mode 100644 hermes_shm/src/memory/multi_page_allocator.cc diff --git a/hermes_shm/include/hermes_shm/memory/allocator/multi_page_allocator.h b/hermes_shm/include/hermes_shm/memory/allocator/multi_page_allocator.h deleted file mode 100644 index b85cf2b9e..000000000 --- a/hermes_shm/include/hermes_shm/memory/allocator/multi_page_allocator.h +++ /dev/null @@ -1,212 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MULTI_PAGE_ALLOCATOR_H_ -#define HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MULTI_PAGE_ALLOCATOR_H_ - -#include "allocator.h" -#include "hermes_shm/thread/lock.h" -#include "mp_page.h" - -namespace hermes_shm::ipc { - -struct MultiPageFreeList { - /// Lock the list - Mutex lock_; - /// Free list for different page sizes - /// Stack allocator - size_t region_off_, region_size_; - /// Number of bytes currently free in this free list - size_t free_size_; - /// Total number of bytes alloc'd from this list - size_t total_alloced_; - /// Total number of bytes freed to this list - size_t total_freed_; - - /** - * The total amount of space allocated by the MultiPageFree list when - * there is \a num_page_caches number of page size free lists - * */ - static size_t GetSizeBytes(size_t num_page_caches) { - return 0; - } - - /** - * Initialize the free list array - * */ - void shm_init(size_t mp_free_list_size, - char *region_start, - size_t region_off, size_t region_size) { - } - - /** Get the free list at index i */ -}; - -struct MultiPageAllocatorHeader : public AllocatorHeader { - /// Number of threads to initially assume - std::atomic concurrency_; - /// Bytes to dedicate to per-thread free list tables - size_t thread_table_size_; - /// Cache every page between these sizes - size_t mp_free_list_size_; - size_t min_page_size_, max_page_size_; - uint32_t min_page_log_, max_page_log_, last_page_idx_; - /// The page sizes to cache - RealNumber growth_rate_; - /// The minimum number of free bytes before a coalesce can be triggered - size_t coalesce_min_size_; - /// The percentage of fragmentation before a coalesce is triggered - RealNumber coalesce_frac_; - - MultiPageAllocatorHeader() = default; - - void Configure(allocator_id_t alloc_id, - size_t custom_header_size, - size_t min_page_size, - size_t max_page_size, - RealNumber growth_rate, - size_t coalesce_min_size, - RealNumber coalesce_frac, - size_t thread_table_size, - uint32_t concurrency) { - } -}; - -class MultiPageAllocator : public Allocator { - private: - MultiPageAllocatorHeader *header_; - - public: - /** - * Allocator constructor - * */ - MultiPageAllocator() - : header_(nullptr) {} - - /** - * Get the ID of this allocator from shared memory - * */ - allocator_id_t GetId() override { - return header_->allocator_id_; - } - - /** - * Initialize the allocator in shared memory - * */ - void shm_init(MemoryBackend *backend, - allocator_id_t alloc_id, - size_t custom_header_size = 0, - size_t min_page_size = 64, - size_t max_page_size = KILOBYTES(32), - RealNumber growth_rate = RealNumber(5, 4), - size_t coalesce_min_size = MEGABYTES(20), - RealNumber coalesce_frac = RealNumber(2, 1), - size_t thread_table_size = MEGABYTES(1), - uint32_t concurrency = 4); - - /** - * Attach an existing allocator from shared memory - * */ - void shm_deserialize(MemoryBackend *backend) override; - - /** - * Allocate a memory of \a size size. The page allocator cannot allocate - * memory larger than the page size. - * */ - OffsetPointer AllocateOffset(size_t size) override; - - /** - * Allocate a memory of \a size size, which is aligned to \a - * alignment. - * */ - OffsetPointer AlignedAllocateOffset(size_t size, size_t alignment) override; - - /** - * Reallocate \a p pointer to \a new_size new size. - * - * @return whether or not the pointer p was changed - * */ - OffsetPointer ReallocateOffsetNoNullCheck( - OffsetPointer p, size_t new_size) override; - - /** - * Free \a ptr pointer. Null check is performed elsewhere. - * */ - void FreeOffsetNoNullCheck(OffsetPointer p) override; - - /** - * Get the current amount of data allocated. Can be used for leak - * checking. - * */ - size_t GetCurrentlyAllocatedSize() override; - - private: - /** Get the index of "x" within the page free list array */ - inline uint32_t IndexLogarithm(size_t x, size_t &round); - - /** Get the pointer to the mp_free_lists_ array */ - void* GetMpFreeListStart(); - - /** Set the page's header */ - void _AllocateHeader(Pointer &p, - size_t page_size, - size_t page_size_idx, - size_t off); - - /** Set the page's header + change allocator stats*/ - void _AllocateHeader(Pointer &p, - MultiPageFreeList &mp_free_list, - size_t page_size, - size_t page_size_idx, - size_t off); - - /** Allocate a page from a thread's mp free list */ - Pointer _Allocate(MultiPageFreeList &free_list, - size_t page_size_idx, size_t page_size); - - /** Allocate a large, cached page */ - bool _AllocateLargeCached(MultiPageFreeList &mp_free_list, - size_t page_size_idx, - size_t page_size, - Pointer &ret); - - /** Allocate a cached page */ - bool _AllocateCached(MultiPageFreeList &mp_free_list, - size_t page_size_idx, - size_t page_size, - Pointer &ret); - - /** Allocate and divide a cached page larger than page_size */ - bool _AllocateBorrowCached(MultiPageFreeList &mp_free_list, - size_t page_size_idx, - size_t page_size, - Pointer &ret); - - /** Allocate a page from the segment */ - bool _AllocateSegment(MultiPageFreeList &mp_free_list, - size_t page_size_idx, - size_t page_size, - Pointer &ret); - - /** Reorganize free space to minimize fragmentation */ - void _Coalesce(MultiPageFreeList &to, tid_t tid); - - /** Create a new thread allocator by borrowing from other allocators */ - void _AddThread(); - - /** Free a page to a free list */ - void _Free(MultiPageFreeList &free_list, Pointer &p); -}; - -} // namespace hermes_shm::ipc - -#endif //HERMES_SHM_INCLUDE_HERMES_SHM_MEMORY_ALLOCATOR_MULTI_PAGE_ALLOCATOR_H_ diff --git a/hermes_shm/src/memory/multi_page_allocator.cc b/hermes_shm/src/memory/multi_page_allocator.cc deleted file mode 100644 index 2d04be254..000000000 --- a/hermes_shm/src/memory/multi_page_allocator.cc +++ /dev/null @@ -1,112 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "hermes_shm/memory/allocator/multi_page_allocator.h" - -namespace hermes_shm::ipc { - -/** - * base^y = x; solve for y (round up) - * */ -uint32_t CountLogarithm(RealNumber base, size_t x, size_t &round) { - uint32_t y = 1; - RealNumber compound(base); - while (compound.as_int() < x) { - compound *= base; - RealNumber compound_exp = compound * compound; - y += 1; - if (compound_exp.as_int() <= x) { - y *= 2; - compound = compound_exp; - } - } - round = compound.as_int(); - return y; -} - -/** - * The index of the free list to allocate pages from - * */ -inline uint32_t MultiPageAllocator::IndexLogarithm(size_t x, size_t &round) { - if (x <= header_->min_page_size_) { - round = header_->min_page_size_; - return 0; - } else if (x > header_->max_page_size_){ - round = x; - return header_->last_page_idx_; - } - size_t log = CountLogarithm(header_->growth_rate_, x, round); - return log - header_->min_page_log_; -} - -/** - * Initialize the allocator in shared memory - * */ -void MultiPageAllocator::shm_init(MemoryBackend *backend, - allocator_id_t alloc_id, - size_t custom_header_size, - size_t min_page_size, - size_t max_page_size, - RealNumber growth_rate, - size_t coalesce_min_size, - RealNumber coalesce_frac, - size_t thread_table_size, - uint32_t concurrency) { -} - -/** - * Attach an existing allocator from shared memory - * */ -void MultiPageAllocator::shm_deserialize(MemoryBackend *backend) { -} - -/** - * Allocate a memory of \a size size. - * */ -OffsetPointer MultiPageAllocator::AllocateOffset(size_t size) { - return OffsetPointer(); -} - -/** - * Allocate a memory of \a size size, which is aligned to \a - * alignment. - * */ -OffsetPointer MultiPageAllocator::AlignedAllocateOffset(size_t size, - size_t alignment) { - return OffsetPointer(); -} - -/** - * Reallocate \a p pointer to \a new_size new size. - * - * @return whether or not the pointer p was changed - * */ -OffsetPointer MultiPageAllocator::ReallocateOffsetNoNullCheck(OffsetPointer p, - size_t new_size) { - return OffsetPointer(); -} - -/** - * Free \a ptr pointer. Null check is performed elsewhere. - * */ -void MultiPageAllocator::FreeOffsetNoNullCheck(OffsetPointer p) { -} - -/** - * Get the current amount of data allocated. Can be used for leak - * checking. - * */ -size_t MultiPageAllocator::GetCurrentlyAllocatedSize() { - return 0; -} - -} // namespace hermes_shm::ipc diff --git a/hermes_shm/test/unit/allocators/allocator.cc b/hermes_shm/test/unit/allocators/allocator.cc index a25a0bfc1..b1029b9eb 100644 --- a/hermes_shm/test/unit/allocators/allocator.cc +++ b/hermes_shm/test/unit/allocators/allocator.cc @@ -67,7 +67,7 @@ void MultiPageAllocationTest(Allocator *alloc) { // Allocate and free pages between 64 bytes and 32MB { - for (size_t r = 0; r < 16; ++r) { + for (size_t r = 0; r < 4; ++r) { for (size_t i = 0; i < alloc_sizes.size(); ++i) { Pointer ps[16]; for (size_t j = 0; j < 16; ++j) { @@ -137,7 +137,7 @@ TEST_CASE("FixedPageAllocator") { TEST_CASE("ScalablePageAllocator") { auto alloc = Pretest(); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); - // PageAllocationTest(alloc); + PageAllocationTest(alloc); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); REQUIRE(alloc->GetCurrentlyAllocatedSize() == 0); diff --git a/hermes_shm/test/unit/allocators/allocator_thread.cc b/hermes_shm/test/unit/allocators/allocator_thread.cc index e5cdd4af2..98b3a5d4c 100644 --- a/hermes_shm/test/unit/allocators/allocator_thread.cc +++ b/hermes_shm/test/unit/allocators/allocator_thread.cc @@ -23,7 +23,12 @@ void MultiThreadedPageAllocationTest(Allocator *alloc) { #pragma omp barrier PageAllocationTest(alloc); #pragma omp barrier - // MultiPageAllocationTest(alloc); + try { + MultiPageAllocationTest(alloc); + } catch (std::shared_ptr &err) { + err->print(); + exit(1); + } #pragma omp barrier } } diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 89ba7d120..71cb3e81c 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -125,7 +125,7 @@ void Hermes::InitSharedMemory() { hipc::MemoryManager::kDefaultBackendSize, server_config_.shmem_name_); main_alloc_ = - mem_mngr->CreateAllocator( + mem_mngr->CreateAllocator( server_config_.shmem_name_, main_alloc_id, sizeof(HermesShmHeader)); From 4ffbe5277e58202de2b58ff0fc2b990038e85221 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 27 Feb 2023 01:32:15 -0600 Subject: [PATCH 153/511] Better BufferPool --- .../internal/shm_archive_or_t.h | 4 +- .../internal/shm_container_macro.h | 2 +- .../internal/shm_deserialize.h | 12 +- .../template/shm_container_base_example.h | 2 +- .../template/shm_container_base_template.h | 2 +- .../data_structures/smart_ptr/manual_ptr.h | 5 + .../data_structures/thread_unsafe/vector.h | 16 +- src/api/bucket.cc | 2 +- src/api/hermes.cc | 31 +-- src/api/hermes.h | 7 +- src/buffer_pool.cc | 234 +++++++++++++++--- src/buffer_pool.h | 124 ++++++++-- src/data_structures.h | 2 + src/hermes_types.h | 3 +- src/rpc.cc | 3 - src/rpc_thallium.cc | 5 +- 16 files changed, 345 insertions(+), 109 deletions(-) diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h index 0b51fba02..7df3cbe78 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_archive_or_t.h @@ -66,12 +66,12 @@ class _ShmArchiveOrT_Header { /** Returns a reference to the internal object */ ShmDeserialize internal_ref(Allocator *alloc) { - return ShmDeserialize(alloc, reinterpret_cast(obj_hdr_)); + return ShmDeserialize(reinterpret_cast(obj_hdr_), alloc); } /** Returns a reference to the internal object */ ShmDeserialize internal_ref(Allocator *alloc) const { - return ShmDeserialize(alloc, reinterpret_cast(obj_hdr_)); + return ShmDeserialize(reinterpret_cast(obj_hdr_), alloc); } }; diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h index 0fa3eccf9..6b333c6bb 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_container_macro.h @@ -350,7 +350,7 @@ POINTER_T GetShmPointer() const {\ \ /** Get a ShmDeserialize object */\ hipc::ShmDeserialize GetShmDeserialize() const {\ - return hipc::ShmDeserialize(alloc_, header_);\ + return hipc::ShmDeserialize(header_, alloc_);\ }\ \ /**====================================\ diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h b/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h index 173d8c93c..d42c61f1e 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/shm_deserialize.h @@ -40,19 +40,25 @@ struct ShmDeserialize { } /** Construct from allocator + offset pointer */ - ShmDeserialize(Allocator *alloc, TypedOffsetPointer &ar) { + ShmDeserialize(TypedOffsetPointer &ar, Allocator *alloc) { alloc_ = alloc; header_ = alloc_->Convert< TypedPointer, OffsetPointer>(ar.ToOffsetPointer()); } - /** Construct from allocator + offset pointer */ - ShmDeserialize(Allocator *alloc, header_t *header) { + /** Construct from header (ptr) + allocator */ + ShmDeserialize(header_t *header, Allocator *alloc) { alloc_ = alloc; header_ = header; } + /** Construct from header (ref) + allocator */ + ShmDeserialize(header_t &header, Allocator *alloc) { + alloc_ = alloc; + header_ = &header; + } + /** Copy constructor */ ShmDeserialize(const ShmDeserialize &other) { shm_strong_copy(other); diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h index aeb7e08dd..b72518833 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_example.h @@ -407,7 +407,7 @@ class ShmContainerExample { /** Get a ShmDeserialize object */ hipc::ShmDeserialize GetShmDeserialize() const { - return hipc::ShmDeserialize(alloc_, header_); + return hipc::ShmDeserialize(header_, alloc_); } /**==================================== diff --git a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h index 2a0c85097..2a3ad5ba4 100644 --- a/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h +++ b/hermes_shm/include/hermes_shm/data_structures/internal/template/shm_container_base_template.h @@ -347,7 +347,7 @@ POINTER_T GetShmPointer() const { /** Get a ShmDeserialize object */ hipc::ShmDeserialize GetShmDeserialize() const { - return hipc::ShmDeserialize(alloc_, header_); + return hipc::ShmDeserialize(header_, alloc_); } /**==================================== diff --git a/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h b/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h index 49d7e95ae..25113ca36 100644 --- a/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h +++ b/hermes_shm/include/hermes_shm/data_structures/smart_ptr/manual_ptr.h @@ -79,6 +79,11 @@ class manual_ptr : public ShmSmartPtr { obj_.shm_deserialize(ar); } + /** Constructor. From a ShmDeserialize. */ + explicit manual_ptr(const ShmDeserialize &ar) { + obj_.shm_deserialize(ar); + } + /** (De)serialize the obj from a TypedPointer */ SHM_SERIALIZE_DESERIALIZE_WRAPPER((T)); }; diff --git a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h index 1c043137a..1e77fbdde 100644 --- a/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h +++ b/hermes_shm/include/hermes_shm/data_structures/thread_unsafe/vector.h @@ -658,56 +658,56 @@ class vector : public ShmContainer { public: /** Beginning of the forward iterator */ vector_iterator begin() { - vector_iterator iter(ShmDeserialize>(alloc_, header_)); + vector_iterator iter(ShmDeserialize>(header_, alloc_)); iter.set_begin(); return iter; } /** End of the forward iterator */ vector_iterator const end() { - vector_iterator iter(ShmDeserialize>(alloc_, header_)); + vector_iterator iter(ShmDeserialize>(header_, alloc_)); iter.set_end(); return iter; } /** Beginning of the constant forward iterator */ vector_citerator cbegin() const { - vector_citerator iter(ShmDeserialize>(alloc_, header_)); + vector_citerator iter(ShmDeserialize>(header_, alloc_)); iter.set_begin(); return iter; } /** End of the forward iterator */ vector_citerator cend() const { - vector_citerator iter(ShmDeserialize>(alloc_, header_)); + vector_citerator iter(ShmDeserialize>(header_, alloc_)); iter.set_end(); return iter; } /** Beginning of the reverse iterator */ vector_riterator rbegin() { - vector_riterator iter(ShmDeserialize>(alloc_, header_)); + vector_riterator iter(ShmDeserialize>(header_, alloc_)); iter.set_begin(); return iter; } /** End of the reverse iterator */ vector_riterator rend() { - vector_citerator iter(ShmDeserialize>(alloc_, header_)); + vector_citerator iter(ShmDeserialize>(header_, alloc_)); iter.set_end(); return iter; } /** Beginning of the constant reverse iterator */ vector_criterator crbegin() const { - vector_criterator iter(ShmDeserialize(alloc_, header_)); + vector_criterator iter(ShmDeserialize(header_, alloc_)); iter.set_begin(); return iter; } /** End of the constant reverse iterator */ vector_criterator crend() const { - vector_criterator iter(ShmDeserialize(alloc_, header_)); + vector_criterator iter(ShmDeserialize(header_, alloc_)); iter.set_end(); return iter; } diff --git a/src/api/bucket.cc b/src/api/bucket.cc index ebf37e4a8..6773f23f9 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -27,7 +27,7 @@ using hermes::adapter::AdapterMode; Bucket::Bucket(const std::string &bkt_name, Context &ctx, const IoClientContext &opts) -: mdm_(&HERMES->mdm_), bpm_(&HERMES->bpm_), name_(bkt_name) { +: mdm_(&HERMES->mdm_), bpm_(HERMES->bpm_.get()), name_(bkt_name) { hipc::string lname(bkt_name); id_ = mdm_->LocalGetOrCreateBucket(lname, opts); } diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 71cb3e81c..69f562c16 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -31,11 +31,6 @@ void Hermes::Init(HermesType mode, std::move(client_config_path)); break; } - case HermesType::kColocated: { - InitColocated(std::move(server_config_path), - std::move(client_config_path)); - break; - } } is_initialized_ = true; is_being_initialized_ = false; @@ -54,9 +49,8 @@ void Hermes::Finalize() { FinalizeClient(); break; } - case HermesType::kColocated: { - FinalizeColocated(); - break; + default: { + throw std::logic_error("Invalid HermesType to launch in"); } } // TODO(llogan): make re-initialization possible. @@ -78,7 +72,8 @@ void Hermes::InitServer(std::string server_config_path) { rpc_.InitServer(); rpc_.InitClient(); mdm_.shm_init(&server_config_, &header_->mdm_); - bpm_.shm_init(&header_->bpm_); + bpm_ = hipc::make_mptr(header_->bpm_, main_alloc_); + bpm_->shm_init(); borg_.shm_init(); } @@ -89,21 +84,11 @@ void Hermes::InitClient(std::string server_config_path, LoadSharedMemory(); rpc_.InitClient(); mdm_.shm_deserialize(&header_->mdm_); - bpm_.shm_deserialize(&header_->bpm_); + bpm_ = hipc::manual_ptr(hipc::ShmDeserialize(&header_->bpm_, + main_alloc_)); borg_.shm_deserialize(); } -void Hermes::InitColocated(std::string server_config_path, - std::string client_config_path) { - LoadServerConfig(server_config_path); - LoadClientConfig(client_config_path); - InitSharedMemory(); - rpc_.InitColocated(); - mdm_.shm_init(&server_config_, &header_->mdm_); - bpm_.shm_init(&header_->bpm_); - borg_.shm_init(); -} - void Hermes::LoadServerConfig(std::string config_path) { if (config_path.size() == 0) { config_path = GetEnvSafe(kHermesServerConf); @@ -154,10 +139,6 @@ void Hermes::FinalizeClient() { rpc_.Finalize(); } -void Hermes::FinalizeColocated() { - rpc_.Finalize(); -} - std::shared_ptr Hermes::GetBucket(std::string name, Context ctx, IoClientContext opts) { diff --git a/src/api/hermes.h b/src/api/hermes.h index bc1891879..9814e67e4 100644 --- a/src/api/hermes.h +++ b/src/api/hermes.h @@ -42,7 +42,7 @@ class VBucket; struct HermesShmHeader { hipc::Pointer ram_tier_; MetadataManagerShmHeader mdm_; - BufferPoolShmHeader bpm_; + hermes::ShmHeader bpm_; }; /** @@ -55,7 +55,7 @@ class Hermes { ServerConfig server_config_; ClientConfig client_config_; MetadataManager mdm_; - BufferPool bpm_; + hipc::manual_ptr bpm_; BufferOrganizer borg_; COMM_TYPE comm_; RPC_TYPE rpc_; @@ -148,9 +148,6 @@ class Hermes { /** Finalize client mode */ void FinalizeClient(); - - /** Finalize colocated mode */ - void FinalizeColocated(); }; #define TRANSPARENT_HERMES\ diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index c47263038..0452586ba 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -21,69 +21,233 @@ namespace hermes { * Initialize the BPM and its shared memory. * REQUIRES mdm to be initialized already. * */ -void BufferPool::shm_init(BufferPoolShmHeader *header) { +void BufferPool::shm_init_main(ShmHeader *header, + hipc::Allocator *alloc) { + shm_init_allocator(alloc); + shm_init_header(header, alloc_); mdm_ = &HERMES->mdm_; borg_ = &HERMES->borg_; - target_allocs_ = hipc::make_mptr>( - HERMES->main_alloc_); - target_allocs_->resize(mdm_->targets_->size()); - shm_serialize(header); -} - -/** Destroy the BPM shared memory. */ -void BufferPool::shm_destroy() { - target_allocs_.shm_destroy(); + // [target] [cpu] [page_size] + header_->ntargets_ = mdm_->targets_->size(); + header_->ncpu_ = HERMES_SYSTEM_INFO->ncpu_; + header_->nslabs_ = 0; + // Get the maximum number of slabs over all targets + for (hipc::ShmRef target : *mdm_->targets_) { + int dev_id = target->id_.GetDeviceId(); + hipc::ShmRef dev_info = (*mdm_->devices_)[dev_id]; + if (header_->nslabs_ < dev_info->slab_sizes_->size()) { + header_->nslabs_ = dev_info->slab_sizes_->size(); + } + } + // Create target free lists + shm_deserialize_main(); + target_allocs_->resize(header_->ntargets_ * header_->ncpu_ * + header_->nslabs_); + // Initialize target free lists + for (size_t i = 0; i < header_->ntargets_; ++i) { + for (size_t j = 0; j < header_->ncpu_; ++j) { + size_t free_list_start = header_->GetCpuFreeList(i, j); + hipc::ShmRef target = (*mdm_->targets_)[i]; + int dev_id = target->id_.GetDeviceId(); + hipc::ShmRef dev_info = (*mdm_->devices_)[dev_id]; + for (size_t k = 0; k < dev_info->slab_sizes_->size(); ++k) { + hipc::ShmRef free_list_p = + (*target_allocs_)[free_list_start + k]; + hipc::ShmRef &stat = free_list_p->first_; + hipc::ShmRef &free_list = free_list_p->second_; + stat->page_size_ = *(*dev_info->slab_sizes_)[k]; + stat->region_off_ = 0; + stat->region_size_ = target->max_cap_; + stat->lock_.Init(); + } + } + } } /** Store the BPM in shared memory */ -void BufferPool::shm_serialize(BufferPoolShmHeader *header) { - target_allocs_ >> header->alloc_ar_; -} +void BufferPool::shm_serialize_main() const {} /** Deserialize the BPM from shared memory */ -void BufferPool::shm_deserialize(BufferPoolShmHeader *header) { +void BufferPool::shm_deserialize_main() { mdm_ = &HERMES->mdm_; borg_ = &HERMES->borg_; - target_allocs_ << header->alloc_ar_; + target_allocs_ = hipc::ShmRef( + header_->free_lists_.internal_ref(alloc_)); +} + +/** Destroy the BPM shared memory. */ +void BufferPool::shm_destroy_main() { + target_allocs_->shm_destroy(); } /** * Allocate buffers from the targets according to the schema - * - * TODO(llogan): use better allocator policy * */ hipc::vector BufferPool::LocalAllocateAndSetBuffers(PlacementSchema &schema, const Blob &blob) { hipc::vector buffers(HERMES->main_alloc_); - size_t blob_off_ = 0; - for (auto plcmnt : schema.plcmnts_) { + size_t blob_off = 0; + int cpu = hermes_shm::NodeThreadId().hash() % HERMES_SYSTEM_INFO->ncpu_; + + for (SubPlacement &plcmnt : schema.plcmnts_) { + // Get the target and device in the placement schema if (plcmnt.tid_.GetNodeId() != mdm_->rpc_->node_id_) { - blob_off_ += plcmnt.size_; + blob_off += plcmnt.size_; continue; } - hipc::ShmRef alloc = - (*target_allocs_)[plcmnt.tid_.GetDeviceId()]; - BufferInfo info; - info.t_off_ = alloc->cur_off_.load(); - alloc->cur_off_ += plcmnt.size_; // NOTE(llogan): allocate emulation - info.t_size_ = plcmnt.size_; - info.blob_off_ = blob_off_; - info.blob_size_ = plcmnt.size_; - info.tid_ = plcmnt.tid_; - buffers.emplace_back(info); + int dev_id = plcmnt.tid_.GetDeviceId(); + hipc::ShmRef dev_info = (*mdm_->devices_)[dev_id]; + + // Get the first CPU free list pair & acquire lock + size_t free_list_start = header_->GetCpuFreeList( + plcmnt.tid_.GetIndex(), cpu); + hipc::ShmRef first_free_list_p = + (*target_allocs_)[free_list_start]; + hermes_shm::ScopedMutex(first_free_list_p->first_->lock_); + + // Get the number of each buffer size to allocate + size_t buffer_count, total_alloced_size; + std::vector coins = CoinSelect(dev_info, + plcmnt.size_, + buffer_count, + total_alloced_size); + + // Allocate buffers + buffers.resize(buffer_count); + AllocateBuffers(plcmnt, buffers, coins, + plcmnt.tid_.GetIndex(), + dev_info->slab_sizes_->size(), + free_list_start, + blob_off); borg_->LocalPlaceBlobInBuffers(blob, buffers); - mdm_->LocalUpdateTargetCapacity(info.tid_, - -static_cast(info.t_size_)); - blob_off_ += plcmnt.size_; + mdm_->LocalUpdateTargetCapacity(plcmnt.tid_, + -static_cast(total_alloced_size)); } return std::move(buffers); } +/** + * Allocate each size of buffer from either the free list or the + * device growth allocator + * */ +void BufferPool::AllocateBuffers(SubPlacement &plcmnt, + hipc::vector &buffers, + std::vector &coins, + u16 target_id, + size_t num_slabs, + size_t free_list_start, + size_t &blob_off) { + // Get this target's stack allocator + size_t target_free_list_start = header_->GetTargetFreeList( + target_id); + hipc::ShmRef target_free_list_p = + (*target_allocs_)[target_free_list_start]; + hipc::ShmRef &target_stat = target_free_list_p->first_; + + for (size_t i = 0; i < num_slabs; ++i) { + if (coins[i].count_ == 0) { continue; } + + // Get this core's free list for the page_size + hipc::ShmRef free_list_p = + (*target_allocs_)[free_list_start + i]; + hipc::ShmRef &stat = free_list_p->first_; + hipc::ShmRef &free_list = free_list_p->second_; + + // Allocate slabs + for (size_t j = 0; j < coins[i].count_; ++j) { + BpSlot slot = AllocateSlabSize(coins[i], stat, free_list, target_stat); + BufferInfo info; + info.t_off_ = slot.t_off_; + info.t_size_ = slot.t_size_; + info.blob_off_ = blob_off; + info.blob_size_ = slot.t_size_; + if (blob_off + info.blob_size_ > plcmnt.size_) { + info.blob_size_ = plcmnt.size_ - blob_off; + } + info.tid_ = plcmnt.tid_; + blob_off += info.blob_size_; + buffers.emplace_back(info); + } + } +} + +/** + * Allocate each size of buffer from either the free list or the + * device growth allocator + * */ +BpSlot BufferPool::AllocateSlabSize(BpCoin &coin, + hipc::ShmRef &stat, + hipc::ShmRef &free_list, + hipc::ShmRef &target_stat) { + BpSlot slot; + + // Case 1: Slab is cached on this core + if (free_list->size()) { + auto first = free_list->begin(); + slot = **first; + free_list->erase(first); + return slot; + } + + // Case 2: Allocate slab from stack + if (slot.IsNull()) { + slot.t_off_ = target_stat->region_off_.fetch_add(coin.slab_size_); + slot.t_size_ = coin.slab_size_; + target_stat->region_size_ -= coin.slab_size_; + return slot; + } + + // Case 3: Coalesce + // TOOD(llogan) + + // Case 4: Out of space + LOG(FATAL) << "Ran out of space in BufferPool" << std::endl; +} + + /** + * Determines a reasonable allocation of buffers based on the size of I/O. + * */ +std::vector BufferPool::CoinSelect(hipc::ShmRef &dev_info, + size_t total_size, + size_t &buffer_count, + size_t &total_alloced_size) { + std::vector coins(dev_info->slab_sizes_->size()); + size_t rem_size = total_size; + buffer_count = 0; + total_alloced_size = 0; + + while (rem_size) { + // Find the slab size nearest to the rem_size + size_t i = 0, slab_size = 0; + for (hipc::ShmRef tmp_slab_size : *dev_info->slab_sizes_) { + slab_size = *tmp_slab_size; + if (slab_size >= rem_size) { + break; + } + ++i; + } + if (i == dev_info->slab_sizes_->size()) { i -= 1; } + + // Divide rem_size into slabs + if (rem_size > slab_size) { + coins[i].count_ = rem_size / slab_size; + coins[i].slab_size_ = slab_size; + rem_size %= slab_size; + } else { + coins[i].count_ = 1; + coins[i].slab_size_ = slab_size; + rem_size = 0; + } + buffer_count += coins[i].count_; + total_alloced_size += coins[i].count_ * coins[i].slab_size_; + } + + return coins; +} + /** * Free buffers from the BufferPool - * - * TODO(llogan): actually implement * */ bool BufferPool::LocalReleaseBuffers(hipc::vector &buffers) { return true; diff --git a/src/buffer_pool.h b/src/buffer_pool.h index 5ca1bc6ea..eb08d2bc7 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -20,39 +20,84 @@ namespace hermes { class MetadataManager; class BufferOrganizer; +class BufferPool; -struct BufferPoolAllocator { - hipc::atomic max_size_; - hipc::atomic cur_off_; +struct BpCoin { + size_t count_; + size_t slab_size_; +}; + +struct BpSlot { + size_t t_off_; /**< Offset of the buffer in the target */ + size_t t_size_; /**< Size of the buffer in the target*/ - /** Default constructor */ - BufferPoolAllocator() = default; + BpSlot() : t_size_(0) {} - /** Copy Constructor */ - BufferPoolAllocator(const BufferPoolAllocator &other) - : max_size_(other.max_size_.load()), cur_off_(other.cur_off_.load()) {} + bool IsNull() { + return t_size_ == 0; + } +}; - /** Move Constructor */ - BufferPoolAllocator(BufferPoolAllocator &&other) - : max_size_(other.max_size_.load()), cur_off_(other.cur_off_.load()) {} +struct BpFreeListStat { + std::atomic region_off_; /**< Current offset in the target */ + std::atomic region_size_; /**< Current space remaining in the tgt */ + size_t page_size_; /**< The size of page in this buffer list */ + size_t cur_count_; /**< Current number of pages allocated */ + size_t max_count_; /**< Max pages allocated at one time */ + Mutex lock_; /**< The modifier lock for this slot */ }; +/** Represents the list of available buffers */ +typedef hipc::slist BpFreeList; + +/** Represents a cache of buffer size in the target */ +typedef hipc::pair BpFreeListPair; + +/** Represents the set of targets */ +typedef hipc::vector BpTargetAllocs; + /** * The shared-memory representation of the BufferPool * */ -struct BufferPoolShmHeader { - hipc::TypedPointer> alloc_ar_; +template<> +struct ShmHeader : public hipc::ShmBaseHeader { + hipc::ShmArchiveOrT free_lists_; + size_t ntargets_; + size_t ncpu_; + size_t nslabs_; + + /** Construct all internal objects */ + ShmHeader(hipc::Allocator *alloc) { + free_lists_.shm_init(alloc); + } + + /** + * Get the free list of the target + * This is where region_off_ & region_size_ in the BpFreeListStat are valid + * */ + size_t GetTargetFreeList(u16 target) { + return target * ncpu_ * nslabs_; + } + + /** + * Get the start of the vector of the free list for the CPU in the target + * This is where page_size_, cur_count_, and max_count_ are valid. + * */ + size_t GetCpuFreeList(int target, int cpu) { + return target * ncpu_ * nslabs_ + cpu * nslabs_; + } }; /** * Responsible for managing the buffering space of all node-local targets. * */ -class BufferPool { +class BufferPool : public hipc::ShmContainer { + SHM_CONTAINER_TEMPLATE((BufferPool), (BufferPool), (ShmHeader)) private: MetadataManager *mdm_; BufferOrganizer *borg_; /** Per-target allocator */ - hipc::mptr> target_allocs_; + hipc::ShmRef target_allocs_; public: BufferPool() = default; @@ -61,16 +106,27 @@ class BufferPool { * Initialize the BPM and its shared memory. * REQUIRES mdm to be initialized already. * */ - void shm_init(BufferPoolShmHeader *header); + void shm_init_main(ShmHeader *header, + hipc::Allocator *alloc); /** Destroy the BPM shared memory. */ - void shm_destroy(); + void shm_destroy_main(); /** Store the BPM in shared memory */ - void shm_serialize(BufferPoolShmHeader *header); + void shm_serialize_main() const; /** Deserialize the BPM from shared memory */ - void shm_deserialize(BufferPoolShmHeader *header); + void shm_deserialize_main(); + + /** Weak move */ + void shm_weak_move_main(ShmHeader *header, + hipc::Allocator *alloc, + BufferPool &other) {} + + /** Strong copy */ + void shm_strong_copy_main(ShmHeader *header, + hipc::Allocator *alloc, + const BufferPool &other) {} /** * Allocate buffers from the targets according to the schema @@ -79,6 +135,36 @@ class BufferPool { LocalAllocateAndSetBuffers(PlacementSchema &schema, const Blob &blob); + /** + * Determines a reasonable allocation of buffers based on the size of I/O. + * Returns the number of each page size to allocate + * */ + std::vector CoinSelect(hipc::ShmRef &dev_info, + size_t total_size, + size_t &buffer_count, + size_t &total_alloced_size); + + /** + * Allocate each size of buffer from either the free list or the + * device growth allocator + * */ + BpSlot AllocateSlabSize(BpCoin &coin, + hipc::ShmRef &stat, + hipc::ShmRef &free_list, + hipc::ShmRef &target_stat); + + /** + * Allocate each size of buffer from either the free list or the + * device growth allocator + * */ + void AllocateBuffers(SubPlacement &plcmnt, + hipc::vector &buffers, + std::vector &coins, + u16 target_id, + size_t num_slabs, + size_t free_list_start, + size_t &blob_off); + /** * Free buffers from the BufferPool * */ diff --git a/src/data_structures.h b/src/data_structures.h index cd0f3d184..a5bcf3e81 100644 --- a/src/data_structures.h +++ b/src/data_structures.h @@ -16,10 +16,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include diff --git a/src/hermes_types.h b/src/hermes_types.h index c4bfdf72e..8f6ad1305 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -62,8 +62,7 @@ typedef double f64; /**< 64-bit float */ enum class HermesType { kNone, kServer, - kClient, - kColocated + kClient }; /** The types of I/O that can be performed (for IoCall RPC) */ diff --git a/src/rpc.cc b/src/rpc.cc index 3b01f7046..43b218dec 100644 --- a/src/rpc.cc +++ b/src/rpc.cc @@ -54,9 +54,6 @@ bool RpcContext::ShouldDoLocalCall(int node_id) { case HermesType::kServer: { return node_id == node_id_; } - case HermesType::kColocated: { - return true; - } default: { LOG(FATAL) << "Invalid HermesType" << std::endl; } diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 211f2c599..559498056 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -87,9 +87,8 @@ void ThalliumRpc::Finalize() { client_engine_->finalize(); break; } - case HermesType::kColocated: { - // TODO(llogan) - break; + default: { + throw std::logic_error("Invalid Hermes initialization type"); } } } From d025c5168e626a9fae341472f29e4a7874ce7e04 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 27 Feb 2023 01:43:09 -0600 Subject: [PATCH 154/511] Add ReleaseBuffers --- src/buffer_pool.cc | 18 ++++++++++++++++++ src/buffer_pool.h | 2 ++ src/metadata_types.h | 1 + 3 files changed, 21 insertions(+) diff --git a/src/buffer_pool.cc b/src/buffer_pool.cc index 0452586ba..7f45aa8a0 100644 --- a/src/buffer_pool.cc +++ b/src/buffer_pool.cc @@ -160,6 +160,7 @@ void BufferPool::AllocateBuffers(SubPlacement &plcmnt, BufferInfo info; info.t_off_ = slot.t_off_; info.t_size_ = slot.t_size_; + info.t_slab_ = j; info.blob_off_ = blob_off; info.blob_size_ = slot.t_size_; if (blob_off + info.blob_size_ > plcmnt.size_) { @@ -250,6 +251,23 @@ std::vector BufferPool::CoinSelect(hipc::ShmRef &dev_info, * Free buffers from the BufferPool * */ bool BufferPool::LocalReleaseBuffers(hipc::vector &buffers) { + int cpu = hermes_shm::NodeThreadId().hash() % HERMES_SYSTEM_INFO->ncpu_; + + for (hipc::ShmRef info : buffers) { + // Acquire the main CPU lock for the target + size_t free_list_start = + header_->GetCpuFreeList(info->tid_.GetIndex(), cpu); + hipc::ShmRef first_free_list_p = + (*target_allocs_)[free_list_start]; + hermes_shm::ScopedMutex(first_free_list_p->first_->lock_); + + // Get this core's free list for the page_size + hipc::ShmRef free_list_p = + (*target_allocs_)[free_list_start + info->t_slab_]; + hipc::ShmRef &stat = free_list_p->first_; + hipc::ShmRef &free_list = free_list_p->second_; + free_list->emplace_front(info->t_off_, info->t_size_); + } return true; } diff --git a/src/buffer_pool.h b/src/buffer_pool.h index eb08d2bc7..0f320f08e 100644 --- a/src/buffer_pool.h +++ b/src/buffer_pool.h @@ -33,6 +33,8 @@ struct BpSlot { BpSlot() : t_size_(0) {} + BpSlot(size_t t_off, size_t t_size) : t_off_(t_off), t_size_(t_size) {} + bool IsNull() { return t_size_ == 0; } diff --git a/src/metadata_types.h b/src/metadata_types.h index cfb53bc0f..49a055f66 100644 --- a/src/metadata_types.h +++ b/src/metadata_types.h @@ -67,6 +67,7 @@ struct TargetInfo { /** Represents an allocated fraction of a target */ struct BufferInfo { TargetId tid_; /**< The destination target */ + int t_slab_; /**< The index of the slab in the target */ size_t t_off_; /**< Offset in the target */ size_t t_size_; /**< Size in the target */ size_t blob_off_; /**< Offset in the blob */ From 71bb35592844daed443d01735a36ebf9660b7fc5 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 27 Feb 2023 01:55:10 -0600 Subject: [PATCH 155/511] vbucket trait interface --- src/api/traits.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/api/traits.h b/src/api/traits.h index e5bebb489..b1b5b79c1 100644 --- a/src/api/traits.h +++ b/src/api/traits.h @@ -13,4 +13,28 @@ #ifndef HERMES_SRC_API_TRAITS_H_ #define HERMES_SRC_API_TRAITS_H_ +namespace hermes::api { + +class VBucket; + +class Trait { + public: + /** Called when AttachTrait is called on VBucket */ + virtual void Attach(VBucket *vbkt) = 0; + + /** Called when DetachTrait is called on VBucket */ + virtual void Detach(VBucket *vbkt) = 0; + + /** Called when a Link is called on VBucket*/ + virtual void OnLink(VBucket *vbkt) = 0; + + /** Called when Unlink is called on VBucket*/ + virtual void OnUnlink(VBucket *vbkt) = 0; + + /** Called when GetLinks is called on VBucket */ + virtual void OnGet(VBucket *vbkt) = 0; +}; + +} // namespace hermes::api + #endif // HERMES_SRC_API_TRAITS_H_ From 1f2ac37974bb064317f0244eb39fc0dca079d126 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 27 Feb 2023 02:22:12 -0600 Subject: [PATCH 156/511] BPM doesn't segfault --- config/hermes_server_default.yaml | 8 ++++---- src/api/hermes.cc | 1 + src/config_server.cc | 9 +++++++-- src/config_server_default.h | 8 ++++---- src/rpc.cc | 3 ++- src/rpc.h | 1 + src/rpc_thallium.cc | 2 +- 7 files changed, 20 insertions(+), 12 deletions(-) diff --git a/config/hermes_server_default.yaml b/config/hermes_server_default.yaml index 91b964968..789bce4ce 100644 --- a/config/hermes_server_default.yaml +++ b/config/hermes_server_default.yaml @@ -22,7 +22,7 @@ devices: # The number of blocks (the size of which is chosen in block_sizes_kb) that each # device should contain for each slab (controlled by num_slabs). This allows for # precise control of the distibution of buffer sizes. - slab_units: [1, 4, 16, 32] + slab_sizes: [ 4KB, 16KB, 64KB, 1MB ] # The maximum theoretical bandwidth (as advertised by the manufacturer) in # Possible units: KBps, MBps, GBps @@ -51,7 +51,7 @@ devices: mount_point: "./" capacity: 50MB block_size: 4KB - slab_units: [ 1, 4, 16, 32 ] + slab_sizes: [ 4KB, 16KB, 64KB, 1MB ] bandwidth: 1GBps latency: 600us is_shared_device: false @@ -61,7 +61,7 @@ devices: mount_point: "./" capacity: 50MB block_size: 4KB - slab_units: [ 1, 4, 16, 32 ] + slab_sizes: [ 4KB, 16KB, 64KB, 1MB ] bandwidth: 500MBps latency: 1200us is_shared_device: false @@ -71,7 +71,7 @@ devices: mount_point: "./" capacity: inf block_size: 64KB # The stripe size of PFS - slab_units: [ 1, 4, 16, 32 ] + slab_sizes: [ 4KB, 16KB, 64KB, 1MB ] bandwidth: 100MBps # Per-device bandwidth latency: 200ms is_shared_device: true diff --git a/src/api/hermes.cc b/src/api/hermes.cc index 69f562c16..1cb15d2b8 100644 --- a/src/api/hermes.cc +++ b/src/api/hermes.cc @@ -69,6 +69,7 @@ void Hermes::StopDaemon() { void Hermes::InitServer(std::string server_config_path) { LoadServerConfig(server_config_path); InitSharedMemory(); + comm_.Init(HermesType::kServer); rpc_.InitServer(); rpc_.InitClient(); mdm_.shm_init(&server_config_, &header_->mdm_); diff --git a/src/config_server.cc b/src/config_server.cc index a19fcf132..18082b4c5 100644 --- a/src/config_server.cc +++ b/src/config_server.cc @@ -51,8 +51,13 @@ void ServerConfig::ParseDeviceInfo(YAML::Node yaml_conf) { ParseSize(dev_info["bandwidth"].as()); dev.header_->latency_ = ParseLatency(dev_info["latency"].as()); - ParseVector>( - dev_info["slab_sizes"], *dev.slab_sizes_); + std::vector size_vec; + ParseVector>( + dev_info["slab_sizes"], size_vec); + dev.slab_sizes_->reserve(size_vec.size()); + for (const std::string &size_str : size_vec) { + dev.slab_sizes_->emplace_back(ParseSize(size_str)); + } devices_.emplace_back(std::move(dev)); } } diff --git a/src/config_server_default.h b/src/config_server_default.h index d19b4a203..927e3a006 100644 --- a/src/config_server_default.h +++ b/src/config_server_default.h @@ -25,7 +25,7 @@ const char* kServerDefaultConfigStr = " # The number of blocks (the size of which is chosen in block_sizes_kb) that each\n" " # device should contain for each slab (controlled by num_slabs). This allows for\n" " # precise control of the distibution of buffer sizes.\n" -" slab_units: [1, 4, 16, 32]\n" +" slab_sizes: [ 4KB, 16KB, 64KB, 1MB ]\n" "\n" " # The maximum theoretical bandwidth (as advertised by the manufacturer) in\n" " # Possible units: KBps, MBps, GBps\n" @@ -54,7 +54,7 @@ const char* kServerDefaultConfigStr = " mount_point: \"./\"\n" " capacity: 50MB\n" " block_size: 4KB\n" -" slab_units: [ 1, 4, 16, 32 ]\n" +" slab_sizes: [ 4KB, 16KB, 64KB, 1MB ]\n" " bandwidth: 1GBps\n" " latency: 600us\n" " is_shared_device: false\n" @@ -64,7 +64,7 @@ const char* kServerDefaultConfigStr = " mount_point: \"./\"\n" " capacity: 50MB\n" " block_size: 4KB\n" -" slab_units: [ 1, 4, 16, 32 ]\n" +" slab_sizes: [ 4KB, 16KB, 64KB, 1MB ]\n" " bandwidth: 500MBps\n" " latency: 1200us\n" " is_shared_device: false\n" @@ -74,7 +74,7 @@ const char* kServerDefaultConfigStr = " mount_point: \"./\"\n" " capacity: inf\n" " block_size: 64KB # The stripe size of PFS\n" -" slab_units: [ 1, 4, 16, 32 ]\n" +" slab_sizes: [ 4KB, 16KB, 64KB, 1MB ]\n" " bandwidth: 100MBps # Per-device bandwidth\n" " latency: 200ms\n" " is_shared_device: true\n" diff --git a/src/rpc.cc b/src/rpc.cc index 43b218dec..68cea38b3 100644 --- a/src/rpc.cc +++ b/src/rpc.cc @@ -20,6 +20,7 @@ void RpcContext::InitRpcContext() { comm_ = &HERMES->comm_; config_ = &HERMES->server_config_; port_ = config_->rpc_.port_; + mode_ = HERMES->mode_; if (hosts_.size()) { return; } auto &hosts = config_->rpc_.host_names_; // Load hosts from hostfile @@ -47,7 +48,7 @@ void RpcContext::InitRpcContext() { /** Check if we should skip an RPC and call a function locally */ bool RpcContext::ShouldDoLocalCall(int node_id) { - switch (comm_->type_) { + switch (mode_) { case HermesType::kClient: { return false; } diff --git a/src/rpc.h b/src/rpc.h index f49da7e5c..efd886647 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -61,6 +61,7 @@ class RpcContext { int port_; /**< port number */ int node_id_; /**< the ID of this node*/ std::vector hosts_; /**< Hostname and ip addr per-node */ + HermesType mode_; /**< The current mode hermes is executing in */ public: RpcContext() = default; diff --git a/src/rpc_thallium.cc b/src/rpc_thallium.cc index 559498056..b3a277f44 100644 --- a/src/rpc_thallium.cc +++ b/src/rpc_thallium.cc @@ -77,7 +77,7 @@ std::string ThalliumRpc::GetServerName(u32 node_id) { /** finalize RPC context */ void ThalliumRpc::Finalize() { - switch (comm_->type_) { + switch (mode_) { case HermesType::kServer: { comm_->WorldBarrier(); this->kill_requested_.store(true); From 56f82980551cddcc85f3debff9921e6f16fe3b87 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 27 Feb 2023 04:53:31 -0600 Subject: [PATCH 157/511] Add back explicit path exclusion to tests. Add backend status to Partials. --- CMakeLists.txt | 1 + adapter/filesystem/filesystem.cc | 34 +++++++----- adapter/mpiio/CMakeLists.txt | 4 +- adapter/posix/CMakeLists.txt | 3 ++ adapter/posix/posix_api.cc | 5 ++ adapter/posix/posix_api.h | 8 +++ adapter/stdio/CMakeLists.txt | 4 +- adapter/test/mpiio/mpiio_adapter_test.cpp | 8 +-- adapter/test/posix/CMakeLists.txt | 1 + adapter/test/posix/posix_adapter_mpi_test.cpp | 17 +++--- adapter/test/posix/posix_adapter_test.cpp | 11 ++-- .../stdio_adapter_low_buffer_space_test.cpp | 9 ++-- .../test/stdio/stdio_adapter_mode_test.cpp | 8 +-- adapter/test/stdio/stdio_adapter_mpi_test.cpp | 11 ++-- adapter/test/stdio/stdio_adapter_test.cpp | 9 ++-- hermes_shm/CMakeLists.txt | 54 ++++++++++--------- src/api/bucket.cc | 15 +++++- src/hermes_types.h | 1 - src/metadata_manager.h | 1 + src/statuses.h | 4 +- 20 files changed, 128 insertions(+), 80 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d824d257a..6e880ccd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ if(NOT DEFINED CMAKE_MACOSX_RPATH) endif() project(HERMES) +set(IS_HERMES_MAIN ON) #------------------------------------------------------------------------------ # Compiler optimization diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 59439215a..52f53bb01 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -87,12 +87,16 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, opts.adapter_mode_ = stat.adapter_mode_; bkt->TryCreateBlob(blob_name.str(), blob_id, ctx, opts); bkt->LockBlob(blob_id, MdLockType::kExternalWrite); - bkt->PartialPutOrCreate(blob_name.str(), - blob_wrap, - p.blob_off_, - blob_id, - opts, - ctx); + auto status = bkt->PartialPutOrCreate(blob_name.str(), + blob_wrap, + p.blob_off_, + blob_id, + opts, + ctx); + if (status.Fail()) { + data_offset = 0; + break; + } bkt->UnlockBlob(blob_id, MdLockType::kExternalWrite); data_offset += p.blob_size_; } @@ -130,13 +134,17 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, opts.adapter_mode_ = stat.adapter_mode_; bkt->TryCreateBlob(blob_name.str(), blob_id, ctx, opts); bkt->LockBlob(blob_id, MdLockType::kExternalRead); - bkt->PartialGetOrCreate(blob_name.str(), - blob_wrap, - p.blob_off_, - p.blob_size_, - blob_id, - opts, - ctx); + auto status = bkt->PartialGetOrCreate(blob_name.str(), + blob_wrap, + p.blob_off_, + p.blob_size_, + blob_id, + opts, + ctx); + if (status.Fail()) { + data_offset = 0; + break; + } bkt->UnlockBlob(blob_id, MdLockType::kExternalRead); data_offset += p.blob_size_; } diff --git a/adapter/mpiio/CMakeLists.txt b/adapter/mpiio/CMakeLists.txt index 425680dbe..0c4aa97bf 100644 --- a/adapter/mpiio/CMakeLists.txt +++ b/adapter/mpiio/CMakeLists.txt @@ -10,8 +10,10 @@ add_library(hermes_mpiio_io_client ${CMAKE_CURRENT_SOURCE_DIR}/mpiio_api_singleton.cc ${CMAKE_CURRENT_SOURCE_DIR}/mpiio_io_client.cc) target_compile_options(hermes_mpiio_io_client PUBLIC -fPIC) +add_dependencies(hermes_mpiio_io_client + hermes_shm_data_structures) target_link_libraries(hermes_mpiio_io_client - MPI::MPI_CXX glog::glog stdc++fs dl) + hermes_shm_data_structures MPI::MPI_CXX glog::glog stdc++fs dl) # Create the MPIIO interceptor set(INTERCEPTOR_DEPS diff --git a/adapter/posix/CMakeLists.txt b/adapter/posix/CMakeLists.txt index 38bcfefea..b094ff936 100644 --- a/adapter/posix/CMakeLists.txt +++ b/adapter/posix/CMakeLists.txt @@ -9,7 +9,10 @@ add_library(hermes_posix_io_client ${CMAKE_CURRENT_SOURCE_DIR}/posix_api_singleton.cc ${CMAKE_CURRENT_SOURCE_DIR}/posix_io_client.cc) target_compile_options(hermes_posix_io_client PUBLIC -fPIC) +add_dependencies(hermes_posix_io_client + hermes_shm_data_structures) target_link_libraries(hermes_posix_io_client + hermes_shm_data_structures MPI::MPI_CXX glog::glog stdc++fs dl) # Create the POSIX interceptor diff --git a/adapter/posix/posix_api.cc b/adapter/posix/posix_api.cc index df1427a5f..4ef81b297 100644 --- a/adapter/posix/posix_api.cc +++ b/adapter/posix/posix_api.cc @@ -37,6 +37,11 @@ namespace stdfs = std::filesystem; extern "C" { +/*static __attribute__((constructor(0))) void init_posix(void) { + auto real_api = HERMES_POSIX_API; + auto fs_api = HERMES_POSIX_FS; +}*/ + /** * POSIX */ diff --git a/adapter/posix/posix_api.h b/adapter/posix/posix_api.h index 568c8ad63..ab354c0bd 100644 --- a/adapter/posix/posix_api.h +++ b/adapter/posix/posix_api.h @@ -21,6 +21,14 @@ #include #include +#ifndef O_TMPFILE +#define O_TMPFILE 0 +#endif + +#ifndef _STAT_VER +#define _STAT_VER 0 +#endif + #define REQUIRE_API(api_name) \ if (api_name == nullptr) { \ LOG(FATAL) << "HERMES Adapter failed to map symbol: " \ diff --git a/adapter/stdio/CMakeLists.txt b/adapter/stdio/CMakeLists.txt index f006048e5..d9d0b9bf1 100644 --- a/adapter/stdio/CMakeLists.txt +++ b/adapter/stdio/CMakeLists.txt @@ -10,8 +10,10 @@ add_library(hermes_stdio_io_client ${CMAKE_CURRENT_SOURCE_DIR}/stdio_api_singleton.cc ${CMAKE_CURRENT_SOURCE_DIR}/stdio_io_client.cc) target_compile_options(hermes_stdio_io_client PUBLIC -fPIC) +add_dependencies(hermes_stdio_io_client + hermes_shm_data_structures) target_link_libraries(hermes_stdio_io_client - MPI::MPI_CXX glog::glog stdc++fs dl) + hermes_shm_data_structures MPI::MPI_CXX glog::glog stdc++fs dl) # Create the STDIO interceptor set(INTERCEPTOR_DEPS diff --git a/adapter/test/mpiio/mpiio_adapter_test.cpp b/adapter/test/mpiio/mpiio_adapter_test.cpp index 80ea998b1..2487cb913 100644 --- a/adapter/test/mpiio/mpiio_adapter_test.cpp +++ b/adapter/test/mpiio/mpiio_adapter_test.cpp @@ -151,8 +151,8 @@ int pretest() { MPI_Barrier(MPI_COMM_WORLD); REQUIRE(info.total_size > 0); #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file_cmp, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file_cmp, false); // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.shared_new_file_cmp); // INTERCEPTOR_LIST->hermes_flush_exclusion.insert( // info.shared_existing_file_cmp); @@ -162,8 +162,8 @@ int pretest() { int posttest(bool compare_data = true) { #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file, false); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { diff --git a/adapter/test/posix/CMakeLists.txt b/adapter/test/posix/CMakeLists.txt index a223dcbb1..65c451ec9 100644 --- a/adapter/test/posix/CMakeLists.txt +++ b/adapter/test/posix/CMakeLists.txt @@ -24,6 +24,7 @@ mpi_daemon(hermes_posix_adapter_mpi_test 2 "[request_size=range-large]" "large" include_directories(${CMAKE_SOURCE_DIR}/adapter) add_executable(posix_simple_io simple_io.cc) +add_dependencies(posix_simple_io hermes_posix) target_link_libraries(posix_simple_io hermes_posix) set(POSIX_TESTS diff --git a/adapter/test/posix/posix_adapter_mpi_test.cpp b/adapter/test/posix/posix_adapter_mpi_test.cpp index 769189b65..3d27f0585 100644 --- a/adapter/test/posix/posix_adapter_mpi_test.cpp +++ b/adapter/test/posix/posix_adapter_mpi_test.cpp @@ -19,14 +19,11 @@ #include "catch_config.h" -#ifndef O_TMPFILE -#define O_TMPFILE 0 -#endif - #include "adapter_test_utils.h" #if HERMES_INTERCEPT == 1 #include "posix/posix_api.h" +#include "posix/posix_fs_api.h" #endif namespace stdfs = std::filesystem; @@ -192,9 +189,9 @@ int pretest() { MPI_Barrier(MPI_COMM_WORLD); // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_shared_file_cmp); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file_cmp, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file_cmp, false); + HERMES->client_config_.SetAdapterPathTracking(info.existing_shared_file_cmp, false); #endif return 0; } @@ -202,9 +199,9 @@ int pretest() { int posttest(bool compare_data = true) { // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_shared_file); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file, false); + HERMES->client_config_.SetAdapterPathTracking(info.existing_shared_file, false); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { diff --git a/adapter/test/posix/posix_adapter_test.cpp b/adapter/test/posix/posix_adapter_test.cpp index 0f705a53f..b6768a6f8 100644 --- a/adapter/test/posix/posix_adapter_test.cpp +++ b/adapter/test/posix/posix_adapter_test.cpp @@ -20,6 +20,7 @@ #include "catch_config.h" #if HERMES_INTERCEPT == 1 #include "posix/posix_api.h" +#include "posix/posix_fs_api.h" #endif #ifndef O_TMPFILE @@ -118,19 +119,17 @@ int pretest() { args.request_size * info.num_iterations); } REQUIRE(info.total_size > 0); - // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file_cmp, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file_cmp, false); #endif return 0; } int posttest(bool compare_data = true) { - // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file_cmp, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file_cmp, false); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { diff --git a/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp b/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp index fa6100d1a..9b04c408c 100644 --- a/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp +++ b/adapter/test/stdio/stdio_adapter_low_buffer_space_test.cpp @@ -21,6 +21,7 @@ #include "catch_config.h" #if HERMES_INTERCEPT == 1 #include "stdio/stdio_api.h" +#include "stdio/stdio_fs_api.h" #endif namespace stdfs = std::filesystem; @@ -99,16 +100,16 @@ int pretest() { } REQUIRE(info.total_size > 0); #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file_cmp, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file_cmp, false); #endif return 0; } int posttest(bool compare_data = true) { #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file, false); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { diff --git a/adapter/test/stdio/stdio_adapter_mode_test.cpp b/adapter/test/stdio/stdio_adapter_mode_test.cpp index 607e2f335..41294e813 100644 --- a/adapter/test/stdio/stdio_adapter_mode_test.cpp +++ b/adapter/test/stdio/stdio_adapter_mode_test.cpp @@ -107,16 +107,16 @@ int pretest() { } REQUIRE(info.total_size > 0); #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file_cmp, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file_cmp, false); #endif return 0; } int posttest(bool compare_data = true) { #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file, false); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { diff --git a/adapter/test/stdio/stdio_adapter_mpi_test.cpp b/adapter/test/stdio/stdio_adapter_mpi_test.cpp index e0b5336ef..d5741d2b3 100644 --- a/adapter/test/stdio/stdio_adapter_mpi_test.cpp +++ b/adapter/test/stdio/stdio_adapter_mpi_test.cpp @@ -20,6 +20,7 @@ #include #if HERMES_INTERCEPT == 1 #include "stdio/stdio_api.h" +#include "stdio/stdio_fs_api.h" #endif namespace stdfs = std::filesystem; @@ -207,8 +208,8 @@ int pretest() { REQUIRE(info.total_size > 0); MPI_Barrier(MPI_COMM_WORLD); #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file_cmp, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file_cmp, false); // INTERCEPTOR_LIST->hermes_flush_exclusion.insert( // info.existing_shared_file_cmp); #endif @@ -217,9 +218,9 @@ int pretest() { int posttest(bool compare_data = true) { #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_shared_file); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file, false); + HERMES->client_config_.SetAdapterPathTracking(info.existing_shared_file, false); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { diff --git a/adapter/test/stdio/stdio_adapter_test.cpp b/adapter/test/stdio/stdio_adapter_test.cpp index a2d8ba45e..ced1281d3 100644 --- a/adapter/test/stdio/stdio_adapter_test.cpp +++ b/adapter/test/stdio/stdio_adapter_test.cpp @@ -21,6 +21,7 @@ #include "catch_config.h" #if HERMES_INTERCEPT == 1 #include "stdio/stdio_api.h" +#include "stdio/stdio_fs_api.h" #endif #include "adapter_test_utils.h" @@ -104,8 +105,8 @@ int pretest() { REQUIRE(info.total_size > 0); // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file_cmp); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file_cmp); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file_cmp, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file_cmp, false); #endif return 0; } @@ -113,8 +114,8 @@ int pretest() { int posttest(bool compare_data = true) { // NOTE(llogan): Are flush exclusions really necessary? #if HERMES_INTERCEPT == 1 - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.existing_file); - // INTERCEPTOR_LIST->hermes_flush_exclusion.insert(info.new_file); + HERMES->client_config_.SetAdapterPathTracking(info.existing_file, false); + HERMES->client_config_.SetAdapterPathTracking(info.new_file, false); #endif if (compare_data && stdfs::exists(info.new_file) && stdfs::exists(info.new_file_cmp)) { diff --git a/hermes_shm/CMakeLists.txt b/hermes_shm/CMakeLists.txt index 13b15871a..bd7f874d0 100644 --- a/hermes_shm/CMakeLists.txt +++ b/hermes_shm/CMakeLists.txt @@ -92,34 +92,38 @@ if(BUILD_Boost_TESTS) endif() ##################CODE COVERAGE -if(HERMES_ENABLE_COVERAGE) - set(COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage" CACHE STRING - "Flags to the coverage program to perform coverage inspection") - mark_as_advanced(COVERAGE_FLAGS) - - macro(set_coverage_flags target) - set_target_properties(${target} - PROPERTIES - COMPILE_FLAGS ${COVERAGE_FLAGS} - LINK_FLAGS ${COVERAGE_FLAGS} - ) - endmacro() +if (NOT IS_HERMES_MAIN) + if(HERMES_ENABLE_COVERAGE) + set(COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage" CACHE STRING + "Flags to the coverage program to perform coverage inspection") + mark_as_advanced(COVERAGE_FLAGS) + + macro(set_coverage_flags target) + set_target_properties(${target} + PROPERTIES + COMPILE_FLAGS ${COVERAGE_FLAGS} + LINK_FLAGS ${COVERAGE_FLAGS} + ) + endmacro() + endif() endif() ##################DOCUMENTATION -if(HERMES_ENABLE_DOXYGEN) - include(UseDoxygenDoc) - - add_doxygen_doc( - BUILD_DIR - ${CMAKE_CURRENT_BINARY_DIR}/_build - DOXY_FILE - ${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in - TARGET_NAME - dox - COMMENT - "HTML documentation" - ) +if (NOT IS_HERMES_MAIN) + if(HERMES_ENABLE_DOXYGEN) + include(UseDoxygenDoc) + + add_doxygen_doc( + BUILD_DIR + ${CMAKE_CURRENT_BINARY_DIR}/_build + DOXY_FILE + ${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in + TARGET_NAME + dox + COMMENT + "HTML documentation" + ) + endif() endif() ##################Build hermes main packages diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 6773f23f9..ca982bfec 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -203,6 +203,12 @@ Status Bucket::PartialPutOrCreate(const std::string &blob_name, if (io_client) { io_client->ReadBlob(hipc::charbuf(name_), full_blob, opts, status); + if (status.size_ != opts.backend_size_) { + LOG(INFO) << "Failed to read blob of size " + << opts.backend_size_ + << "from backend (PartialPut)"; + return PARTIAL_PUT_OR_CREATE_OVERFLOW; + } } } // Ensure the blob can hold the update @@ -232,6 +238,7 @@ Status Bucket::Get(BlobId blob_id, Blob &blob, Context &ctx) { * @param blob_name the semantic name of the blob * @param blob the buffer to put final data in * @param blob_off the offset within the blob to begin the Put + * @param blob_size the total amount of data to read * @param blob_id [out] the blob id corresponding to blob_name * @param io_ctx information required to perform I/O to the backend * @param opts specific configuration of the I/O to perform @@ -252,7 +259,7 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, Get(blob_id, full_blob, ctx); } if (full_blob.size() != opts.backend_size_) { - // Case 2: The blob did not exist (need to read from backend) + // Case 2: The blob did not exist (or at least not fully) // Read blob using adapter LOG(INFO) << "Blob did not exist. Reading blob from backend." << std::endl; IoStatus status; @@ -260,6 +267,12 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, full_blob.resize(opts.backend_size_); if (io_client) { io_client->ReadBlob(hipc::charbuf(name_), full_blob, opts, status); + if (status.size_ != opts.backend_size_) { + LOG(INFO) << "Failed to read blob of size " + << opts.backend_size_ + << "from backend (PartialCreate)"; + return PARTIAL_GET_OR_CREATE_OVERFLOW; + } if (opts.adapter_mode_ != AdapterMode::kBypass) { Put(blob_name, full_blob, blob_id, ctx); } diff --git a/src/hermes_types.h b/src/hermes_types.h index 8f6ad1305..090c4b581 100644 --- a/src/hermes_types.h +++ b/src/hermes_types.h @@ -23,7 +23,6 @@ #include "data_structures.h" #include "constants.h" -#include "statuses.h" /** * \file hermes_types.h diff --git a/src/metadata_manager.h b/src/metadata_manager.h index ee5e27631..e7928e947 100644 --- a/src/metadata_manager.h +++ b/src/metadata_manager.h @@ -18,6 +18,7 @@ #include "status.h" #include "rpc.h" #include "metadata_types.h" +#include "statuses.h" #include "rpc_thallium_serialization.h" #include "adapter/io_client/io_client_factory.h" diff --git a/src/statuses.h b/src/statuses.h index ebcd90835..9f0016e80 100644 --- a/src/statuses.h +++ b/src/statuses.h @@ -27,7 +27,9 @@ const Status DPE_MIN_IO_TIME_NO_SOLUTION( const Status BUFFER_POOL_OUT_OF_RAM( "Could not allocate the ram tier of storage in BPM"); const Status PARTIAL_GET_OR_CREATE_OVERFLOW( - "The read exceeds the size of the backend's data"); + "The read exceeds the size of the backend's data (PartialGet)"); +const Status PARTIAL_PUT_OR_CREATE_OVERFLOW( + "The read exceeds the size of the backend's data (PartialPut)"); } // namespace hermes From 95587830d258ce243e1582b646d0831addeb7e50 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 27 Feb 2023 06:00:53 -0600 Subject: [PATCH 158/511] Strong boundary checking for file end in base class --- adapter/filesystem/filesystem.cc | 36 +++++++++++++++++++++++++++----- adapter/io_client/io_client.h | 14 +++++++++++-- adapter/mpiio/mpiio_io_client.cc | 8 +++++++ adapter/posix/posix_io_client.cc | 10 +++++++++ adapter/stdio/stdio_io_client.cc | 10 +++++++++ src/api/bucket.cc | 12 +++++------ src/api/bucket.h | 2 ++ 7 files changed, 79 insertions(+), 13 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 52f53bb01..7cda53f95 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -45,20 +45,38 @@ void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { if (!exists) { LOG(INFO) << "File not opened before by adapter" << std::endl; // Create the new bucket - FsIoOptions opts; - opts.type_ = type_; stat.bkt_id_ = HERMES->GetBucket(path, ctx, opts); + stat.backend_size_ = stat.bkt_id_->GetSize(IoClientContext(type_)); // Allocate internal hermes data auto stat_ptr = std::make_shared(stat); FilesystemIoClientObject fs_ctx(&mdm->fs_mdm_, (void*)stat_ptr.get()); io_client_->HermesOpen(f, stat, fs_ctx); mdm->Create(f, stat_ptr); } else { - LOG(INFO) << "File opened by adapter" << std::endl; + LOG(INFO) << "File already opened by adapter" << std::endl; exists->UpdateTime(); } } +/** + * The amount of data to read from the backend if the blob + * does not exist. + * */ +static inline size_t GetBackendSize(size_t file_off, + size_t file_size, + size_t page_size) { + if (file_off + page_size <= file_size) { + // Case 1: The file has more than "PageSize" bytes remaining + return page_size; + } else if(file_off < file_size) { + // Case 2: The file has less than "PageSize" bytes remaining + return file_size - file_off; + } else { + // Case 3: The offset is beyond the size of the backend file + return 0; + } +} + size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, IoStatus &io_status, FsIoOptions opts) { @@ -81,9 +99,12 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, const Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); hipc::charbuf blob_name(p.CreateBlobName(kPageSize)); BlobId blob_id; + size_t file_off = off + data_offset; opts.type_ = type_; opts.backend_off_ = p.page_ * kPageSize; - opts.backend_size_ = kPageSize; + opts.backend_size_ = GetBackendSize(file_off, + stat.backend_size_, + kPageSize); opts.adapter_mode_ = stat.adapter_mode_; bkt->TryCreateBlob(blob_name.str(), blob_id, ctx, opts); bkt->LockBlob(blob_id, MdLockType::kExternalWrite); @@ -91,6 +112,7 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, blob_wrap, p.blob_off_, blob_id, + io_status, opts, ctx); if (status.Fail()) { @@ -128,8 +150,11 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); hipc::charbuf blob_name(p.CreateBlobName(kPageSize)); BlobId blob_id; + size_t file_off = off + data_offset; opts.backend_off_ = p.page_ * kPageSize; - opts.backend_size_ = kPageSize; + opts.backend_size_ = GetBackendSize(file_off, + stat.backend_size_, + kPageSize); ; opts.type_ = type_; opts.adapter_mode_ = stat.adapter_mode_; bkt->TryCreateBlob(blob_name.str(), blob_id, ctx, opts); @@ -139,6 +164,7 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, p.blob_off_, p.blob_size_, blob_id, + io_status, opts, ctx); if (status.Fail()) { diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index e401dd673..78975e677 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -72,6 +72,15 @@ struct IoClientContext { mpi_count_(0), backend_off_(0), backend_size_(0) {} + + /** Contains only the AdapterType */ + IoClientContext(AdapterType type) : type_(type), + dpe_(hapi::PlacementPolicy::kNone), + flags_(), + mpi_type_(MPI_CHAR), + mpi_count_(0), + backend_off_(0), + backend_size_(0) {} }; /** Any relevant statistics from the I/O client */ @@ -79,7 +88,6 @@ struct IoClientStats { int flags_; /**< open() flags for POSIX */ mode_t st_mode_; /**< protection */ size_t backend_size_; /**< size of the object in the backend */ - size_t bkt_size_; /**< size of the object in Hermes */ uid_t st_uid_; /**< user ID of owner */ gid_t st_gid_; /**< group ID of owner */ off64_t st_ptr_; /**< current ptr of FILE */ @@ -131,11 +139,13 @@ struct IoStatus { int mpi_ret_; /**< MPI return value */ MPI_Status mpi_status_; /**< MPI status */ MPI_Status *mpi_status_ptr_; /**< MPI status pointer */ + bool success_; /**< Whether the I/O succeeded */ /** Default constructor */ IoStatus() : size_(0), mpi_ret_(MPI_SUCCESS), - mpi_status_ptr_(&mpi_status_) {} + mpi_status_ptr_(&mpi_status_), + success_(true) {} }; /** A structure to represent Hermes request */ diff --git a/adapter/mpiio/mpiio_io_client.cc b/adapter/mpiio/mpiio_io_client.cc index a41681e41..a9a9ee89b 100644 --- a/adapter/mpiio/mpiio_io_client.cc +++ b/adapter/mpiio/mpiio_io_client.cc @@ -88,6 +88,7 @@ void MpiioIoClient::WriteBlob(const hipc::charbuf &bkt_name, const IoClientContext &opts, IoStatus &status) { std::string filename = bkt_name.str(); + status.success_ = true; LOG(INFO) << "Write called for filename to destination: " << filename << " on offset: " << opts.backend_off_ << " and size: " << full_blob.size() << "." @@ -99,12 +100,14 @@ void MpiioIoClient::WriteBlob(const hipc::charbuf &bkt_name, MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); if (status.mpi_ret_ != MPI_SUCCESS) { + status.success_ = false; return; } status.mpi_ret_ = real_api->MPI_File_seek(fh, opts.backend_off_, MPI_SEEK_SET); if (status.mpi_ret_ != MPI_SUCCESS) { + status.success_ = false; goto ERROR; } status.mpi_ret_ = real_api->MPI_File_write(fh, @@ -115,6 +118,7 @@ void MpiioIoClient::WriteBlob(const hipc::charbuf &bkt_name, MPI_Get_count(status.mpi_status_ptr_, opts.mpi_type_, &write_count); if (write_count != opts.mpi_count_) { + status.success_ = false; LOG(ERROR) << "writing failed: wrote " << write_count << " / " << opts.mpi_count_ << "." << std::endl; @@ -132,6 +136,7 @@ void MpiioIoClient::ReadBlob(const hipc::charbuf &bkt_name, const IoClientContext &opts, IoStatus &status) { std::string filename = bkt_name.str(); + status.success_ = true; LOG(INFO) << "Reading from: " << filename << " on offset: " << opts.backend_off_ << " and size: " << full_blob.size() << "." @@ -143,12 +148,14 @@ void MpiioIoClient::ReadBlob(const hipc::charbuf &bkt_name, MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); if (status.mpi_ret_ != MPI_SUCCESS) { + status.success_ = false; return; } status.mpi_ret_ = real_api->MPI_File_seek(fh, opts.backend_off_, MPI_SEEK_SET); if (status.mpi_ret_ != MPI_SUCCESS) { + status.success_ = false; goto ERROR; } status.mpi_ret_ = real_api->MPI_File_read(fh, @@ -159,6 +166,7 @@ void MpiioIoClient::ReadBlob(const hipc::charbuf &bkt_name, MPI_Get_count(status.mpi_status_ptr_, opts.mpi_type_, &read_count); if (read_count != opts.mpi_count_) { + status.success_ = false; LOG(ERROR) << "reading failed: read " << read_count << " / " << opts.mpi_count_ << "." << std::endl; diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 5dcad0e5d..0ae58de4d 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -87,6 +87,7 @@ void PosixIoClient::WriteBlob(const hipc::charbuf &bkt_name, const IoClientContext &opts, IoStatus &status) { (void) opts; + status.success_ = true; LOG(INFO) << "Writing to file: " << bkt_name.str() << " offset: " << opts.backend_off_ << " size:" << full_blob.size() << "." @@ -95,12 +96,16 @@ void PosixIoClient::WriteBlob(const hipc::charbuf &bkt_name, int fd = real_api->open(bkt_name.str().c_str(), O_RDWR | O_CREAT); if (fd < 0) { status.size_ = 0; + status.success_ = false; return; } status.size_ = real_api->pwrite(fd, full_blob.data(), full_blob.size(), opts.backend_off_); + if (status.size_ != full_blob.size()) { + status.success_ = false; + } real_api->close(fd); } @@ -110,6 +115,7 @@ void PosixIoClient::ReadBlob(const hipc::charbuf &bkt_name, const IoClientContext &opts, IoStatus &status) { (void) opts; + status.success_ = true; LOG(INFO) << "Reading from file: " << bkt_name.str() << " offset: " << opts.backend_off_ << " size:" << full_blob.size() << "." @@ -118,12 +124,16 @@ void PosixIoClient::ReadBlob(const hipc::charbuf &bkt_name, int fd = real_api->open(bkt_name.str().c_str(), O_RDONLY); if (fd < 0) { status.size_ = 0; + status.success_ = false; return; } status.size_ = real_api->pread(fd, full_blob.data(), full_blob.size(), opts.backend_off_); + if (status.size_ != full_blob.size()) { + status.success_ = false; + } real_api->close(fd); } diff --git a/adapter/stdio/stdio_io_client.cc b/adapter/stdio/stdio_io_client.cc index ef3c973d3..3d4f88360 100644 --- a/adapter/stdio/stdio_io_client.cc +++ b/adapter/stdio/stdio_io_client.cc @@ -75,6 +75,7 @@ void StdioIoClient::WriteBlob(const hipc::charbuf &bkt_name, const Blob &full_blob, const IoClientContext &opts, IoStatus &status) { + status.success_ = true; std::string filename = bkt_name.str(); LOG(INFO) << "Writing to file: " << filename << " offset: " << opts.backend_off_ @@ -83,6 +84,7 @@ void StdioIoClient::WriteBlob(const hipc::charbuf &bkt_name, FILE *fh = real_api->fopen(filename.c_str(), "r+"); if (fh == nullptr) { status.size_ = 0; + status.success_ = false; return; } real_api->fseek(fh, opts.backend_off_, SEEK_SET); @@ -90,6 +92,9 @@ void StdioIoClient::WriteBlob(const hipc::charbuf &bkt_name, sizeof(char), full_blob.size(), fh); + if (status.size_ != full_blob.size()) { + status.success_ = false; + } real_api->fclose(fh); } @@ -98,6 +103,7 @@ void StdioIoClient::ReadBlob(const hipc::charbuf &bkt_name, Blob &full_blob, const IoClientContext &opts, IoStatus &status) { + status.success_ = true; std::string filename = bkt_name.str(); LOG(INFO) << "Reading from file: " << filename << " on offset: " << opts.backend_off_ @@ -106,6 +112,7 @@ void StdioIoClient::ReadBlob(const hipc::charbuf &bkt_name, FILE *fh = real_api->fopen(filename.c_str(), "r"); if (fh == nullptr) { status.size_ = 0; + status.success_ = false; return; } real_api->fseek(fh, opts.backend_off_, SEEK_SET); @@ -113,6 +120,9 @@ void StdioIoClient::ReadBlob(const hipc::charbuf &bkt_name, sizeof(char), full_blob.size(), fh); + if (status.size_ != full_blob.size()) { + status.success_ = false; + } real_api->fclose(fh); } diff --git a/src/api/bucket.cc b/src/api/bucket.cc index ca982bfec..2f0f054f4 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -177,6 +177,7 @@ Status Bucket::PartialPutOrCreate(const std::string &blob_name, const Blob &blob, size_t blob_off, BlobId &blob_id, + IoStatus &status, const IoClientContext &opts, Context &ctx) { Blob full_blob; @@ -193,17 +194,16 @@ Status Bucket::PartialPutOrCreate(const std::string &blob_name, LOG(INFO) << "Blob existed. Reading from Hermes." << std::endl; Get(blob_id, full_blob, ctx); } - if (full_blob.size() != opts.backend_size_) { - // Case 3: The blob did not exist (need to read from backend) + if (full_blob.size() < opts.backend_size_) { + // Case 3: The blob did not fully exist (need to read from backend) // Read blob using adapter LOG(INFO) << "Blob didn't fully exist. Reading from backend." << std::endl; - IoStatus status; auto io_client = IoClientFactory::Get(opts.type_); full_blob.resize(opts.backend_size_); if (io_client) { io_client->ReadBlob(hipc::charbuf(name_), full_blob, opts, status); - if (status.size_ != opts.backend_size_) { + if (!status.success_) { LOG(INFO) << "Failed to read blob of size " << opts.backend_size_ << "from backend (PartialPut)"; @@ -249,6 +249,7 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, size_t blob_off, size_t blob_size, BlobId &blob_id, + IoStatus &status, const IoClientContext &opts, Context &ctx) { Blob full_blob; @@ -262,12 +263,11 @@ Status Bucket::PartialGetOrCreate(const std::string &blob_name, // Case 2: The blob did not exist (or at least not fully) // Read blob using adapter LOG(INFO) << "Blob did not exist. Reading blob from backend." << std::endl; - IoStatus status; auto io_client = IoClientFactory::Get(opts.type_); full_blob.resize(opts.backend_size_); if (io_client) { io_client->ReadBlob(hipc::charbuf(name_), full_blob, opts, status); - if (status.size_ != opts.backend_size_) { + if (!status.success_) { LOG(INFO) << "Failed to read blob of size " << opts.backend_size_ << "from backend (PartialCreate)"; diff --git a/src/api/bucket.h b/src/api/bucket.h index 80dc72377..6db300ec9 100644 --- a/src/api/bucket.h +++ b/src/api/bucket.h @@ -158,6 +158,7 @@ class Bucket { const Blob &blob, size_t blob_off, BlobId &blob_id, + IoStatus &status, const IoClientContext &opts, Context &ctx); @@ -185,6 +186,7 @@ class Bucket { size_t blob_off, size_t blob_size, BlobId &blob_id, + IoStatus &status, const IoClientContext &opts, Context &ctx); From 4f4ca2a97633d6cb2105138b8c0e5d0b582e20c1 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 27 Feb 2023 07:51:26 -0600 Subject: [PATCH 159/511] Posix write passes --- adapter/filesystem/filesystem.cc | 13 +++++------ adapter/filesystem/filesystem.h | 20 +---------------- adapter/io_client/io_client.h | 37 +++++++++++++++++++++++++++++--- adapter/mpiio/mpiio_api.h | 4 ++++ adapter/posix/posix_io_client.cc | 6 ++++++ adapter/stdio/stdio_io_client.cc | 3 +++ src/api/bucket.cc | 2 +- src/metadata_manager.cc | 29 ++++++++++++++++++------- 8 files changed, 77 insertions(+), 37 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 7cda53f95..5b45e252e 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -34,18 +34,19 @@ File Filesystem::Open(AdapterStat &stat, const std::string &path) { void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { auto mdm = HERMES_FS_METADATA_MANAGER; - FsIoOptions opts; Context ctx; - opts.type_ = type_; - stat.bkt_id_ = HERMES->GetBucket(path, ctx, opts); - // TODO(llogan): can avoid two unordered_map queries here - stat.adapter_mode_ = mdm->GetAdapterMode(path); - stat.page_size_ = mdm->GetAdapterPageSize(path); std::shared_ptr exists = mdm->Find(f); if (!exists) { LOG(INFO) << "File not opened before by adapter" << std::endl; // Create the new bucket + FsIoOptions opts; + opts.type_ = type_; + if (stat.is_trunc_) { opts.MarkTruncated(); } stat.bkt_id_ = HERMES->GetBucket(path, ctx, opts); + // Update bucket stats + // TODO(llogan): can avoid two unordered_map queries here + stat.adapter_mode_ = mdm->GetAdapterMode(path); + stat.page_size_ = mdm->GetAdapterPageSize(path); stat.backend_size_ = stat.bkt_id_->GetSize(IoClientContext(type_)); // Allocate internal hermes data auto stat_ptr = std::make_shared(stat); diff --git a/adapter/filesystem/filesystem.h b/adapter/filesystem/filesystem.h index d71930d46..beb8877e3 100644 --- a/adapter/filesystem/filesystem.h +++ b/adapter/filesystem/filesystem.h @@ -66,9 +66,6 @@ struct AdapterStat : public IoClientStats { } }; -/**< Whether to perform seek */ -#define HERMES_FS_SEEK (1<< (HERMES_IO_CLIENT_FLAGS_COUNT)) - /** * A structure to represent IO options for FS adapter. * For now, nothing additional than the typical IoClientContext. @@ -76,22 +73,7 @@ struct AdapterStat : public IoClientStats { struct FsIoOptions : public IoClientContext { /** Default constructor */ FsIoOptions() : IoClientContext() { - flags_.SetBits(HERMES_FS_SEEK); - } - - /** Enable seek for this I/O */ - void SetSeek() { - flags_.SetBits(HERMES_FS_SEEK); - } - - /** Disable seek for this I/O */ - void UnsetSeek() { - flags_.UnsetBits(HERMES_FS_SEEK); - } - - /** Whether or not to perform seek in FS adapter */ - bool DoSeek() { - return flags_.OrBits(HERMES_FS_SEEK); + SetSeek(); } /** return IO options with \a mpi_type MPI data type */ diff --git a/adapter/io_client/io_client.h b/adapter/io_client/io_client.h index 78975e677..fa299e85c 100644 --- a/adapter/io_client/io_client.h +++ b/adapter/io_client/io_client.h @@ -46,11 +46,15 @@ struct IoClientObject { }; /** Put or get data directly from I/O client */ -#define HERMES_IO_CLIENT_BYPASS (1<<0) +#define HERMES_IO_CLIENT_BYPASS (1 << 0) /** Only put or get data from a Hermes buffer; no fallback to I/O client */ -#define HERMES_IO_CLIENT_NO_FALLBACK (1<<1) +#define HERMES_IO_CLIENT_NO_FALLBACK (1 << 1) +/** Whether to perform seek */ +#define HERMES_FS_SEEK (1 << 2) +/** Whether to perform truncate */ +#define HERMES_FS_TRUNC (1 << 3) /** The number of I/O client flags (used for extending flag field) */ -#define HERMES_IO_CLIENT_FLAGS_COUNT 2 +#define HERMES_IO_CLIENT_FLAGS_COUNT 4 /** Represents any relevant settings for an I/O client operation */ struct IoClientContext { @@ -81,6 +85,31 @@ struct IoClientContext { mpi_count_(0), backend_off_(0), backend_size_(0) {} + + /** Enable seek for this I/O */ + void SetSeek() { + flags_.SetBits(HERMES_FS_SEEK); + } + + /** Disable seek for this I/O */ + void UnsetSeek() { + flags_.UnsetBits(HERMES_FS_SEEK); + } + + /** Whether or not to perform seek in FS adapter */ + bool DoSeek() const { + return flags_.OrBits(HERMES_FS_SEEK); + } + + /** Marks the file as truncated */ + void MarkTruncated() { + flags_.SetBits(HERMES_FS_TRUNC); + } + + /** Whether a file is marked truncated */ + bool IsTruncated() const { + return flags_.OrBits(HERMES_FS_TRUNC); + } }; /** Any relevant statistics from the I/O client */ @@ -100,6 +129,7 @@ struct IoClientStats { FILE *fh_; /**< real STDIO file handler */ MPI_File mpi_fh_; /**< real MPI file handler */ + bool is_trunc_; /**< File is truncated */ bool is_append_; /**< File is in append mode */ int amode_; /**< access mode (MPI) */ MPI_Info info_; /**< Info object (handle) */ @@ -114,6 +144,7 @@ struct IoClientStats { st_atim_(), st_mtim_(), st_ctim_(), + is_trunc_(false), is_append_(false), amode_(0), comm_(MPI_COMM_SELF), diff --git a/adapter/mpiio/mpiio_api.h b/adapter/mpiio/mpiio_api.h index aee4ac984..517586a2e 100644 --- a/adapter/mpiio/mpiio_api.h +++ b/adapter/mpiio/mpiio_api.h @@ -19,6 +19,10 @@ #include #include +#ifndef MPI_MODE_TRUNCATE +#define MPI_MODE_TRUNCATE 0 +#endif + #define REQUIRE_API(api_name) \ if (api_name == nullptr) { \ LOG(FATAL) << "HERMES Adapter failed to map symbol: " \ diff --git a/adapter/posix/posix_io_client.cc b/adapter/posix/posix_io_client.cc index 0ae58de4d..12ee5ea52 100644 --- a/adapter/posix/posix_io_client.cc +++ b/adapter/posix/posix_io_client.cc @@ -29,6 +29,9 @@ void PosixIoClient::RealOpen(IoClientObject &f, if (stat.flags_ & O_APPEND) { stat.is_append_ = true; } + if (stat.flags_ & O_TRUNC) { + stat.is_trunc_ = true; + } } /** @@ -79,6 +82,9 @@ void PosixIoClient::InitBucketState(const hipc::charbuf &bkt_name, real_api->fstat(fd, &buf); stat.true_size_ = buf.st_size; real_api->close(fd); + + LOG(INFO) << "The size of the file " + << filename << " on disk is " << stat.true_size_ << std::endl; } /** Write blob to backend */ diff --git a/adapter/stdio/stdio_io_client.cc b/adapter/stdio/stdio_io_client.cc index 3d4f88360..9dc9b7d71 100644 --- a/adapter/stdio/stdio_io_client.cc +++ b/adapter/stdio/stdio_io_client.cc @@ -26,6 +26,9 @@ void StdioIoClient::RealOpen(IoClientObject &f, if (stat.mode_str_.find('a') != std::string::npos) { stat.is_append_ = true; } + if (stat.mode_str_.find('w')) { + stat.is_trunc_ = true; + } } /** diff --git a/src/api/bucket.cc b/src/api/bucket.cc index 2f0f054f4..8641f38de 100644 --- a/src/api/bucket.cc +++ b/src/api/bucket.cc @@ -182,7 +182,7 @@ Status Bucket::PartialPutOrCreate(const std::string &blob_name, Context &ctx) { Blob full_blob; // Put the blob - if (blob_off == 0 && blob.size() == opts.backend_size_) { + if (blob_off == 0 && blob.size() >= opts.backend_size_) { // Case 1: We're overriding the entire blob // Put the entire blob, no need to load from storage LOG(INFO) << "Putting the entire blob." << std::endl; diff --git a/src/metadata_manager.cc b/src/metadata_manager.cc index cada1542a..09b81acf6 100644 --- a/src/metadata_manager.cc +++ b/src/metadata_manager.cc @@ -128,23 +128,36 @@ BucketId MetadataManager::LocalGetOrCreateBucket( // Emplace bucket if it does not already exist if (bkt_id_map_->try_emplace(bkt_name, bkt_id)) { + LOG(INFO) << "Creating bucket for the first time: " + << bkt_name.str() << std::endl; BucketInfo info(HERMES->main_alloc_); (*info.name_) = bkt_name; info.header_->internal_size_ = 0; - auto io_client = IoClientFactory::Get(opts.type_); - if (io_client) { - io_client->InitBucketState(bkt_name, - opts, - info.header_->client_state_); - } bkt_map_->emplace(bkt_id, std::move(info)); } else { + LOG(INFO) << "Found existing bucket: " + << bkt_name.str() << std::endl; auto iter = bkt_id_map_->find(bkt_name); if (iter == bkt_id_map_->end()) { return BucketId::GetNull(); } - hipc::ShmRef> info = (*iter); - bkt_id = *info->second_; + hipc::ShmRef> id_info = (*iter); + bkt_id = *id_info->second_; + if (opts.IsTruncated()) { + // TODO(llogan): clear bucket + } + } + + + // TODO(llogan): Optimization. This should be done only during the + // creation of the bucket. I'm only doing this for the sake of not + // refactoring the unit tests. + hipc::ShmRef info = (*bkt_map_)[bkt_id]; + auto io_client = IoClientFactory::Get(opts.type_); + if (io_client) { + io_client->InitBucketState(bkt_name, + opts, + info->header_->client_state_); } return bkt_id; From f5950bb75129a7565af4afd5b0500a74eca28866 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 27 Feb 2023 08:24:06 -0600 Subject: [PATCH 160/511] Don't use file_off in filesystem.cc --- adapter/filesystem/filesystem.cc | 6 ++---- adapter/test/posix/posix_adapter_basic_test.cpp | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/adapter/filesystem/filesystem.cc b/adapter/filesystem/filesystem.cc index 5b45e252e..4f21279b0 100644 --- a/adapter/filesystem/filesystem.cc +++ b/adapter/filesystem/filesystem.cc @@ -100,10 +100,9 @@ size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, const Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); hipc::charbuf blob_name(p.CreateBlobName(kPageSize)); BlobId blob_id; - size_t file_off = off + data_offset; opts.type_ = type_; opts.backend_off_ = p.page_ * kPageSize; - opts.backend_size_ = GetBackendSize(file_off, + opts.backend_size_ = GetBackendSize(opts.backend_off_, stat.backend_size_, kPageSize); opts.adapter_mode_ = stat.adapter_mode_; @@ -151,9 +150,8 @@ size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, Blob blob_wrap((const char*)ptr + data_offset, p.blob_size_); hipc::charbuf blob_name(p.CreateBlobName(kPageSize)); BlobId blob_id; - size_t file_off = off + data_offset; opts.backend_off_ = p.page_ * kPageSize; - opts.backend_size_ = GetBackendSize(file_off, + opts.backend_size_ = GetBackendSize(opts.backend_off_, stat.backend_size_, kPageSize); ; opts.type_ = type_; diff --git a/adapter/test/posix/posix_adapter_basic_test.cpp b/adapter/test/posix/posix_adapter_basic_test.cpp index ee8ef163c..1dcde746c 100644 --- a/adapter/test/posix/posix_adapter_basic_test.cpp +++ b/adapter/test/posix/posix_adapter_basic_test.cpp @@ -407,14 +407,14 @@ TEST_CASE("BatchedReadSequential", } SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_WRONLY); + test::test_open(info.existing_file.c_str(), O_RDONLY); REQUIRE(test::fh_orig != -1); for (size_t i = 0; i < info.num_iterations; ++i) { test::test_seek(0, SEEK_SET); REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); + test::test_read(info.write_data.data(), args.request_size); + REQUIRE(test::size_read_orig == args.request_size); } test::test_close(); REQUIRE(test::status_orig == 0); From c124eb042a90a4f8e5dca155cb36f7582127a986 Mon Sep 17 00:00:00 2001 From: lukemartinlogan Date: Mon, 27 Feb 2023 15:53:44 -0600 Subject: [PATCH 161/511] Begin fstat check --- adapter/test/posix/posix_adapter_basic_test.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/adapter/test/posix/posix_adapter_basic_test.cpp b/adapter/test/posix/posix_adapter_basic_test.cpp index 1dcde746c..fce088ecd 100644 --- a/adapter/test/posix/posix_adapter_basic_test.cpp +++ b/adapter/test/posix/posix_adapter_basic_test.cpp @@ -520,7 +520,7 @@ TEST_CASE("BatchedUpdateStrideFixed", test::test_seek(offset, SEEK_SET); REQUIRE(((size_t)test::status_orig) == offset); test::test_write(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); + REQUIRE(test::size_written_orig == args.request_size); } test::test_close(); REQUIRE(test::status_orig == 0); @@ -536,8 +536,6 @@ TEST_CASE("BatchedReadStrideDynamic", std::to_string(info.num_iterations) + "]" "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { test::test_open(info.existing_file.c_str(), O_RDWR); REQUIRE(test::fh_orig != -1); @@ -575,7 +573,7 @@ TEST_CASE("BatchedUpdateStrideDynamic", test::test_seek(offset, SEEK_SET); REQUIRE(((size_t)test::status_orig) == offset); test::test_write(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); + REQUIRE(test::size_written_orig == args.request_size); } test::test_close(); REQUIRE(test::status_orig == 0); @@ -909,7 +907,7 @@ TEST_CASE("BatchedUpdateStrideNegative", test::test_seek(offset, SEEK_SET); REQUIRE(((size_t)test::status_orig) == offset); test::test_write(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); + REQUIRE(test::size_written_orig == args.request_size); } test::test_close(); REQUIRE(test::status_orig == 0); @@ -1047,7 +1045,7 @@ TEST_CASE("BatchedUpdateStride2D", test::test_seek(offset, SEEK_SET); REQUIRE(((size_t)test::status_orig) == offset); test::test_write(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); + REQUIRE(test::size_written_orig == args.request_size); } test::test_close(); REQUIRE(test::status_orig == 0); From 94cf5ec75ae372d7760c4de73f42e02533cd0189 Mon Sep 17 00:00:00 2001 From: Luke Date: Tue, 28 Feb 2023 03:28:12 -0600 Subject: [PATCH 162/511] hermes_shm? --- ci/hermes/packages/hermes/package.py | 2 + hermes_shm/.gitignore | 13 + hermes_shm/CMake/FindHermesShm.cmake | 43 + hermes_shm/CMake/UseDoxygenDoc.cmake | 33 + hermes_shm/COPYING | 52 + hermes_shm/CPPLINT.cfg | 2 + hermes_shm/benchmark/CMakeLists.txt | 6 + hermes_shm/benchmark/allocator/CMakeLists.txt | 19 + hermes_shm/benchmark/allocator/allocator.cc | 219 ++ hermes_shm/benchmark/allocator/test_init.cc | 21 + hermes_shm/benchmark/allocator/test_init.h | 46 + .../benchmark/data_structure/CMakeLists.txt | 28 + hermes_shm/benchmark/data_structure/atomic.cc | 246 ++ hermes_shm/benchmark/data_structure/list.cc | 11 + hermes_shm/benchmark/data_structure/string.cc | 98 + .../benchmark/data_structure/test_init.cc | 47 + .../benchmark/data_structure/test_init.h | 54 + .../benchmark/data_structure/unordered_map.cc | 36 + hermes_shm/benchmark/data_structure/vector.cc | 236 ++ .../benchmark/data_structure_mpi/list.cc | 4 + .../data_structure_mpi/unordered_map.cc | 4 + .../benchmark/data_structure_mpi/vector.cc | 4 + hermes_shm/benchmark/lock/CMakeLists.txt | 18 + hermes_shm/benchmark/lock/benchmark_mutex.cc | 22 + hermes_shm/benchmark/lock/test_init.cc | 19 + hermes_shm/benchmark/lock/test_init.h | 20 + .../code_generators/cpp_macro_generator.py | 27 + hermes_shm/doc/Doxyfile.in | 2685 +++++++++++++++++ hermes_shm/example/CMakeLists.txt | 23 + hermes_shm/example/allocator.cc | 57 + hermes_shm/example/container.cc | 91 + hermes_shm/example/list.cc | 77 + hermes_shm/example/vector.cc | 75 + .../include/hermes_shm/constants/constants.h | 18 + .../hermes_shm/constants/singleton_macros.h | 24 + .../data_structures/internal/shm_internal.h | 15 + .../data_structures/serialization/thallium.h | 115 + .../data_structures/smart_ptr/unique_ptr.h | 119 + .../data_structures/thread_unsafe/iqueue.h | 353 +++ .../data_structures/thread_unsafe/slist.h | 516 ++++ .../memory/allocator/fixed_page_allocator.h | 112 + .../allocator/scalable_page_allocator.h | 185 ++ .../hermes_shm/memory/memory_registry.h | 123 + hermes_shm/readme.md | 5 + hermes_shm/scripts/docs.sh | 9 + hermes_shm/scripts/lint.sh | 12 + hermes_shm/scripts/preamble.py | 93 + hermes_shm/scripts/singleton_generator.py | 98 + hermes_shm/src/memory/fixed_page_allocator.cc | 120 + hermes_shm/src/memory/memory_registry.cc | 26 + .../src/memory/scalable_page_allocator.cc | 285 ++ .../unit/data_structures/containers/iqueue.cc | 39 + .../unit/data_structures/containers/iqueue.h | 109 + .../unit/data_structures/containers/slist.cc | 59 + .../unit/data_structures/containers/tuple.cc | 82 + .../data_structures/containers/unique_ptr.cc | 46 + 56 files changed, 6901 insertions(+) create mode 100644 hermes_shm/.gitignore create mode 100644 hermes_shm/CMake/FindHermesShm.cmake create mode 100644 hermes_shm/CMake/UseDoxygenDoc.cmake create mode 100644 hermes_shm/COPYING create mode 100644 hermes_shm/CPPLINT.cfg create mode 100644 hermes_shm/benchmark/CMakeLists.txt create mode 100644 hermes_shm/benchmark/allocator/CMakeLists.txt create mode 100644 hermes_shm/benchmark/allocator/allocator.cc create mode 100644 hermes_shm/benchmark/allocator/test_init.cc create mode 100644 hermes_shm/benchmark/allocator/test_init.h create mode 100644 hermes_shm/benchmark/data_structure/CMakeLists.txt create mode 100644 hermes_shm/benchmark/data_structure/atomic.cc create mode 100644 hermes_shm/benchmark/data_structure/list.cc create mode 100644 hermes_shm/benchmark/data_structure/string.cc create mode 100644 hermes_shm/benchmark/data_structure/test_init.cc create mode 100644 hermes_shm/benchmark/data_structure/test_init.h create mode 100644 hermes_shm/benchmark/data_structure/unordered_map.cc create mode 100644 hermes_shm/benchmark/data_structure/vector.cc create mode 100644 hermes_shm/benchmark/data_structure_mpi/list.cc create mode 100644 hermes_shm/benchmark/data_structure_mpi/unordered_map.cc create mode 100644 hermes_shm/benchmark/data_structure_mpi/vector.cc create mode 100644 hermes_shm/benchmark/lock/CMakeLists.txt create mode 100644 hermes_shm/benchmark/lock/benchmark_mutex.cc create mode 100644 hermes_shm/benchmark/lock/test_init.cc create mode 100644 hermes_shm/benchmark/lock/test_init.h create mode 100644 hermes_shm/code_generators/cpp_macro_generator.py create mode 100644 hermes_shm/doc/Doxyfile.in create mode 100644 hermes_shm/example/CMakeLists.txt create mode 100644 hermes_shm/example/allocator.cc create mode 100644 hermes_shm/example/container.cc create mode 100644 hermes_shm/example/list.cc create mode 100644 hermes_shm/example/vector.cc create mode 100644 hermes_shm/include/hermes_shm/constants/constants.h create mode 100644 hermes_shm/include/hermes_shm/constants/singleton_macros.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/internal/shm_internal.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/serialization/thallium.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/smart_ptr/unique_ptr.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/thread_unsafe/iqueue.h create mode 100644 hermes_shm/include/hermes_shm/data_structures/thread_unsafe/slist.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/fixed_page_allocator.h create mode 100644 hermes_shm/include/hermes_shm/memory/allocator/scalable_page_allocator.h create mode 100644 hermes_shm/include/hermes_shm/memory/memory_registry.h create mode 100644 hermes_shm/readme.md create mode 100755 hermes_shm/scripts/docs.sh create mode 100644 hermes_shm/scripts/lint.sh create mode 100644 hermes_shm/scripts/preamble.py create mode 100644 hermes_shm/scripts/singleton_generator.py create mode 100644 hermes_shm/src/memory/fixed_page_allocator.cc create mode 100644 hermes_shm/src/memory/memory_registry.cc create mode 100644 hermes_shm/src/memory/scalable_page_allocator.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/iqueue.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/iqueue.h create mode 100644 hermes_shm/test/unit/data_structures/containers/slist.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/tuple.cc create mode 100644 hermes_shm/test/unit/data_structures/containers/unique_ptr.cc diff --git a/ci/hermes/packages/hermes/package.py b/ci/hermes/packages/hermes/package.py index 6ba5a4853..9e04a6d2b 100644 --- a/ci/hermes/packages/hermes/package.py +++ b/ci/hermes/packages/hermes/package.py @@ -5,6 +5,7 @@ class Hermes(CMakePackage): url = "https://github.com/HDFGroup/hermes/tarball/master" git = "https://github.com/HDFGroup/hermes.git" version('master', branch='master') + version('dev-priv', git='git@github.com:lukemartinlogan/hermes.git', branch='new-borg') variant('vfd', default=False, description='Enable HDF5 VFD') depends_on('mochi-thallium~cereal@0.8.3') depends_on('catch2@3.0.1') @@ -12,6 +13,7 @@ class Hermes(CMakePackage): depends_on('mpich@3.3.2:') depends_on('glog@0.4:') depends_on('yaml-cpp') + depends_on('boost@1.7:') depends_on('hdf5@1.13.0:', when='+vfd') def cmake_args(self): diff --git a/hermes_shm/.gitignore b/hermes_shm/.gitignore new file mode 100644 index 000000000..440d2972b --- /dev/null +++ b/hermes_shm/.gitignore @@ -0,0 +1,13 @@ +cmake* +.idea +*.cmd +*.symvers +*.cmd +*.mod +*.mod.c +*.ko +*.order +*.o +*.o.cmd +*.o.d +build diff --git a/hermes_shm/CMake/FindHermesShm.cmake b/hermes_shm/CMake/FindHermesShm.cmake new file mode 100644 index 000000000..4f2912b53 --- /dev/null +++ b/hermes_shm/CMake/FindHermesShm.cmake @@ -0,0 +1,43 @@ +# Find labstor header and library. +# + +# This module defines the following uncached variables: +# HermesShm_FOUND, if false, do not try to use labstor. +# HermesShm_INCLUDE_DIRS, where to find labstor.h. +# HermesShm_LIBRARIES, the libraries to link against to use the labstor library +# HermesShm_LIBRARY_DIRS, the directory where the labstor library is found. + +find_path( + HermesShm_INCLUDE_DIR + hermes_shm/hermes_shm.h +) + +if( HermesShm_INCLUDE_DIR ) + get_filename_component(HermesShm_DIR ${HermesShm_INCLUDE_DIR} PATH) + + find_library( + HermesShm_LIBRARY + NAMES hermes_shm_data_structures + ) + + if( HermesShm_LIBRARY ) + set(HermesShm_LIBRARY_DIR "") + get_filename_component(HermesShm_LIBRARY_DIRS ${HermesShm_LIBRARY} PATH) + # Set uncached variables as per standard. + set(HermesShm_FOUND ON) + set(HermesShm_INCLUDE_DIRS ${HermesShm_INCLUDE_DIR}) + set(HermesShm_LIBRARIES ${HermesShm_LIBRARY}) + endif(HermesShm_LIBRARY) +else(HermesShm_INCLUDE_DIR) + message(STATUS "FindHermesShm: Could not find hermes_shm.h") +endif(HermesShm_INCLUDE_DIR) + +if(HermesShm_FOUND) + if(NOT HermesShm_FIND_QUIETLY) + message(STATUS "FindHermesShm: Found both hermes_shm.h and libhermes_shm.a") + endif(NOT HermesShm_FIND_QUIETLY) +else(HermesShm_FOUND) + if(HermesShm_FIND_REQUIRED) + message(STATUS "FindHermesShm: Could not find hermes_shm.h and/or libhermes_shm.a") + endif(HermesShm_FIND_REQUIRED) +endif(HermesShm_FOUND) diff --git a/hermes_shm/CMake/UseDoxygenDoc.cmake b/hermes_shm/CMake/UseDoxygenDoc.cmake new file mode 100644 index 000000000..b9601910b --- /dev/null +++ b/hermes_shm/CMake/UseDoxygenDoc.cmake @@ -0,0 +1,33 @@ +find_package(Perl REQUIRED) +find_package(Doxygen REQUIRED) + +function(add_doxygen_doc) + set(options) + set(oneValueArgs BUILD_DIR DOXY_FILE TARGET_NAME COMMENT) + set(multiValueArgs) + + cmake_parse_arguments(DOXY_DOC + "${options}" + "${oneValueArgs}" + "${multiValueArgs}" + ${ARGN} + ) + + configure_file( + ${DOXY_DOC_DOXY_FILE} + ${DOXY_DOC_BUILD_DIR}/Doxyfile + @ONLY + ) + + add_custom_target(${DOXY_DOC_TARGET_NAME} + COMMAND + ${DOXYGEN_EXECUTABLE} Doxyfile + WORKING_DIRECTORY + ${DOXY_DOC_BUILD_DIR} + COMMENT + "Building ${DOXY_DOC_COMMENT} with Doxygen" + VERBATIM + ) + + message(STATUS "Added ${DOXY_DOC_TARGET_NAME} [Doxygen] target to build documentation") +endfunction() \ No newline at end of file diff --git a/hermes_shm/COPYING b/hermes_shm/COPYING new file mode 100644 index 000000000..bb9689a91 --- /dev/null +++ b/hermes_shm/COPYING @@ -0,0 +1,52 @@ +Copyright Notice and License Terms for +Hermes I/O Buffering Software Library and Utilities + +------------------------------------------------------------------------------ + +Hermes I/O Buffering Software Library and Utilities +Copyright 2018-2021, The HDF Group and Illinois Institute of Technology + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of The HDF Group, Illinois Institute of Technology, nor + the names of Contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +DISCLAIMER: + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +You are under no obligation whatsoever to provide any bug fixes, patches, or +upgrades to the features, functionality or performance of the source code +("Enhancements") to anyone; however, if you choose to make your Enhancements +available either publicly, or directly to the copyright holders, without +imposing a separate written license agreement for such Enhancements, then you +hereby grant the following license: a non-exclusive, royalty-free perpetual +license to install, use, modify, prepare derivative works, incorporate into +other computer software, distribute, and sublicense such enhancements or +derivative works thereof, in binary and source code form. + +------------------------------------------------------------------------------ + +Hermes was developed with support from the National Science Foundation (NSF) +under award NSF OCI-1835764. diff --git a/hermes_shm/CPPLINT.cfg b/hermes_shm/CPPLINT.cfg new file mode 100644 index 000000000..f7d7492eb --- /dev/null +++ b/hermes_shm/CPPLINT.cfg @@ -0,0 +1,2 @@ +set noparent +filter=-build/header_guard,-build/include_subdir,-runtime/references,-readability/casting,-runtime/int,-build/include,-build/c++11,-build/c++14 \ No newline at end of file diff --git a/hermes_shm/benchmark/CMakeLists.txt b/hermes_shm/benchmark/CMakeLists.txt new file mode 100644 index 000000000..9533d420f --- /dev/null +++ b/hermes_shm/benchmark/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +add_subdirectory(data_structure) +add_subdirectory(allocator) +add_subdirectory(lock) \ No newline at end of file diff --git a/hermes_shm/benchmark/allocator/CMakeLists.txt b/hermes_shm/benchmark/allocator/CMakeLists.txt new file mode 100644 index 000000000..0858bdd58 --- /dev/null +++ b/hermes_shm/benchmark/allocator/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +include_directories( ${Boost_INCLUDE_DIRS} ) +include_directories( ${TEST_MAIN} ) +add_executable(benchmark_allocators + ${TEST_MAIN}/main.cc + test_init.cc + allocator.cc +) +add_dependencies(benchmark_allocators hermes_shm_data_structures) +target_link_libraries(benchmark_allocators + hermes_shm_data_structures + Catch2::Catch2 + MPI::MPI_CXX + OpenMP::OpenMP_CXX + ${Boost_LIBRARIES}) diff --git a/hermes_shm/benchmark/allocator/allocator.cc b/hermes_shm/benchmark/allocator/allocator.cc new file mode 100644 index 000000000..563990bbb --- /dev/null +++ b/hermes_shm/benchmark/allocator/allocator.cc @@ -0,0 +1,219 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include "test_init.h" +#include "omp.h" + +#include +#include + +/** Test cases for the allocator */ +class AllocatorTestSuite { + public: + std::string alloc_type_; + Allocator *alloc_; + static std::stringstream ss_; + static int test_count_; + + //////////////////// + /// Test Cases + //////////////////// + + /** Constructor */ + AllocatorTestSuite(AllocatorType alloc_type, Allocator *alloc) + : alloc_(alloc) { + switch (alloc_type) { + case AllocatorType::kStackAllocator: { + alloc_type_ = "hipc::StackAllocator"; + break; + } + case AllocatorType::kMallocAllocator: { + alloc_type_ = "hipc::MallocAllocator"; + break; + } + case AllocatorType::kFixedPageAllocator: { + alloc_type_ = "hipc::FixedPageAllocator"; + break; + } + } + } + + /** Allocate and Free a single size in a single loop */ + void AllocateAndFreeFixedSize(int count, size_t size) { + Timer t; + t.Resume(); + for (int i = 0; i < count; ++i) { + Pointer p = alloc_->Allocate(size); + alloc_->Free(p); + } +#pragma omp barrier + t.Pause(); + + TestOutput("AllocateAndFreeFixedSize", size, t); + } + + /** Allocate a fixed size in a loop, and then free in another loop */ + void AllocateThenFreeFixedSize(int count, size_t size) { + Timer t; + std::vector cache(count); + t.Resume(); + for (int i = 0; i < count; ++i) { + cache[i] = alloc_->Allocate(size); + } + for (int i = 0; i < count; ++i) { + alloc_->Free(cache[i]); + } +#pragma omp barrier + t.Pause(); + + TestOutput("AllocateThenFreeFixedSize", size, t); + } + + /** Allocate, Free, Reallocate, Free in a loop */ + + //////////////////// + /// Test Output + //////////////////// + + /** The CSV header */ + void TestOutputHeader() { + ss_ << "test_name" << "," + << "alloc_type" << "," + << "alloc_size" << "," + << "nthreads" << "," + << "time" << std::endl; + } + + /** The CSV test case */ + void TestOutput(const std::string &test_name, size_t obj_size, Timer &t) { + int rank = omp_get_thread_num(); + if (rank != 0) { return; } + if (test_count_ == 0) { + TestOutputHeader(); + } + ss_ << test_name << "," + << alloc_type_ << "," + << obj_size << "," + << omp_get_num_threads() << "," + << t.GetMsec() << std::endl; + ++test_count_; + } + + /** Print the CSV output */ + static void PrintTestOutput() { + std::cout << ss_.str() << std::endl; + } +}; + +/** The output text */ +std::stringstream AllocatorTestSuite::ss_; + +/** Number of tests currently conducted */ +int AllocatorTestSuite::test_count_ = 0; + +/** The minor number to use for allocators */ +static int minor = 1; + +/** Create the allocator + backend for the test */ +template +Allocator* Pretest(MemoryBackendType backend_type, + Args&& ...args) { + int rank = omp_get_thread_num(); + allocator_id_t alloc_id(0, minor); + Allocator *alloc; + auto mem_mngr = HERMES_MEMORY_MANAGER; + + if (rank == 0) { + // Create the allocator + backend + std::string shm_url = "test_allocators"; + mem_mngr->CreateBackend( + MemoryManager::kDefaultBackendSize, shm_url); + alloc = mem_mngr->CreateAllocator( + shm_url, alloc_id, 0, std::forward(args)...); + } +#pragma omp barrier + if (rank != 0){ + // Retrieve the allocator + backend + alloc = mem_mngr->GetAllocator(alloc_id); + } + +# pragma omp barrier + if (rank == 0) { + minor += 1; + } + + return alloc; +} + +/** Destroy the allocator + backend from the test */ +void Posttest() { + int rank = omp_get_thread_num(); +#pragma omp barrier + if (rank == 0) { + std::string shm_url = "test_allocators"; + auto mem_mngr = HERMES_MEMORY_MANAGER; + } +} + +/** A series of allocator benchmarks for a particular thread */ +template +void AllocatorTest(AllocatorType alloc_type, + MemoryBackendType backend_type, + Args&& ...args) { + Allocator *alloc = Pretest( + backend_type, std::forward(args)...); + // Allocate many, and then free many + AllocatorTestSuite(alloc_type, alloc).AllocateThenFreeFixedSize( + (2<<10), MEGABYTES(1)); + // Allocate and free immediately + AllocatorTestSuite(alloc_type, alloc).AllocateAndFreeFixedSize( + (2<<10), MEGABYTES(1)); + Posttest(); +} + +/** Test different allocators on a particular thread */ +void FullAllocatorTestPerThread() { + // Malloc allocator + AllocatorTest( + AllocatorType::kMallocAllocator, + MemoryBackendType::kNullBackend); + // Stack allocator + AllocatorTest( + AllocatorType::kStackAllocator, + MemoryBackendType::kPosixShmMmap); + // Fixed page allocator + AllocatorTest( + AllocatorType::kFixedPageAllocator, + MemoryBackendType::kPosixShmMmap); +} + +/** Spawn multiple threads and run allocator tests */ +void FullAllocatorTestThreaded(int nthreads) { + HERMES_THREAD_MANAGER->GetThreadStatic(); + + omp_set_dynamic(0); +#pragma omp parallel num_threads(nthreads) + { +#pragma omp barrier + FullAllocatorTestPerThread(); +#pragma omp barrier + } +} + +TEST_CASE("AllocatorBenchmark") { + FullAllocatorTestThreaded(1); + /*FullAllocatorTestThreaded(2); + FullAllocatorTestThreaded(4); + FullAllocatorTestThreaded(8);*/ + AllocatorTestSuite::PrintTestOutput(); +} diff --git a/hermes_shm/benchmark/allocator/test_init.cc b/hermes_shm/benchmark/allocator/test_init.cc new file mode 100644 index 000000000..26553deef --- /dev/null +++ b/hermes_shm/benchmark/allocator/test_init.cc @@ -0,0 +1,21 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "test_init.h" +#include "hermes_shm/data_structures/thread_unsafe/vector.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" + +void MainPretest() { +} + +void MainPosttest() { +} diff --git a/hermes_shm/benchmark/allocator/test_init.h b/hermes_shm/benchmark/allocator/test_init.h new file mode 100644 index 000000000..9a81364bf --- /dev/null +++ b/hermes_shm/benchmark/allocator/test_init.h @@ -0,0 +1,46 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_BENCHMARK_DATA_STRUCTURE_TEST_INIT_H_ +#define HERMES_BENCHMARK_DATA_STRUCTURE_TEST_INIT_H_ + +#include +#include +#include +#include +#include + +#include + +#include "hermes_shm/data_structures/data_structure.h" +#include + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::Pointer; + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::MemoryManager; +using hermes_shm::ipc::Pointer; + +using Timer = hermes_shm::HighResMonotonicTimer; + +extern std::string shm_url; + +#endif //HERMES_BENCHMARK_DATA_STRUCTURE_TEST_INIT_H_ diff --git a/hermes_shm/benchmark/data_structure/CMakeLists.txt b/hermes_shm/benchmark/data_structure/CMakeLists.txt new file mode 100644 index 000000000..95a3c2c11 --- /dev/null +++ b/hermes_shm/benchmark/data_structure/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +include_directories( ${Boost_INCLUDE_DIRS} ) +include_directories( ${TEST_MAIN} ) +add_executable(benchmark_data_structures + ${TEST_MAIN}/main.cc + test_init.cc + atomic.cc + string.cc + list.cc + vector.cc + # manual_ptr.cc + # unique_ptr.cc + unordered_map.cc + # unordered_map_thread.cc +) +add_dependencies(benchmark_data_structures hermes_shm_data_structures) +target_link_libraries(benchmark_data_structures + hermes_shm_data_structures + Catch2::Catch2 + MPI::MPI_CXX + OpenMP::OpenMP_CXX + ${Boost_LIBRARIES}) + +make_gprof(benchmark_data_structures ${CMAKE_CURRENT_BINARY_DIR}) \ No newline at end of file diff --git a/hermes_shm/benchmark/data_structure/atomic.cc b/hermes_shm/benchmark/data_structure/atomic.cc new file mode 100644 index 000000000..b02350c61 --- /dev/null +++ b/hermes_shm/benchmark/data_structure/atomic.cc @@ -0,0 +1,246 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include "test_init.h" + +#include +#include +#include "omp.h" + +/** Stringstream for storing test output */ +std::stringstream ss; + +/** Print the CSV output */ +static void PrintTestOutput() { + std::cout << ss.str() << std::endl; +} + +/** Number of tests executed */ +int test_count = 0; + +/** Global atomic counter */ +template +struct GlobalAtomicCounter { + static AtomicT count_; +}; +#define GLOBAL_COUNTER(Atomic, T)\ + template<>\ + Atomic GlobalAtomicCounter>::count_ = Atomic(0); +GLOBAL_COUNTER(std::atomic, uint16_t) +GLOBAL_COUNTER(std::atomic, uint32_t) +GLOBAL_COUNTER(std::atomic, uint64_t) +GLOBAL_COUNTER(hipc::nonatomic, uint16_t) +GLOBAL_COUNTER(hipc::nonatomic, uint32_t) +GLOBAL_COUNTER(hipc::nonatomic, uint64_t) + +/** Atomic Test Suite */ +template +class AtomicInstructionTestSuite { + public: + std::string memory_order_; + std::string atomic_type_; + + public: + ///////////////// + /// Test Cases + ///////////////// + + /** Constructor */ + AtomicInstructionTestSuite() { + if constexpr(MemoryOrder == std::memory_order_relaxed) { + memory_order_ = "std::memory_order_relaxed"; + } else if constexpr(MemoryOrder == std::memory_order_consume) { + memory_order_ = "std::memory_order_consume"; + } else if constexpr(MemoryOrder == std::memory_order_acquire) { + memory_order_ = "std::memory_order_acquire"; + } else if constexpr(MemoryOrder == std::memory_order_release) { + memory_order_ = "std::memory_order_release"; + } else if constexpr(MemoryOrder == std::memory_order_acq_rel) { + memory_order_ = "std::memory_order_acq_rel"; + } else if constexpr(MemoryOrder == std::memory_order_seq_cst) { + memory_order_ = "std::memory_order_seq_cst"; + } + + if constexpr(std::is_same_v, AtomicT>) { + atomic_type_ = "std::atomic"; + } else if constexpr(std::is_same_v, AtomicT>) { + atomic_type_ = "non-atomic"; + } + } + + /** Atomic Increment */ + void AtomicIncrement(size_t count) { + Timer t; +#pragma omp barrier + t.Resume(); + for (size_t i = 0; i < count; ++i) { + GlobalAtomicCounter::count_ += 1; + } +#pragma omp barrier + t.Pause(); + TestOutput("AtomicIncrement", count, t); + } + + /** Atomic Fetch Add */ + void AtomicFetchAdd(size_t count) { + Timer t; +#pragma omp barrier + t.Resume(); + for (size_t i = 0; i < count; ++i) { + GlobalAtomicCounter::count_.fetch_add(1, MemoryOrder); + } +#pragma omp barrier + t.Pause(); + TestOutput("AtomicFetchAdd", count, t); + } + + /** Atomic Assign */ + void AtomicAssign(size_t count) { + Timer t; +#pragma omp barrier + t.Resume(); + for (size_t i = 0; i < count; ++i) { + GlobalAtomicCounter::count_ = i; + } +#pragma omp barrier + t.Pause(); + TestOutput("AtomicAssign", count, t); + } + + /** Atomic Exchange */ + void AtomicExchange(size_t count) { + Timer t; +#pragma omp barrier + t.Resume(); + for (size_t i = 0; i < count; ++i) { + GlobalAtomicCounter::count_.exchange(i, MemoryOrder); + } +#pragma omp barrier + t.Pause(); + TestOutput("AtomicExchange", count, t); + } + + /** Atomic Fetch */ + void AtomicFetch(size_t count) { + Timer t; +#pragma omp barrier + t.Resume(); + for (size_t i = 0; i < count; ++i) { + size_t x = GlobalAtomicCounter::count_.load(MemoryOrder); + } +#pragma omp barrier + t.Pause(); + TestOutput("AtomicFetch", count, t); + } + + ///////////////// + /// Test Output + ///////////////// + + /** The CSV header */ + void TestOutputHeader() { + ss << "test_name" << "," + << "atomic_type" << "," + << "type_size" << "," + << "atomic_size" << "," + << "memory_order" << "," + << "count" << "," + << "nthreads" << "," + << "MOps" << "," + << "time" << std::endl; + } + + /** The CSV test case */ + void TestOutput(const std::string &test_name, size_t count, Timer &t) { + int rank = omp_get_thread_num(); + if (rank != 0) { return; } + if (test_count == 0) { + TestOutputHeader(); + } + int nthreads = omp_get_num_threads(); + ss << test_name << "," + << atomic_type_ << "," + << sizeof(T) << "," + << sizeof(AtomicT) << "," + << memory_order_ << "," + << count << "," + << omp_get_num_threads() << "," + << count * nthreads / t.GetUsec() << "," + << t.GetUsec() << std::endl; + ++test_count; + } +}; + +/** + * Compare different atomic instructions on a particular thread. + * Given the atomic type and memory order. + * */ +template +void TestAtomicInstructionsPerThread() { + int count = (1<<20); + AtomicInstructionTestSuite().AtomicIncrement(count); + AtomicInstructionTestSuite().AtomicFetchAdd(count); + AtomicInstructionTestSuite().AtomicAssign(count); + AtomicInstructionTestSuite().AtomicExchange(count); + AtomicInstructionTestSuite().AtomicFetch(count); +} + +/** + * Compare the differences between different memory orders on a particular + * thread. Given the atomic type. + * */ +template +void TestMemoryOrdersPerThread() { + TestAtomicInstructionsPerThread(); + TestAtomicInstructionsPerThread(); + TestAtomicInstructionsPerThread(); + TestAtomicInstructionsPerThread(); + TestAtomicInstructionsPerThread(); + TestAtomicInstructionsPerThread(); +} + +/** + * Compare the differences between different atomic types on a particular + * thread. + * */ +void TestAtomicTypes() { + TestMemoryOrdersPerThread, uint16_t>(); + TestMemoryOrdersPerThread, uint32_t>(); + TestMemoryOrdersPerThread, uint64_t>(); + + TestMemoryOrdersPerThread, uint16_t>(); + TestMemoryOrdersPerThread, uint32_t>(); + TestMemoryOrdersPerThread, uint64_t>(); +} + +/** + * Compare the differences between different memory orders and atomic + * instructions with multiple threads. Given number of threads. + * */ +void TestAtomicInstructions(int nthreads) { + omp_set_dynamic(0); +#pragma omp parallel num_threads(nthreads) + { +#pragma omp barrier + TestAtomicTypes(); +#pragma omp barrier + } +} + +TEST_CASE("AtomicInstructionTest") { + TestAtomicInstructions(1); + TestAtomicInstructions(2); + TestAtomicInstructions(4); + TestAtomicInstructions(8); + PrintTestOutput(); +} diff --git a/hermes_shm/benchmark/data_structure/list.cc b/hermes_shm/benchmark/data_structure/list.cc new file mode 100644 index 000000000..a60f997aa --- /dev/null +++ b/hermes_shm/benchmark/data_structure/list.cc @@ -0,0 +1,11 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ diff --git a/hermes_shm/benchmark/data_structure/string.cc b/hermes_shm/benchmark/data_structure/string.cc new file mode 100644 index 000000000..afb4e201f --- /dev/null +++ b/hermes_shm/benchmark/data_structure/string.cc @@ -0,0 +1,98 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "basic_test.h" +#include "test_init.h" + +#include +#include + +template +class StringTestSuite { + public: + std::string str_type_; + + ///////////////// + /// Test Cases + ///////////////// + + /** Constructor */ + StringTestSuite() { + if constexpr(std::is_same_v) { + str_type_ = "std::string"; + } else if constexpr(std::is_same_v) { + str_type_ = "hipc::string"; + } + } + + /** Construct + destruct in a loop */ + void ConstructDestructTest(int count, int length) { + char *data = (char *) malloc(length + 1); + data[length] = 0; + memset(data, 1, length); + + Timer t; + t.Resume(); + for (int i = 0; i < count; ++i) { + T hello(data); + } + t.Pause(); + + TestOutput("ConstructDestructTest", t); + } + + /** Construct in a loop, and then destruct in a loop */ + void ConstructThenDestructTest(int count, int length) { + char *data = (char *) malloc(length + 1); + data[length] = 0; + memset(data, 1, length); + + std::vector vec(count); + + Timer t; + t.Resume(); + for (int i = 0; i < count; ++i) { + vec[i] = T(data); + } + vec.clear(); + t.Pause(); + + TestOutput("ConstructThenDestructTest", t); + } + + ///////////////// + /// Test Output + ///////////////// + + /** Output test results */ + void TestOutput(const std::string &test_name, Timer &t) { + printf("%s, %s, %lf\n", + test_name.c_str(), + str_type_.c_str(), + t.GetMsec()); + } +}; + +template +void StringTest() { + StringTestSuite().ConstructDestructTest(1000000, 10); + // StringTestSuite().ConstructThenDestructTest(1000000, MEGABYTES(1)); +} + +void FullStringTest() { + StringTest(); + StringTest(); +} + +TEST_CASE("StringBenchmark") { + FullStringTest(); +} diff --git a/hermes_shm/benchmark/data_structure/test_init.cc b/hermes_shm/benchmark/data_structure/test_init.cc new file mode 100644 index 000000000..9a325d01a --- /dev/null +++ b/hermes_shm/benchmark/data_structure/test_init.cc @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "test_init.h" +#include "hermes_shm/data_structures/thread_unsafe/vector.h" +#include "hermes_shm/memory/allocator/stack_allocator.h" + +std::unique_ptr alloc_inst_g; +std::unique_ptr segment_g; + +void MainPretest() { + // Boost shared memory + bipc::shared_memory_object::remove("LabStorBoostBench"); + segment_g = std::make_unique( + bipc::create_only, "LabStorBoostBench", GIGABYTES(4)); + alloc_inst_g = std::make_unique( + segment_g->get_segment_manager()); + + // hermes shared memory + std::string shm_url = "LabStorSelfBench"; + allocator_id_t alloc_id(0, 1); + auto mem_mngr = HERMES_MEMORY_MANAGER; + mem_mngr->CreateBackend( + MemoryManager::kDefaultBackendSize, shm_url); + auto alloc = mem_mngr->CreateAllocator( + shm_url, alloc_id, 0); + + for (int i = 0; i < 1000000; ++i) { + Pointer p; + void *ptr = alloc->AllocatePtr(KILOBYTES(4), p); + memset(ptr, 0, KILOBYTES(4)); + alloc->Free(p); + } +} + +void MainPosttest() { + bipc::shared_memory_object::remove("LabstorBoostBench"); +} diff --git a/hermes_shm/benchmark/data_structure/test_init.h b/hermes_shm/benchmark/data_structure/test_init.h new file mode 100644 index 000000000..df7493359 --- /dev/null +++ b/hermes_shm/benchmark/data_structure/test_init.h @@ -0,0 +1,54 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_BENCHMARK_DATA_STRUCTURE_TEST_INIT_H_ +#define HERMES_BENCHMARK_DATA_STRUCTURE_TEST_INIT_H_ + +#include +#include +#include +#include +#include + +#include + +#include "hermes_shm/data_structures/data_structure.h" +#include + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::Pointer; + +using hermes_shm::ipc::MemoryBackendType; +using hermes_shm::ipc::MemoryBackend; +using hermes_shm::ipc::allocator_id_t; +using hermes_shm::ipc::AllocatorType; +using hermes_shm::ipc::Allocator; +using hermes_shm::ipc::MemoryManager; +using hermes_shm::ipc::Pointer; + +namespace bipc = boost::interprocess; + +typedef bipc::managed_shared_memory::segment_manager segment_manager_t; +typedef boost::container::scoped_allocator_adaptor< +bipc::allocator> + void_allocator; + +extern std::unique_ptr alloc_inst_g; +extern std::unique_ptr segment_g; + +using Timer = hermes_shm::HighResMonotonicTimer; + +#endif //HERMES_BENCHMARK_DATA_STRUCTURE_TEST_INIT_H_ diff --git a/hermes_shm/benchmark/data_structure/unordered_map.cc b/hermes_shm/benchmark/data_structure/unordered_map.cc new file mode 100644 index 000000000..f18d2c54e --- /dev/null +++ b/hermes_shm/benchmark/data_structure/unordered_map.cc @@ -0,0 +1,36 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Copyright (C) 2022 SCS Lab , + * Luke Logan , + * Jaime Cernuda Garcia + * Jay Lofstead , + * Anthony Kougkas , + * Xian-He Sun + * + * This file is part of hermes + * + * hermes 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 Lesser 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 + * . + */ diff --git a/hermes_shm/benchmark/data_structure/vector.cc b/hermes_shm/benchmark/data_structure/vector.cc new file mode 100644 index 000000000..5676027dc --- /dev/null +++ b/hermes_shm/benchmark/data_structure/vector.cc @@ -0,0 +1,236 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// Boost interprocess +#include +#include +#include +#include +#include + +// Boost private +#include +#include +#include + +// Std +#include +#include + +// hermes +#include +#include + +#include "basic_test.h" +#include "test_init.h" + +namespace bipc = boost::interprocess; + +#define SET_VAR_TO_INT_OR_STRING(TYPE, VAR, VAL)\ + if constexpr(std::is_same_v) {\ + VAR = hipc::string(std::to_string(VAL));\ + } else if constexpr(std::is_same_v) {\ + VAR = std::string(std::to_string(VAL));\ + } else {\ + VAR = VAL;\ + } + +/** + * A series of performance tests for vectors + * OUTPUT: + * [test_name] [vec_type] [internal_type] [time_ms] + * */ +template +class VectorTest { + public: + std::string vec_type; + std::string internal_type; + VecT *vec; + + VectorTest() { + if constexpr(std::is_same_v, VecT>) { + vec = new VecT(); + vec_type = "std::vector"; + } else if constexpr(std::is_same_v, VecT>) { + vec = new VecT(); + vec_type = "hipc::vector"; + } else if constexpr(std::is_same_v, VecT>) { + vec = new VecT(); + vec_type = "boost::vector"; + } else if constexpr(std::is_same_v, VecT>) { + vec = BoostIpcVector(); + vec_type = "bipc::vector"; + } else { + std::cout << "INVALID: none of the vector tests matched" << std::endl; + return; + } + + if constexpr(std::is_same_v) { + internal_type = "hipc::string"; + } else if constexpr(std::is_same_v) { + internal_type = "std::string"; + } else if constexpr(std::is_same_v) { + internal_type = "int"; + } + } + + void TestOutput(const std::string &test_name, Timer &t) { + printf("%s, %s, %s, %lf\n", + test_name.c_str(), + vec_type.c_str(), + internal_type.c_str(), + t.GetMsec()); + } + + void ResizeTest(VecT &vec, int count) { + Timer t; + T var; + + SET_VAR_TO_INT_OR_STRING(T, var, 124); + + t.Resume(); + vec.resize(count); + t.Pause(); + + TestOutput("FixedResize", t); + } + + void ReserveEmplaceTest(VecT &vec, int count) { + Timer t; + T var; + SET_VAR_TO_INT_OR_STRING(T, var, 124); + + t.Resume(); + vec.reserve(count); + for (int i = 0; i < count; ++i) { + vec.emplace_back(var); + } + t.Pause(); + + TestOutput("FixedEmplace", t); + } + + void GetTest(VecT &vec, int count) { + Timer t; + T var; + SET_VAR_TO_INT_OR_STRING(T, var, 124); + + vec.reserve(count); + for (int i = 0; i < count; ++i) { + vec.emplace_back(var); + } + + t.Resume(); + for (int i = 0; i < count; ++i) { + auto x = vec[i]; + } + t.Pause(); + + TestOutput("FixedGet", t); + } + + void ForwardIteratorTest(VecT &vec, int count) { + Timer t; + T var; + SET_VAR_TO_INT_OR_STRING(T, var, 124); + + vec.reserve(count); + for (int i = 0; i < count; ++i) { + vec.emplace_back(var); + } + + t.Resume(); + int i = 0; + for (auto x : vec) { + ++i; + } + t.Pause(); + + TestOutput("ForwardIterator", t); + } + + void CopyTest(VecT &vec, int count) { + Timer t; + T var; + SET_VAR_TO_INT_OR_STRING(T, var, 124); + + vec.reserve(count); + for (int i = 0; i < count; ++i) { + vec.emplace_back(var); + } + + t.Resume(); + VecT vec2(vec); + t.Pause(); + + TestOutput("Copy", t); + } + + void MoveTest(VecT &vec, int count) { + Timer t; + T var; + SET_VAR_TO_INT_OR_STRING(T, var, 124); + + vec.reserve(count); + for (int i = 0; i < count; ++i) { + vec.emplace_back(var); + } + + t.Resume(); + VecT vec2(std::move(vec)); + t.Pause(); + + TestOutput("Move", t); + } + + VecT *BoostIpcVector() { + void_allocator &alloc_inst = *alloc_inst_g; + bipc::managed_shared_memory &segment = *segment_g; + VecT *vec = segment.construct("BoostVector")(alloc_inst); + return vec; + } + + void Test() { + ResizeTest(*vec, 1000000); + ReserveEmplaceTest(*vec, 1000000); + GetTest(*vec, 1000000); + ForwardIteratorTest(*vec, 1000000); + CopyTest(*vec, 1000000); + MoveTest(*vec, 1000000); + } +}; + +void FullVectorTest() { + // std::vector tests + VectorTest>().Test(); + // VectorTest>().Test(); + // VectorTest>().Test(); + + // boost::vector tests +// VectorTest>().Test(); +// VectorTest>().Test(); +// VectorTest>().Test(); + + // boost::ipc::vector tests + // VectorTest>().Test(); + // VectorTest>().Test(); + // VectorTest>().Test(); + + // hipc::vector tests + VectorTest>().Test(); + // VectorTest>().Test(); + // VectorTest>().Test(); +} + +TEST_CASE("VectorBenchmark") { + FullVectorTest(); +} diff --git a/hermes_shm/benchmark/data_structure_mpi/list.cc b/hermes_shm/benchmark/data_structure_mpi/list.cc new file mode 100644 index 000000000..277a87800 --- /dev/null +++ b/hermes_shm/benchmark/data_structure_mpi/list.cc @@ -0,0 +1,4 @@ +// +// Created by lukemartinlogan on 2/23/23. +// + diff --git a/hermes_shm/benchmark/data_structure_mpi/unordered_map.cc b/hermes_shm/benchmark/data_structure_mpi/unordered_map.cc new file mode 100644 index 000000000..277a87800 --- /dev/null +++ b/hermes_shm/benchmark/data_structure_mpi/unordered_map.cc @@ -0,0 +1,4 @@ +// +// Created by lukemartinlogan on 2/23/23. +// + diff --git a/hermes_shm/benchmark/data_structure_mpi/vector.cc b/hermes_shm/benchmark/data_structure_mpi/vector.cc new file mode 100644 index 000000000..277a87800 --- /dev/null +++ b/hermes_shm/benchmark/data_structure_mpi/vector.cc @@ -0,0 +1,4 @@ +// +// Created by lukemartinlogan on 2/23/23. +// + diff --git a/hermes_shm/benchmark/lock/CMakeLists.txt b/hermes_shm/benchmark/lock/CMakeLists.txt new file mode 100644 index 000000000..86a2d1d88 --- /dev/null +++ b/hermes_shm/benchmark/lock/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.10) +project(hermes_shm) + +set(CMAKE_CXX_STANDARD 17) + +include_directories( ${Boost_INCLUDE_DIRS} ) +include_directories( ${TEST_MAIN} ) +add_executable(benchmark_lock + ${TEST_MAIN}/main.cc + test_init.cc + benchmark_mutex.cc +) +add_dependencies(benchmark_lock hermes_shm_data_structures) +target_link_libraries(benchmark_lock + hermes_shm_data_structures + Catch2::Catch2 + MPI::MPI_CXX + OpenMP::OpenMP_CXX) diff --git a/hermes_shm/benchmark/lock/benchmark_mutex.cc b/hermes_shm/benchmark/lock/benchmark_mutex.cc new file mode 100644 index 000000000..abc3bf3c4 --- /dev/null +++ b/hermes_shm/benchmark/lock/benchmark_mutex.cc @@ -0,0 +1,22 @@ +// +// Created by lukemartinlogan on 2/26/23. +// + +#include "hermes_shm/util/timer.h" +#include "hermes_shm/thread/lock.h" +#include "test_init.h" +#include "basic_test.h" +#include + +TEST_CASE("TestMutex") { + Timer t; + t.Resume(); + int j = 0; + size_t ops = (1ull << 26); + hermes_shm::Mutex lock; + for (size_t i = 0; i < ops; ++i) { + lock.TryLock(); + } + t.Pause(); + std::cout << ops / t.GetUsec() << std::endl; +} \ No newline at end of file diff --git a/hermes_shm/benchmark/lock/test_init.cc b/hermes_shm/benchmark/lock/test_init.cc new file mode 100644 index 000000000..0fe134776 --- /dev/null +++ b/hermes_shm/benchmark/lock/test_init.cc @@ -0,0 +1,19 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "test_init.h" + +void MainPretest() { +} + +void MainPosttest() { +} diff --git a/hermes_shm/benchmark/lock/test_init.h b/hermes_shm/benchmark/lock/test_init.h new file mode 100644 index 000000000..f7606b266 --- /dev/null +++ b/hermes_shm/benchmark/lock/test_init.h @@ -0,0 +1,20 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_BENCHMARK_DATA_STRUCTURE_TEST_INIT_H_ +#define HERMES_BENCHMARK_DATA_STRUCTURE_TEST_INIT_H_ + +#include + +using Timer = hermes_shm::HighResMonotonicTimer; + +#endif //HERMES_BENCHMARK_DATA_STRUCTURE_TEST_INIT_H_ diff --git a/hermes_shm/code_generators/cpp_macro_generator.py b/hermes_shm/code_generators/cpp_macro_generator.py new file mode 100644 index 000000000..43f657553 --- /dev/null +++ b/hermes_shm/code_generators/cpp_macro_generator.py @@ -0,0 +1,27 @@ +from code_generators.c_macro.macro_generator import CppMacroGenerator +import pathlib, os + +PROJECT_ROOT=pathlib.Path(__file__).parent.parent.resolve() + +DATA_STRUCTURE_TEMPLATES='include/hermes_shm/data_structures/internal/template' +DATA_STRUCTURE_INTERNAL='include/hermes_shm/data_structures/internal' + +CppMacroGenerator().generate( + os.path.join(PROJECT_ROOT, + f"{DATA_STRUCTURE_TEMPLATES}/shm_container_base_template.h"), + os.path.join(PROJECT_ROOT, + f"{DATA_STRUCTURE_INTERNAL}/shm_container_macro.h"), + "SHM_CONTAINER_TEMPLATE", + ["CLASS_NAME", "TYPED_CLASS", "TYPED_HEADER"], + ["TYPE_UNWRAP", "TYPE_UNWRAP", "TYPE_UNWRAP"], + "HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_MACRO_H_") + +CppMacroGenerator().generate( + os.path.join(PROJECT_ROOT, + f"{DATA_STRUCTURE_TEMPLATES}/shm_container_extend_template.h"), + os.path.join(PROJECT_ROOT, + f"{DATA_STRUCTURE_INTERNAL}/shm_container_extend_macro.h"), + "SHM_CONTAINER_EXTEND_TEMPLATE", + ["CLASS_NAME", "TYPED_CLASS", "TYPED_HEADER"], + ["TYPE_UNWRAP", "TYPE_UNWRAP", "TYPE_UNWRAP"], + "HERMES_DATA_STRUCTURES_INTERNAL_SHM_CONTAINER_EXTEND_MACRO_H_") \ No newline at end of file diff --git a/hermes_shm/doc/Doxyfile.in b/hermes_shm/doc/Doxyfile.in new file mode 100644 index 000000000..e351f448e --- /dev/null +++ b/hermes_shm/doc/Doxyfile.in @@ -0,0 +1,2685 @@ +# Doxyfile 1.9.5 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = Hermes + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 0.8.0-beta + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Hierarchical Distributed I/O Buffering System" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# numer of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = "status=A Status object." \ + "ctx{1}=ctx The Context for this \1." \ + "bool{1}=true if \1, otherwise false." + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = @PROJECT_SOURCE_DIR@/adapter \ + @PROJECT_SOURCE_DIR@/gotcha_intercept \ + @PROJECT_SOURCE_DIR@/src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding +# "INPUT_ENCODING" for further information on supported encodings. + +INPUT_FILE_ENCODING = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.h \ + *.cc + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = @PROJECT_SOURCE_DIR@/src/stb_ds.h + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = front_page.md + +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. Default setting AUTO_LIGHT +# enables light output unless the user preference is dark output. Other options +# are DARK to always use dark mode, LIGHT to always use light mode, AUTO_DARK to +# default to dark mode unless the user prefers light mode, and TOGGLE to let the +# user toggle between dark and light mode via a button. +# Possible values are: LIGHT Always generate light output., DARK Always generate +# dark output., AUTO_LIGHT Automatically set the mode according to the user +# preference, use light mode if no preference is set (the default)., AUTO_DARK +# Automatically set the mode according to the user preference, use dark mode if +# no preference is set. and TOGGLE Allow to user to switch between light and +# dark mode via a button.. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /