The Sparta Modeling Framework
Loading...
Searching...
No Matches
StatisticsArchives.hpp
1// <StatisticsArchives> -*- C++ -*-
2
3#pragma once
4
5#include "sparta/statistics/dispatch/StatisticsHierRootNodes.hpp"
6#include "sparta/statistics/dispatch/archives/RootArchiveNode.hpp"
7#include "sparta/statistics/dispatch/archives/ArchiveController.hpp"
8
9#include <filesystem>
10
11#include <boost/archive/binary_iarchive.hpp>
12
13namespace sparta {
14namespace statistics {
15
19class StatisticsArchives : public StatisticsHierRootNodes<RootArchiveNode>
20{
21public:
26 StatisticsArchives() = default;
27
33 explicit StatisticsArchives(const std::string & db_dir)
34 {
35 namespace sfs = std::filesystem;
36 sfs::path p(db_dir);
37
38 if (!sfs::is_directory(p)) {
39 throw SpartaException(
40 "The path given is not a directory: ") << db_dir;
41 }
42
43 //Archives are organized as follows:
44 //
45 // db_directory
46 // db_subdirectory <-> foo.csv
47 // db_subdirectory <-> bar.json
48 // ... ...
49 //
50 //We need to loop over the subdirectories, and create
51 //a RootArchiveNode object for each one.
52 std::vector<sfs::directory_entry> subdirs;
53 std::copy(sfs::directory_iterator(p),
54 sfs::directory_iterator(),
55 std::back_inserter(subdirs));
56
57 auto dir_iter = subdirs.begin();
58 while (dir_iter != subdirs.end()) {
59 const std::string archive_fulldir = dir_iter->path().string();
60 createArchivePlaceholderForExistingDatabase_(archive_fulldir);
61 ++dir_iter;
62 }
63 }
64
70 void saveTo(const std::string & dir);
71
72private:
80 void createArchivePlaceholderForExistingDatabase_(
81 const std::string & archive_fulldir)
82 {
83 std::vector<std::string> split;
84 boost::split(split, archive_fulldir, boost::is_any_of("/"));
85 const std::string archive_name = split.back();
86 archive_placeholder_dirs_[archive_name] = archive_fulldir;
87 }
88
95 std::vector<std::string> getLazyLoadedRootNames_() const override {
96 std::vector<std::string> names;
97 names.reserve(archive_placeholder_dirs_.size());
98 for (const auto & dir : archive_placeholder_dirs_) {
99 names.emplace_back(dir.first);
100 }
101 return names;
102 }
103
108 void onNamedRootRequest_(const std::string & root_name) override {
109 auto iter = archive_placeholder_dirs_.find(root_name);
110 if (iter != archive_placeholder_dirs_.end()) {
111 loadArchiveFspartaxistingDatabase_(iter->second);
112 archive_placeholder_dirs_.erase(iter);
113 }
114 }
115
117 void recursSetParentForChildNodes_(ArchiveNode * parent) const {
118 for (auto & child : parent->getChildren()) {
119 child->setParent(parent);
120 recursSetParentForChildNodes_(child.get());
121 }
122 }
123
127 void loadArchiveFspartaxistingDatabase_(const std::string & archive_fulldir)
128 {
129 std::shared_ptr<RootArchiveNode> root(new RootArchiveNode);
130
131 const std::string meta_filename = archive_fulldir + "/archive_tree.bin";
132 std::ifstream fin(meta_filename, std::ios::binary);
133 if (!fin) {
134 throw SpartaException(
135 "Unable to open archive file for read: ") << meta_filename;
136 }
137
138 boost::archive::binary_iarchive ia(fin);
139 ia >> *root;
140
141 //Give everyone in this archive tree easy access to their
142 //raw values filename
143 const std::string binary_filename = archive_fulldir + "/values.bin";
144 root->setMetadataValue("output_filename", binary_filename);
145
146 //Give the root archive node a controller it can use to
147 //save the archive to another directory. Offline controllers
148 //do not implement synchronization.
149 std::shared_ptr<ArchiveController> controller(
150 new OfflineArchiveController(archive_fulldir));
151 root->setArchiveController(controller);
152
153 //Make the connection from child nodes to their parent node
154 recursSetParentForChildNodes_(root.get());
155
156 //The archive directories given to us are in the form:
157 // "db_directory/db_subdirectory"
158 //
159 //The unique archive name is simply the db_subdirectory, which
160 //will be something like 'foo.csv', 'bar.html', etc.
161 std::vector<std::string> split;
162 boost::split(split, archive_fulldir, boost::is_any_of("/"));
163 const std::string archive_name = split.back();
164 addHierarchyRoot(archive_name, root);
165 }
166
167 std::unordered_map<std::string, std::string> archive_placeholder_dirs_;
168};
169
170} // namespace statistics
171} // namespace sparta
Used to construct and throw a standard C++ exception. Inherits from std::exception.
This class owns and coordinates a group of named archives.
StatisticsArchives(const std::string &db_dir)
void saveTo(const std::string &dir)
Utility class that holds onto statistics node hierarchies, accessible by a name that you choose.
void addHierarchyRoot(const std::string &storage_name, std::shared_ptr< RootArchiveNode > &root)
Append a statistics hierarchy root node to this set.
Macros for handling exponential backoff.