Compare commits
5 Commits
e5b3546292
...
master
Author | SHA1 | Date | |
---|---|---|---|
889761f538 | |||
738e1a2071 | |||
2d5478c19e | |||
241a0c0906 | |||
0ba56d428f |
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Erik Scholz
|
||||
|
||||
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.
|
24
external/CMakeLists.txt
vendored
24
external/CMakeLists.txt
vendored
@ -28,29 +28,7 @@ if (NOT TARGET nlohmann_json::nlohmann_json)
|
||||
FetchContent_MakeAvailable(json)
|
||||
endif()
|
||||
|
||||
if (NOT TARGET zstd::zstd)
|
||||
# TODO: try find_package() first
|
||||
# TODO: try pkg-config next (will work on most distros)
|
||||
|
||||
set(ZSTD_BUILD_STATIC ON)
|
||||
set(ZSTD_BUILD_SHARED OFF)
|
||||
set(ZSTD_BUILD_PROGRAMS OFF)
|
||||
set(ZSTD_BUILD_CONTRIB OFF)
|
||||
set(ZSTD_BUILD_TESTS OFF)
|
||||
FetchContent_Declare(zstd
|
||||
URL "https://github.com/facebook/zstd/releases/download/v1.5.6/zstd-1.5.6.tar.gz"
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||
SOURCE_SUBDIR build/cmake
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(zstd)
|
||||
|
||||
add_library(zstd INTERFACE) # somehow zstd fkd this up
|
||||
target_include_directories(zstd INTERFACE ${zstd_SOURCE_DIR}/lib/)
|
||||
target_link_libraries(zstd INTERFACE libzstd_static)
|
||||
#TODO: new zstd also provides zstd::libzstd
|
||||
add_library(zstd::zstd ALIAS zstd)
|
||||
endif()
|
||||
add_subdirectory(./zstd)
|
||||
|
||||
#if (NOT TARGET solanaceae_plugin)
|
||||
#FetchContent_Declare(solanaceae_plugin
|
||||
|
32
external/zstd/CMakeLists.txt
vendored
Normal file
32
external/zstd/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
cmake_minimum_required(VERSION 3.24 FATAL_ERROR)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
if (NOT TARGET zstd::libzstd)
|
||||
find_package(zstd CONFIG GLOBAL QUIET)
|
||||
endif()
|
||||
|
||||
if (NOT TARGET zstd::libzstd)
|
||||
# TODO: try find_package() first
|
||||
# TODO: try pkg-config next (will work on most distros)
|
||||
|
||||
set(ZSTD_BUILD_STATIC ON)
|
||||
set(ZSTD_BUILD_SHARED OFF)
|
||||
set(ZSTD_BUILD_PROGRAMS OFF)
|
||||
set(ZSTD_BUILD_CONTRIB OFF)
|
||||
set(ZSTD_BUILD_TESTS OFF)
|
||||
FetchContent_Declare(zstd
|
||||
URL "https://github.com/facebook/zstd/releases/download/v1.5.6/zstd-1.5.6.tar.gz"
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||
SOURCE_SUBDIR build/cmake
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(zstd)
|
||||
|
||||
add_library(libzstd_tmp INTERFACE) # somehow zstd fkd this up
|
||||
target_include_directories(libzstd_tmp INTERFACE ${zstd_SOURCE_DIR}/lib/)
|
||||
target_link_libraries(libzstd_tmp INTERFACE libzstd_static)
|
||||
#TODO: new zstd also provides zstd::libzstd
|
||||
add_library(zstd::libzstd ALIAS libzstd_tmp)
|
||||
endif()
|
||||
|
@ -32,7 +32,7 @@ target_include_directories(solanaceae_file2_zstd PUBLIC .)
|
||||
target_compile_features(solanaceae_file2_zstd PUBLIC cxx_std_17)
|
||||
target_link_libraries(solanaceae_file2_zstd PUBLIC
|
||||
solanaceae_file2
|
||||
zstd::zstd
|
||||
zstd::libzstd
|
||||
)
|
||||
|
||||
########################################
|
||||
@ -40,8 +40,8 @@ target_link_libraries(solanaceae_file2_zstd PUBLIC
|
||||
add_library(solanaceae_object_store_backend_filesystem
|
||||
./solanaceae/object_store/backends/file2_stack.hpp
|
||||
./solanaceae/object_store/backends/file2_stack.cpp
|
||||
./solanaceae/object_store/backends/filesystem_storage.hpp
|
||||
./solanaceae/object_store/backends/filesystem_storage.cpp
|
||||
./solanaceae/object_store/backends/filesystem_storage_atomic.hpp
|
||||
./solanaceae/object_store/backends/filesystem_storage_atomic.cpp
|
||||
)
|
||||
|
||||
target_include_directories(solanaceae_object_store_backend_filesystem PUBLIC .)
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "./filesystem_storage.hpp"
|
||||
#include "./filesystem_storage_atomic.hpp"
|
||||
|
||||
#include <solanaceae/object_store/meta_components.hpp>
|
||||
#include <solanaceae/object_store/serializer_json.hpp>
|
||||
@ -29,17 +29,17 @@ static const char* metaFileTypeSuffix(MetaFileType mft) {
|
||||
|
||||
namespace Backends {
|
||||
|
||||
FilesystemStorage::FilesystemStorage(
|
||||
FilesystemStorageAtomic::FilesystemStorageAtomic(
|
||||
ObjectStore2& os,
|
||||
std::string_view storage_path,
|
||||
MetaFileType mft_new
|
||||
) : _os(os), _storage_path(storage_path), _mft_new(mft_new) {
|
||||
}
|
||||
|
||||
FilesystemStorage::~FilesystemStorage(void) {
|
||||
FilesystemStorageAtomic::~FilesystemStorageAtomic(void) {
|
||||
}
|
||||
|
||||
ObjectHandle FilesystemStorage::newObject(ByteSpan id, bool throw_construct) {
|
||||
ObjectHandle FilesystemStorageAtomic::newObject(ByteSpan id, bool throw_construct) {
|
||||
{ // first check if id is already used (TODO: solve the multi obj/backend problem)
|
||||
auto exising_oh = _os.getOneObjectByID(id);
|
||||
if (static_cast<bool>(exising_oh)) {
|
||||
@ -96,7 +96,7 @@ ObjectHandle FilesystemStorage::newObject(ByteSpan id, bool throw_construct) {
|
||||
return oh;
|
||||
}
|
||||
|
||||
bool FilesystemStorage::write(Object o, std::function<write_to_storage_fetch_data_cb>& data_cb) {
|
||||
bool FilesystemStorageAtomic::write(Object o, std::function<write_to_storage_fetch_data_cb>& data_cb) {
|
||||
auto& reg = _os.registry();
|
||||
|
||||
if (!reg.valid(o)) {
|
||||
@ -303,7 +303,7 @@ bool FilesystemStorage::write(Object o, std::function<write_to_storage_fetch_dat
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FilesystemStorage::read(Object o, std::function<read_from_storage_put_data_cb>& data_cb) {
|
||||
bool FilesystemStorageAtomic::read(Object o, std::function<read_from_storage_put_data_cb>& data_cb) {
|
||||
auto& reg = _os.registry();
|
||||
|
||||
if (!reg.valid(o)) {
|
||||
@ -355,11 +355,11 @@ bool FilesystemStorage::read(Object o, std::function<read_from_storage_put_data_
|
||||
return true;
|
||||
}
|
||||
|
||||
void FilesystemStorage::scanAsync(void) {
|
||||
void FilesystemStorageAtomic::scanAsync(void) {
|
||||
scanPathAsync(_storage_path);
|
||||
}
|
||||
|
||||
size_t FilesystemStorage::scanPath(std::string_view path) {
|
||||
size_t FilesystemStorageAtomic::scanPath(std::string_view path) {
|
||||
// TODO: extract so async can work (or/and make iteratable generator)
|
||||
|
||||
if (path.empty() || !std::filesystem::is_directory(path)) {
|
||||
@ -615,7 +615,7 @@ size_t FilesystemStorage::scanPath(std::string_view path) {
|
||||
return scanned_objs.size();
|
||||
}
|
||||
|
||||
void FilesystemStorage::scanPathAsync(std::string path) {
|
||||
void FilesystemStorageAtomic::scanPathAsync(std::string path) {
|
||||
// add path to queue
|
||||
// HACK: if path is known/any fragment is in the path, this operation blocks (non async)
|
||||
scanPath(path); // TODO: make async and post result
|
@ -9,15 +9,15 @@ namespace Backends {
|
||||
|
||||
// TODO: rename to atomic filesystem store?
|
||||
// provides meta and atomic read/write on your filesystem
|
||||
struct FilesystemStorage : public StorageBackendIMeta, public StorageBackendIAtomic {
|
||||
struct FilesystemStorageAtomic : public StorageBackendIMeta, public StorageBackendIAtomic {
|
||||
ObjectStore2& _os;
|
||||
|
||||
FilesystemStorage(
|
||||
FilesystemStorageAtomic(
|
||||
ObjectStore2& os,
|
||||
std::string_view storage_path = "test_obj_store",
|
||||
MetaFileType mft_new = MetaFileType::BINARY_MSGPACK
|
||||
);
|
||||
~FilesystemStorage(void);
|
||||
~FilesystemStorageAtomic(void);
|
||||
|
||||
// TODO: fix the path for this specific fs?
|
||||
// for now we assume a single storage path per backend (there can be multiple per type)
|
@ -9,8 +9,8 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// fwd enum (obj cant depend on Contact3
|
||||
enum class Contact3 : uint32_t;
|
||||
// fwd enum (obj cant depend on Contact4
|
||||
enum class Contact4 : uint32_t;
|
||||
|
||||
namespace ObjectStore::Components {
|
||||
|
||||
@ -38,7 +38,7 @@ namespace ObjectStore::Components {
|
||||
bool have_all {false};
|
||||
BitSet have;
|
||||
};
|
||||
entt::dense_map<Contact3, Entry> others;
|
||||
entt::dense_map<Contact4, Entry> others;
|
||||
};
|
||||
|
||||
|
||||
@ -137,7 +137,7 @@ namespace ObjectStore::Components {
|
||||
|
||||
#if 0
|
||||
struct TransferStatsSeparated {
|
||||
entt::dense_map<Contact3, TransferStats> stats;
|
||||
entt::dense_map<Contact4, TransferStats> stats;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -126,7 +126,7 @@ void ObjectStore2::throwEventDestroy(const Object o) {
|
||||
std::cout << "OS debug: event destroy " << entt::to_integral(o) << "\n";
|
||||
dispatch(
|
||||
ObjectStore_Event::object_destroy,
|
||||
ObjectStore::Events::ObjectUpdate{
|
||||
ObjectStore::Events::ObjectDestory{
|
||||
ObjectHandle{_reg, o}
|
||||
}
|
||||
);
|
||||
|
@ -49,7 +49,7 @@ struct StorageBackendIFile2 {
|
||||
FILE2_READ = 1u << 0,
|
||||
FILE2_WRITE = 1u << 1,
|
||||
|
||||
// only relevant for backend implementing this (ideally all)
|
||||
// only relevant for backends implementing this (ideally all)
|
||||
FILE2_NO_COMP = 1u << 2,// dont do any de-/compression
|
||||
FILE2_NO_ENC = 1u << 3, // dont do any de-/encryption
|
||||
|
||||
|
@ -12,3 +12,14 @@ target_link_libraries(solanaceae_file2_zstd_test PUBLIC
|
||||
|
||||
add_test(NAME solanaceae_file2_zstd_test COMMAND solanaceae_file2_zstd_test)
|
||||
|
||||
########################################
|
||||
|
||||
add_executable(solanaceae_backend_fs_atomic_test
|
||||
./test_backend_fs_atomic.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(solanaceae_backend_fs_atomic_test PUBLIC
|
||||
solanaceae_object_store_backend_filesystem
|
||||
)
|
||||
|
||||
add_test(NAME solanaceae_backend_fs_atomic_test COMMAND solanaceae_backend_fs_atomic_test)
|
||||
|
76
test/test_backend_fs_atomic.cpp
Normal file
76
test/test_backend_fs_atomic.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
#include <solanaceae/object_store/object_store.hpp>
|
||||
#include <solanaceae/object_store/backends/filesystem_storage_atomic.hpp>
|
||||
|
||||
#include <solanaceae/object_store/meta_components.hpp>
|
||||
#include <solanaceae/object_store/meta_components_file.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
int main(void) {
|
||||
const auto temp_dir_str = (std::filesystem::temp_directory_path() / "test_obj_store_tests").u8string();
|
||||
|
||||
assert(!std::filesystem::exists(temp_dir_str));
|
||||
|
||||
// test1, create store with 2 objects
|
||||
{
|
||||
ObjectStore2 os;
|
||||
Backends::FilesystemStorageAtomic fsa{os, temp_dir_str};
|
||||
|
||||
// empty, does nothing
|
||||
fsa.scanAsync();
|
||||
assert(!std::filesystem::exists(temp_dir_str));
|
||||
|
||||
{ // o1
|
||||
// id1
|
||||
std::vector<uint8_t> id{0x00, 0x13, 0x37, 0x01};
|
||||
auto o = fsa.newObject(ByteSpan{id});
|
||||
std::vector<uint8_t> data{0x01, 0x01, 0x11, 0xf1, 0xae, 0x0b, 0x33};
|
||||
static_cast<StorageBackendIAtomic&>(fsa).write(o, ByteSpan{data});
|
||||
}
|
||||
|
||||
{ // o2
|
||||
// id2
|
||||
std::vector<uint8_t> id{0x00, 0x13, 0x37, 0x02};
|
||||
auto o = fsa.newObject(ByteSpan{id});
|
||||
std::vector<uint8_t> data{0x11, 0x11, 0x11, 0xff, 0xff, 0xee, 0xee};
|
||||
static_cast<StorageBackendIAtomic&>(fsa).write(o, ByteSpan{data});
|
||||
}
|
||||
}
|
||||
|
||||
assert(std::filesystem::exists(temp_dir_str));
|
||||
|
||||
// test2, load store created in test1
|
||||
{
|
||||
ObjectStore2 os;
|
||||
|
||||
Backends::FilesystemStorageAtomic fsa{os, temp_dir_str};
|
||||
|
||||
fsa.scanAsync();
|
||||
|
||||
assert(os.registry().storage<Object>().size() == 2);
|
||||
|
||||
{ // o1
|
||||
std::vector<uint8_t> id{0x00, 0x13, 0x37, 0x01};
|
||||
auto o = os.getOneObjectByID(ByteSpan{id});
|
||||
assert(static_cast<bool>(o));
|
||||
|
||||
std::vector<uint8_t> orig_data{0x01, 0x01, 0x11, 0xf1, 0xae, 0x0b, 0x33};
|
||||
// TODO: read and test content
|
||||
|
||||
//static_cast<StorageBackendIAtomic&>(fsa).write(o, ByteSpan{data});
|
||||
}
|
||||
|
||||
{ // o2
|
||||
std::vector<uint8_t> id{0x00, 0x13, 0x37, 0x02};
|
||||
auto o = os.getOneObjectByID(ByteSpan{id});
|
||||
assert(static_cast<bool>(o));
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::remove_all(temp_dir_str);
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user