Skip to content

Commit 764ca0e

Browse files
authored
Merge pull request #475 from wildmeshing/dzint/445-add-cache-class
Add `Cache` class
2 parents 04f1459 + 1a0226a commit 764ca0e

File tree

9 files changed

+482
-3
lines changed

9 files changed

+482
-3
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ include(spdlog)
8484
include(gmp)
8585
include(mshio)
8686
include(predicates)
87+
include(jse)
8788

8889
# Core library
8990
add_library(wildmeshing_toolkit)
@@ -114,6 +115,7 @@ target_link_libraries(wildmeshing_toolkit PUBLIC
114115
gmp::gmp
115116
mshio::mshio
116117
predicates::predicates
118+
nlohmann_json::nlohmann_json
117119
)
118120

119121
add_subdirectory(components)

cmake/recipes/components/delaunay_psm.cmake

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ add_library(delaunay_psm STATIC ${delauanay_psm_SOURCE_DIR}/Delaunay_psm.cpp)
1919
target_compile_definitions(delaunay_psm PUBLIC GEO_STATIC_LIBS)
2020
target_compile_features(delaunay_psm PRIVATE cxx_std_11)
2121
target_include_directories(delaunay_psm PUBLIC ${delauanay_psm_SOURCE_DIR})
22-
add_library(geogram::delaunay_psm ALIAS delaunay_psm)
22+
add_library(geogram::delaunay_psm ALIAS delaunay_psm)
23+
24+
set_target_properties(delaunay_psm PROPERTIES FOLDER third_party)
File renamed without changes.

cmake/recipes/paraviewo.cmake

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,8 @@ set_target_properties(fmt PROPERTIES FOLDER third_party)
1919
set_target_properties(tinyxml2 PROPERTIES FOLDER third_party)
2020

2121
set_target_properties(hdf5-static PROPERTIES FOLDER third_party)
22-
set_target_properties(hdf5_hl-static PROPERTIES FOLDER third_party)
22+
set_target_properties(hdf5_hl-static PROPERTIES FOLDER third_party)
23+
24+
set_target_properties(gen_hdf5-static PROPERTIES FOLDER third_party)
25+
set_target_properties(H5detect PROPERTIES FOLDER third_party)
26+
set_target_properties(H5make_libsettings PROPERTIES FOLDER third_party)

src/wmtk/io/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

