Compare commits

...

5 Commits

Author SHA1 Message Date
889761f538 rename fs atomic impl and add simple testcase
pre refactor
2025-04-30 16:10:56 +02:00
738e1a2071 refactor zstd cmake and prefer system lib 2025-04-06 20:50:16 +02:00
2d5478c19e fix last mentions of contact3 2025-03-12 22:21:11 +01:00
241a0c0906 fix destruction even and updated to contact4 2025-03-06 16:13:57 +01:00
0ba56d428f Create LICENSE 2025-02-07 12:53:42 +01:00
11 changed files with 162 additions and 44 deletions

21
LICENSE Normal file
View 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.

View File

@ -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
View 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()

View File

@ -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 .)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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}
}
);

View File

@ -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

View File

@ -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)

View 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;
}