22
set(SRC_FILES
3+
Cache.cpp
4+
Cache.hpp
35
HDF5Reader.hpp
46
HDF5Reader.cpp
57
HDF5Writer.hpp

src/wmtk/io/Cache.cpp

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
#include "Cache.hpp"
2+
3+
#include <fmt/format.h>
4+
#include <chrono>
5+
#include <exception>
6+
#include <fstream>
7+
#include <iostream>
8+
#include <sstream>
9+
#include <wmtk/io/HDF5Writer.hpp>
10+
#include <wmtk/io/MeshReader.hpp>
11+
#include <wmtk/utils/Logger.hpp>
12+
13+
#include <nlohmann/json.hpp>
14+
15+
#include <filesystem>
16+
17+
namespace fs = std::filesystem;
18+
19+
long long nanoseconds_timestamp()
20+
{
21+
return std::chrono::duration_cast<std::chrono::nanoseconds>(
22+
std::chrono::system_clock::now().time_since_epoch())
23+
.count();
24+
}
25+
26+
std::string number_to_hex(long long l)
27+
{
28+
return fmt::format("{0:x}", l);
29+
}
30+
31+
namespace wmtk::io {
32+
33+
std::filesystem::path Cache::create_unique_directory(
34+
const std::string& prefix,
35+
const std::filesystem::path& location,
36+
size_t max_tries)
37+
{
38+
const fs::path tmp = location.empty() ? std::filesystem::temp_directory_path() : location;
39+
40+
const std::string timestamp = number_to_hex(nanoseconds_timestamp());
41+
42+
fs::path unique_dir;
43+
for (size_t i = 0; i < max_tries; ++i) {
44+
unique_dir = tmp / (prefix + "_" + timestamp + "_" + number_to_hex(i));
45+
46+
if (std::filesystem::create_directory(unique_dir)) {
47+
return unique_dir;
48+
}
49+
}
50+
51+
throw std::runtime_error("Could not generate a unique directory.");
52+
}
53+
54+
Cache::Cache(const std::string& prefix, const std::filesystem::path location)
55+
: m_cache_dir(location)
56+
{
57+
m_cache_dir = create_unique_directory(prefix, location);
58+
}
59+
60+
Cache::~Cache()
61+
{
62+
const size_t max_tries = 1000;
63+
for (size_t i = 0; fs::exists(m_cache_dir) && i < max_tries; ++i) {
64+
fs::remove_all(m_cache_dir);
65+
}
66+
67+
if (fs::exists(m_cache_dir)) {
68+
wmtk::logger().warn("Could not remove cache folder {}", fs::absolute(m_cache_dir));
69+
}
70+
}
71+
72+
const std::filesystem::path& Cache::create_unique_file(
73+
const std::string& filename,
74+
const std::string& extension,
75+
size_t max_tries)
76+
{
77+
const std::string timestamp = number_to_hex(nanoseconds_timestamp());
78+
79+
for (size_t i = 0; i < max_tries; ++i) {
80+
const fs::path p =
81+
m_cache_dir / (filename + "_" + timestamp + "_" + number_to_hex(i) + extension);
82+
83+
if (fs::exists(p)) {
84+
continue;
85+
}
86+
87+
// try to touch the file
88+
std::ofstream ofs(p);
89+
if (ofs.is_open()) {
90+
m_file_paths[filename] = p;
91+
ofs.close();
92+
return m_file_paths[filename];
93+
}
94+
ofs.close();
95+
}
96+
97+
throw std::runtime_error("Could not generate a unique file.");
98+
}
99+
100+
const std::filesystem::path& Cache::get_file_path(const std::string& filename)
101+
{
102+
const auto it = m_file_paths.find(filename);
103+
104+
if (it == m_file_paths.end()) {
105+
// filename does not exist yet --> create it
106+
return create_unique_file(filename, "");
107+
} else {
108+
return it->second;
109+
}
110+
}
111+
112+
std::filesystem::path Cache::get_file_path(const std::string& filename) const
113+
{
114+
const auto it = m_file_paths.find(filename);
115+
116+
if (it == m_file_paths.end()) {
117+
// filename does not exist yet --> create it
118+
throw std::runtime_error("File with name '" + filename + "' does not exist in cache");
119+
} else {
120+
return it->second;
121+
}
122+
}
123+
124+
std::filesystem::path Cache::get_cache_path() const
125+
{
126+
return m_cache_dir;
127+
}
128+
129+
std::shared_ptr<Mesh> Cache::read_mesh(const std::string& name) const
130+
{
131+
const fs::path p = get_file_path(name);
132+
return wmtk::read_mesh(p);
133+
}
134+
135+
void Cache::write_mesh(Mesh& m, const std::string& name)
136+
{
137+
const auto it = m_file_paths.find(name);
138+
139+
fs::path p;
140+
141+
if (it == m_file_paths.end()) {
142+
// file does not exist yet --> create it
143+
p = create_unique_file(name, ".hdf5");
144+
m_file_paths[name] = p;
145+
} else {
146+
p = it->second;
147+
}
148+
149+
HDF5Writer writer(p);
150+
m.serialize(writer);
151+
}
152+
153+
bool Cache::export_cache(const std::filesystem::path& export_location)
154+
{
155+
if (fs::exists(export_location)) {
156+
return false;
157+
}
158+
159+
fs::path cache_content_path;
160+
161+
// create a json with all cached names
162+
{
163+
nlohmann::json cache_content;
164+
for (const auto& [first, second] : m_file_paths) {
165+
cache_content[first] = fs::relative(second, m_cache_dir).string();
166+
}
167+
168+
cache_content_path = create_unique_file(m_cache_content_name, ".json");
169+
std::ofstream o(cache_content_path);
170+
o << std::setw(4) << cache_content << std::endl;
171+
o.close();
172+
}
173+
174+
// copy folder to export location
175+
fs::copy(m_cache_dir, export_location, fs::copy_options::recursive);
176+
177+
// delete json
178+
fs::remove(cache_content_path);
179+
180+
return true;
181+
}
182+
183+
bool Cache::import_cache(const std::filesystem::path& import_location)
184+
{
185+
if (!fs::exists(import_location)) {
186+
return false;
187+
}
188+
if (!m_file_paths.empty()) {
189+
return false;
190+
}
191+
192+
// remove current directory
193+
fs::remove_all(m_cache_dir);
194+
// copy import
195+
fs::copy(import_location, m_cache_dir, fs::copy_options::recursive);
196+
197+
// find json
198+
fs::path cache_content_path;
199+
for (const auto& f : fs::directory_iterator(m_cache_dir)) {
200+
const fs::path p = f.path();
201+
if (p.stem().string().rfind(m_cache_content_name, 0) == 0) {
202+
cache_content_path = p;
203+
break;
204+
}
205+
}
206+
207+
if (cache_content_path.empty()) {
208+
return false;
209+
}
210+
211+
// read json
212+
{
213+
std::ifstream i(cache_content_path);
214+
const nlohmann::json cache_content = nlohmann::json::parse(i);
215+
216+
std::map<std::string, std::string> map_paths =
217+
cache_content.get<std::map<std::string, std::string>>();
218+
219+
// make file paths absolute
220+
for (auto& [first, second] : map_paths) {
221+
m_file_paths[first] = m_cache_dir / second;
222+
}
223+
}
224+
225+
// delete json
226+
fs::remove(cache_content_path);
227+
228+
return true;
229+
}
230+
231+
} // namespace wmtk::io

0 commit comments

Comments
 (0)