├── .github ├── architecture.png ├── bench.gif └── logo.png ├── .gitignore ├── ARCHITECTURE.md ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── VERSION ├── build ├── CMakeLists.txt ├── cmake │ ├── FindLZ4.cmake │ └── FindZSTD.cmake └── launcher.sh ├── cli ├── bench.c ├── bench.h ├── makefile ├── monotone └── monotone.c ├── examples └── write_and_read.c ├── makefile ├── monotone ├── cloud │ ├── cloud │ │ ├── cloud.h │ │ ├── cloud_config.h │ │ ├── cloud_mgr.c │ │ ├── cloud_mgr.h │ │ ├── id.h │ │ ├── mock.c │ │ ├── mock.h │ │ ├── monotone_cloud.h │ │ └── source.h │ ├── makefile │ └── s3 │ │ ├── monotone_s3.h │ │ ├── s3.c │ │ ├── s3.h │ │ ├── s3_io.c │ │ ├── s3_io.h │ │ ├── s3_op.c │ │ ├── s3_op.h │ │ ├── s3_request.c │ │ └── s3_request.h ├── engine │ ├── engine │ │ ├── engine.c │ │ ├── engine.h │ │ ├── engine_cursor.h │ │ ├── engine_recover.c │ │ ├── engine_recover.h │ │ ├── engine_show.c │ │ ├── engine_show.h │ │ ├── lockage.h │ │ ├── monotone_engine.h │ │ ├── op.c │ │ ├── op.h │ │ ├── ref.h │ │ ├── refresh.c │ │ ├── refresh.h │ │ ├── service.h │ │ ├── service_req.h │ │ ├── worker.c │ │ ├── worker.h │ │ ├── worker_mgr.c │ │ ├── worker_mgr.h │ │ ├── write.c │ │ └── write.h │ ├── io │ │ ├── comparator.h │ │ ├── event.h │ │ ├── index.h │ │ ├── index_iterator.h │ │ ├── index_op.c │ │ ├── index_op.h │ │ ├── index_writer.h │ │ ├── iterator.h │ │ ├── mapping.h │ │ ├── memtable.c │ │ ├── memtable.h │ │ ├── memtable_iterator.h │ │ ├── merge_iterator.h │ │ ├── merger.c │ │ ├── merger.h │ │ ├── monotone_io.h │ │ ├── part.c │ │ ├── part.h │ │ ├── part_cursor.h │ │ ├── part_iterator.h │ │ ├── reader.h │ │ ├── region.h │ │ ├── region_iterator.h │ │ ├── region_writer.h │ │ ├── stats.h │ │ ├── writer.c │ │ └── writer.h │ ├── makefile │ ├── storage │ │ ├── monotone_storage.h │ │ ├── pipeline.c │ │ ├── pipeline.h │ │ ├── storage.h │ │ ├── storage_mgr.c │ │ ├── storage_mgr.h │ │ ├── tier.h │ │ └── tier_config.h │ └── wal │ │ ├── log.h │ │ ├── log_drop.h │ │ ├── log_write.h │ │ ├── monotone_wal.h │ │ ├── wal.c │ │ ├── wal.h │ │ ├── wal_cursor.c │ │ ├── wal_cursor.h │ │ ├── wal_file.h │ │ └── wal_id.h ├── main │ ├── api │ │ ├── monotone.c │ │ ├── monotone.h │ │ └── monotone_private.h │ ├── command │ │ ├── cmd.h │ │ ├── lex.c │ │ ├── lex.h │ │ ├── monotone_command.h │ │ ├── parse.c │ │ ├── parse.h │ │ ├── parse_cloud.c │ │ ├── parse_cloud.h │ │ ├── parse_config.c │ │ ├── parse_config.h │ │ ├── parse_debug.c │ │ ├── parse_debug.h │ │ ├── parse_misc.h │ │ ├── parse_partition.c │ │ ├── parse_partition.h │ │ ├── parse_pipeline.c │ │ ├── parse_pipeline.h │ │ ├── parse_storage.c │ │ ├── parse_storage.h │ │ └── parse_system.h │ ├── main │ │ ├── execute.c │ │ ├── execute.h │ │ ├── main.c │ │ ├── main.h │ │ └── monotone_main.h │ └── makefile ├── makefile └── runtime │ ├── config │ ├── config.c │ ├── config.h │ ├── control.h │ ├── error_injection.h │ ├── global.h │ ├── monotone_config.h │ └── var.h │ ├── lib │ ├── cache.h │ ├── compression.h │ ├── compression_lz4.c │ ├── compression_lz4.h │ ├── compression_mgr.c │ ├── compression_mgr.h │ ├── compression_zstd.c │ ├── compression_zstd.h │ ├── crc.c │ ├── crc.h │ ├── data.h │ ├── data_op.h │ ├── decode.h │ ├── encode.h │ ├── encryption.h │ ├── encryption_aes.c │ ├── encryption_aes.h │ ├── encryption_mgr.c │ ├── encryption_mgr.h │ ├── heap.h │ ├── json.c │ ├── json.h │ ├── memory_mgr.h │ ├── monotone_lib.h │ ├── random.c │ ├── random.h │ ├── rbtree.c │ ├── rbtree.h │ ├── uuid.c │ └── uuid.h │ ├── makefile │ └── runtime │ ├── allocator.h │ ├── atomic.h │ ├── buf.h │ ├── c.h │ ├── clock.h │ ├── cond_var.h │ ├── error.h │ ├── exception.h │ ├── file.h │ ├── fs.h │ ├── guard.h │ ├── iov.h │ ├── list.h │ ├── log.h │ ├── logger.c │ ├── logger.h │ ├── macro.h │ ├── misc.h │ ├── monotone_runtime.h │ ├── mutex.h │ ├── runtime.c │ ├── runtime.h │ ├── rwlock.h │ ├── spinlock.h │ ├── str.h │ ├── thread.h │ ├── throw.h │ ├── vfs.c │ └── vfs.h └── test ├── README.md ├── cloud ├── alter_cloud.test ├── alter_cloud.test.ok ├── cloud_drop.test ├── cloud_drop.test.ok ├── cloud_move.test ├── cloud_move.test.ok ├── cloud_rebalance.test ├── cloud_rebalance.test.ok ├── cloud_refresh.test ├── cloud_refresh.test.ok ├── cloud_storage.test ├── cloud_storage.test.ok ├── create_cloud.test ├── create_cloud.test.ok ├── download.test ├── download.test.ok ├── drop_cloud.test ├── drop_cloud.test.ok ├── upload.test └── upload.test.ok ├── functional ├── mapping.test ├── mapping.test.ok ├── mapping_custom.test ├── mapping_custom.test.ok ├── memtable.test ├── memtable.test.ok ├── partition.test ├── partition.test.ok ├── serial.test └── serial.test.ok ├── makefile ├── monotone-test ├── plan ├── recovery ├── crash.test ├── crash.test.ok ├── recovery_cloud.test ├── recovery_cloud.test.ok ├── recovery_config.test ├── recovery_config.test.ok ├── recovery_serial.test ├── recovery_serial.test.ok ├── recovery_storage.test ├── recovery_storage.test.ok ├── wal.test ├── wal.test.ok ├── wal_crc.test └── wal_crc.test.ok ├── s3 ├── s3.test └── s3.test.ok ├── storage ├── alter_pipeline.test ├── alter_pipeline.test.ok ├── alter_storage.test ├── alter_storage.test.ok ├── compression.test ├── compression.test.ok ├── create.test ├── create.test.ok ├── create_storage.test ├── create_storage.test.ok ├── drop.test ├── drop.test.ok ├── drop_storage.test ├── drop_storage.test.ok ├── encryption.test ├── encryption.test.ok ├── move.test ├── move.test.ok ├── rebalance.test ├── rebalance.test.ok ├── refresh.test ├── refresh.test.ok ├── service.test └── service.test.ok ├── suite ├── monotone_test.h ├── suite.c ├── suite.h ├── suite_cmd.c ├── suite_cmd.h └── test.h └── test.c /.github/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmwkaa/monotone/3613431cd3c1a05ab76455430bc9f93bc8332038/.github/architecture.png -------------------------------------------------------------------------------- /.github/bench.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmwkaa/monotone/3613431cd3c1a05ab76455430bc9f93bc8332038/.github/bench.gif -------------------------------------------------------------------------------- /.github/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmwkaa/monotone/3613431cd3c1a05ab76455430bc9f93bc8332038/.github/logo.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | cli/_benchmark 3 | test/core 4 | test/vgcore.* 5 | build/CMakeCache.txt 6 | build/CMakeFiles 7 | build/Makefile 8 | build/cmake_install.cmake 9 | build/libmonotone_so.c 10 | build/libmonotone.a 11 | build/libmonotone.so 12 | build/monotone-test 13 | build/monotone 14 | build/example_write_and_read 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### Monotone Changelog 2 | 3 | ## 1.1.0 (2025-02-13) 4 | 5 | Changing the project license to MIT 6 | 7 | ## 1.0.0 (2024-04-16) 8 | 9 | **The first public Monotone GA release.** 10 | 11 | Embeddable Cloud-Native Storage for events and time-series data. 12 | 13 | This release includes core functionality listed in the official 14 | documentation at the moment of release. 15 | 16 | https://monotone.studio 17 | 18 | **Features** 19 | 20 | - Automatic Range Partitioning 21 | - Transparent Compression 22 | - Transparent Encryption 23 | - Multiple Storages 24 | - Data Tiering 25 | - Bottomless Storage 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2025 Dmitry Simonenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.1.0 2 | -------------------------------------------------------------------------------- /build/cmake/FindLZ4.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Find the LZ4 compression library 3 | # 4 | # export: 5 | # 6 | # LZ4_INCLUDE_DIR 7 | # LZ4_LIBRARIES 8 | # LZ4_FOUND 9 | # 10 | 11 | find_path(LZ4_INCLUDE_DIR 12 | NAMES lz4frame.h 13 | HINTS ${LZ4_ROOT_DIR}/include) 14 | 15 | find_library(LZ4_LIBRARIES 16 | NAMES lz4 17 | HINTS ${LZ4_ROOT_DIR}/lib) 18 | 19 | include(FindPackageHandleStandardArgs) 20 | find_package_handle_standard_args(LZ4 DEFAULT_MSG LZ4_LIBRARIES LZ4_INCLUDE_DIR) 21 | 22 | mark_as_advanced(LZ4_LIBRARIES LZ4_INCLUDE_DIR) 23 | -------------------------------------------------------------------------------- /build/cmake/FindZSTD.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Find the Zstd compression library 3 | # 4 | # export: 5 | # 6 | # ZSTD_INCLUDE_DIR 7 | # ZSTD_LIBRARIES 8 | # ZSTD_FOUND 9 | # 10 | 11 | find_path(ZSTD_INCLUDE_DIR 12 | NAMES zstd.h 13 | HINTS ${ZSTD_ROOT_DIR}/include) 14 | 15 | find_library(ZSTD_LIBRARIES 16 | NAMES zstd 17 | HINTS ${ZSTD_ROOT_DIR}/lib) 18 | 19 | include(FindPackageHandleStandardArgs) 20 | find_package_handle_standard_args(ZSTD DEFAULT_MSG ZSTD_LIBRARIES ZSTD_INCLUDE_DIR) 21 | 22 | mark_as_advanced(ZSTD_LIBRARIES ZSTD_INCLUDE_DIR) 23 | -------------------------------------------------------------------------------- /build/launcher.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # compiler call wrapper 4 | # 5 | # extract CC -c and -o 6 | # 7 | path_compile= 8 | path_output= 9 | for ((arg=1; arg<=$#; arg++)); do 10 | next=$((arg+1)) 11 | if [ "${!arg}" == "-c" ]; then 12 | path_compile="${!next}" 13 | elif [ "${!arg}" == "-o" ]; then 14 | path_output="${!next}" 15 | fi 16 | done 17 | 18 | # linker or compiler call 19 | if [ -z "$path_compile" ]; then 20 | echo "$1 -o $path_output" 21 | else 22 | # shorten path to / 23 | path_rel=`echo ${path_compile} | awk -F "/" '{ print $(NF-1) "/" $NF }'` 24 | echo "$1 -c ${path_rel}" 25 | fi 26 | 27 | exec "$@" 28 | -------------------------------------------------------------------------------- /cli/bench.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Instance Instance; 15 | typedef struct BenchConfig BenchConfig; 16 | typedef struct Bench Bench; 17 | 18 | struct Instance 19 | { 20 | volatile bool writer_active; 21 | pthread_t writer_id; 22 | atomic_u64 written; 23 | atomic_u64 written_bytes; 24 | uint64_t written_last; 25 | uint64_t written_last_bytes; 26 | monotone_t* env; 27 | BenchConfig* config; 28 | }; 29 | 30 | struct BenchConfig 31 | { 32 | const char* path; 33 | int instances; 34 | int workers; 35 | int size_event; 36 | int size_metric; 37 | int size_batch; 38 | bool cloud; 39 | bool wal; 40 | }; 41 | 42 | struct Bench 43 | { 44 | bool active; 45 | volatile bool report_active; 46 | pthread_t report_id; 47 | atomic_u32 current; 48 | int instances_count; 49 | Instance* instances; 50 | BenchConfig* config; 51 | }; 52 | 53 | void bench_init(Bench*); 54 | int bench_main(Bench*, BenchConfig*); 55 | -------------------------------------------------------------------------------- /cli/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @(cd .. && make --no-print-directory) 3 | clean: 4 | @(cd .. && make --no-print-directory clean) 5 | -------------------------------------------------------------------------------- /cli/monotone: -------------------------------------------------------------------------------- 1 | ../build/monotone -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | all: build/CMakeCache.txt 2 | @(cd build && make --no-print-directory) 3 | build/CMakeCache.txt: 4 | @(cd build && cmake -DCMAKE_BUILD_TYPE=Debug .) 5 | debug: 6 | @(cd build && cmake -DCMAKE_BUILD_TYPE=Debug .) 7 | @(echo) 8 | @(cd build && make --no-print-directory) 9 | release: 10 | @(cd build && cmake -DCMAKE_BUILD_TYPE=Release .) 11 | @(echo) 12 | @(cd build && make --no-print-directory) 13 | clean: 14 | @(cd build && make clean --no-print-directory) 15 | -------------------------------------------------------------------------------- /monotone/cloud/cloud/cloud.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct CloudIf CloudIf; 15 | typedef struct Cloud Cloud; 16 | 17 | struct CloudIf 18 | { 19 | Cloud* (*create)(CloudIf*, CloudConfig*); 20 | void (*free)(Cloud*); 21 | void (*attach)(Cloud*, Source*); 22 | void (*detach)(Cloud*, Source*); 23 | void (*download)(Cloud*, Source*, Id*); 24 | void (*upload)(Cloud*, Source*, Id*); 25 | void (*remove)(Cloud*, Source*, Id*); 26 | void (*read)(Cloud*, Source*, Id*, Buf*, uint32_t, uint64_t); 27 | }; 28 | 29 | struct Cloud 30 | { 31 | int refs; 32 | CloudIf* iface; 33 | CloudConfig* config; 34 | List link; 35 | }; 36 | 37 | static inline Cloud* 38 | cloud_allocate(CloudIf* iface, CloudConfig* config) 39 | { 40 | return iface->create(iface, config); 41 | } 42 | 43 | static inline void 44 | cloud_free(Cloud* self) 45 | { 46 | self->iface->free(self); 47 | } 48 | 49 | static inline void 50 | cloud_ref(Cloud* self) 51 | { 52 | self->refs++; 53 | } 54 | 55 | static inline void 56 | cloud_unref(Cloud* self) 57 | { 58 | self->refs--; 59 | } 60 | 61 | static inline void 62 | cloud_attach(Cloud* self, Source* source) 63 | { 64 | self->iface->attach(self, source); 65 | } 66 | 67 | static inline void 68 | cloud_detach(Cloud* self, Source* source) 69 | { 70 | self->iface->detach(self, source); 71 | } 72 | 73 | static inline void 74 | cloud_download(Cloud* self, Source* source, Id* id) 75 | { 76 | self->iface->download(self, source, id); 77 | } 78 | 79 | static inline void 80 | cloud_upload(Cloud* self, Source* source, Id* id) 81 | { 82 | self->iface->upload(self, source, id); 83 | } 84 | 85 | static inline void 86 | cloud_remove(Cloud* self, Source* source, Id* id) 87 | { 88 | self->iface->remove(self, source, id); 89 | } 90 | 91 | static inline void 92 | cloud_read(Cloud* self, Source* source, Id* id, Buf* buf, 93 | uint32_t size, uint64_t offset) 94 | { 95 | self->iface->read(self, source, id, buf, size, offset); 96 | } 97 | -------------------------------------------------------------------------------- /monotone/cloud/cloud/cloud_mgr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct CloudMgr CloudMgr; 15 | 16 | struct CloudMgr 17 | { 18 | List list; 19 | int list_count; 20 | }; 21 | 22 | void cloud_mgr_init(CloudMgr*); 23 | void cloud_mgr_free(CloudMgr*); 24 | void cloud_mgr_open(CloudMgr*); 25 | void cloud_mgr_create(CloudMgr*, CloudConfig*, bool); 26 | void cloud_mgr_drop(CloudMgr*, Str*, bool); 27 | void cloud_mgr_alter(CloudMgr*, CloudConfig*, int, bool); 28 | void cloud_mgr_rename(CloudMgr*, Str*, Str*, bool); 29 | void cloud_mgr_show(CloudMgr*, Str*, Buf*); 30 | Cloud* 31 | cloud_mgr_find(CloudMgr*, Str*); 32 | -------------------------------------------------------------------------------- /monotone/cloud/cloud/id.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Id Id; 15 | 16 | enum 17 | { 18 | ID_NONE = 0, 19 | ID = 1 << 0, 20 | ID_INCOMPLETE = 1 << 1, 21 | ID_COMPLETE = 1 << 2, 22 | ID_CLOUD = 1 << 3, 23 | ID_CLOUD_INCOMPLETE = 1 << 4 24 | }; 25 | 26 | struct Id 27 | { 28 | uint64_t min; 29 | uint64_t max; 30 | } packed; 31 | 32 | static inline void 33 | id_path(Id* self, Source* source, int state, char* path) 34 | { 35 | switch (state) { 36 | case ID: 37 | // / 38 | source_pathfmt(source, path, PATH_MAX, "%020" PRIu64, self->min); 39 | break; 40 | case ID_INCOMPLETE: 41 | // /.incomplete 42 | source_pathfmt(source, path, PATH_MAX, "%020" PRIu64 ".incomplete", 43 | self->min); 44 | break; 45 | case ID_COMPLETE: 46 | // /.complete 47 | source_pathfmt(source, path, PATH_MAX, "%020" PRIu64 ".complete", 48 | self->min); 49 | break; 50 | case ID_CLOUD: 51 | // /.cloud 52 | source_pathfmt(source, path, PATH_MAX, "%020" PRIu64 ".cloud", 53 | self->min); 54 | break; 55 | case ID_CLOUD_INCOMPLETE: 56 | // /.cloud.incomplete 57 | source_pathfmt(source, path, PATH_MAX, "%020" PRIu64 ".cloud.incomplete", 58 | self->min); 59 | break; 60 | default: 61 | abort(); 62 | break; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /monotone/cloud/cloud/mock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | extern CloudIf cloud_mock; 15 | -------------------------------------------------------------------------------- /monotone/cloud/cloud/monotone_cloud.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | // source 15 | #include "cloud/source.h" 16 | #include "cloud/id.h" 17 | 18 | // cloud 19 | #include "cloud/cloud_config.h" 20 | #include "cloud/cloud.h" 21 | #include "cloud/cloud_mgr.h" 22 | 23 | // cloud mock 24 | #include "cloud/mock.h" 25 | -------------------------------------------------------------------------------- /monotone/cloud/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @(cd ../.. && make --no-print-directory) 3 | clean: 4 | @(cd ../.. && make --no-print-directory clean) 5 | -------------------------------------------------------------------------------- /monotone/cloud/s3/monotone_s3.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | #include "s3/s3_io.h" 15 | #include "s3/s3_request.h" 16 | #include "s3/s3_op.h" 17 | #include "s3/s3.h" 18 | -------------------------------------------------------------------------------- /monotone/cloud/s3/s3.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct S3 S3; 15 | 16 | struct S3 17 | { 18 | Cloud cloud; 19 | Cache cache; 20 | }; 21 | 22 | always_inline static inline S3* 23 | s3_of(Cloud* self) 24 | { 25 | return (S3*)self; 26 | } 27 | 28 | extern CloudIf cloud_s3; 29 | -------------------------------------------------------------------------------- /monotone/cloud/s3/s3_io.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // monotone. 4 | // 5 | // embeddable cloud-native storage for events 6 | // and time-series data. 7 | // 8 | // Copyright (c) 2023-2025 Dmitry Simonenko 9 | // 10 | // MIT Licensed. 11 | // 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | S3Io* 25 | s3_io_allocate(Cloud* cloud) 26 | { 27 | auto self = (S3Io*)mn_malloc(sizeof(S3Io)); 28 | list_init(&self->link); 29 | self->cloud = cloud; 30 | self->handle = curl_easy_init(); 31 | if (self->handle == NULL) 32 | { 33 | mn_free(self); 34 | error_system(); 35 | } 36 | return self; 37 | } 38 | 39 | void 40 | s3_io_free(S3Io* self) 41 | { 42 | if (self->handle) 43 | curl_easy_cleanup(self->handle); 44 | mn_free(self); 45 | } 46 | -------------------------------------------------------------------------------- /monotone/cloud/s3/s3_io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct S3Io S3Io; 15 | 16 | typedef size_t (*S3Function)(void* ptr, size_t len, size_t nmemb, void* arg); 17 | 18 | struct S3Io 19 | { 20 | void* handle; 21 | Cloud* cloud; 22 | List link; 23 | }; 24 | 25 | S3Io* s3_io_allocate(Cloud*); 26 | void s3_io_free(S3Io*); 27 | -------------------------------------------------------------------------------- /monotone/cloud/s3/s3_op.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct S3Upload S3Upload; 15 | 16 | struct S3Upload 17 | { 18 | File* file; 19 | uint64_t file_offset; 20 | S3Io* io; 21 | }; 22 | 23 | void s3_op_download(S3Io*, Source*, Id*, File*); 24 | void s3_op_upload(S3Io*, Source*, Id*, File*); 25 | void s3_op_delete(S3Io*, Source*, Id*); 26 | void s3_op_read(S3Io*, Source*, Id*, Buf*, uint32_t, uint64_t); 27 | void s3_op_create_bucket(S3Io*, Source*); 28 | void s3_op_drop_bucket(S3Io*, Source*); 29 | -------------------------------------------------------------------------------- /monotone/cloud/s3/s3_request.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct S3Request S3Request; 15 | 16 | struct S3Request 17 | { 18 | S3Io* io; 19 | S3Function on_read; 20 | S3Function on_write; 21 | void* arg; 22 | Source* source; 23 | Id* id; 24 | const char* method; 25 | const char* content_type; 26 | uint64_t content_length; 27 | const char* range; 28 | char date[64]; 29 | char authorization[256]; 30 | char url[1024]; 31 | }; 32 | 33 | void s3_request_execute(S3Request*); 34 | -------------------------------------------------------------------------------- /monotone/engine/engine/engine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Engine Engine; 15 | 16 | struct Engine 17 | { 18 | // locking 19 | Mutex lock; 20 | CondVar cond_var; 21 | // partition mapping 22 | Mapping mapping; 23 | // objects 24 | Pipeline pipeline; 25 | StorageMgr storage_mgr; 26 | Wal* wal; 27 | Service* service; 28 | Comparator* comparator; 29 | }; 30 | 31 | void engine_init(Engine*, Comparator*, Wal*, Service*, CloudMgr*); 32 | void engine_free(Engine*); 33 | void engine_open(Engine*); 34 | void engine_close(Engine*); 35 | void engine_set_serial(Engine*); 36 | Ref* engine_lock(Engine*, uint64_t, LockType, bool, bool); 37 | void engine_unlock(Engine*, Ref*, LockType); 38 | -------------------------------------------------------------------------------- /monotone/engine/engine/engine_recover.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | void engine_recover(Engine*); 15 | -------------------------------------------------------------------------------- /monotone/engine/engine/engine_show.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | enum 15 | { 16 | ENGINE_SHOW_STORAGES, 17 | ENGINE_SHOW_PARTITION, 18 | ENGINE_SHOW_PARTITIONS 19 | }; 20 | 21 | void engine_show(Engine*, int, Str*, uint64_t, Buf*, bool); 22 | -------------------------------------------------------------------------------- /monotone/engine/engine/lockage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Lock Lock; 15 | typedef struct Lockage Lockage; 16 | 17 | typedef enum 18 | { 19 | LOCK_SERVICE, 20 | LOCK_ACCESS, 21 | LOCK_MAX 22 | } LockType; 23 | 24 | struct Lock 25 | { 26 | pthread_t locker; 27 | int locker_refs; 28 | int pending; 29 | }; 30 | 31 | struct Lockage 32 | { 33 | Lock locks[LOCK_MAX]; 34 | Mutex* mutex; 35 | CondVar* cond_var; 36 | }; 37 | 38 | static inline void 39 | lockage_init(Lockage* self) 40 | { 41 | LockType type = LOCK_SERVICE; 42 | for (; type < LOCK_MAX; type++) 43 | { 44 | auto lock = &self->locks[type]; 45 | lock->locker = 0; 46 | lock->locker_refs = 0; 47 | lock->pending = 0; 48 | } 49 | self->mutex = NULL; 50 | self->cond_var = NULL; 51 | } 52 | 53 | static inline void 54 | lockage_set(Lockage* self, Mutex* mutex, CondVar* cond_var) 55 | { 56 | self->mutex = mutex; 57 | self->cond_var = cond_var; 58 | } 59 | 60 | static inline void 61 | lockage_lock(Lockage* self, LockType type) 62 | { 63 | // mutex must be always taken before this call 64 | auto lock = &self->locks[type]; 65 | 66 | // nested call 67 | pthread_t pthread_id = pthread_self(); 68 | if (pthread_equal(pthread_id, lock->locker)) 69 | { 70 | lock->locker_refs++; 71 | return; 72 | } 73 | 74 | // wait for lock 75 | for (;;) 76 | { 77 | if (lock->locker == 0) 78 | { 79 | lock->locker = pthread_id; 80 | lock->locker_refs = 0; 81 | break; 82 | } 83 | lock->pending++; 84 | cond_var_wait(self->cond_var, self->mutex); 85 | lock->pending--; 86 | } 87 | } 88 | 89 | static inline void 90 | lockage_unlock(Lockage* self, LockType type) 91 | { 92 | // mutex must be always taken before this call 93 | auto lock = &self->locks[type]; 94 | 95 | lock->locker_refs--; 96 | if (lock->locker_refs > 0) 97 | return; 98 | 99 | // wakeup waiter 100 | lock->locker = 0; 101 | lock->locker_refs = 0; 102 | if (lock->pending > 0) 103 | { 104 | // using broadcast since cond var can be shared between 105 | // other lock types 106 | cond_var_broadcast(self->cond_var); 107 | return; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /monotone/engine/engine/monotone_engine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | // service 15 | #include "engine/service_req.h" 16 | #include "engine/service.h" 17 | 18 | // partition reference 19 | #include "engine/lockage.h" 20 | #include "engine/ref.h" 21 | 22 | // engine 23 | #include "engine/engine.h" 24 | #include "engine/engine_recover.h" 25 | #include "engine/engine_cursor.h" 26 | #include "engine/engine_show.h" 27 | #include "engine/write.h" 28 | 29 | // refresh 30 | #include "engine/refresh.h" 31 | 32 | // service operations 33 | #include "engine/op.h" 34 | 35 | // worker 36 | #include "engine/worker.h" 37 | #include "engine/worker_mgr.h" 38 | -------------------------------------------------------------------------------- /monotone/engine/engine/op.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | // operations 15 | void engine_fill_nolock(Engine*, uint64_t, uint64_t); 16 | void engine_fill(Engine*, uint64_t, uint64_t); 17 | void engine_drop(Engine*, uint64_t, bool, int); 18 | void engine_drop_range(Engine*, uint64_t, uint64_t, int); 19 | 20 | // cloud 21 | void engine_download(Engine*, uint64_t, bool, bool); 22 | void engine_download_range(Engine*, uint64_t, uint64_t, bool); 23 | void engine_upload(Engine*, uint64_t, bool, bool); 24 | void engine_upload_range(Engine*, uint64_t, uint64_t, bool); 25 | void engine_refresh(Engine*, Refresh*, uint64_t, Str*, bool); 26 | void engine_refresh_range(Engine*, Refresh*, uint64_t, uint64_t, Str*); 27 | 28 | // general 29 | void engine_rebalance(Engine*, Refresh*); 30 | void engine_checkpoint(Engine*); 31 | void engine_gc(Engine*); 32 | 33 | // service 34 | bool engine_service(Engine*, Refresh*, ServiceFilter, bool); 35 | void engine_resume(Engine*); 36 | -------------------------------------------------------------------------------- /monotone/engine/engine/ref.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Ref Ref; 15 | 16 | struct Ref 17 | { 18 | Part* part; 19 | Lockage lockage; 20 | Slice slice; 21 | }; 22 | 23 | static inline Ref* 24 | ref_allocate(uint64_t min, uint64_t max) 25 | { 26 | auto self = (Ref*)mn_malloc(sizeof(Ref)); 27 | self->part = NULL; 28 | lockage_init(&self->lockage); 29 | slice_init(&self->slice, min, max); 30 | return self; 31 | } 32 | 33 | static inline void 34 | ref_free(Ref* self) 35 | { 36 | if (self->part) 37 | part_free(self->part); 38 | mn_free(self); 39 | } 40 | 41 | static inline void 42 | ref_prepare(Ref* self, Mutex* mutex, CondVar* cond_var, Part* part) 43 | { 44 | self->part = part; 45 | lockage_set(&self->lockage, mutex, cond_var); 46 | } 47 | 48 | always_inline static inline Ref* 49 | ref_of(Slice* slice) 50 | { 51 | return container_of(slice, Ref, slice); 52 | } 53 | 54 | static inline void 55 | ref_lock(Ref* self, LockType type) 56 | { 57 | lockage_lock(&self->lockage, type); 58 | } 59 | 60 | static inline void 61 | ref_unlock(Ref* self, LockType type) 62 | { 63 | lockage_unlock(&self->lockage, type); 64 | } 65 | -------------------------------------------------------------------------------- /monotone/engine/engine/refresh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Refresh Refresh; 15 | 16 | struct Refresh 17 | { 18 | Ref* ref; 19 | Part* origin; 20 | Part* part; 21 | Memtable* memtable; 22 | Storage* storage_origin; 23 | Storage* storage; 24 | Merger merger; 25 | Engine* engine; 26 | }; 27 | 28 | void refresh_init(Refresh*, Engine*); 29 | void refresh_free(Refresh*); 30 | void refresh_reset(Refresh*); 31 | void refresh_run(Refresh*, uint64_t, Str*, bool); 32 | -------------------------------------------------------------------------------- /monotone/engine/engine/service_req.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Action Action; 15 | typedef struct ServiceReq ServiceReq; 16 | 17 | typedef enum 18 | { 19 | ACTION_NONE, 20 | ACTION_ROTATE, 21 | ACTION_GC, 22 | ACTION_REBALANCE, 23 | ACTION_DROP_ON_STORAGE, 24 | ACTION_DROP_ON_CLOUD, 25 | ACTION_REFRESH, 26 | ACTION_DOWNLOAD, 27 | ACTION_UPLOAD 28 | } ActionType; 29 | 30 | struct Action 31 | { 32 | ActionType type; 33 | }; 34 | 35 | struct ServiceReq 36 | { 37 | uint64_t id; 38 | List link; 39 | int current; 40 | int actions_count; 41 | Action actions[]; 42 | }; 43 | 44 | static inline ServiceReq* 45 | service_req_allocate(uint64_t id, int count, va_list args) 46 | { 47 | auto self = (ServiceReq*)mn_malloc(sizeof(ServiceReq) + sizeof(Action) * count); 48 | self->id = id; 49 | self->current = 0; 50 | self->actions_count = count; 51 | list_init(&self->link); 52 | for (int i = 0; i < count; i++) 53 | self->actions[i].type = va_arg(args, ActionType); 54 | return self; 55 | } 56 | 57 | static inline void 58 | service_req_free(ServiceReq* self) 59 | { 60 | mn_free(self); 61 | } 62 | 63 | static inline bool 64 | service_req_is_upload(ServiceReq* self) 65 | { 66 | return self->actions[self->current].type == ACTION_UPLOAD; 67 | } 68 | -------------------------------------------------------------------------------- /monotone/engine/engine/worker.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // monotone. 4 | // 5 | // embeddable cloud-native storage for events 6 | // and time-series data. 7 | // 8 | // Copyright (c) 2023-2025 Dmitry Simonenko 9 | // 10 | // MIT Licensed. 11 | // 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | static void* 23 | worker_main(void* arg) 24 | { 25 | Worker* self = arg; 26 | runtime_init(self->context); 27 | thread_set_name(&self->thread, "worker"); 28 | 29 | for (;;) 30 | { 31 | bool shutdown = engine_service(self->engine, &self->refresh, self->filter, true); 32 | if (shutdown) 33 | break; 34 | } 35 | 36 | return NULL; 37 | } 38 | 39 | void 40 | worker_init(Worker* self, Engine* engine, ServiceFilter filter) 41 | { 42 | self->engine = engine; 43 | self->filter = filter; 44 | self->context = NULL; 45 | refresh_init(&self->refresh, engine); 46 | thread_init(&self->thread); 47 | } 48 | 49 | void 50 | worker_free(Worker* self) 51 | { 52 | refresh_free(&self->refresh); 53 | } 54 | 55 | void 56 | worker_start(Worker* self) 57 | { 58 | self->context = mn_runtime.context; 59 | int rc; 60 | rc = thread_create(&self->thread, worker_main, self); 61 | if (unlikely(rc == -1)) 62 | error_system(); 63 | } 64 | 65 | void 66 | worker_stop(Worker* self) 67 | { 68 | thread_join(&self->thread); 69 | } 70 | -------------------------------------------------------------------------------- /monotone/engine/engine/worker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Worker Worker; 15 | 16 | struct Worker 17 | { 18 | Refresh refresh; 19 | Engine* engine; 20 | ServiceFilter filter; 21 | Context* context; 22 | Thread thread; 23 | }; 24 | 25 | void worker_init(Worker*, Engine*, ServiceFilter); 26 | void worker_free(Worker*); 27 | void worker_start(Worker*); 28 | void worker_stop(Worker*); 29 | -------------------------------------------------------------------------------- /monotone/engine/engine/worker_mgr.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // monotone. 4 | // 5 | // embeddable cloud-native storage for events 6 | // and time-series data. 7 | // 8 | // Copyright (c) 2023-2025 Dmitry Simonenko 9 | // 10 | // MIT Licensed. 11 | // 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | void 23 | worker_mgr_init(WorkerMgr* self) 24 | { 25 | self->workers = NULL; 26 | self->workers_count = 0; 27 | } 28 | 29 | void 30 | worker_mgr_start(WorkerMgr* self, Engine* engine) 31 | { 32 | int workers = config_workers(); 33 | int workers_upload = config_workers_upload(); 34 | 35 | self->workers_count = workers + workers_upload; 36 | self->workers = mn_malloc(sizeof(Worker) * self->workers_count); 37 | 38 | int i = 0; 39 | if (workers_upload == 0) 40 | { 41 | for (; i < workers; i++) 42 | worker_init(&self->workers[i], engine, SERVICE_ANY); 43 | } else 44 | { 45 | for (; i < workers; i++) 46 | worker_init(&self->workers[i], engine, SERVICE_WITHOUT_UPLOAD); 47 | for (; i < self->workers_count; i++) 48 | worker_init(&self->workers[i], engine, SERVICE_UPLOAD); 49 | } 50 | for (i = 0; i < self->workers_count; i++) 51 | worker_start(&self->workers[i]); 52 | } 53 | 54 | void 55 | worker_mgr_stop(WorkerMgr* self) 56 | { 57 | for (int i = 0; i < self->workers_count; i++) 58 | { 59 | worker_stop(&self->workers[i]); 60 | worker_free(&self->workers[i]); 61 | } 62 | mn_free(self->workers); 63 | self->workers = NULL; 64 | self->workers_count = 0; 65 | } 66 | -------------------------------------------------------------------------------- /monotone/engine/engine/worker_mgr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct WorkerMgr WorkerMgr; 15 | 16 | struct WorkerMgr 17 | { 18 | int workers_count; 19 | Worker* workers; 20 | }; 21 | 22 | void worker_mgr_init(WorkerMgr*); 23 | void worker_mgr_start(WorkerMgr*, Engine*); 24 | void worker_mgr_stop(WorkerMgr*); 25 | -------------------------------------------------------------------------------- /monotone/engine/engine/write.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | void engine_write(Engine*, EventArg*, int); 15 | void engine_write_replay(Engine*, LogWrite*); 16 | -------------------------------------------------------------------------------- /monotone/engine/io/comparator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Comparator Comparator; 15 | 16 | struct Comparator 17 | { 18 | int unused; 19 | }; 20 | 21 | static inline void 22 | comparator_init(Comparator* self) 23 | { 24 | self->unused = 0; 25 | } 26 | 27 | hot static inline int64_t 28 | compare(Comparator* self, Event* a, Event* b) 29 | { 30 | unused(self); 31 | // compare by [id, key] 32 | int64_t diff = a->id - b->id; 33 | if (likely(diff != 0)) 34 | return diff; 35 | if (a->key_size == 0 && b->key_size == 0) 36 | return 0; 37 | int size; 38 | if (a->key_size < b->key_size) 39 | size = a->key_size; 40 | else 41 | size = b->key_size; 42 | int rc = memcmp(a->data, b->data, size); 43 | if (rc == 0) 44 | return (int64_t)a->key_size - (int64_t)b->key_size; 45 | return rc; 46 | } 47 | -------------------------------------------------------------------------------- /monotone/engine/io/event.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct EventArg EventArg; 15 | typedef struct Event Event; 16 | 17 | enum 18 | { 19 | MN_DELETE = 1 20 | }; 21 | 22 | struct EventArg 23 | { 24 | int flags; 25 | uint64_t id; 26 | void* key; 27 | size_t key_size; 28 | void* value; 29 | size_t value_size; 30 | }; 31 | 32 | struct Event 33 | { 34 | uint64_t id; 35 | uint8_t flags; 36 | uint8_t key_size; 37 | uint32_t data_size; 38 | uint8_t data[]; 39 | } packed; 40 | 41 | always_inline hot static inline int 42 | event_is_delete(Event* self) 43 | { 44 | return self->flags & MN_DELETE; 45 | } 46 | 47 | always_inline hot static inline int 48 | event_size(Event* self) 49 | { 50 | return sizeof(Event) + self->key_size + self->data_size; 51 | } 52 | 53 | always_inline hot static inline uint8_t* 54 | event_key(Event* self) 55 | { 56 | return self->data; 57 | } 58 | 59 | always_inline hot static inline uint8_t* 60 | event_value(Event* self) 61 | { 62 | return self->data + self->key_size; 63 | } 64 | 65 | hot static inline void 66 | event_init(Event* self, EventArg* arg) 67 | { 68 | self->id = arg->id; 69 | self->flags = arg->flags; 70 | self->key_size = arg->key_size; 71 | self->data_size = arg->key_size + arg->value_size; 72 | if (arg->key_size > 0) 73 | memcpy(self->data, arg->key, arg->key_size); 74 | if (arg->value_size > 0) 75 | memcpy(self->data + arg->key_size, arg->value, arg->value_size); 76 | } 77 | 78 | static inline Event* 79 | event_allocate(Heap* heap, EventArg* arg) 80 | { 81 | auto arg_size = arg->key_size + arg->value_size; 82 | auto event = (Event*)heap_allocate(heap, sizeof(Event) + arg_size); 83 | event_init(event, arg); 84 | return event; 85 | } 86 | 87 | static inline Event* 88 | event_copy(Heap* heap, Event* src) 89 | { 90 | auto event = (Event*)heap_allocate(heap, event_size(src)); 91 | memcpy(event, src, event_size(src)); 92 | return event; 93 | } 94 | 95 | static inline Event* 96 | event_malloc(EventArg* arg) 97 | { 98 | auto arg_size = arg->key_size + arg->value_size; 99 | auto event = (Event*)mn_malloc(sizeof(Event) + arg_size); 100 | event_init(event, arg); 101 | return event; 102 | } 103 | 104 | always_inline static inline void 105 | event_free(Event* self) 106 | { 107 | mn_free(self); 108 | } 109 | -------------------------------------------------------------------------------- /monotone/engine/io/index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct IndexRegion IndexRegion; 15 | typedef struct Index Index; 16 | 17 | #define INDEX_MAGIC 0x20849615 18 | #define INDEX_VERSION 0 19 | 20 | struct IndexRegion 21 | { 22 | uint32_t offset; 23 | uint32_t crc; 24 | uint64_t min; 25 | uint64_t max; 26 | uint32_t size; 27 | uint32_t size_origin; 28 | uint32_t events; 29 | uint32_t reserved[4]; 30 | } packed; 31 | 32 | struct Index 33 | { 34 | uint32_t crc; 35 | uint32_t crc_data; 36 | uint32_t magic; 37 | uint32_t version; 38 | Id id; 39 | uint32_t size; 40 | uint32_t size_origin; 41 | uint64_t size_regions; 42 | uint64_t size_regions_origin; 43 | uint64_t size_total; 44 | uint64_t size_total_origin; 45 | uint32_t regions; 46 | uint64_t events; 47 | uint64_t time_create; 48 | uint64_t time_refresh; 49 | uint32_t refreshes; 50 | uint64_t lsn; 51 | uint8_t compression; 52 | uint8_t encryption; 53 | uint32_t reserved[4]; 54 | } packed; 55 | 56 | static inline void 57 | index_init(Index* self) 58 | { 59 | memset(self, 0, sizeof(*self)); 60 | } 61 | 62 | static inline IndexRegion* 63 | index_get(Index* self, Buf* data, int pos) 64 | { 65 | unused(self); 66 | assert(pos < (int)self->regions); 67 | return &((IndexRegion*)data->start)[pos]; 68 | } 69 | 70 | static inline uint64_t 71 | index_region_min(Index* self, Buf* data, int pos) 72 | { 73 | return index_get(self, data, pos)->min; 74 | } 75 | 76 | static inline uint64_t 77 | index_region_max(Index* self, Buf* data, int pos) 78 | { 79 | return index_get(self, data, pos)->max; 80 | } 81 | 82 | static inline uint64_t 83 | index_min(Index* self, Buf* data) 84 | { 85 | return index_region_min(self, data, 0); 86 | } 87 | 88 | static inline uint64_t 89 | index_max(Index* self, Buf* data) 90 | { 91 | return index_region_max(self, data, self->regions - 1); 92 | } 93 | -------------------------------------------------------------------------------- /monotone/engine/io/index_iterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct IndexIterator IndexIterator; 15 | 16 | struct IndexIterator 17 | { 18 | Index* index; 19 | Buf* index_data; 20 | IndexRegion* current; 21 | int pos; 22 | }; 23 | 24 | static inline void 25 | index_iterator_init(IndexIterator* self) 26 | { 27 | self->index = NULL; 28 | self->index_data = NULL; 29 | self->current = NULL; 30 | self->pos = 0; 31 | } 32 | 33 | hot static inline int 34 | index_iterator_search(IndexIterator* self, uint64_t id) 35 | { 36 | int begin = 0; 37 | int end = self->index->regions - 1; 38 | while (begin != end) 39 | { 40 | int mid = begin + (end - begin) / 2; 41 | auto at = index_region_max(self->index, self->index_data, mid); 42 | if (compare_u64(at, id) < 0) 43 | begin = mid + 1; 44 | else 45 | end = mid; 46 | } 47 | if (unlikely(end >= (int)self->index->regions)) 48 | end = self->index->regions - 1; 49 | return end; 50 | } 51 | 52 | hot static inline void 53 | index_iterator_open(IndexIterator* self, 54 | Index* index, 55 | Buf* index_data, 56 | Event* event) 57 | { 58 | self->index = index; 59 | self->index_data = index_data; 60 | self->current = NULL; 61 | self->pos = 0; 62 | if (unlikely(index == NULL || index->regions == 0)) 63 | return; 64 | 65 | if (event == NULL) 66 | { 67 | self->current = index_get(index, index_data, 0); 68 | return; 69 | } 70 | 71 | self->pos = index_iterator_search(self, event->id); 72 | int rc = compare_u64(index_region_max(index, index_data, self->pos), event->id); 73 | if (rc < 0) 74 | self->pos++; 75 | if (unlikely(self->pos >= (int)index->regions)) 76 | return; 77 | 78 | self->current = index_get(index, index_data, self->pos); 79 | } 80 | 81 | static inline bool 82 | index_iterator_has(IndexIterator* self) 83 | { 84 | return self->current != NULL; 85 | } 86 | 87 | static inline IndexRegion* 88 | index_iterator_at(IndexIterator* self) 89 | { 90 | return self->current; 91 | } 92 | 93 | static inline void 94 | index_iterator_next(IndexIterator* self) 95 | { 96 | self->pos++; 97 | self->current = NULL; 98 | if (unlikely(self->pos >= (int)self->index->regions)) 99 | return; 100 | self->current = index_get(self->index, self->index_data, self->pos); 101 | } 102 | -------------------------------------------------------------------------------- /monotone/engine/io/index_op.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | void index_open(File*, Source*, Id*, int, Index*); 15 | void index_read(File*, Source*, Index*, Buf*, bool); 16 | -------------------------------------------------------------------------------- /monotone/engine/io/iterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Iterator Iterator; 15 | 16 | typedef bool (*IteratorHas)(Iterator*); 17 | typedef Event* (*IteratorAt)(Iterator*); 18 | typedef void (*IteratorNext)(Iterator*); 19 | typedef void (*IteratorClose)(Iterator*); 20 | 21 | struct Iterator 22 | { 23 | IteratorHas has; 24 | IteratorAt at; 25 | IteratorNext next; 26 | IteratorClose close; 27 | }; 28 | 29 | static inline bool 30 | iterator_has(Iterator* self) 31 | { 32 | return self->has(self); 33 | } 34 | 35 | static inline Event* 36 | iterator_at(Iterator* self) 37 | { 38 | return self->at(self); 39 | } 40 | 41 | static inline void 42 | iterator_next(Iterator* self) 43 | { 44 | self->next(self); 45 | } 46 | 47 | static inline void 48 | iterator_close(Iterator* self) 49 | { 50 | if (self->close) 51 | self->close(self); 52 | } 53 | -------------------------------------------------------------------------------- /monotone/engine/io/memtable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct MemtablePage MemtablePage; 15 | typedef struct Memtable Memtable; 16 | 17 | struct MemtablePage 18 | { 19 | RbtreeNode node; 20 | int events_count; 21 | Event* events[]; 22 | }; 23 | 24 | struct Memtable 25 | { 26 | Comparator* comparator; 27 | Rbtree tree; 28 | int size_page; 29 | int size_split; 30 | int count_pages; 31 | atomic_u64 count; 32 | atomic_u64 lsn_min; 33 | atomic_u64 lsn_max; 34 | List iterators; 35 | int iterators_count; 36 | Heap heap; 37 | }; 38 | 39 | void memtable_init(Memtable*, int, int, Comparator*); 40 | void memtable_free(Memtable*); 41 | void memtable_move(Memtable*, Memtable*); 42 | Event* memtable_set(Memtable*, Event*); 43 | void memtable_unset(Memtable*, Event*); 44 | Event* memtable_max(Memtable*); 45 | bool memtable_seek(Memtable*, Event*, MemtablePage**, int*); 46 | void memtable_follow(Memtable*, uint64_t); 47 | -------------------------------------------------------------------------------- /monotone/engine/io/merger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct MergerReq MergerReq; 15 | typedef struct Merger Merger; 16 | 17 | struct MergerReq 18 | { 19 | Part* origin; 20 | Memtable* memtable; 21 | Source* source; 22 | }; 23 | 24 | struct Merger 25 | { 26 | Part* part; 27 | PartIterator part_iterator; 28 | MemtableIterator memtable_iterator; 29 | MergeIterator merge_iterator; 30 | Writer writer; 31 | }; 32 | 33 | void merger_init(Merger*); 34 | void merger_free(Merger*); 35 | void merger_reset(Merger*); 36 | void merger_execute(Merger*, MergerReq*); 37 | -------------------------------------------------------------------------------- /monotone/engine/io/monotone_io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | // event 15 | #include "io/event.h" 16 | #include "io/comparator.h" 17 | 18 | // iterator 19 | #include "io/iterator.h" 20 | #include "io/merge_iterator.h" 21 | 22 | // memtable 23 | #include "io/memtable.h" 24 | #include "io/memtable_iterator.h" 25 | 26 | // region 27 | #include "io/region.h" 28 | #include "io/region_iterator.h" 29 | #include "io/region_writer.h" 30 | 31 | // index 32 | #include "io/index.h" 33 | #include "io/index_iterator.h" 34 | #include "io/index_writer.h" 35 | #include "io/index_op.h" 36 | 37 | // writer 38 | #include "io/writer.h" 39 | 40 | // partition 41 | #include "io/part.h" 42 | 43 | // stats 44 | #include "io/stats.h" 45 | 46 | // reader 47 | #include "io/reader.h" 48 | 49 | // partition iterator 50 | #include "io/part_iterator.h" 51 | #include "io/part_cursor.h" 52 | 53 | // mapping 54 | #include "io/mapping.h" 55 | 56 | // merger 57 | #include "io/merger.h" 58 | -------------------------------------------------------------------------------- /monotone/engine/io/part.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Part Part; 15 | 16 | struct Part 17 | { 18 | Id id; 19 | int state; 20 | uint64_t time_create; 21 | uint64_t time_refresh; 22 | bool refresh; 23 | Memtable* memtable; 24 | Memtable memtable_a; 25 | Memtable memtable_b; 26 | File file; 27 | Index index; 28 | Buf index_data; 29 | Cloud* cloud; 30 | Source* source; 31 | Comparator* comparator; 32 | List link; 33 | }; 34 | 35 | Part* 36 | part_allocate(Comparator*, Source*, Id*); 37 | void part_free(Part*); 38 | void part_open(Part*, int, bool); 39 | void part_create(Part*, int); 40 | void part_delete(Part*, int); 41 | void part_rename(Part*, int, int); 42 | void part_download(Part*); 43 | void part_upload(Part*); 44 | void part_offload(Part*, bool); 45 | 46 | static inline void 47 | part_set(Part* self, int state) 48 | { 49 | self->state |= state; 50 | } 51 | 52 | static inline void 53 | part_unset(Part* self, int state) 54 | { 55 | self->state &= ~state; 56 | } 57 | 58 | static inline bool 59 | part_has(Part* self, int mask) 60 | { 61 | return (self->state & mask) > 0; 62 | } 63 | 64 | static inline void 65 | part_set_time_create(Part* self, uint64_t time) 66 | { 67 | self->time_create = time; 68 | } 69 | 70 | static inline void 71 | part_set_time_refresh(Part* self, uint64_t time) 72 | { 73 | self->time_refresh = time; 74 | } 75 | 76 | static inline void 77 | part_set_cloud(Part* self, Cloud* cloud) 78 | { 79 | self->cloud = cloud; 80 | } 81 | 82 | static inline Memtable* 83 | part_memtable(Part* self, Memtable** prev) 84 | { 85 | if (self->memtable == &self->memtable_a) 86 | *prev = &self->memtable_b; 87 | else 88 | *prev = &self->memtable_a; 89 | return self->memtable; 90 | } 91 | 92 | static inline Memtable* 93 | part_memtable_rotate(Part* self) 94 | { 95 | Memtable* prev = self->memtable; 96 | Memtable* current; 97 | if (prev == &self->memtable_a) 98 | current = &self->memtable_b; 99 | else 100 | current = &self->memtable_a; 101 | self->memtable = current; 102 | return prev; 103 | } 104 | 105 | static inline bool 106 | part_refresh_ready(Part* self) 107 | { 108 | if (self->refresh) 109 | return false; 110 | if (! self->source->refresh_wm) 111 | return false; 112 | return heap_used(&self->memtable->heap) > (uint32_t)self->source->refresh_wm; 113 | } 114 | -------------------------------------------------------------------------------- /monotone/engine/io/region.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Region Region; 15 | 16 | struct Region 17 | { 18 | uint32_t size; 19 | uint32_t events; 20 | uint32_t reserve[4]; 21 | // u32 offset[] 22 | // data 23 | } packed; 24 | 25 | static inline Event* 26 | region_get(Region* self, int pos) 27 | { 28 | assert(pos < (int)self->events); 29 | auto start = (char*)self + sizeof(Region); 30 | auto offset = (uint32_t*)start; 31 | return (Event*)(start + (sizeof(uint32_t) * self->events) + 32 | offset[pos]); 33 | } 34 | -------------------------------------------------------------------------------- /monotone/engine/io/writer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Writer Writer; 15 | 16 | struct Writer 17 | { 18 | File* file; 19 | Iov iov; 20 | RegionWriter region_writer; 21 | IndexWriter index_writer; 22 | Compression* compression; 23 | Encryption* encryption; 24 | Source* source; 25 | }; 26 | 27 | void writer_init(Writer*); 28 | void writer_free(Writer*); 29 | void writer_reset(Writer*); 30 | void writer_start(Writer*, Source*, File*); 31 | void writer_stop(Writer*, Id*, uint32_t, uint64_t, uint64_t, uint64_t, bool); 32 | void writer_add(Writer*, Event*); 33 | -------------------------------------------------------------------------------- /monotone/engine/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @(cd ../.. && make --no-print-directory) 3 | clean: 4 | @(cd ../.. && make --no-print-directory clean) 5 | -------------------------------------------------------------------------------- /monotone/engine/storage/monotone_storage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | // storage 15 | #include "storage/storage.h" 16 | #include "storage/storage_mgr.h" 17 | 18 | // tier 19 | #include "storage/tier_config.h" 20 | #include "storage/tier.h" 21 | 22 | // pipeline 23 | #include "storage/pipeline.h" 24 | -------------------------------------------------------------------------------- /monotone/engine/storage/pipeline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Pipeline Pipeline; 15 | 16 | struct Pipeline 17 | { 18 | List list; 19 | int list_count; 20 | StorageMgr* storage_mgr; 21 | }; 22 | 23 | void pipeline_init(Pipeline*, StorageMgr*); 24 | void pipeline_free(Pipeline*); 25 | void pipeline_open(Pipeline*); 26 | bool pipeline_empty(Pipeline*); 27 | void pipeline_alter(Pipeline*, List*); 28 | void pipeline_rename(Pipeline*, Str*, Str*); 29 | void pipeline_show(Pipeline*, Buf*); 30 | Tier* pipeline_primary(Pipeline*); 31 | -------------------------------------------------------------------------------- /monotone/engine/storage/storage_mgr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct StorageMgr StorageMgr; 15 | 16 | struct StorageMgr 17 | { 18 | List list; 19 | int list_count; 20 | CloudMgr* cloud_mgr; 21 | }; 22 | 23 | void storage_mgr_init(StorageMgr*, CloudMgr*); 24 | void storage_mgr_free(StorageMgr*); 25 | void storage_mgr_open(StorageMgr*); 26 | bool storage_mgr_create_main(StorageMgr*); 27 | bool storage_mgr_create(StorageMgr*, Source*, bool); 28 | void storage_mgr_drop(StorageMgr*, Str*, bool); 29 | void storage_mgr_alter(StorageMgr*, Source*, int, bool); 30 | void storage_mgr_rename(StorageMgr*, Str*, Str*, bool); 31 | void storage_mgr_rename_cloud(StorageMgr*, Str*, Str*); 32 | void storage_mgr_show(StorageMgr*, Buf*, bool); 33 | 34 | Storage* 35 | storage_mgr_find(StorageMgr*, Str*); 36 | Part* 37 | storage_mgr_find_part(StorageMgr*, Storage*, uint64_t); 38 | 39 | static inline Storage* 40 | storage_mgr_first(StorageMgr* self) 41 | { 42 | assert(self->list_count > 0); 43 | return container_of(self->list.next, Storage, link); 44 | } 45 | -------------------------------------------------------------------------------- /monotone/engine/storage/tier.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Tier Tier; 15 | 16 | struct Tier 17 | { 18 | Storage* storage; 19 | TierConfig* config; 20 | List link; 21 | }; 22 | 23 | static inline void 24 | tier_free(Tier* self) 25 | { 26 | if (self->storage) 27 | storage_unref(self->storage); 28 | if (self->config) 29 | tier_config_free(self->config); 30 | mn_free(self); 31 | } 32 | 33 | static inline Tier* 34 | tier_allocate(TierConfig* config) 35 | { 36 | auto self = (Tier*)mn_malloc(sizeof(Tier)); 37 | self->storage = NULL; 38 | self->config = NULL; 39 | list_init(&self->link); 40 | guard(tier_free, self); 41 | self->config = tier_config_copy(config); 42 | return unguard(); 43 | } 44 | 45 | static inline void 46 | tier_resolve(Tier* self, StorageMgr* storage_mgr) 47 | { 48 | assert(! self->storage); 49 | auto storage = storage_mgr_find(storage_mgr, &self->config->name); 50 | if (! storage) 51 | error("storage '%.*s': not exists", str_size(&self->config->name), 52 | str_of(&self->config->name)); 53 | self->storage = storage; 54 | storage_ref(storage); 55 | } 56 | -------------------------------------------------------------------------------- /monotone/engine/wal/log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct LogOp LogOp; 15 | typedef struct Log Log; 16 | 17 | struct LogOp 18 | { 19 | Event* event; 20 | Event* prev; 21 | void* ref; 22 | }; 23 | 24 | struct Log 25 | { 26 | Buf op; 27 | LogWrite write; 28 | Iov iov; 29 | }; 30 | 31 | static inline void 32 | log_init(Log* self) 33 | { 34 | buf_init(&self->op); 35 | log_write_init(&self->write); 36 | iov_init(&self->iov); 37 | } 38 | 39 | static inline void 40 | log_free(Log* self) 41 | { 42 | buf_free(&self->op); 43 | iov_free(&self->iov); 44 | } 45 | 46 | static inline LogOp* 47 | log_of(Log* self, int pos) 48 | { 49 | auto op = (LogOp*)self->op.start; 50 | return &op[pos]; 51 | } 52 | 53 | static inline LogOp* 54 | log_first(Log* self) 55 | { 56 | return log_of(self, 0); 57 | } 58 | 59 | static inline LogOp* 60 | log_last(Log* self) 61 | { 62 | return log_of(self, self->write.count - 1); 63 | } 64 | 65 | static inline LogOp* 66 | log_end(Log* self) 67 | { 68 | return log_of(self, self->write.count); 69 | } 70 | 71 | static inline void 72 | log_cleanup(Log* self) 73 | { 74 | auto pos = log_first(self); 75 | auto end = log_end(self); 76 | for (; pos < end; pos++) 77 | { 78 | if (pos->event) 79 | event_free(pos->event); 80 | } 81 | } 82 | 83 | static inline void 84 | log_reset(Log* self) 85 | { 86 | buf_reset(&self->op); 87 | log_write_reset(&self->write); 88 | iov_reset(&self->iov); 89 | } 90 | 91 | hot static inline LogOp* 92 | log_add(Log* self) 93 | { 94 | buf_reserve(&self->op, sizeof(LogOp)); 95 | auto op = (LogOp*)self->op.position; 96 | op->event = NULL; 97 | op->prev = NULL; 98 | op->ref = NULL; 99 | self->write.count++; 100 | buf_advance(&self->op, sizeof(LogOp)); 101 | return op; 102 | } 103 | 104 | hot static inline void 105 | log_add_event(Log* self, LogOp* op, Event* event) 106 | { 107 | // add log write header before the first entry 108 | if (self->write.count == 1) 109 | { 110 | iov_add(&self->iov, &self->write, sizeof(self->write)); 111 | self->write.size += sizeof(LogWrite); 112 | } 113 | iov_add(&self->iov, event, event_size(event)); 114 | op->event = event; 115 | self->write.size += event_size(event); 116 | 117 | // calculate crc 118 | if (var_int_of(&config()->wal_crc)) 119 | self->write.crc = global()->crc(self->write.crc, event, event_size(event)); 120 | } 121 | 122 | hot static inline void 123 | log_pushback(Log* self) 124 | { 125 | self->write.count--; 126 | buf_truncate(&self->op, sizeof(LogOp)); 127 | } 128 | -------------------------------------------------------------------------------- /monotone/engine/wal/log_drop.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct LogDrop LogDrop; 15 | 16 | struct LogDrop 17 | { 18 | LogWrite write; 19 | uint64_t id; 20 | } packed; 21 | 22 | static inline void 23 | log_drop_init(LogDrop* self, uint64_t id) 24 | { 25 | auto write = &self->write; 26 | write->crc = 0; 27 | write->lsn = 0; 28 | write->type = LOG_DROP; 29 | write->count = 0; 30 | write->size = sizeof(LogDrop); 31 | self->id = id; 32 | // calculate crc 33 | if (var_int_of(&config()->wal_crc)) 34 | self->write.crc = global()->crc(self->write.crc, &id, sizeof(id)); 35 | } 36 | -------------------------------------------------------------------------------- /monotone/engine/wal/log_write.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct LogWrite LogWrite; 15 | 16 | enum 17 | { 18 | LOG_WRITE, 19 | LOG_DROP 20 | }; 21 | 22 | struct LogWrite 23 | { 24 | uint32_t crc; 25 | uint64_t lsn; 26 | uint8_t type; 27 | uint32_t count; 28 | uint32_t size; 29 | } packed; 30 | 31 | static inline void 32 | log_write_init(LogWrite* self) 33 | { 34 | self->crc = 0; 35 | self->lsn = 0; 36 | self->type = LOG_WRITE; 37 | self->count = 0; 38 | self->size = 0; 39 | } 40 | 41 | static inline void 42 | log_write_reset(LogWrite* self) 43 | { 44 | self->crc = 0; 45 | self->lsn = 0; 46 | self->type = LOG_WRITE; 47 | self->count = 0; 48 | self->size = 0; 49 | } 50 | 51 | static inline Event* 52 | log_write_first(LogWrite* self) 53 | { 54 | return (Event*)((uintptr_t)self + sizeof(*self)); 55 | } 56 | 57 | static inline Event* 58 | log_write_next(LogWrite* self, Event* at) 59 | { 60 | auto next = (uintptr_t)at + event_size(at); 61 | auto eof = (uintptr_t)self + self->size; 62 | if (next >= eof) 63 | return NULL; 64 | return (Event*)next; 65 | } 66 | 67 | static inline void 68 | log_write_seal(LogWrite* self) 69 | { 70 | if (var_int_of(&config()->wal_crc)) 71 | self->crc = global()->crc(self->crc, (char*)self + sizeof(uint32_t), 72 | sizeof(LogWrite) - sizeof(uint32_t)); 73 | } 74 | -------------------------------------------------------------------------------- /monotone/engine/wal/monotone_wal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | // log 15 | #include "wal/log_write.h" 16 | #include "wal/log_drop.h" 17 | #include "wal/log.h" 18 | 19 | // id manager 20 | #include "wal/wal_id.h" 21 | 22 | // wal 23 | #include "wal/wal_file.h" 24 | #include "wal/wal.h" 25 | #include "wal/wal_cursor.h" 26 | -------------------------------------------------------------------------------- /monotone/engine/wal/wal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Wal Wal; 15 | 16 | struct Wal 17 | { 18 | Mutex lock; 19 | WalId list; 20 | WalFile* current; 21 | }; 22 | 23 | void wal_init(Wal*); 24 | void wal_free(Wal*); 25 | void wal_open(Wal*); 26 | void wal_rotate(Wal*, uint64_t); 27 | void wal_gc(Wal*, uint64_t); 28 | bool wal_write(Wal*, Log*); 29 | bool wal_write_op(Wal*, LogWrite*); 30 | void wal_show(Wal*, Buf*); 31 | -------------------------------------------------------------------------------- /monotone/engine/wal/wal_cursor.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // monotone. 4 | // 5 | // embeddable cloud-native storage for events 6 | // and time-series data. 7 | // 8 | // Copyright (c) 2023-2025 Dmitry Simonenko 9 | // 10 | // MIT Licensed. 11 | // 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | void 22 | wal_cursor_init(WalCursor* self) 23 | { 24 | self->file_offset = 0; 25 | self->file = NULL; 26 | self->wal = NULL; 27 | buf_init(&self->buf); 28 | } 29 | 30 | void 31 | wal_cursor_open(WalCursor* self, Wal* wal, uint64_t lsn) 32 | { 33 | self->file = NULL; 34 | self->file_offset = 0; 35 | self->wal = wal; 36 | 37 | // find nearest file with id <= lsn 38 | uint64_t id; 39 | if (lsn == 0) 40 | id = wal_id_min(&wal->list); 41 | else 42 | id = wal_id_find(&wal->list, lsn); 43 | if (id == UINT64_MAX) 44 | return; 45 | self->file = wal_file_allocate(id); 46 | wal_file_open(self->file); 47 | 48 | // rewind to the start lsn 49 | for (;;) 50 | { 51 | if (! wal_cursor_next(self)) 52 | break; 53 | auto write = wal_cursor_at(self); 54 | if (write->lsn >= lsn) 55 | { 56 | // rewind 57 | self->file_offset -= write->size; 58 | break; 59 | } 60 | } 61 | } 62 | 63 | void 64 | wal_cursor_close(WalCursor* self) 65 | { 66 | if (self->file) 67 | { 68 | wal_file_close(self->file); 69 | wal_file_free(self->file); 70 | self->file = NULL; 71 | } 72 | buf_free(&self->buf); 73 | } 74 | 75 | LogWrite* 76 | wal_cursor_at(WalCursor* self) 77 | { 78 | return (LogWrite*)self->buf.start; 79 | } 80 | 81 | bool 82 | wal_cursor_next(WalCursor* self) 83 | { 84 | if (unlikely(self->file == NULL)) 85 | return false; 86 | 87 | auto wal = self->wal; 88 | for (;;) 89 | { 90 | auto file = self->file; 91 | if (wal_file_pread(file, self->file_offset, &self->buf)) 92 | { 93 | auto write = wal_cursor_at(self); 94 | self->file_offset += write->size; 95 | return true; 96 | } 97 | 98 | // get to the next file id 99 | uint64_t id; 100 | id = wal_id_next(&wal->list, file->id); 101 | if (id == UINT64_MAX) 102 | break; 103 | 104 | // close previous file 105 | wal_file_close(file); 106 | wal_file_free(file); 107 | 108 | // open next file 109 | self->file_offset = 0; 110 | self->file = NULL; 111 | self->file = wal_file_allocate(id); 112 | wal_file_open(self->file); 113 | } 114 | 115 | return false; 116 | } 117 | -------------------------------------------------------------------------------- /monotone/engine/wal/wal_cursor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct WalCursor WalCursor; 15 | 16 | struct WalCursor 17 | { 18 | Buf buf; 19 | WalFile* file; 20 | uint64_t file_offset; 21 | Wal* wal; 22 | }; 23 | 24 | void wal_cursor_init(WalCursor*); 25 | void wal_cursor_open(WalCursor*, Wal*, uint64_t); 26 | void wal_cursor_close(WalCursor*); 27 | bool wal_cursor_next(WalCursor*); 28 | LogWrite* 29 | wal_cursor_at(WalCursor*); 30 | -------------------------------------------------------------------------------- /monotone/main/api/monotone.h: -------------------------------------------------------------------------------- 1 | #ifndef MONOTONE_H 2 | #define MONOTONE_H 3 | 4 | // 5 | // monotone. 6 | // 7 | // embeddable cloud-native storage for events 8 | // and time-series data. 9 | // 10 | // Copyright (c) 2023-2025 Dmitry Simonenko 11 | // 12 | // MIT Licensed. 13 | // 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define MONOTONE_API __attribute__((visibility("default"))) 25 | 26 | typedef struct monotone monotone_t; 27 | typedef struct monotone_event monotone_event_t; 28 | typedef struct monotone_cursor monotone_cursor_t; 29 | 30 | enum 31 | { 32 | MONOTONE_DELETE = 1 33 | }; 34 | 35 | struct monotone_event 36 | { 37 | int flags; 38 | uint64_t id; 39 | void* key; 40 | size_t key_size; 41 | void* value; 42 | size_t value_size; 43 | }; 44 | 45 | // environment 46 | MONOTONE_API monotone_t* 47 | monotone_init(void); 48 | 49 | MONOTONE_API void 50 | monotone_free(void*); 51 | 52 | MONOTONE_API const char* 53 | monotone_error(monotone_t*); 54 | 55 | MONOTONE_API int 56 | monotone_open(monotone_t*, const char* path); 57 | 58 | MONOTONE_API int 59 | monotone_execute(monotone_t*, const char* command, char** result); 60 | 61 | // batch write 62 | MONOTONE_API int 63 | monotone_write(monotone_t*, monotone_event_t*, int count); 64 | 65 | // cursor 66 | MONOTONE_API monotone_cursor_t* 67 | monotone_cursor(monotone_t*, const char* options, monotone_event_t*); 68 | 69 | MONOTONE_API int 70 | monotone_read(monotone_cursor_t*, monotone_event_t*); 71 | 72 | MONOTONE_API int 73 | monotone_next(monotone_cursor_t*); 74 | 75 | #ifdef __cplusplus 76 | } 77 | #endif 78 | 79 | #endif // MONOTONE_H 80 | -------------------------------------------------------------------------------- /monotone/main/api/monotone_private.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | -------------------------------------------------------------------------------- /monotone/main/command/cmd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Cmd Cmd; 15 | 16 | typedef void (*CmdFree)(Cmd*); 17 | 18 | typedef enum 19 | { 20 | CMD_UNDEF, 21 | CMD_SHOW, 22 | CMD_SET, 23 | CMD_DEBUG, 24 | CMD_CHECKPOINT, 25 | CMD_SERVICE, 26 | CMD_REBALANCE, 27 | CMD_CLOUD_CREATE, 28 | CMD_CLOUD_DROP, 29 | CMD_CLOUD_ALTER, 30 | CMD_STORAGE_CREATE, 31 | CMD_STORAGE_DROP, 32 | CMD_STORAGE_ALTER, 33 | CMD_PIPELINE_ALTER, 34 | CMD_PARTITION_CREATE, 35 | CMD_PARTITION_DROP, 36 | CMD_PARTITION_DROP_RANGE, 37 | CMD_PARTITION_MOVE, 38 | CMD_PARTITION_MOVE_RANGE, 39 | CMD_PARTITION_REFRESH, 40 | CMD_PARTITION_REFRESH_RANGE, 41 | CMD_PARTITION_DOWNLOAD, 42 | CMD_PARTITION_DOWNLOAD_RANGE, 43 | CMD_PARTITION_UPLOAD, 44 | CMD_PARTITION_UPLOAD_RANGE, 45 | CMD_MAX 46 | } CmdType; 47 | 48 | struct Cmd 49 | { 50 | CmdType type; 51 | CmdFree free; 52 | }; 53 | 54 | static inline void* 55 | cmd_allocate(CmdType type, CmdFree free, size_t size) 56 | { 57 | assert(size >= sizeof(Cmd)); 58 | Cmd* self = mn_malloc(size); 59 | self->type = type; 60 | self->free = free; 61 | return self; 62 | } 63 | 64 | static inline void 65 | cmd_free(Cmd* self) 66 | { 67 | if (self->free) 68 | self->free(self); 69 | mn_free(self); 70 | } 71 | -------------------------------------------------------------------------------- /monotone/main/command/lex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Token Token; 15 | typedef struct Lex Lex; 16 | 17 | enum 18 | { 19 | KEOF, 20 | // values 21 | KREAL, 22 | KINT, 23 | KSTRING, 24 | KNAME, 25 | KTRUE, 26 | KFALSE, 27 | // modificators 28 | KUSEC, 29 | KMSEC, 30 | KSEC, 31 | KMIN, 32 | KHOUR, 33 | KDAY, 34 | KWEEK, 35 | KMONTH, 36 | KYEAR, 37 | KKB, 38 | KKIB, 39 | KMB, 40 | KMIB, 41 | KGB, 42 | KGIB, 43 | KTB, 44 | KTIB, 45 | // keywowrds 46 | KRESET, 47 | KSET, 48 | KTO, 49 | KSHOW, 50 | KALL, 51 | KCONFIG, 52 | KCHECKPOINT, 53 | KSERVICE, 54 | KCREATE, 55 | KSTORAGE, 56 | KSTORAGES, 57 | KPARTITION, 58 | KPARTITIONS, 59 | KIF, 60 | KNOT, 61 | KEXISTS, 62 | KDROP, 63 | KPIPELINE, 64 | KALTER, 65 | KRENAME, 66 | KMOVE, 67 | KBETWEEN, 68 | KAND, 69 | KINTO, 70 | KREFRESH, 71 | KREBALANCE, 72 | KON, 73 | KCLOUD, 74 | KCLOUDS, 75 | KDOWNLOAD, 76 | KUPLOAD, 77 | KVERBOSE, 78 | KDEBUG, 79 | KWAL, 80 | KMEMORY 81 | }; 82 | 83 | struct Token 84 | { 85 | int id; 86 | union { 87 | uint64_t integer; 88 | double real; 89 | struct { 90 | Str string; 91 | bool string_escape; 92 | }; 93 | }; 94 | }; 95 | 96 | struct Lex 97 | { 98 | char* pos; 99 | char* end; 100 | bool keywords; 101 | Token backlog[4]; 102 | int backlog_size; 103 | }; 104 | 105 | static inline void 106 | token_init(Token* tk) 107 | { 108 | memset(tk, 0, sizeof(*tk)); 109 | } 110 | 111 | void lex_init(Lex*); 112 | void lex_start(Lex*, Str*); 113 | void lex_keywords(Lex*, bool); 114 | void lex_next(Lex*, Token*); 115 | void lex_push(Lex*, Token*); 116 | bool lex_if(Lex*, int, Token*); 117 | bool lex_if_name(Lex*, Token*); 118 | -------------------------------------------------------------------------------- /monotone/main/command/monotone_command.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | // lex 15 | #include "command/lex.h" 16 | 17 | // command 18 | #include "command/cmd.h" 19 | 20 | // parse 21 | #include "command/parse_misc.h" 22 | #include "command/parse_system.h" 23 | #include "command/parse_config.h" 24 | #include "command/parse_cloud.h" 25 | #include "command/parse_storage.h" 26 | #include "command/parse_pipeline.h" 27 | #include "command/parse_partition.h" 28 | #include "command/parse_debug.h" 29 | #include "command/parse.h" 30 | -------------------------------------------------------------------------------- /monotone/main/command/parse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | Cmd* parse(Lex*); 15 | -------------------------------------------------------------------------------- /monotone/main/command/parse_cloud.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct CmdCloudCreate CmdCloudCreate; 15 | typedef struct CmdCloudDrop CmdCloudDrop; 16 | typedef struct CmdCloudAlter CmdCloudAlter; 17 | 18 | struct CmdCloudCreate 19 | { 20 | Cmd cmd; 21 | bool if_not_exists; 22 | CloudConfig* config; 23 | }; 24 | 25 | struct CmdCloudDrop 26 | { 27 | Cmd cmd; 28 | bool if_exists; 29 | Token name; 30 | }; 31 | 32 | struct CmdCloudAlter 33 | { 34 | Cmd cmd; 35 | bool if_exists; 36 | Token name; 37 | Token name_new; 38 | CloudConfig* config; 39 | int config_mask; 40 | }; 41 | 42 | static inline CmdCloudCreate* 43 | cmd_cloud_create_of(Cmd* self) 44 | { 45 | return (CmdCloudCreate*)self; 46 | } 47 | 48 | static inline CmdCloudDrop* 49 | cmd_cloud_drop_of(Cmd* self) 50 | { 51 | return (CmdCloudDrop*)self; 52 | } 53 | 54 | static inline CmdCloudAlter* 55 | cmd_cloud_alter_of(Cmd* self) 56 | { 57 | return (CmdCloudAlter*)self; 58 | } 59 | 60 | static inline void 61 | cmd_cloud_create_free(Cmd* self) 62 | { 63 | auto cmd = cmd_cloud_create_of(self); 64 | if (cmd->config) 65 | cloud_config_free(cmd->config); 66 | } 67 | 68 | static inline CmdCloudCreate* 69 | cmd_cloud_create_allocate(void) 70 | { 71 | CmdCloudCreate* self; 72 | self = cmd_allocate(CMD_CLOUD_CREATE, cmd_cloud_create_free, 73 | sizeof(*self)); 74 | self->if_not_exists = false; 75 | self->config = NULL; 76 | return self; 77 | } 78 | 79 | static inline CmdCloudDrop* 80 | cmd_cloud_drop_allocate(void) 81 | { 82 | CmdCloudDrop* self; 83 | self = cmd_allocate(CMD_CLOUD_DROP, NULL, sizeof(*self)); 84 | self->if_exists = false; 85 | token_init(&self->name); 86 | return self; 87 | } 88 | 89 | static inline void 90 | cmd_cloud_alter_free(Cmd* self) 91 | { 92 | auto cmd = cmd_cloud_alter_of(self); 93 | if (cmd->config) 94 | cloud_config_free(cmd->config); 95 | } 96 | 97 | static inline CmdCloudAlter* 98 | cmd_cloud_alter_allocate(void) 99 | { 100 | CmdCloudAlter* self; 101 | self = cmd_allocate(CMD_CLOUD_ALTER, cmd_cloud_alter_free, 102 | sizeof(*self)); 103 | self->if_exists = false; 104 | self->config = NULL; 105 | self->config_mask = 0; 106 | token_init(&self->name); 107 | token_init(&self->name_new); 108 | return self; 109 | } 110 | 111 | Cmd* parse_cloud_create(Lex*); 112 | Cmd* parse_cloud_drop(Lex*); 113 | Cmd* parse_cloud_alter(Lex*); 114 | -------------------------------------------------------------------------------- /monotone/main/command/parse_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct CmdShowOp CmdShowOp; 15 | typedef struct CmdShow CmdShow; 16 | typedef struct CmdSet CmdSet; 17 | 18 | enum 19 | { 20 | SHOW_MEMORY, 21 | SHOW_WAL, 22 | SHOW_CLOUDS, 23 | SHOW_STORAGES, 24 | SHOW_PARTITION, 25 | SHOW_PARTITIONS, 26 | SHOW_PIPELINE, 27 | SHOW_CONFIG, 28 | SHOW_NAME 29 | }; 30 | 31 | struct CmdShowOp 32 | { 33 | int type; 34 | bool debug; 35 | Token name; 36 | List link; 37 | }; 38 | 39 | struct CmdShow 40 | { 41 | Cmd cmd; 42 | List list; 43 | int list_count; 44 | }; 45 | 46 | struct CmdSet 47 | { 48 | Cmd cmd; 49 | Token name; 50 | Token value; 51 | }; 52 | 53 | static inline CmdShow* 54 | cmd_show_of(Cmd* self) 55 | { 56 | return (CmdShow*)self; 57 | } 58 | 59 | static inline CmdSet* 60 | cmd_set_of(Cmd* self) 61 | { 62 | return (CmdSet*)self; 63 | } 64 | 65 | static inline void 66 | cmd_show_free(Cmd* self) 67 | { 68 | auto cmd = cmd_show_of(self); 69 | list_foreach_safe(&cmd->list) 70 | { 71 | auto op = list_at(CmdShowOp, link); 72 | mn_free(op); 73 | } 74 | } 75 | 76 | static inline CmdShowOp* 77 | cmd_show_allocate_op(int type, Token* name, bool debug) 78 | { 79 | CmdShowOp* self = mn_malloc(sizeof(CmdShowOp)); 80 | self->type = type; 81 | self->debug = debug; 82 | self->name = *name; 83 | list_init(&self->link); 84 | return self; 85 | } 86 | 87 | static inline CmdShow* 88 | cmd_show_allocate(void) 89 | { 90 | CmdShow* self; 91 | self = cmd_allocate(CMD_SHOW, cmd_show_free, sizeof(*self)); 92 | self->list_count = 0; 93 | list_init(&self->list); 94 | return self; 95 | } 96 | 97 | static inline CmdSet* 98 | cmd_set_allocate(Token* name, Token* value) 99 | { 100 | CmdSet* self; 101 | self = cmd_allocate(CMD_SET, NULL, sizeof(*self)); 102 | self->name = *name; 103 | self->value = *value; 104 | return self; 105 | } 106 | 107 | Cmd* parse_show(Lex*); 108 | Cmd* parse_set(Lex*); 109 | -------------------------------------------------------------------------------- /monotone/main/command/parse_debug.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // monotone. 4 | // 5 | // embeddable cloud-native storage for events 6 | // and time-series data. 7 | // 8 | // Copyright (c) 2023-2025 Dmitry Simonenko 9 | // 10 | // MIT Licensed. 11 | // 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | Cmd* 24 | parse_debug(Lex* self) 25 | { 26 | // DEBUG command 27 | int id; 28 | Token name; 29 | if (! lex_if(self, KSTRING, &name)) 30 | error("DEBUG 'name' expected"); 31 | 32 | // DEBUG WAL CREATE 33 | // DEBUG WAL GC 34 | // DEBUG WAL SHOW 35 | // DEBUG MEMORY GC 36 | if (str_compare_raw(&name.string, "wal_create", 10)) 37 | id = DEBUG_WAL_CREATE; 38 | else 39 | if (str_compare_raw(&name.string, "wal_gc", 6)) 40 | id = DEBUG_WAL_GC; 41 | else 42 | if (str_compare_raw(&name.string, "wal_read", 8)) 43 | id = DEBUG_WAL_READ; 44 | else 45 | if (str_compare_raw(&name.string, "memory_gc", 9)) 46 | id = DEBUG_MEMORY_GC; 47 | else 48 | error("DEBUG: unknown command"); 49 | 50 | auto cmd = cmd_debug_allocate(); 51 | cmd->command = id; 52 | return &cmd->cmd; 53 | } 54 | -------------------------------------------------------------------------------- /monotone/main/command/parse_debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct CmdDebug CmdDebug; 15 | 16 | enum 17 | { 18 | DEBUG_WAL_CREATE, 19 | DEBUG_WAL_GC, 20 | DEBUG_WAL_READ, 21 | DEBUG_MEMORY_GC 22 | }; 23 | 24 | struct CmdDebug 25 | { 26 | Cmd cmd; 27 | int command; 28 | }; 29 | 30 | static inline CmdDebug* 31 | cmd_debug_of(Cmd* self) 32 | { 33 | return (CmdDebug*)self; 34 | } 35 | 36 | static inline CmdDebug* 37 | cmd_debug_allocate(void) 38 | { 39 | CmdDebug* self; 40 | self = cmd_allocate(CMD_DEBUG, NULL, sizeof(*self)); 41 | self->command = 0; 42 | return self; 43 | } 44 | 45 | Cmd* parse_debug(Lex*); 46 | -------------------------------------------------------------------------------- /monotone/main/command/parse_misc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | static inline bool 15 | parse_if_not_exists(Lex* self) 16 | { 17 | if (! lex_if(self, KIF, NULL)) 18 | return false; 19 | if (! lex_if(self, KNOT, NULL)) 20 | error("IF 'NOT' EXISTS expected"); 21 | if (! lex_if(self, KEXISTS, NULL)) 22 | error("IF NOT 'EXISTS' expected"); 23 | return true; 24 | } 25 | 26 | static inline bool 27 | parse_if_exists(Lex* self) 28 | { 29 | if (! lex_if(self, KIF, NULL)) 30 | return false; 31 | if (! lex_if(self, KEXISTS, NULL)) 32 | error("IF 'EXISTS' expected"); 33 | return true; 34 | } 35 | 36 | static inline bool 37 | parse_if_cloud(Lex* self) 38 | { 39 | if (! lex_if(self, KIF, NULL)) 40 | return false; 41 | if (! lex_if(self, KCLOUD, NULL)) 42 | error("IF 'CLOUD' expected"); 43 | return true; 44 | } 45 | 46 | static inline void 47 | parse_int(Lex* self, Token* name, int64_t* value) 48 | { 49 | // int 50 | Token tk; 51 | if (! lex_if(self, KINT, &tk)) 52 | error("%.*s 'integer' expected", str_size(&name->string), 53 | str_of(&name->string)); 54 | 55 | *value = tk.integer; 56 | } 57 | 58 | static inline void 59 | parse_bool(Lex* self, Token* name, bool* value) 60 | { 61 | // [true/false] 62 | if (lex_if(self, KTRUE, NULL)) 63 | { 64 | *value = true; 65 | } else 66 | if (lex_if(self, KFALSE, NULL)) 67 | { 68 | *value = false; 69 | } else { 70 | error("%.*s 'true|false' expected", str_size(&name->string), 71 | str_of(&name->string)); 72 | } 73 | } 74 | 75 | static inline void 76 | parse_string(Lex* self, Token* name, Str* value) 77 | { 78 | // string 79 | Token tk; 80 | if (! lex_if(self, KSTRING, &tk)) 81 | error("%.*s 'string'expected", str_size(&name->string), 82 | str_of(&name->string)); 83 | 84 | str_free(value); 85 | str_copy(value, &tk.string); 86 | } 87 | 88 | static inline void 89 | parse_uuid(Lex* self, Token* name, Uuid* value) 90 | { 91 | // string 92 | Token tk; 93 | if (! lex_if(self, KSTRING, &tk)) 94 | error("%.*s 'string' expected", str_size(&name->string), 95 | str_of(&name->string)); 96 | 97 | uuid_from_string(value, &tk.string); 98 | } 99 | -------------------------------------------------------------------------------- /monotone/main/command/parse_partition.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct CmdPartition CmdPartition; 15 | 16 | struct CmdPartition 17 | { 18 | Cmd cmd; 19 | uint64_t min; 20 | uint64_t max; 21 | bool if_exists; 22 | bool if_cloud; 23 | int mask; 24 | Token storage; 25 | }; 26 | 27 | static inline CmdPartition* 28 | cmd_partition_of(Cmd* self) 29 | { 30 | return (CmdPartition*)self; 31 | } 32 | 33 | static inline CmdPartition* 34 | cmd_partition_allocate(CmdType type) 35 | { 36 | CmdPartition* self; 37 | self = cmd_allocate(type, NULL, sizeof(*self)); 38 | self->min = 0; 39 | self->max = 0; 40 | self->if_exists = false; 41 | self->if_cloud = false; 42 | self->mask = ID_NONE; 43 | token_init(&self->storage); 44 | return self; 45 | } 46 | 47 | Cmd* parse_partition_create(Lex*); 48 | Cmd* parse_partition_drop(Lex*); 49 | Cmd* parse_partition_drop_range(Lex*); 50 | Cmd* parse_partition_move(Lex*); 51 | Cmd* parse_partition_move_range(Lex*); 52 | Cmd* parse_partition_refresh(Lex*); 53 | Cmd* parse_partition_refresh_range(Lex*); 54 | Cmd* parse_partition_download(Lex*); 55 | Cmd* parse_partition_download_range(Lex*); 56 | Cmd* parse_partition_upload(Lex*); 57 | Cmd* parse_partition_upload_range(Lex*); 58 | -------------------------------------------------------------------------------- /monotone/main/command/parse_pipeline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct CmdPipelineAlter CmdPipelineAlter; 15 | 16 | struct CmdPipelineAlter 17 | { 18 | Cmd cmd; 19 | List list; 20 | int list_count; 21 | }; 22 | 23 | static inline CmdPipelineAlter* 24 | cmd_pipeline_alter_of(Cmd* self) 25 | { 26 | return (CmdPipelineAlter*)self; 27 | } 28 | 29 | static inline void 30 | cmd_pipeline_alter_free(Cmd* self) 31 | { 32 | auto cmd = cmd_pipeline_alter_of(self); 33 | list_foreach_safe(&cmd->list) 34 | { 35 | auto config = list_at(TierConfig, link); 36 | tier_config_free(config); 37 | } 38 | } 39 | 40 | static inline CmdPipelineAlter* 41 | cmd_pipeline_alter_allocate(void) 42 | { 43 | CmdPipelineAlter* self; 44 | self = cmd_allocate(CMD_PIPELINE_ALTER, cmd_pipeline_alter_free, 45 | sizeof(*self)); 46 | self->list_count = 0; 47 | list_init(&self->list); 48 | return self; 49 | } 50 | 51 | static inline void 52 | cmd_pipeline_alter_add(CmdPipelineAlter* self, TierConfig* config) 53 | { 54 | list_append(&self->list, &config->link); 55 | self->list_count++; 56 | } 57 | 58 | Cmd* parse_pipeline_alter(Lex*); 59 | -------------------------------------------------------------------------------- /monotone/main/command/parse_storage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct CmdStorageCreate CmdStorageCreate; 15 | typedef struct CmdStorageDrop CmdStorageDrop; 16 | typedef struct CmdStorageAlter CmdStorageAlter; 17 | 18 | struct CmdStorageCreate 19 | { 20 | Cmd cmd; 21 | bool if_not_exists; 22 | Source* config; 23 | }; 24 | 25 | struct CmdStorageDrop 26 | { 27 | Cmd cmd; 28 | bool if_exists; 29 | Token name; 30 | }; 31 | 32 | struct CmdStorageAlter 33 | { 34 | Cmd cmd; 35 | bool if_exists; 36 | Token name; 37 | Token name_new; 38 | Source* config; 39 | int config_mask; 40 | }; 41 | 42 | static inline CmdStorageCreate* 43 | cmd_storage_create_of(Cmd* self) 44 | { 45 | return (CmdStorageCreate*)self; 46 | } 47 | 48 | static inline CmdStorageDrop* 49 | cmd_storage_drop_of(Cmd* self) 50 | { 51 | return (CmdStorageDrop*)self; 52 | } 53 | 54 | static inline CmdStorageAlter* 55 | cmd_storage_alter_of(Cmd* self) 56 | { 57 | return (CmdStorageAlter*)self; 58 | } 59 | 60 | static inline void 61 | cmd_storage_create_free(Cmd* self) 62 | { 63 | auto cmd = cmd_storage_create_of(self); 64 | if (cmd->config) 65 | source_free(cmd->config); 66 | } 67 | 68 | static inline CmdStorageCreate* 69 | cmd_storage_create_allocate(void) 70 | { 71 | CmdStorageCreate* self; 72 | self = cmd_allocate(CMD_STORAGE_CREATE, cmd_storage_create_free, 73 | sizeof(*self)); 74 | self->if_not_exists = false; 75 | self->config = NULL; 76 | return self; 77 | } 78 | 79 | static inline CmdStorageDrop* 80 | cmd_storage_drop_allocate(void) 81 | { 82 | CmdStorageDrop* self; 83 | self = cmd_allocate(CMD_STORAGE_DROP, NULL, sizeof(*self)); 84 | self->if_exists = false; 85 | token_init(&self->name); 86 | return self; 87 | } 88 | 89 | static inline void 90 | cmd_storage_alter_free(Cmd* self) 91 | { 92 | auto cmd = cmd_storage_alter_of(self); 93 | if (cmd->config) 94 | source_free(cmd->config); 95 | } 96 | 97 | static inline CmdStorageAlter* 98 | cmd_storage_alter_allocate(void) 99 | { 100 | CmdStorageAlter* self; 101 | self = cmd_allocate(CMD_STORAGE_ALTER, cmd_storage_alter_free, 102 | sizeof(*self)); 103 | self->if_exists = false; 104 | self->config = NULL; 105 | self->config_mask = 0; 106 | token_init(&self->name); 107 | token_init(&self->name_new); 108 | return self; 109 | } 110 | 111 | Cmd* parse_storage_create(Lex*); 112 | Cmd* parse_storage_drop(Lex*); 113 | Cmd* parse_storage_alter(Lex*); 114 | -------------------------------------------------------------------------------- /monotone/main/command/parse_system.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct CmdService CmdService; 15 | 16 | struct CmdService 17 | { 18 | Cmd cmd; 19 | }; 20 | 21 | static inline CmdService* 22 | cmd_service_of(Cmd* self) 23 | { 24 | return (CmdService*)self; 25 | } 26 | 27 | static inline CmdService* 28 | cmd_service_allocate(CmdType type) 29 | { 30 | CmdService* self; 31 | self = cmd_allocate(type, NULL, sizeof(*self)); 32 | return self; 33 | } 34 | 35 | static inline Cmd* 36 | parse_checkpoint(Lex* self) 37 | { 38 | unused(self); 39 | return &cmd_service_allocate(CMD_CHECKPOINT)->cmd; 40 | } 41 | 42 | static inline Cmd* 43 | parse_service(Lex* self) 44 | { 45 | unused(self); 46 | return &cmd_service_allocate(CMD_SERVICE)->cmd; 47 | } 48 | 49 | static inline Cmd* 50 | parse_rebalance(Lex* self) 51 | { 52 | unused(self); 53 | return &cmd_service_allocate(CMD_REBALANCE)->cmd; 54 | } 55 | -------------------------------------------------------------------------------- /monotone/main/main/execute.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Execute Execute; 15 | typedef struct Executable Executable; 16 | 17 | typedef void (*ExecuteFunction)(Executable*); 18 | 19 | enum 20 | { 21 | EXECUTE_LOCK_NONE, 22 | EXECUTE_LOCK_SHARED, 23 | EXECUTE_LOCK_EXCLUSIVE, 24 | }; 25 | 26 | struct Execute 27 | { 28 | ExecuteFunction function; 29 | int lock; 30 | }; 31 | 32 | struct Executable 33 | { 34 | Main* main; 35 | Cmd* cmd; 36 | Buf* output; 37 | }; 38 | 39 | void main_execute(Main*, const char*, char**); 40 | -------------------------------------------------------------------------------- /monotone/main/main/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Main Main; 15 | 16 | struct Main 17 | { 18 | Rwlock lock; 19 | File lock_directory; 20 | Engine engine; 21 | Wal wal; 22 | Service service; 23 | WorkerMgr worker_mgr; 24 | CloudMgr cloud_mgr; 25 | MemoryMgr memory_mgr; 26 | CompressionMgr compression_mgr; 27 | EncryptionMgr encryption_mgr; 28 | Random random; 29 | Comparator comparator; 30 | Logger logger; 31 | Context context; 32 | Control control; 33 | Config config; 34 | Global global; 35 | }; 36 | 37 | void main_init(Main*); 38 | void main_free(Main*); 39 | void main_prepare(Main*); 40 | void main_start(Main*, const char*); 41 | void main_stop(Main*); 42 | -------------------------------------------------------------------------------- /monotone/main/main/monotone_main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | #include "main/main.h" 15 | #include "main/execute.h" 16 | -------------------------------------------------------------------------------- /monotone/main/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @(cd ../.. && make --no-print-directory) 3 | clean: 4 | @(cd ../.. && make --no-print-directory clean) 5 | -------------------------------------------------------------------------------- /monotone/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @(cd .. && make --no-print-directory) 3 | clean: 4 | @(cd .. && make --no-print-directory clean) 5 | -------------------------------------------------------------------------------- /monotone/runtime/config/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Config Config; 15 | 16 | struct Config 17 | { 18 | // main 19 | Var version; 20 | Var uuid; 21 | Var directory; 22 | Var online; 23 | Var sync; 24 | // log 25 | Var log; 26 | Var log_to_file; 27 | Var log_to_stdout; 28 | // memory manager 29 | Var mm_page_size; 30 | Var mm_limit; 31 | Var mm_limit_wm; 32 | Var mm_limit_behaviour; 33 | Var mm_cache; 34 | // wal 35 | Var wal; 36 | Var wal_rotate_wm; 37 | Var wal_sync_on_rotate; 38 | Var wal_sync_on_write; 39 | Var wal_crc; 40 | // engine 41 | Var serial; 42 | Var interval; 43 | Var compression; 44 | Var compression_level; 45 | Var workers; 46 | Var workers_upload; 47 | // state 48 | Var ssn; 49 | Var lsn; 50 | Var clouds; 51 | Var storages; 52 | Var pipeline; 53 | // testing 54 | Var error_refresh_1; 55 | Var error_refresh_2; 56 | Var error_refresh_3; 57 | Var error_download; 58 | Var error_upload; 59 | Var error_wal; 60 | Var test_bool; 61 | Var test_int; 62 | Var test_string; 63 | Var test_data; 64 | List list; 65 | List list_persistent; 66 | int count; 67 | int count_visible; 68 | int count_config; 69 | int count_persistent; 70 | }; 71 | 72 | void config_init(Config*); 73 | void config_free(Config*); 74 | void config_prepare(Config*); 75 | void config_open(Config*, const char*); 76 | void config_save(Config*, const char*); 77 | void config_print(Config*); 78 | void config_show(Config*, Buf*); 79 | Var* config_find(Config*, Str*); 80 | -------------------------------------------------------------------------------- /monotone/runtime/config/control.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Control Control; 15 | 16 | struct Control 17 | { 18 | void (*save_config)(void*); 19 | void (*lock)(void*, bool); 20 | void (*unlock)(void*); 21 | void* arg; 22 | }; 23 | 24 | static inline void 25 | control_init(Control* self) 26 | { 27 | memset(self, 0, sizeof(*self)); 28 | } 29 | -------------------------------------------------------------------------------- /monotone/runtime/config/error_injection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | #define error_injection(name) \ 15 | if (unlikely(var_int_of(&config()->name))) \ 16 | error("error injection: %s", #name) 17 | -------------------------------------------------------------------------------- /monotone/runtime/config/monotone_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | // config 15 | #include "config/var.h" 16 | #include "config/config.h" 17 | 18 | // control 19 | #include "config/control.h" 20 | 21 | // shared state 22 | #include "config/global.h" 23 | 24 | // debug 25 | #include "config/error_injection.h" 26 | -------------------------------------------------------------------------------- /monotone/runtime/lib/cache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Cache Cache; 15 | 16 | struct Cache 17 | { 18 | Spinlock lock; 19 | List list; 20 | int list_count; 21 | }; 22 | 23 | static inline void 24 | cache_init(Cache* self) 25 | { 26 | self->list_count = 0; 27 | list_init(&self->list); 28 | spinlock_init(&self->lock); 29 | } 30 | 31 | static inline void 32 | cache_free(Cache* self) 33 | { 34 | assert(! self->list_count); 35 | spinlock_free(&self->lock); 36 | } 37 | 38 | static inline void 39 | cache_reset(Cache* self) 40 | { 41 | spinlock_lock(&self->lock); 42 | list_init(&self->list); 43 | self->list_count = 0; 44 | spinlock_unlock(&self->lock); 45 | } 46 | 47 | static inline List* 48 | cache_pop(Cache* self) 49 | { 50 | spinlock_lock(&self->lock); 51 | if (likely(self->list_count > 0)) 52 | { 53 | auto obj = list_pop(&self->list); 54 | self->list_count--; 55 | spinlock_unlock(&self->lock); 56 | return obj; 57 | } 58 | spinlock_unlock(&self->lock); 59 | return NULL; 60 | } 61 | 62 | static inline void 63 | cache_push(Cache* self, List* obj) 64 | { 65 | spinlock_lock(&self->lock); 66 | list_append(&self->list, obj); 67 | self->list_count++; 68 | spinlock_unlock(&self->lock); 69 | } 70 | -------------------------------------------------------------------------------- /monotone/runtime/lib/compression.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct CompressionIf CompressionIf; 15 | typedef struct Compression Compression; 16 | 17 | enum 18 | { 19 | COMPRESSION_NONE = 0, 20 | COMPRESSION_ZSTD = 1, 21 | COMPRESSION_LZ4 = 2 22 | }; 23 | 24 | struct CompressionIf 25 | { 26 | int id; 27 | Compression* (*create)(CompressionIf*); 28 | void (*free)(Compression*); 29 | void (*compress)(Compression*, Buf*, int, int, Buf**); 30 | void (*decompress)(Compression*, Buf*, uint8_t*, int, int); 31 | }; 32 | 33 | struct Compression 34 | { 35 | CompressionIf* iface; 36 | List link; 37 | }; 38 | 39 | static inline Compression* 40 | compression_create(CompressionIf* iface) 41 | { 42 | return iface->create(iface); 43 | } 44 | 45 | static inline void 46 | compression_free(Compression* self) 47 | { 48 | return self->iface->free(self); 49 | } 50 | 51 | static inline Compression* 52 | compression_of(List* link) 53 | { 54 | return container_of(link, Compression, link); 55 | } 56 | 57 | static inline void 58 | compression_compress(Compression* self, Buf* buf, int level, 59 | int argc, 60 | Buf** argv) 61 | { 62 | self->iface->compress(self, buf, level, argc, argv); 63 | } 64 | 65 | static inline void 66 | compression_decompress(Compression* self, 67 | Buf* buf, 68 | uint8_t* data, 69 | int data_size, 70 | int data_size_uncompressed) 71 | { 72 | self->iface->decompress(self, buf, 73 | data, 74 | data_size, 75 | data_size_uncompressed); 76 | } 77 | -------------------------------------------------------------------------------- /monotone/runtime/lib/compression_lz4.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | extern CompressionIf compression_lz4; 15 | -------------------------------------------------------------------------------- /monotone/runtime/lib/compression_mgr.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // monotone. 4 | // 5 | // embeddable cloud-native storage for events 6 | // and time-series data. 7 | // 8 | // Copyright (c) 2023-2025 Dmitry Simonenko 9 | // 10 | // MIT Licensed. 11 | // 12 | 13 | #include 14 | #include 15 | 16 | void 17 | compression_mgr_init(CompressionMgr* self) 18 | { 19 | cache_init(&self->cache_zstd); 20 | cache_init(&self->cache_lz4); 21 | } 22 | 23 | void 24 | compression_mgr_free(CompressionMgr* self) 25 | { 26 | list_foreach_safe(&self->cache_zstd.list) 27 | { 28 | auto ref = list_at(Compression, link); 29 | compression_free(ref); 30 | } 31 | cache_reset(&self->cache_zstd); 32 | cache_free(&self->cache_zstd); 33 | 34 | cache_reset(&self->cache_lz4); 35 | cache_free(&self->cache_lz4); 36 | } 37 | 38 | Compression* 39 | compression_mgr_pop(CompressionMgr* self, int id) 40 | { 41 | if (id == COMPRESSION_ZSTD) 42 | { 43 | auto ref = cache_pop(&self->cache_zstd); 44 | if (likely(ref)) 45 | return compression_of(ref); 46 | return compression_create(&compression_zstd); 47 | } 48 | if (id == COMPRESSION_LZ4) 49 | { 50 | auto ref = cache_pop(&self->cache_lz4); 51 | if (likely(ref)) 52 | return compression_of(ref); 53 | return compression_create(&compression_lz4); 54 | } 55 | return NULL; 56 | } 57 | 58 | void 59 | compression_mgr_push(CompressionMgr* self, Compression* compression) 60 | { 61 | if (compression->iface->id == COMPRESSION_ZSTD) 62 | { 63 | cache_push(&self->cache_zstd, &compression->link); 64 | return; 65 | } 66 | if (compression->iface->id == COMPRESSION_LZ4) 67 | { 68 | cache_push(&self->cache_zstd, &compression->link); 69 | return; 70 | } 71 | abort(); 72 | } 73 | 74 | int 75 | compression_mgr_of(Str* name) 76 | { 77 | if (!name || str_empty(name)) 78 | return COMPRESSION_NONE; 79 | if (str_compare_raw(name, "none", 4)) 80 | return COMPRESSION_NONE; 81 | if (str_compare_raw(name, "zstd", 4)) 82 | return COMPRESSION_ZSTD; 83 | if (str_compare_raw(name, "lz4", 3)) 84 | return COMPRESSION_LZ4; 85 | return -1; 86 | } 87 | -------------------------------------------------------------------------------- /monotone/runtime/lib/compression_mgr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct CompressionMgr CompressionMgr; 15 | 16 | struct CompressionMgr 17 | { 18 | Cache cache_zstd; 19 | Cache cache_lz4; 20 | }; 21 | 22 | void compression_mgr_init(CompressionMgr*); 23 | void compression_mgr_free(CompressionMgr*); 24 | Compression* 25 | compression_mgr_pop(CompressionMgr*, int); 26 | void compression_mgr_push(CompressionMgr*, Compression*); 27 | int compression_mgr_of(Str*); 28 | -------------------------------------------------------------------------------- /monotone/runtime/lib/compression_zstd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | extern CompressionIf compression_zstd; 15 | -------------------------------------------------------------------------------- /monotone/runtime/lib/crc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef uint32_t (*CrcFunction)(uint32_t crc, 15 | const void* data, 16 | int data_size); 17 | 18 | uint32_t crc32(uint32_t, const void*, int); 19 | bool crc32_sse_supported(void); 20 | uint32_t crc32_sse(uint32_t, const void*, int); 21 | -------------------------------------------------------------------------------- /monotone/runtime/lib/data_op.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | hot static inline bool 15 | map_find(uint8_t** pos, const char* name, int64_t name_size) 16 | { 17 | int count; 18 | data_read_map(pos, &count); 19 | int i; 20 | for (i = 0; i < count; i++) 21 | { 22 | Str key; 23 | data_read_string(pos, &key); 24 | if (str_compare_raw(&key, name, name_size)) 25 | return true; 26 | data_skip(pos); 27 | } 28 | return false; 29 | } 30 | 31 | hot static inline bool 32 | map_find_path(uint8_t** pos, Str* path) 33 | { 34 | const char* current = str_of(path); 35 | int left = str_size(path); 36 | for (;;) 37 | { 38 | int size = -1; 39 | int i = 0; 40 | for (; i < left; i++) { 41 | if (current[i] == '.') { 42 | size = i; 43 | break; 44 | } 45 | } 46 | if (size == -1) { 47 | if (! map_find(pos, current, left)) 48 | return false; 49 | break; 50 | } 51 | if (! map_find(pos, current, size)) 52 | return false; 53 | current += (size + 1); 54 | left -= (size + 1); 55 | } 56 | return true; 57 | } 58 | 59 | static inline bool 60 | map_has(uint8_t* map, Str* path) 61 | { 62 | return map_find_path(&map, path) > 0; 63 | } 64 | 65 | hot static inline bool 66 | array_find(uint8_t** pos, int position) 67 | { 68 | int count; 69 | data_read_array(pos, &count); 70 | if (unlikely(count <= position)) 71 | return false; 72 | int i; 73 | for (i = 0; i < position; i++) 74 | data_skip(pos); 75 | return true; 76 | } 77 | 78 | static inline bool 79 | array_has(uint8_t* array, int idx) 80 | { 81 | return array_find(&array, idx) > 0; 82 | } 83 | -------------------------------------------------------------------------------- /monotone/runtime/lib/encode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | always_inline hot static inline void 15 | encode_map(Buf* self, int count) 16 | { 17 | auto pos = buf_reserve(self, data_size_map(count)); 18 | data_write_map(pos, count); 19 | } 20 | 21 | always_inline hot static inline void 22 | encode_map32(Buf* self, int size) 23 | { 24 | auto pos = buf_reserve(self, data_size_map32()); 25 | data_write_map32(pos, size); 26 | } 27 | 28 | always_inline hot static inline void 29 | encode_array(Buf* self, int count) 30 | { 31 | auto pos = buf_reserve(self, data_size_array(count)); 32 | data_write_array(pos, count); 33 | } 34 | 35 | always_inline hot static inline void 36 | encode_array32(Buf* self, int count) 37 | { 38 | auto pos = buf_reserve(self, data_size_array32()); 39 | data_write_array32(pos, count); 40 | } 41 | 42 | always_inline hot static inline void 43 | encode_raw(Buf* self, const char* pointer, int size) 44 | { 45 | auto pos = buf_reserve(self, data_size_string(size)); 46 | data_write_raw(pos, pointer, size); 47 | } 48 | 49 | always_inline hot static inline void 50 | encode_buf(Buf* self, Buf* buf) 51 | { 52 | auto pos = buf_reserve(self, data_size_string(buf_size(buf))); 53 | data_write_raw(pos, (char*)buf->start, buf_size(buf)); 54 | } 55 | 56 | always_inline hot static inline void 57 | encode_cstr(Buf* self, const char* pointer) 58 | { 59 | encode_raw(self, pointer, strlen(pointer)); 60 | } 61 | 62 | always_inline hot static inline void 63 | encode_string(Buf* self, Str* string) 64 | { 65 | auto pos = buf_reserve(self, data_size_string(str_size(string))); 66 | data_write_string(pos, string); 67 | } 68 | 69 | always_inline hot static inline void 70 | encode_string32(Buf* self, int size) 71 | { 72 | auto pos = buf_reserve(self, data_size_string32()); 73 | data_write_string32(pos, size); 74 | } 75 | 76 | always_inline hot static inline void 77 | encode_integer(Buf* self, uint64_t value) 78 | { 79 | auto pos = buf_reserve(self, data_size_integer(value)); 80 | data_write_integer(pos, value); 81 | } 82 | 83 | always_inline hot static inline void 84 | encode_bool(Buf* self, bool value) 85 | { 86 | auto pos = buf_reserve(self, data_size_bool()); 87 | data_write_bool(pos, value); 88 | } 89 | 90 | always_inline hot static inline void 91 | encode_real(Buf* self, double value) 92 | { 93 | auto pos = buf_reserve(self, data_size_real(value)); 94 | data_write_real(pos, value); 95 | } 96 | 97 | always_inline hot static inline void 98 | encode_null(Buf* self) 99 | { 100 | auto pos = buf_reserve(self, data_size_null()); 101 | data_write_null(pos); 102 | } 103 | -------------------------------------------------------------------------------- /monotone/runtime/lib/encryption.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct EncryptionIf EncryptionIf; 15 | typedef struct Encryption Encryption; 16 | 17 | enum 18 | { 19 | ENCRYPTION_NONE = 0, 20 | ENCRYPTION_AES = 1 21 | }; 22 | 23 | struct EncryptionIf 24 | { 25 | int id; 26 | Encryption* (*create)(EncryptionIf*); 27 | void (*free)(Encryption*); 28 | void (*encrypt)(Encryption*, Random*, Str*, Buf*, int, Buf**); 29 | void (*decrypt)(Encryption*, Str*, Buf*, uint8_t*, int); 30 | }; 31 | 32 | struct Encryption 33 | { 34 | EncryptionIf* iface; 35 | List link; 36 | }; 37 | 38 | static inline Encryption* 39 | encryption_create(EncryptionIf* iface) 40 | { 41 | return iface->create(iface); 42 | } 43 | 44 | static inline void 45 | encryption_free(Encryption* self) 46 | { 47 | return self->iface->free(self); 48 | } 49 | 50 | static inline Encryption* 51 | encryption_of(List* link) 52 | { 53 | return container_of(link, Encryption, link); 54 | } 55 | 56 | static inline void 57 | encryption_encrypt(Encryption* self, Random* random, 58 | Str* key, 59 | Buf* buf, 60 | int argc, 61 | Buf** argv) 62 | { 63 | self->iface->encrypt(self, random, key, buf, argc, argv); 64 | } 65 | 66 | static inline void 67 | encryption_decrypt(Encryption* self, Str* key, 68 | Buf* buf, 69 | uint8_t* data, 70 | int data_size) 71 | { 72 | self->iface->decrypt(self, key, buf, data, data_size); 73 | } 74 | -------------------------------------------------------------------------------- /monotone/runtime/lib/encryption_aes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | extern EncryptionIf encryption_aes; 15 | -------------------------------------------------------------------------------- /monotone/runtime/lib/encryption_mgr.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // monotone. 4 | // 5 | // embeddable cloud-native storage for events 6 | // and time-series data. 7 | // 8 | // Copyright (c) 2023-2025 Dmitry Simonenko 9 | // 10 | // MIT Licensed. 11 | // 12 | 13 | #include 14 | #include 15 | 16 | void 17 | encryption_mgr_init(EncryptionMgr* self) 18 | { 19 | cache_init(&self->cache_aes); 20 | } 21 | 22 | void 23 | encryption_mgr_free(EncryptionMgr* self) 24 | { 25 | list_foreach_safe(&self->cache_aes.list) 26 | { 27 | auto ref = list_at(Encryption, link); 28 | encryption_free(ref); 29 | } 30 | cache_reset(&self->cache_aes); 31 | cache_free(&self->cache_aes); 32 | } 33 | 34 | Encryption* 35 | encryption_mgr_pop(EncryptionMgr* self, int id) 36 | { 37 | if (id == ENCRYPTION_AES) 38 | { 39 | auto ref = cache_pop(&self->cache_aes); 40 | if (likely(ref)) 41 | return encryption_of(ref); 42 | return encryption_create(&encryption_aes); 43 | } 44 | return NULL; 45 | } 46 | 47 | void 48 | encryption_mgr_push(EncryptionMgr* self, Encryption* encryption) 49 | { 50 | if (encryption->iface->id == ENCRYPTION_AES) 51 | { 52 | cache_push(&self->cache_aes, &encryption->link); 53 | return; 54 | } 55 | abort(); 56 | } 57 | 58 | int 59 | encryption_mgr_of(Str* name) 60 | { 61 | if (!name || str_empty(name)) 62 | return ENCRYPTION_NONE; 63 | if (str_compare_raw(name, "none", 4)) 64 | return COMPRESSION_NONE; 65 | if (str_compare_raw(name, "aes", 3)) 66 | return ENCRYPTION_AES; 67 | return -1; 68 | } 69 | -------------------------------------------------------------------------------- /monotone/runtime/lib/encryption_mgr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct EncryptionMgr EncryptionMgr; 15 | 16 | struct EncryptionMgr 17 | { 18 | Cache cache_aes; 19 | }; 20 | 21 | void encryption_mgr_init(EncryptionMgr*); 22 | void encryption_mgr_free(EncryptionMgr*); 23 | Encryption* 24 | encryption_mgr_pop(EncryptionMgr*, int); 25 | void encryption_mgr_push(EncryptionMgr*, Encryption*); 26 | int encryption_mgr_of(Str*); 27 | -------------------------------------------------------------------------------- /monotone/runtime/lib/heap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Heap Heap; 15 | 16 | struct Heap 17 | { 18 | Page* list; 19 | Page* list_tail; 20 | atomic_u32 list_count; 21 | MemoryMgr* memory_mgr; 22 | }; 23 | 24 | static inline void 25 | heap_init(Heap* self, MemoryMgr* memory_mgr) 26 | { 27 | self->list = NULL; 28 | self->list_tail = NULL; 29 | self->list_count = 0; 30 | self->memory_mgr = memory_mgr; 31 | } 32 | 33 | static inline void 34 | heap_reset(Heap* self) 35 | { 36 | uint32_t count = atomic_u32_of(&self->list_count); 37 | if (count > 0) 38 | memory_mgr_push(self->memory_mgr, 39 | self->list, 40 | self->list_tail, 41 | count); 42 | self->list = NULL; 43 | self->list_tail = NULL; 44 | atomic_u32_set(&self->list_count, 0); 45 | } 46 | 47 | static inline size_t 48 | heap_used(Heap* self) 49 | { 50 | uint32_t count = atomic_u32_of(&self->list_count); 51 | return count * (self->memory_mgr->page_size + sizeof(Page)); 52 | } 53 | 54 | hot static inline void* 55 | heap_allocate(Heap* self, int size) 56 | { 57 | if (unlikely(size > self->memory_mgr->page_size)) 58 | return NULL; 59 | Page* page; 60 | if (unlikely(self->list == NULL || 61 | (self->memory_mgr->page_size - self->list_tail->used) < size)) 62 | { 63 | page = memory_mgr_pop(self->memory_mgr); 64 | if (self->list == NULL) 65 | self->list = page; 66 | else 67 | self->list_tail->next = page; 68 | self->list_tail = page; 69 | atomic_u32_inc(&self->list_count); 70 | } else { 71 | page = self->list_tail; 72 | } 73 | void* ptr = page->data + page->used; 74 | page->used += size; 75 | return ptr; 76 | } 77 | -------------------------------------------------------------------------------- /monotone/runtime/lib/json.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Json Json; 15 | 16 | struct Json 17 | { 18 | const char* json; 19 | int json_size; 20 | int pos; 21 | Buf buf; 22 | }; 23 | 24 | void json_init(Json*); 25 | void json_free(Json*); 26 | void json_reset(Json*); 27 | void json_parse(Json*, Str*); 28 | void json_export(Buf*, uint8_t**); 29 | void json_export_pretty(Buf*, uint8_t**); 30 | -------------------------------------------------------------------------------- /monotone/runtime/lib/monotone_lib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | // data structures 15 | #include "lib/rbtree.h" 16 | 17 | // hashing 18 | #include "lib/random.h" 19 | #include "lib/uuid.h" 20 | #include "lib/crc.h" 21 | 22 | // marshaling 23 | #include "lib/data.h" 24 | #include "lib/data_op.h" 25 | #include "lib/encode.h" 26 | #include "lib/decode.h" 27 | 28 | // json 29 | #include "lib/json.h" 30 | 31 | // cache 32 | #include "lib/cache.h" 33 | 34 | // compression 35 | #include "lib/compression.h" 36 | #include "lib/compression_lz4.h" 37 | #include "lib/compression_zstd.h" 38 | #include "lib/compression_mgr.h" 39 | 40 | // encryption 41 | #include "lib/encryption.h" 42 | #include "lib/encryption_aes.h" 43 | #include "lib/encryption_mgr.h" 44 | 45 | // heap 46 | #include "lib/memory_mgr.h" 47 | #include "lib/heap.h" 48 | -------------------------------------------------------------------------------- /monotone/runtime/lib/random.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // monotone. 4 | // 5 | // embeddable cloud-native storage for events 6 | // and time-series data. 7 | // 8 | // Copyright (c) 2023-2025 Dmitry Simonenko 9 | // 10 | // MIT Licensed. 11 | // 12 | 13 | #include 14 | #include 15 | 16 | void 17 | random_init(Random* self) 18 | { 19 | self->seed[0] = 0; 20 | self->seed[1] = 0; 21 | spinlock_init(&self->lock); 22 | } 23 | 24 | void 25 | random_free(Random* self) 26 | { 27 | spinlock_free(&self->lock); 28 | } 29 | 30 | void 31 | random_open(Random* self) 32 | { 33 | uint64_t seed_random_dev[2] = { 0, 0 }; 34 | 35 | int fd; 36 | fd = vfs_open("/dev/urandom", O_RDONLY, 0644); 37 | if (unlikely(fd != -1)) 38 | { 39 | vfs_read(fd, seed_random_dev, sizeof(uint64_t) * 2); 40 | vfs_close(fd); 41 | } 42 | 43 | struct timespec ts; 44 | clock_gettime(CLOCK_MONOTONIC, &ts); 45 | 46 | uint64_t seed; 47 | seed = getpid() ^ getuid() ^ ts.tv_sec ^ ts.tv_nsec; 48 | seed_random_dev[0] ^= seed ^ rand(); 49 | seed_random_dev[1] ^= seed ^ rand(); 50 | 51 | self->seed[0] = seed_random_dev[0]; 52 | self->seed[1] = seed_random_dev[1]; 53 | } 54 | 55 | static inline uint64_t 56 | random_xorshift128plus(Random* self) 57 | { 58 | uint64_t a = self->seed[0]; 59 | uint64_t b = self->seed[1]; 60 | self->seed[0] = b; 61 | a ^= a << 23; 62 | self->seed[1] = a ^ b ^ (a >> 17) ^ (b >> 26); 63 | return self->seed[1] + b; 64 | } 65 | 66 | uint64_t 67 | random_generate(Random* self) 68 | { 69 | spinlock_lock(&self->lock); 70 | auto value = random_xorshift128plus(self); 71 | spinlock_unlock(&self->lock); 72 | return value; 73 | } 74 | 75 | void 76 | random_generate_alnum(Random* self, uint8_t* data, int data_size) 77 | { 78 | int data_pos = 0; 79 | for (;;) 80 | { 81 | uint64_t rnd = random_generate(self); 82 | uint8_t* pos = (uint8_t*)&rnd; 83 | for (int i = 0; i < 8; i++) 84 | { 85 | if (! isalnum(pos[i])) 86 | continue; 87 | data[data_pos] = pos[i]; 88 | data_pos++; 89 | if (data_pos == data_size) 90 | return; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /monotone/runtime/lib/random.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Random Random; 15 | 16 | struct Random 17 | { 18 | Spinlock lock; 19 | uint64_t seed[2]; 20 | }; 21 | 22 | void random_init(Random*); 23 | void random_free(Random*); 24 | void random_open(Random*); 25 | uint64_t random_generate(Random*); 26 | void random_generate_alnum(Random*, uint8_t*, int); 27 | -------------------------------------------------------------------------------- /monotone/runtime/lib/rbtree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct RbtreeNode RbtreeNode; 15 | typedef struct Rbtree Rbtree; 16 | 17 | struct RbtreeNode 18 | { 19 | RbtreeNode* p; 20 | RbtreeNode* l, *r; 21 | char color; 22 | }; 23 | 24 | struct Rbtree 25 | { 26 | RbtreeNode* root; 27 | }; 28 | 29 | #define rbtree_get_def(name) \ 30 | \ 31 | extern int \ 32 | name(Rbtree* self, \ 33 | void* arg, \ 34 | void* key, \ 35 | RbtreeNode** match);\ 36 | 37 | #define rbtree_get(name, compare) \ 38 | \ 39 | int \ 40 | name(Rbtree* self, \ 41 | void* arg, \ 42 | void* key, \ 43 | RbtreeNode** match) \ 44 | { \ 45 | unused(arg); \ 46 | unused(key); \ 47 | RbtreeNode *n = self->root; \ 48 | *match = NULL; \ 49 | int64_t rc = 0; \ 50 | while (n) \ 51 | { \ 52 | *match = n; \ 53 | rc = (compare); \ 54 | if (rc < 0) \ 55 | n = n->r; \ 56 | else \ 57 | if (rc > 0) \ 58 | n = n->l; \ 59 | else \ 60 | break; \ 61 | } \ 62 | return rc; \ 63 | } 64 | 65 | #define rbtree_free(name, executable) \ 66 | \ 67 | static inline void \ 68 | name(RbtreeNode* n, void* arg) \ 69 | { \ 70 | if (n->l) \ 71 | name(n->l, arg); \ 72 | if (n->r) \ 73 | name(n->r, arg); \ 74 | executable; \ 75 | } 76 | 77 | void rbtree_init(Rbtree*); 78 | void rbtree_init_node(RbtreeNode*); 79 | void rbtree_set(Rbtree*, RbtreeNode*, int, RbtreeNode*); 80 | void rbtree_replace(Rbtree*, RbtreeNode*, RbtreeNode*); 81 | void rbtree_remove(Rbtree*, RbtreeNode*); 82 | 83 | RbtreeNode* 84 | rbtree_min(Rbtree*); 85 | 86 | RbtreeNode* 87 | rbtree_max(Rbtree*); 88 | 89 | RbtreeNode* 90 | rbtree_next(Rbtree*, RbtreeNode*); 91 | 92 | RbtreeNode* 93 | rbtree_prev(Rbtree*, RbtreeNode*); 94 | -------------------------------------------------------------------------------- /monotone/runtime/lib/uuid.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // monotone. 4 | // 5 | // embeddable cloud-native storage for events 6 | // and time-series data. 7 | // 8 | // Copyright (c) 2023-2025 Dmitry Simonenko 9 | // 10 | // MIT Licensed. 11 | // 12 | 13 | #include 14 | #include 15 | 16 | typedef struct uuid_bits uuid_bits_t; 17 | 18 | struct uuid_bits 19 | { 20 | uint32_t a; 21 | uint16_t b; 22 | uint16_t c; 23 | uint16_t d; 24 | uint16_t e; 25 | uint32_t f; 26 | } packed; 27 | 28 | void 29 | uuid_init(Uuid* self) 30 | { 31 | self->a = 0; 32 | self->b = 0; 33 | } 34 | 35 | void 36 | uuid_generate(Uuid* self, Random* random) 37 | { 38 | self->a = random_generate(random); 39 | self->b = random_generate(random); 40 | } 41 | 42 | void 43 | uuid_to_string(Uuid* self, char* string, int size) 44 | { 45 | assert(size >= UUID_SZ); 46 | 47 | auto bits = (uuid_bits_t*)self; 48 | snprintf(string, size, "%08x-%04x-%04x-%04x-%04x%08x", 49 | bits->a, bits->b, bits->c, 50 | bits->d, bits->e, bits->f); 51 | } 52 | 53 | int 54 | uuid_from_string_nothrow(Uuid* self, Str* src) 55 | { 56 | if (unlikely(str_size(src) < (UUID_SZ - 1))) 57 | return -1; 58 | 59 | auto string = str_of(src); 60 | auto bits = (uuid_bits_t*)self; 61 | 62 | // convert 63 | uint64_t value = 0; 64 | int i = 0; 65 | for (; i < 36; i++) 66 | { 67 | switch (i) { 68 | case 8: 69 | if (unlikely(string[i] != '-')) 70 | return -1; 71 | bits->a = value; 72 | value = 0; 73 | break; 74 | case 13: 75 | if (unlikely(string[i] != '-')) 76 | return -1; 77 | bits->b = value; 78 | value = 0; 79 | break; 80 | case 18: 81 | if (unlikely(string[i] != '-')) 82 | return -1; 83 | bits->c = value; 84 | value = 0; 85 | break; 86 | case 23: 87 | if (unlikely(string[i] != '-')) 88 | return -1; 89 | bits->d = value; 90 | value = 0; 91 | break; 92 | case 28: 93 | bits->e = value; 94 | value = 0; 95 | // fallthrough 96 | default: 97 | { 98 | uint8_t byte = string[i]; 99 | if (byte >= '0' && byte <= '9') 100 | byte = byte - '0'; 101 | else 102 | if (byte >= 'a' && byte <= 'f') 103 | byte = byte - 'a' + 10; 104 | else 105 | if (byte >= 'A' && byte <= 'F') 106 | byte = byte - 'A' + 10; 107 | else 108 | return -1; 109 | value = (value << 4) | (byte & 0xF); 110 | break; 111 | } 112 | } 113 | } 114 | bits->f = value; 115 | return 0; 116 | } 117 | 118 | void 119 | uuid_from_string(Uuid* self, Str* src) 120 | { 121 | int rc = uuid_from_string_nothrow(self, src); 122 | if (unlikely(rc == -1)) 123 | error("%s", "failed to parse uuid"); 124 | } 125 | -------------------------------------------------------------------------------- /monotone/runtime/lib/uuid.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Uuid Uuid; 15 | 16 | #define UUID_SZ 37 17 | 18 | struct Uuid 19 | { 20 | uint64_t a; 21 | uint64_t b; 22 | }; 23 | 24 | void uuid_init(Uuid*); 25 | void uuid_generate(Uuid*, Random*); 26 | void uuid_to_string(Uuid*, char*, int); 27 | void uuid_from_string(Uuid*, Str*); 28 | int uuid_from_string_nothrow(Uuid*, Str*); 29 | 30 | static inline bool 31 | uuid_empty(Uuid* self) 32 | { 33 | return self->a == 0 && self->b == 0; 34 | } 35 | 36 | static inline bool 37 | uuid_compare(Uuid *l, Uuid *r) 38 | { 39 | return l->a == r->a && l->b == r->b; 40 | } 41 | -------------------------------------------------------------------------------- /monotone/runtime/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @(cd ../.. && make --no-print-directory) 3 | clean: 4 | @(cd ../.. && make --no-print-directory clean) 5 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | static inline void* 15 | mn_malloc(size_t size) 16 | { 17 | auto ptr = malloc(size); 18 | if (unlikely(ptr == NULL)) 19 | error_system(); 20 | return ptr; 21 | } 22 | 23 | static inline void* 24 | mn_realloc(void* pointer, size_t size) 25 | { 26 | auto ptr = realloc(pointer, size); 27 | if (unlikely(ptr == NULL)) 28 | error_system(); 29 | return ptr; 30 | } 31 | 32 | static inline void 33 | mn_free(void* pointer) 34 | { 35 | free(pointer); 36 | } 37 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/atomic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef volatile uint32_t atomic_u32; 15 | typedef volatile uint64_t atomic_u64; 16 | 17 | static inline uint32_t 18 | atomic_u32_of(atomic_u32* self) 19 | { 20 | return __sync_fetch_and_add(self, 0); 21 | } 22 | 23 | static inline uint32_t 24 | atomic_u32_inc(atomic_u32* self) 25 | { 26 | return __sync_fetch_and_add(self, 1); 27 | } 28 | 29 | static inline uint32_t 30 | atomic_u32_dec(atomic_u32* self) 31 | { 32 | return __sync_fetch_and_sub(self, 1); 33 | } 34 | 35 | static inline uint32_t 36 | atomic_u32_set(atomic_u32* self, uint32_t value) 37 | { 38 | return __sync_lock_test_and_set(self, value); 39 | } 40 | 41 | static inline uint64_t 42 | atomic_u64_of(atomic_u64* self) 43 | { 44 | return __sync_fetch_and_add(self, 0); 45 | } 46 | 47 | static inline uint64_t 48 | atomic_u64_add(atomic_u64* self, uint64_t value) 49 | { 50 | return __sync_fetch_and_add(self, value); 51 | } 52 | 53 | static inline uint64_t 54 | atomic_u64_inc(atomic_u64* self) 55 | { 56 | return __sync_fetch_and_add(self, 1); 57 | } 58 | 59 | static inline uint64_t 60 | atomic_u64_dec(atomic_u64* self) 61 | { 62 | return __sync_fetch_and_sub(self, 1); 63 | } 64 | 65 | static inline uint64_t 66 | atomic_u64_set(atomic_u64* self, uint64_t value) 67 | { 68 | return __sync_lock_test_and_set(self, value); 69 | } 70 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/c.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | #ifndef _GNU_SOURCE 15 | #define _GNU_SOURCE 16 | #endif 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/clock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | static inline uint64_t 15 | time_us(void) 16 | { 17 | struct timespec t; 18 | clock_gettime(CLOCK_REALTIME, &t); 19 | uint64_t time_ns = t.tv_sec * (uint64_t)1e9 + t.tv_nsec; 20 | // us 21 | return time_ns / 1000; 22 | } 23 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/cond_var.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct CondVar CondVar; 15 | 16 | struct CondVar 17 | { 18 | pthread_cond_t var; 19 | }; 20 | 21 | static inline void 22 | cond_var_init(CondVar* self) 23 | { 24 | pthread_cond_init(&self->var, NULL); 25 | } 26 | 27 | static inline void 28 | cond_var_free(CondVar* self) 29 | { 30 | pthread_cond_destroy(&self->var); 31 | } 32 | 33 | static inline void 34 | cond_var_signal(CondVar* self) 35 | { 36 | pthread_cond_signal(&self->var); 37 | } 38 | 39 | static inline void 40 | cond_var_broadcast(CondVar* self) 41 | { 42 | pthread_cond_broadcast(&self->var); 43 | } 44 | 45 | static inline void 46 | cond_var_wait(CondVar* self, Mutex* mutex) 47 | { 48 | pthread_cond_wait(&self->var, &mutex->lock); 49 | } 50 | 51 | static inline void 52 | cond_var_timedwait(CondVar* self, Mutex* mutex, int time_ms) 53 | { 54 | struct timeval tv; 55 | gettimeofday(&tv, NULL); 56 | struct timespec ts; 57 | ts.tv_sec = tv.tv_sec + (time_ms / 1000); 58 | ts.tv_nsec = (tv.tv_usec * 1000) + (time_ms % 1000) * 1000000; 59 | pthread_cond_timedwait(&self->var, &mutex->lock, &ts); 60 | } 61 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Error Error; 15 | 16 | struct Error 17 | { 18 | char text[256]; 19 | int text_len; 20 | const char* file; 21 | const char* function; 22 | int line; 23 | LogFunction log; 24 | void* log_arg; 25 | }; 26 | 27 | static inline void 28 | error_init(Error* self, LogFunction log, void* log_arg) 29 | { 30 | self->text_len = 0; 31 | self->text[0] = 0; 32 | self->file = NULL; 33 | self->function = NULL; 34 | self->line = 0; 35 | self->log = log; 36 | self->log_arg = log_arg; 37 | } 38 | 39 | static inline void 40 | error_reset(Error* self) 41 | { 42 | self->text_len = 0; 43 | self->text[0] = 0; 44 | self->file = NULL; 45 | self->function = NULL; 46 | self->line = 0; 47 | } 48 | 49 | static inline void no_return 50 | error_throw_as(Error* self, 51 | ExceptionMgr* mgr, 52 | const char* file, 53 | const char* function, int line, 54 | const char* fmt, 55 | ...) 56 | { 57 | va_list args; 58 | if (self->log) 59 | { 60 | va_start(args, fmt); 61 | if (self->log) 62 | self->log(self->log_arg, file, function, line, "error: ", fmt, args); 63 | va_end(args); 64 | } 65 | va_start(args, fmt); 66 | self->file = file; 67 | self->function = function; 68 | self->line = line; 69 | self->text_len = vsnprintf(self->text, sizeof(self->text), fmt, args); 70 | va_end(args); 71 | exception_mgr_throw(mgr); 72 | } 73 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/exception.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Guard Guard; 15 | typedef struct Exception Exception; 16 | typedef struct ExceptionMgr ExceptionMgr; 17 | 18 | typedef void (*GuardFunction)(void*); 19 | 20 | struct Guard 21 | { 22 | GuardFunction function; 23 | void* function_arg; 24 | Guard* prev; 25 | }; 26 | 27 | struct Exception 28 | { 29 | Exception* prev; 30 | bool triggered; 31 | Guard* guard_stack; 32 | jmp_buf buf; 33 | }; 34 | 35 | struct ExceptionMgr 36 | { 37 | Exception* last; 38 | }; 39 | 40 | static inline void 41 | exception_mgr_init(ExceptionMgr* self) 42 | { 43 | self->last = NULL; 44 | } 45 | 46 | static inline void 47 | exception_mgr_execute_guards(Guard* guard) 48 | { 49 | for (; guard; guard = guard->prev) 50 | { 51 | if (guard->function == NULL) 52 | continue; 53 | guard->function(guard->function_arg); 54 | guard->function = NULL; 55 | } 56 | } 57 | 58 | static inline void no_return 59 | exception_mgr_throw(ExceptionMgr* self) 60 | { 61 | auto current = self->last; 62 | assert(current); 63 | exception_mgr_execute_guards(current->guard_stack); 64 | current->guard_stack = NULL; 65 | current->triggered = true; 66 | longjmp(self->last->buf, 1); 67 | } 68 | 69 | #define exception_mgr_enter(self, exception) \ 70 | ({ \ 71 | (exception)->prev = (self)->last; \ 72 | (exception)->triggered = false; \ 73 | (exception)->guard_stack = NULL; \ 74 | (self)->last = (exception); \ 75 | setjmp((exception)->buf) == 0; \ 76 | }) 77 | 78 | always_inline static inline bool 79 | exception_mgr_leave(ExceptionMgr* self, Exception* exception) 80 | { 81 | self->last = exception->prev; 82 | return exception->triggered; 83 | } 84 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/fs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | static inline bool 15 | fs_exists(const char* fmt, ...) 16 | { 17 | va_list args; 18 | va_start(args, fmt); 19 | char path[PATH_MAX]; 20 | vsnprintf(path, sizeof(path), fmt, args); 21 | va_end(args); 22 | return vfs_size(path) >= 0; 23 | } 24 | 25 | static inline void 26 | fs_mkdir(int mode, const char* fmt, ...) 27 | { 28 | va_list args; 29 | va_start(args, fmt); 30 | char path[PATH_MAX]; 31 | vsnprintf(path, sizeof(path), fmt, args); 32 | va_end(args); 33 | int rc = vfs_mkdir(path, mode); 34 | if (unlikely(rc == -1)) 35 | error_system(); 36 | } 37 | 38 | static inline void 39 | fs_unlink(const char* fmt, ...) 40 | { 41 | va_list args; 42 | va_start(args, fmt); 43 | char path[PATH_MAX]; 44 | vsnprintf(path, sizeof(path), fmt, args); 45 | va_end(args); 46 | int rc = vfs_unlink(path); 47 | if (unlikely(rc == -1)) 48 | error_system(); 49 | } 50 | 51 | static inline void 52 | fs_rename(const char* old, const char* fmt, ...) 53 | { 54 | va_list args; 55 | va_start(args, fmt); 56 | char path[PATH_MAX]; 57 | vsnprintf(path, sizeof(path), fmt, args); 58 | va_end(args); 59 | int rc = vfs_rename(old, path); 60 | if (unlikely(rc == -1)) 61 | error_system(); 62 | } 63 | 64 | static inline int64_t 65 | fs_size(const char* fmt, ...) 66 | { 67 | va_list args; 68 | va_start(args, fmt); 69 | char path[PATH_MAX]; 70 | vsnprintf(path, sizeof(path), fmt, args); 71 | va_end(args); 72 | return vfs_size(path); 73 | } 74 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/guard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | always_inline static inline Guard* 15 | guard_pop(void) 16 | { 17 | auto exception = mn_runtime.exception_mgr.last; 18 | auto self = exception->guard_stack; 19 | exception->guard_stack = self->prev; 20 | return self; 21 | } 22 | 23 | always_inline static inline void 24 | guard_runner(Guard* self) 25 | { 26 | if (! self->function) 27 | return; 28 | guard_pop(); 29 | self->function(self->function_arg); 30 | self->function = NULL; 31 | } 32 | 33 | always_inline static inline void* 34 | unguard(void) 35 | { 36 | auto self = guard_pop(); 37 | self->function = NULL; 38 | return self->function_arg; 39 | } 40 | 41 | #define guard_as(self, func, func_arg) \ 42 | Guard __attribute((cleanup(guard_runner))) self = { \ 43 | .function = (GuardFunction)func, \ 44 | .function_arg = func_arg, \ 45 | .prev = ({ \ 46 | auto exception = mn_runtime.exception_mgr.last; \ 47 | auto prev = exception->guard_stack; \ 48 | exception->guard_stack = &self; \ 49 | prev; \ 50 | }) \ 51 | } 52 | 53 | #define guard_auto_def(name, line, func, func_arg) \ 54 | guard_as(name##line, func, func_arg) 55 | 56 | #define guard_auto(name, line, func, func_arg) \ 57 | guard_auto_def(name, line, func, func_arg) 58 | 59 | #define guard(func, func_arg) \ 60 | guard_auto(_guard_, __LINE__, func, func_arg) 61 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/iov.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Iov Iov; 15 | 16 | struct Iov 17 | { 18 | Buf iov; 19 | int iov_count; 20 | int size; 21 | }; 22 | 23 | static inline void 24 | iov_init(Iov* self) 25 | { 26 | self->size = 0; 27 | self->iov_count = 0; 28 | buf_init(&self->iov); 29 | } 30 | 31 | static inline void 32 | iov_free(Iov* self) 33 | { 34 | buf_free(&self->iov); 35 | } 36 | 37 | static inline void 38 | iov_reset(Iov* self) 39 | { 40 | self->size = 0; 41 | self->iov_count = 0; 42 | buf_reset(&self->iov); 43 | } 44 | 45 | static inline struct iovec* 46 | iov_pointer(Iov* self) 47 | { 48 | return (struct iovec*)self->iov.start; 49 | } 50 | 51 | static inline void 52 | iov_reserve(Iov* self, int count) 53 | { 54 | buf_reserve(&self->iov, sizeof(struct iovec) * count); 55 | } 56 | 57 | static inline void 58 | iov_add(Iov* self, void* pointer, int size) 59 | { 60 | buf_reserve(&self->iov, sizeof(struct iovec)); 61 | auto iov = (struct iovec*)self->iov.position; 62 | iov->iov_base = pointer; 63 | iov->iov_len = size; 64 | buf_advance(&self->iov, sizeof(struct iovec)); 65 | self->iov_count++; 66 | self->size += size; 67 | } 68 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/list.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct List List; 15 | 16 | struct List 17 | { 18 | List* next; 19 | List* prev; 20 | }; 21 | 22 | static inline void 23 | list_init(List* self) 24 | { 25 | self->next = self->prev = self; 26 | } 27 | 28 | static inline bool 29 | list_empty(List* self) 30 | { 31 | return self->next == self && 32 | self->prev == self; 33 | } 34 | 35 | static inline bool 36 | list_is_last(List* self, List* link) 37 | { 38 | return link->next == self; 39 | } 40 | 41 | static inline void 42 | list_append(List* self, List* link) 43 | { 44 | link->next = self; 45 | link->prev = self->prev; 46 | link->prev->next = link; 47 | link->next->prev = link; 48 | } 49 | 50 | static inline void 51 | list_unlink(List* link) 52 | { 53 | link->prev->next = link->next; 54 | link->next->prev = link->prev; 55 | } 56 | 57 | static inline void 58 | list_push(List* self, List* link) 59 | { 60 | link->next = self->next; 61 | link->prev = self; 62 | link->prev->next = link; 63 | link->next->prev = link; 64 | } 65 | 66 | static inline List* 67 | list_pop(List* self) 68 | { 69 | List* pop = self->next; 70 | list_unlink(pop); 71 | return pop; 72 | } 73 | 74 | #define list_foreach(list) \ 75 | for (typeof(list) _i = (list)->next; _i != list; _i = _i->next) 76 | 77 | #define list_foreach_safe(list) \ 78 | for (typeof(list) _i_copy, _i = (list)->next; \ 79 | _i != list && (_i_copy = _i->next); \ 80 | _i = _i_copy) 81 | 82 | #define list_foreach_after(list, link) \ 83 | for (typeof(list) _i = (link)->next; _i != list; _i = _i->next) 84 | 85 | #define list_foreach_reverse(list) \ 86 | for (typeof(list) _i = (list)->prev; _i != list; _i = _i->prev) 87 | 88 | #define list_foreach_reverse_safe(list) \ 89 | for (typeof(list) _i_copy, _i = (list)->prev; \ 90 | _i != list && (_i_copy = _i->prev); \ 91 | _i = _i_copy) 92 | 93 | #define list_at(type, link) container_of(_i, type, link) 94 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef void (*LogFunction)(void* arg, 15 | const char* file, 16 | const char* function, int line, 17 | const char* prefix, 18 | const char* fmt, 19 | va_list args); 20 | 21 | static inline void 22 | log_at(LogFunction log, void* log_arg, 23 | const char* file, 24 | const char* function, int line, 25 | const char* fmt, 26 | ...) 27 | { 28 | if (log == NULL) 29 | return; 30 | va_list args; 31 | va_start(args, fmt); 32 | log(log_arg, file, function, line, "", fmt, args); 33 | va_end(args); 34 | } 35 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/logger.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // monotone. 4 | // 5 | // embeddable cloud-native storage for events 6 | // and time-series data. 7 | // 8 | // Copyright (c) 2023-2025 Dmitry Simonenko 9 | // 10 | // MIT Licensed. 11 | // 12 | 13 | #include 14 | 15 | void 16 | logger_set_enable(Logger* self, bool enable) 17 | { 18 | self->enable = enable; 19 | } 20 | 21 | void 22 | logger_set_to_stdout(Logger *self, bool enable) 23 | { 24 | self->to_stdout = enable; 25 | } 26 | 27 | void 28 | logger_init(Logger* self) 29 | { 30 | self->enable = true; 31 | self->to_stdout = true; 32 | self->fd = -1; 33 | } 34 | 35 | void 36 | logger_open(Logger* self, const char* path) 37 | { 38 | int rc; 39 | rc = vfs_open(path, O_APPEND|O_RDWR|O_CREAT, 0644); 40 | if (unlikely(rc == -1)) 41 | error_system(); 42 | self->fd = rc; 43 | } 44 | 45 | void 46 | logger_close(Logger* self) 47 | { 48 | if (self->fd != -1) 49 | { 50 | vfs_close(self->fd); 51 | self->fd = -1; 52 | } 53 | } 54 | 55 | void 56 | logger_write(Logger* self, 57 | const char* file, 58 | const char* function, 59 | int line, 60 | const char* prefix, 61 | const char* fmt, 62 | va_list args) 63 | { 64 | unused(file); 65 | unused(function); 66 | unused(line); 67 | if (! self->enable) 68 | return; 69 | 70 | int len = 0; 71 | char buffer[1024]; 72 | 73 | // time 74 | struct timeval tv; 75 | gettimeofday(&tv, NULL); 76 | len += strftime(buffer + len, sizeof(buffer) - len, "%d.%m.%y %H:%M:%S.", 77 | localtime(&tv.tv_sec)); 78 | len += snprintf(buffer + len, sizeof(buffer) - len, "%03d ", 79 | (signed)tv.tv_usec / 1000); 80 | 81 | // prefix 82 | if (prefix) 83 | len += snprintf(buffer + len, sizeof(buffer) - len, "%s", prefix); 84 | 85 | // message 86 | len += vsnprintf(buffer + len, sizeof(buffer) - len, fmt, args); 87 | len += snprintf(buffer + len, sizeof(buffer) - len, "\n"); 88 | 89 | // write 90 | if (self->fd != -1) 91 | vfs_write(self->fd, buffer, len); 92 | 93 | if (self->to_stdout) 94 | vfs_write(STDOUT_FILENO, buffer, len); 95 | } 96 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Logger Logger; 15 | 16 | struct Logger 17 | { 18 | bool enable; 19 | bool to_stdout; 20 | int fd; 21 | }; 22 | 23 | void logger_init(Logger*); 24 | void logger_open(Logger*, const char*); 25 | void logger_set_enable(Logger*, bool enable); 26 | void logger_set_to_stdout(Logger*, bool enable); 27 | void logger_close(Logger*); 28 | void logger_write(Logger*, const char*, const char*, int, const char*, 29 | const char*, va_list); 30 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/macro.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | #define likely(expr) __builtin_expect(!! (expr), 1) 15 | #define unlikely(expr) __builtin_expect(!! (expr), 0) 16 | #define hot __attribute__((hot)) 17 | #define always_inline __attribute__((always_inline)) 18 | #define packed __attribute__((packed)) 19 | #define no_return __attribute__((noreturn)) 20 | #define fallthrough __attribute__((fallthrough)); 21 | #define auto __auto_type 22 | #define unused(name) (void)name 23 | 24 | #define source_file __FILE__ 25 | #define source_function __func__ 26 | #define source_line __LINE__ 27 | 28 | #define container_of(ptr, type, field) \ 29 | ((type*)((char*)(ptr) - __builtin_offsetof(type, field))) 30 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/misc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | always_inline static inline int64_t 15 | compare_u64(uint64_t a, uint64_t b) 16 | { 17 | return (int64_t)a - (int64_t)b; 18 | } 19 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/monotone_runtime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | // compiler 15 | #include "runtime/c.h" 16 | #include "runtime/macro.h" 17 | 18 | // os 19 | #include "runtime/atomic.h" 20 | #include "runtime/spinlock.h" 21 | #include "runtime/rwlock.h" 22 | #include "runtime/mutex.h" 23 | #include "runtime/cond_var.h" 24 | #include "runtime/thread.h" 25 | 26 | // basic data structures 27 | #include "runtime/list.h" 28 | #include "runtime/misc.h" 29 | 30 | // exceptions 31 | #include "runtime/exception.h" 32 | #include "runtime/log.h" 33 | #include "runtime/error.h" 34 | 35 | // runtime 36 | #include "runtime/runtime.h" 37 | #include "runtime/throw.h" 38 | #include "runtime/guard.h" 39 | 40 | // allocator 41 | #include "runtime/allocator.h" 42 | #include "runtime/str.h" 43 | #include "runtime/buf.h" 44 | 45 | // clock 46 | #include "runtime/clock.h" 47 | 48 | // file io 49 | #include "runtime/iov.h" 50 | #include "runtime/vfs.h" 51 | #include "runtime/fs.h" 52 | #include "runtime/file.h" 53 | #include "runtime/logger.h" 54 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/mutex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Mutex Mutex; 15 | 16 | struct Mutex 17 | { 18 | pthread_mutex_t lock; 19 | }; 20 | 21 | static inline void 22 | mutex_init(Mutex* self) 23 | { 24 | pthread_mutex_init(&self->lock, NULL); 25 | } 26 | 27 | static inline void 28 | mutex_free(Mutex* self) 29 | { 30 | pthread_mutex_destroy(&self->lock); 31 | } 32 | 33 | static inline void 34 | mutex_lock(Mutex* self) 35 | { 36 | pthread_mutex_lock(&self->lock); 37 | } 38 | 39 | static inline void 40 | mutex_unlock(Mutex* self) 41 | { 42 | pthread_mutex_unlock(&self->lock); 43 | } 44 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/runtime.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // monotone. 4 | // 5 | // embeddable cloud-native storage for events 6 | // and time-series data. 7 | // 8 | // Copyright (c) 2023-2025 Dmitry Simonenko 9 | // 10 | // MIT Licensed. 11 | // 12 | 13 | #include 14 | 15 | __thread Runtime mn_runtime; 16 | 17 | void 18 | runtime_init(Context* context) 19 | { 20 | exception_mgr_init(&mn_runtime.exception_mgr); 21 | error_init(&mn_runtime.error, context->log, context->log_arg); 22 | mn_runtime.context = context; 23 | } 24 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/runtime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Context Context; 15 | typedef struct Runtime Runtime; 16 | 17 | struct Context 18 | { 19 | LogFunction log; 20 | void* log_arg; 21 | void* global; 22 | }; 23 | 24 | struct Runtime 25 | { 26 | ExceptionMgr exception_mgr; 27 | Error error; 28 | Context* context; 29 | }; 30 | 31 | extern __thread Runtime mn_runtime; 32 | 33 | void runtime_init(Context*); 34 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/rwlock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Rwlock Rwlock; 15 | 16 | struct Rwlock 17 | { 18 | pthread_rwlock_t lock; 19 | }; 20 | 21 | static inline void 22 | rwlock_init(Rwlock* self) 23 | { 24 | pthread_rwlock_init(&self->lock, NULL); 25 | } 26 | 27 | static inline void 28 | rwlock_free(Rwlock* self) 29 | { 30 | pthread_rwlock_destroy(&self->lock); 31 | } 32 | 33 | static inline void 34 | rwlock_rdlock(Rwlock* self) 35 | { 36 | pthread_rwlock_rdlock(&self->lock); 37 | } 38 | 39 | static inline void 40 | rwlock_wrlock(Rwlock* self) 41 | { 42 | pthread_rwlock_wrlock(&self->lock); 43 | } 44 | 45 | static inline void 46 | rwlock_lock(Rwlock* self, bool shared) 47 | { 48 | if (shared) 49 | rwlock_rdlock(self); 50 | else 51 | rwlock_wrlock(self); 52 | } 53 | 54 | static inline void 55 | rwlock_unlock(Rwlock* self) 56 | { 57 | pthread_rwlock_unlock(&self->lock); 58 | } 59 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/spinlock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Spinlock Spinlock; 15 | 16 | struct Spinlock 17 | { 18 | pthread_spinlock_t lock; 19 | }; 20 | 21 | static inline void 22 | spinlock_init(Spinlock* self) 23 | { 24 | pthread_spin_init(&self->lock, PTHREAD_PROCESS_PRIVATE); 25 | } 26 | 27 | static inline void 28 | spinlock_free(Spinlock* self) 29 | { 30 | pthread_spin_destroy(&self->lock); 31 | } 32 | 33 | static inline void 34 | spinlock_lock(Spinlock* self) 35 | { 36 | pthread_spin_lock(&self->lock); 37 | } 38 | 39 | static inline void 40 | spinlock_unlock(Spinlock* self) 41 | { 42 | pthread_spin_unlock(&self->lock); 43 | } 44 | 45 | #if 0 46 | typedef uint8_t Spinlock; 47 | 48 | #if defined(__x86_64__) || defined(__i386) || defined(_X86_) 49 | # define MN_SPINLOCK_BACKOFF __asm__ ("pause") 50 | #else 51 | # define MN_SPINLOCK_BACKOFF 52 | #endif 53 | 54 | static inline void 55 | spinlock_init(Spinlock* self) 56 | { 57 | *self = 0; 58 | } 59 | 60 | static inline void 61 | spinlock_free(Spinlock* self) 62 | { 63 | *self = 0; 64 | } 65 | 66 | static inline void 67 | spinlock_lock(Spinlock* self) 68 | { 69 | if (__sync_lock_test_and_set(self, 1) != 0) { 70 | unsigned int spcount = 0U; 71 | for (;;) { 72 | MN_SPINLOCK_BACKOFF; 73 | if (*self == 0U && __sync_lock_test_and_set(self, 1) == 0) 74 | break; 75 | if (++spcount > 100U) 76 | usleep(0); 77 | } 78 | } 79 | } 80 | 81 | static inline void 82 | spinlock_unlock(Spinlock* self) 83 | { 84 | __sync_lock_release(self); 85 | } 86 | #endif 87 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Thread Thread; 15 | 16 | typedef void* (*ThreadFunction)(void*); 17 | 18 | struct Thread 19 | { 20 | pthread_t id; 21 | ThreadFunction function; 22 | void* arg; 23 | }; 24 | 25 | static inline void 26 | thread_init(Thread* self) 27 | { 28 | self->id = 0; 29 | self->function = NULL; 30 | self->arg = NULL; 31 | } 32 | 33 | static inline int 34 | thread_create(Thread* self, ThreadFunction function, void* arg) 35 | { 36 | self->function = function; 37 | self->arg = arg; 38 | int rc; 39 | rc = pthread_create(&self->id, NULL, function, self->arg); 40 | if (rc != 0) 41 | return -1; 42 | return 0; 43 | } 44 | 45 | static inline int 46 | thread_join(Thread* self) 47 | { 48 | int rc; 49 | rc = pthread_join(self->id, NULL); 50 | if (rc != 0) 51 | return -1; 52 | self->id = 0; 53 | return 0; 54 | } 55 | 56 | static inline int 57 | thread_set_name(Thread* self, const char* name) 58 | { 59 | int rc; 60 | rc = pthread_setname_np(self->id, name); 61 | return rc; 62 | } 63 | 64 | static inline void 65 | thread_set_sigmask_default(void) 66 | { 67 | sigset_t mask; 68 | sigemptyset(&mask); 69 | sigaddset(&mask, SIGPIPE); 70 | pthread_sigmask(SIG_BLOCK, &mask, NULL); 71 | } 72 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/throw.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | // enter/leave 15 | #define enter(exception) \ 16 | exception_mgr_enter(&mn_runtime.exception_mgr, exception) 17 | 18 | #define leave(exception) \ 19 | exception_mgr_leave(&mn_runtime.exception_mgr, exception) 20 | 21 | // throw 22 | #define rethrow() \ 23 | exception_mgr_throw(&mn_runtime.exception_mgr) 24 | 25 | #define error_throw(fmt, ...) \ 26 | error_throw_as(&mn_runtime.error, \ 27 | &mn_runtime.exception_mgr, \ 28 | source_file, \ 29 | source_function, \ 30 | source_line, \ 31 | fmt, ## __VA_ARGS__) 32 | 33 | // errors 34 | #define error(fmt, ...) \ 35 | error_throw(fmt, ## __VA_ARGS__) 36 | 37 | #define error_system() \ 38 | error_throw("%s(): %s (errno: %d)", source_function, \ 39 | strerror(errno), errno) 40 | 41 | #define error_data() \ 42 | error_throw("data read error") 43 | 44 | // log 45 | #define log(fmt, ...) \ 46 | log_at(mn_runtime.context->log, \ 47 | mn_runtime.context->log_arg, \ 48 | source_file, \ 49 | source_function, \ 50 | source_line, fmt, ## __VA_ARGS__) 51 | -------------------------------------------------------------------------------- /monotone/runtime/runtime/vfs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | int vfs_unlink(const char*); 15 | int vfs_rename(const char*, const char*); 16 | int vfs_mkdir(const char*, int); 17 | int vfs_rmdir(const char*); 18 | int vfs_open(const char*, int, int); 19 | int vfs_close(int); 20 | int vfs_flock_shared(int); 21 | int vfs_flock_exclusive(int); 22 | int vfs_flock_unlock(int); 23 | int vfs_sync(int); 24 | int vfs_sync_file_range(int, uint64_t, uint64_t); 25 | int vfs_truncate(int, uint64_t); 26 | int64_t vfs_read(int, void*, uint64_t); 27 | int64_t vfs_pread(int, uint64_t, void*, uint64_t); 28 | int64_t vfs_write(int, void*, uint64_t); 29 | int64_t vfs_pwrite(int, void*, uint64_t, uint64_t); 30 | int64_t vfs_writev(int, struct iovec*, int); 31 | int64_t vfs_pwritev(int, uint64_t, struct iovec*, int); 32 | int64_t vfs_seek(int, uint64_t); 33 | int64_t vfs_size_fd(int); 34 | int64_t vfs_size(char*); 35 | void *vfs_mmap(int, uint64_t); 36 | void *vfs_mremap(void*, uint64_t, uint64_t); 37 | int vfs_munmap(void*, uint64_t); 38 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | 2 | ![image description](../.github/logo.png) 3 | 4 | ### Monotone QA and Testing 5 | 6 | Monotone is using a custom-made test suite. 7 | 8 | Test [Plan](plan). 9 | 10 | #### Testing Groups 11 | 12 | - `functional` 13 | 14 | Basic CRUD and Partition mapping. 15 | 16 | - `storage` 17 | 18 | Storage-specific DDL commands, data management, compression, and encryption. 19 | 20 | - `cloud` 21 | 22 | Cloud-specific DDL commands are tested using the cloud mock interface. 23 | 24 | - `recovery` 25 | 26 | Storage behavior after restart, WAL, crash recovery, and error injections. 27 | 28 | - `s3` 29 | 30 | S3 testing using `minio` (which is required to be run locally). These tests must be run explicitly. 31 | 32 | #### Memory testing 33 | 34 | `Valgrind` is an essential tool for memory testing. 35 | 36 | Our policy is that Valgrind should have no warnings or leaks when running the test suite. 37 | -------------------------------------------------------------------------------- /test/cloud/alter_cloud.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: alter cloud parsing 14 | alter 15 | alter cloud 16 | alter cloud if 17 | alter cloud if abc 18 | alter cloud if not abc 19 | alter cloud if exists 20 | alter cloud if exists test abc 21 | 22 | # test: alter cloud rename (already exists) 23 | create cloud test2 (type 'mock') 24 | create cloud test (type 'mock') 25 | show clouds 26 | 27 | alter cloud test rename 28 | alter cloud test rename to 29 | alter cloud test rename to test 30 | alter cloud test rename to test2 31 | 32 | # test: alter cloud rename 33 | drop cloud test2 34 | alter cloud test rename to test2 35 | show clouds 36 | drop cloud test2 37 | 38 | # test: alter cloud rename if exists 39 | alter cloud if exists test rename to test2 40 | show clouds 41 | 42 | # test: alter cloud rename (storage cascade) 43 | create cloud test (type 'mock') 44 | create storage test (cloud 'test') 45 | show storages debug 46 | 47 | alter cloud test rename to test2 48 | show storages debug 49 | show clouds 50 | drop storage test 51 | drop cloud test2 52 | 53 | # test: alter cloud set 54 | create cloud test (type 'mock') 55 | alter cloud test set 56 | alter cloud test set abc 57 | alter cloud test set ( 58 | alter cloud test set (type 59 | alter cloud test set (url,) 60 | alter cloud test set (url 123 61 | alter cloud test set (url '', 62 | 63 | # url 64 | alter cloud test set (url 'localhost') 65 | show clouds 66 | 67 | # login 68 | alter cloud test set (login 'admin') 69 | show clouds 70 | 71 | # password 72 | alter cloud test set (password 'admin') 73 | show clouds 74 | 75 | # access_key 76 | alter cloud test set (access_key 'admin2') 77 | show clouds 78 | 79 | # secret_key 80 | alter cloud test set (secret_key 'admin2') 81 | show clouds 82 | 83 | close 84 | -------------------------------------------------------------------------------- /test/cloud/cloud_drop.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: alter storage set cloud 14 | create cloud mock (type 'mock') 15 | show clouds 16 | 17 | alter storage main set (cloud 'mock', sync false) 18 | show storages debug 19 | 20 | # test: create partition 21 | insert 0 22 | insert 1 23 | insert 2 24 | show storages debug 25 | show partitions debug 26 | select 27 | 28 | # test: drop (no files) 29 | drop partition 0 30 | show partitions debug 31 | 32 | # test: create partition 33 | insert 0 34 | insert 1 35 | insert 2 36 | show storages debug 37 | show partitions debug 38 | select 39 | 40 | # test: refresh (upload on cloud) 41 | refresh partition 0 42 | show partitions debug 43 | select 44 | 45 | # test: insert 46 | insert 1 x 47 | insert 2 x 48 | 49 | # test: drop on storage (not exists) 50 | drop partition 0 on storage 51 | show partitions debug 52 | select 53 | 54 | # test: drop on cloud 55 | drop partition 0 on cloud 56 | 57 | # test: partition remains 58 | show partitions debug 59 | select 60 | 61 | # test: drop 62 | drop partition 0 63 | show partitions debug 64 | select 65 | 66 | # test: insert 67 | insert 0 z 68 | insert 1 z 69 | insert 2 z 70 | 71 | # test: refresh and download 72 | refresh partition 0 73 | download partition 0 74 | show partitions debug 75 | select 76 | 77 | # test: drop (all files present) 78 | drop partition 0 79 | show partitions debug 80 | select 81 | 82 | # test: create partition 83 | service 84 | service 85 | 86 | insert 0 87 | insert 1 88 | insert 2 89 | show storages debug 90 | show partitions debug 91 | select 92 | 93 | # test: checkpoint 94 | checkpoint 95 | show partitions debug 96 | select 97 | 98 | # test: drop (still on service) 99 | drop partition 0 100 | show partitions debug 101 | select 102 | 103 | # test: service 104 | service 105 | service 106 | show partitions debug 107 | select 108 | 109 | # test: alter storage set cloud_drop_local 110 | show storages debug 111 | alter storage main set (cloud_drop_local false) 112 | show storages debug 113 | 114 | # test: create partition 115 | insert 0 116 | insert 1 117 | insert 2 118 | show storages debug 119 | show partitions debug 120 | select 121 | 122 | # test: refresh (upload on cloud, keep locally) 123 | refresh partition 0 124 | show partitions debug 125 | select 126 | 127 | close 128 | -------------------------------------------------------------------------------- /test/cloud/cloud_move.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: create partition 14 | insert 0 15 | insert 1 16 | insert 2 17 | show storages debug 18 | select 19 | 20 | # test: create cloud storage 21 | create cloud mock (type 'mock') 22 | show clouds 23 | 24 | create storage test (cloud 'mock', sync false, compression 'zstd') 25 | show storages debug 26 | 27 | # test: move to cloud 28 | move partition 0 into test 29 | show storages debug 30 | show partitions debug 31 | select 32 | 33 | # test: move from cloud 34 | move partition 0 into main 35 | show storages debug 36 | show partitions debug 37 | select 38 | 39 | close 40 | -------------------------------------------------------------------------------- /test/cloud/cloud_rebalance.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: create storages 14 | create cloud mock (type 'mock') 15 | show clouds 16 | 17 | create storage hot (sync false) 18 | create storage cold (cloud 'mock', sync false) 19 | 20 | # test: alter pipeline set partitions 21 | alter pipeline set hot (partitions 2), cold 22 | show pipeline 23 | 24 | # test: create partition #1 (< partitions) 25 | insert 0 26 | show partitions debug 27 | 28 | # test: create partition #2 (= partitions) 29 | insert 10 30 | show partitions debug 31 | 32 | # test: create partition #3 (> partitions) 33 | insert 20 34 | show partitions debug 35 | 36 | # test: rebalance 37 | rebalance 38 | show partitions debug 39 | 40 | # test: create partitions (> partitions) 41 | insert 30 42 | insert 300 43 | insert 3000 44 | insert 30000 45 | insert 300000 46 | show partitions debug 47 | refresh partitions between 0 and 300010 48 | 49 | # test: rebalance 50 | rebalance 51 | show partitions debug 52 | select 53 | 54 | close 55 | -------------------------------------------------------------------------------- /test/cloud/cloud_refresh.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: alter storage set cloud 14 | create cloud mock (type 'mock') 15 | show clouds 16 | 17 | alter storage main set (cloud 'mock', sync false) 18 | show storages debug 19 | 20 | # test: create partition 21 | insert 0 22 | insert 1 23 | insert 2 24 | show storages debug 25 | show partitions debug 26 | select 27 | 28 | # test: refresh (refresh + upload + drop) 29 | refresh partition 0 30 | show partitions debug 31 | select 32 | files 00000000-0000-0000-0000-000000000000 33 | 34 | # test: update 35 | insert 1 x 36 | insert 2 x 37 | show partitions debug 38 | 39 | # test: select (memtable + cloud) 40 | select 41 | 42 | # test: refresh (download, drop, refresh, upload, drop) 43 | refresh partition 0 44 | show partitions debug 45 | select 46 | files 00000000-0000-0000-0000-000000000000 47 | 48 | # test: update 49 | insert 1 y 50 | insert 2 y 51 | show partitions debug 52 | 53 | # test: download 54 | download partition 0 55 | show partitions debug 56 | files 00000000-0000-0000-0000-000000000000 57 | 58 | # test: select (memtable + storage, cloud) 59 | select 60 | 61 | # test: refresh (drop, refresh, upload, drop) 62 | refresh partition 0 63 | show partitions debug 64 | select 65 | files 00000000-0000-0000-0000-000000000000 66 | 67 | # test: drop 68 | drop partition 0 69 | files 00000000-0000-0000-0000-000000000000 70 | 71 | close 72 | -------------------------------------------------------------------------------- /test/cloud/cloud_storage.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: create storage with cloud (not found) 14 | create storage test (cloud 'unknown') 15 | 16 | # test: create storage with cloud 17 | create cloud mock (type 'mock') 18 | show clouds 19 | 20 | create storage test (cloud 'mock', sync false) 21 | show storages debug 22 | 23 | # test: alter storage set cloud none (no partitions) 24 | alter storage test set (cloud '') 25 | show storages debug 26 | 27 | # test: alter storage set cloud (unknown) 28 | alter storage test set (cloud 'undef') 29 | 30 | # test: alter storage set cloud (no partitions) 31 | alter storage test set (cloud 'mock') 32 | show storages debug 33 | 34 | # test: create partition (no file) 35 | alter pipeline set test 36 | insert 0 37 | show partitions debug 38 | show storages debug 39 | 40 | # test: alter storage set cloud none (no files) 41 | alter storage test set (cloud '') 42 | show storages debug 43 | 44 | # test: alter storage set cloud 45 | alter storage test set (cloud 'mock') 46 | 47 | # test: refresh (create cloud file) 48 | refresh partition 0 49 | show partitions debug 50 | show storages debug 51 | 52 | # test: alter storage set cloud none #1 (exists on cloud) 53 | alter storage test set (cloud '') 54 | show storages debug 55 | 56 | # test: download partition 57 | download partition 0 58 | show storages debug 59 | show partitions debug 60 | 61 | # test: alter storage set cloud none #2 (exists on cloud and storage) 62 | alter storage test set (cloud '') 63 | show storages debug 64 | 65 | # test: drop partition from cloud 66 | drop partition 0 on cloud 67 | show storages debug 68 | show partitions debug 69 | 70 | # test: alter storage set cloud none #2 (exists on storage only) 71 | alter storage test set (cloud '') 72 | show storages debug 73 | show partitions debug 74 | select 75 | 76 | # test: alter storage set cloud (storage partitions exists) 77 | alter storage test set (cloud 'mock') 78 | show storages debug 79 | show partitions debug 80 | 81 | # test: upload 82 | upload partition 0 83 | show storages debug 84 | show partitions debug 85 | select 86 | 87 | # test: drop partition from storage 88 | drop partition 0 on storage 89 | show storages debug 90 | show partitions debug 91 | select 92 | 93 | close 94 | -------------------------------------------------------------------------------- /test/cloud/create_cloud.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: no clouds after create 14 | show clouds 15 | 16 | # test: create cloud parsing 17 | create 18 | create cloud 19 | create cloud if 20 | create cloud if abc 21 | create cloud if not abc 22 | create cloud if not exists 23 | create cloud 123 24 | create cloud test junk 25 | create cloud test ( 26 | create cloud test (123 27 | create cloud test (name 28 | create cloud test (type 29 | create cloud test (type int 30 | create cloud test (type false 31 | create cloud test (type '', 32 | create cloud test (type '',) 33 | 34 | # test: create cloud (no options) 35 | create cloud test 36 | show clouds 37 | 38 | # test: create cloud 39 | create cloud test (type 'mock') 40 | show cloud test 41 | show clouds 42 | 43 | # test: create cloud (exists) 44 | create cloud test 45 | 46 | # test: create cloud if not exists 47 | create cloud if not exists test 48 | show clouds 49 | 50 | # test: create cloud (options) 51 | drop cloud test 52 | 53 | # type 54 | create cloud test (type 55 | create cloud test (type 123 56 | create cloud test (type '') 57 | show clouds 58 | 59 | # type (unknown) 60 | create cloud test (type 'abc') 61 | show clouds 62 | 63 | # url 64 | create cloud test (type 'mock', url 123) 65 | create cloud test (type 'mock', url 'http://127.0.0.1:9000') 66 | show clouds 67 | drop cloud test 68 | 69 | # login 70 | create cloud test (type 'mock', login 123) 71 | create cloud test (type 'mock', login 'login') 72 | show clouds 73 | drop cloud test 74 | 75 | # password 76 | create cloud test (type 'mock', password 123) 77 | create cloud test (type 'mock', password 'password') 78 | show clouds 79 | drop cloud test 80 | 81 | # access_key 82 | create cloud test (type 'mock', access_key 123) 83 | create cloud test (type 'mock', access_key 'login') 84 | show clouds 85 | drop cloud test 86 | 87 | # secret_key 88 | create cloud test (type 'mock', secret_key 123) 89 | create cloud test (type 'mock', secret_key 'password') 90 | show clouds 91 | drop cloud test 92 | 93 | close 94 | -------------------------------------------------------------------------------- /test/cloud/download.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: download parsing 14 | download 15 | download abc 16 | download partition 17 | download partition abc 18 | download partition 0 junk 19 | 20 | # test: download (partition does not exists) 21 | download partition 0 22 | 23 | # test: download if exists 24 | download partition if exists 0 25 | 26 | # test: download from storage without cloud 27 | insert 0 28 | download partition 0 29 | 30 | # test: download if cloud 31 | insert 0 32 | download partition 0 if cloud 33 | 34 | # test: create storage with cloud 35 | create cloud mock (type 'mock') 36 | show clouds 37 | 38 | create storage test (cloud 'mock', sync false) 39 | show storages debug 40 | alter pipeline set test 41 | 42 | # test: create partitions 43 | insert 10 44 | insert 20 45 | show partitions debug 46 | 47 | # test: download (no files) 48 | download partition 10 49 | show partitions debug 50 | select 51 | 52 | # test: refresh (create and upload) 53 | refresh partition 10 54 | show partitions debug 55 | select 56 | 57 | # test: download 58 | download partition 10 59 | show partitions debug 60 | select 61 | 62 | # test: download (already exists) 63 | download partition 10 64 | show partitions debug 65 | select 66 | 67 | # test: drop from storage 68 | drop partition 10 on storage 69 | show partitions debug 70 | select 71 | 72 | # test: download #2 73 | download partition 10 74 | show partitions debug 75 | select 76 | 77 | # test: download partitions parsing 78 | download partitions 79 | download partitions abc 80 | download partitions between 81 | download partitions between abc 82 | download partitions between 0 83 | download partitions between 10 84 | download partitions between 10 abc 85 | download partitions between 10 and 86 | download partitions between 10 and abc 87 | download partitions between 10 and 30 abc 88 | 89 | # test: drop from storage 90 | refresh partition 10 91 | refresh partition 20 92 | show partitions debug 93 | 94 | drop partition 10 on storage 95 | drop partition 20 on storage 96 | show partitions debug 97 | 98 | # test: download partitions 99 | download partitions between 10 and 30 100 | show partitions debug 101 | select 102 | 103 | close 104 | -------------------------------------------------------------------------------- /test/cloud/drop_cloud.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: drop cloud parsing 14 | drop 15 | drop cloud 16 | drop cloud if 17 | drop cloud if 123 18 | drop cloud if not 19 | drop cloud if exists 20 | drop cloud if exists 123 21 | drop cloud 123 22 | 23 | # test: drop cloud 24 | create cloud test (type 'mock') 25 | show clouds 26 | 27 | drop cloud test 28 | show clouds 29 | 30 | # test: drop cloud (does not exists) 31 | drop cloud test 32 | 33 | # test: drop cloud if exists 34 | drop cloud if exists test 35 | 36 | # test: create storage (with cloud) 37 | create cloud s3 (type 'mock') 38 | create storage test (cloud 's3') 39 | show storages debug 40 | 41 | # test: drop cloud (with storage) 42 | drop cloud s3 43 | show clouds 44 | 45 | # test: drop cloud (with storage) #2 46 | drop storage test 47 | show storages debug 48 | 49 | drop cloud s3 50 | show clouds 51 | 52 | close 53 | -------------------------------------------------------------------------------- /test/cloud/upload.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: upload parsing 14 | upload 15 | upload abc 16 | upload partition 17 | upload partition abc 18 | upload partition 0 junk 19 | 20 | # test: upload (partition does not exists) 21 | upload partition 0 22 | 23 | # test: upload if exists 24 | upload partition if exists 0 25 | 26 | # test: upload without cloud 27 | insert 0 28 | upload partition 0 29 | 30 | # test: upload if cloud 31 | upload partition 0 if cloud 32 | 33 | # test: create storage with cloud 34 | create cloud mock (type 'mock') 35 | show clouds 36 | 37 | create storage test (cloud 'mock', sync false) 38 | show storages debug 39 | alter pipeline set test 40 | 41 | # test: create partitions 42 | insert 10 43 | insert 20 44 | show partitions debug 45 | 46 | # test: upload (without storage file) 47 | upload partition 10 48 | show partitions debug 49 | 50 | # test: refresh 51 | refresh partition 10 52 | show partitions debug 53 | select 54 | 55 | # test: upload (already exists) 56 | upload partition 10 57 | show partitions debug 58 | 59 | # test: download 60 | download partition 10 61 | show partitions debug 62 | select 63 | 64 | # test: drop from cloud 65 | drop partition 10 on cloud 66 | show partitions debug 67 | select 68 | 69 | # test: upload 70 | upload partition 10 71 | show partitions debug 72 | select 73 | 74 | # test: download partitions 75 | refresh partition 20 76 | download partitions between 10 and 30 77 | show partitions debug 78 | 79 | # test: drop partitions on cloud 80 | drop partitions between 10 and 30 on cloud 81 | show partitions debug 82 | 83 | # test: upload partitions parsing 84 | upload partitions 85 | upload partitions abc 86 | upload partitions between 87 | upload partitions between abc 88 | upload partitions between 0 89 | upload partitions between 10 90 | upload partitions between 10 abc 91 | upload partitions between 10 and 92 | upload partitions between 10 and abc 93 | upload partitions between 10 and 30 abc 94 | 95 | # test: upload partitions #1 96 | upload partitions between 10 and 30 97 | show partitions debug 98 | 99 | # test: upload partitions #2 100 | upload partitions between 10 and 30 101 | show partitions debug 102 | select 103 | 104 | # test: create empty partition 105 | create partition 50 60 106 | refresh partition 50 107 | show partitions debug 108 | 109 | close 110 | -------------------------------------------------------------------------------- /test/functional/mapping.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | alter storage main set (region_size 60) 14 | show storages debug 15 | 16 | # test: create partitions 17 | insert 10 18 | insert 11 19 | insert 19 20 | 21 | insert 20 22 | insert 21 23 | 24 | show partitions debug 25 | 26 | # test: select (no key) 27 | select 28 | 29 | # test: select 30 | select 0 31 | select 1 32 | select 3 33 | 34 | select 10 35 | select 11 36 | select 12 37 | 38 | select 20 39 | select 21 40 | select 23 41 | 42 | # test: refresh 43 | refresh partition 10 44 | refresh partition 20 45 | files 00000000-0000-0000-0000-000000000000 46 | 47 | show partitions debug 48 | 49 | # test: select 50 | select 51 | 52 | # test: create partition (in the past) 53 | insert 0 54 | insert 1 55 | insert 2 56 | insert 3 57 | insert 4 58 | insert 5 59 | insert 6 60 | insert 7 61 | insert 8 62 | insert 9 63 | show partitions debug 64 | refresh partition 0 65 | show partitions debug 66 | 67 | # test: select 68 | select 69 | select 9 70 | 71 | # test: create partition (in the future) 72 | insert 4096 73 | show partitions debug 74 | refresh partition 4096 75 | show partitions debug 76 | files 00000000-0000-0000-0000-000000000000 77 | 78 | # test: select 79 | select 80 | 81 | # test: select (gap) 82 | select 21 83 | select 22 84 | select 4096 85 | select 4097 86 | 87 | # test: partition has only deletes 88 | delete 4096 89 | 90 | # test: select 91 | select 21 92 | select 4096 93 | select 4097 94 | 95 | # test: create partition (in the future) #2 96 | insert 8096 97 | 98 | # test: select 99 | select 21 100 | 101 | select 4090 102 | select 8090 103 | 104 | # test: partition has only deletes #2 105 | delete 8096 106 | 107 | # test: select 108 | select 109 | 110 | # test: create partition (in the future) #3 111 | insert 100000 112 | 113 | # test: select 114 | select 115 | 116 | close 117 | -------------------------------------------------------------------------------- /test/functional/mapping_custom.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: create partition 14 | create partition 150 450 15 | show partitions debug 16 | 17 | # test: create partition (left) 18 | insert 120 19 | show partitions debug 20 | 21 | # test: create partition (left, near) 22 | insert 140 23 | show partitions debug 24 | 25 | # test: create partition (overlap right) 26 | create partition 120 170 27 | show partitions debug 28 | 29 | # test: create partition (fill left-right gaps) 30 | create partition 80 500 31 | show partitions debug 32 | select 33 | 34 | # test: set zero interval 35 | set interval to 0 36 | 37 | # test: set interval 38 | set interval to 1000 39 | 40 | # test: insert 41 | insert 0 42 | show partitions debug 43 | select 44 | 45 | # test: insert #2 46 | insert 1200 47 | insert 1300 48 | insert 1500 49 | insert 1800 50 | insert 1900 51 | show partitions debug 52 | select 53 | 54 | # test: insert #3 55 | insert 2000 56 | show partitions debug 57 | select 58 | 59 | # test: set interval 60 | set interval to 10000 61 | 62 | insert 2900 63 | show partitions debug 64 | select 65 | 66 | # test: drop partition 67 | drop partition 150 68 | show partitions debug 69 | select 70 | 71 | # test: insert #4 (backfill + overlap) 72 | insert 150 73 | show partitions debug 74 | select 75 | 76 | # test: drop partition 77 | drop partition 150 78 | drop partition 3000 79 | show partitions debug 80 | select 81 | 82 | # test: insert #4 (gapfill) 83 | insert 3000 84 | insert 4000 85 | insert 5000 86 | show partitions debug 87 | select 88 | 89 | # test: insert #5 90 | insert 10000 91 | insert 20000 92 | show partitions debug 93 | select 94 | 95 | # test: set interval to 1 96 | set interval to 1 97 | insert 30000 98 | insert 30001 99 | insert 30002 100 | show partitions debug 101 | select 102 | 103 | # test: drop partition 104 | drop partition 30001 105 | show partitions debug 106 | select 107 | 108 | close 109 | -------------------------------------------------------------------------------- /test/functional/serial.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set uuid to '00000000-0000-0000-0000-000000000000' 8 | set compression to '' 9 | set sync to false 10 | open 11 | 12 | # test: serial enabled by default 13 | show serial 14 | 15 | # test: start from zero 16 | show ssn 17 | 18 | # test: insert 19 | insert -1 20 | 21 | # test: select 22 | show ssn 23 | select 24 | 25 | # test: insert 26 | insert -1 27 | insert -1 28 | insert -1 29 | insert -1 30 | insert -1 31 | insert -1 32 | insert -1 33 | 34 | # test: select 35 | show ssn 36 | select 37 | 38 | # test: set ssn 39 | set ssn to 0 40 | show ssn 41 | 42 | # test: insert 43 | insert -1 xxx 44 | insert -1 xxx 45 | insert -1 xxx 46 | 47 | # test: select 48 | show ssn 49 | select 50 | 51 | close 52 | -------------------------------------------------------------------------------- /test/functional/serial.test.ok: -------------------------------------------------------------------------------- 1 | init 2 | set workers to 0 3 | set workers_upload to 0 4 | set interval to 10 5 | set uuid to '00000000-0000-0000-0000-000000000000' 6 | set compression to '' 7 | set sync to false 8 | open 9 | # test: serial enabled by default 10 | show serial 11 | true 12 | # test: start from zero 13 | show ssn 14 | 0 15 | # test: insert 16 | insert -1 17 | # test: select 18 | show ssn 19 | 1 20 | select 21 | [0] 22 | (eof) 23 | # test: insert 24 | insert -1 25 | insert -1 26 | insert -1 27 | insert -1 28 | insert -1 29 | insert -1 30 | insert -1 31 | # test: select 32 | show ssn 33 | 8 34 | select 35 | [0] 36 | [1] 37 | [2] 38 | [3] 39 | [4] 40 | [5] 41 | [6] 42 | [7] 43 | (eof) 44 | # test: set ssn 45 | set ssn to 0 46 | show ssn 47 | 0 48 | # test: insert 49 | insert -1 xxx 50 | insert -1 xxx 51 | insert -1 xxx 52 | # test: select 53 | show ssn 54 | 3 55 | select 56 | [0, xxx] 57 | [1, xxx] 58 | [2, xxx] 59 | [3] 60 | [4] 61 | [5] 62 | [6] 63 | [7] 64 | (eof) 65 | close 66 | -------------------------------------------------------------------------------- /test/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @(cd .. && make --no-print-directory) 3 | clean: 4 | @(cd .. && make --no-print-directory clean) 5 | -------------------------------------------------------------------------------- /test/monotone-test: -------------------------------------------------------------------------------- 1 | ../build/monotone-test -------------------------------------------------------------------------------- /test/plan: -------------------------------------------------------------------------------- 1 | # 2 | 3 | # functional 4 | directory functional 5 | group functional 6 | test memtable 7 | test partition 8 | test mapping 9 | test mapping_custom 10 | test serial 11 | 12 | # storage 13 | directory storage 14 | group storage 15 | test create_storage 16 | test drop_storage 17 | test alter_storage 18 | test alter_pipeline 19 | test create 20 | test refresh 21 | test move 22 | test drop 23 | test rebalance 24 | test service 25 | test compression 26 | test encryption 27 | 28 | # cloud 29 | directory cloud 30 | group cloud 31 | test create_cloud 32 | test drop_cloud 33 | test alter_cloud 34 | test download 35 | test upload 36 | test cloud_storage 37 | test cloud_refresh 38 | test cloud_move 39 | test cloud_drop 40 | test cloud_rebalance 41 | 42 | # recovery 43 | directory recovery 44 | group recovery 45 | test wal 46 | test wal_crc 47 | test recovery_config 48 | test recovery_storage 49 | test recovery_cloud 50 | test recovery_serial 51 | test crash 52 | 53 | # s3 54 | directory s3 55 | group_optional s3 56 | test s3 57 | -------------------------------------------------------------------------------- /test/recovery/recovery_cloud.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set wal to false 9 | set uuid to '00000000-0000-0000-0000-000000000000' 10 | set compression to '' 11 | set sync to false 12 | open 13 | 14 | # test: alter storage set cloud 15 | create cloud mock (type 'mock') 16 | show clouds 17 | 18 | alter storage main set (cloud 'mock', sync false) 19 | 20 | # test: create partition 21 | insert 0 22 | insert 1 23 | insert 2 24 | insert 3 25 | refresh partition 0 26 | show partitions debug 27 | files 00000000-0000-0000-0000-000000000000 28 | select 29 | 30 | # test: close/open 31 | close 32 | 33 | init 34 | set workers to 0 35 | set workers_upload to 0 36 | set interval to 10 37 | set wal to false 38 | set sync to false 39 | open 40 | files 00000000-0000-0000-0000-000000000000 41 | 42 | # test: validate partition 43 | show partitions debug 44 | select 45 | 46 | # test: download 47 | download partition 0 48 | show partitions debug 49 | 50 | # test: close/open 51 | close 52 | 53 | init 54 | set workers to 0 55 | set workers_upload to 0 56 | set interval to 10 57 | set wal to false 58 | set sync to false 59 | open 60 | files 00000000-0000-0000-0000-000000000000 61 | 62 | # test: validate partition 63 | show partitions debug 64 | select 65 | 66 | # test: update/refresh 67 | insert 2 z 68 | insert 3 z 69 | refresh partition 0 70 | 71 | # test: close/open 72 | close 73 | 74 | init 75 | set workers to 0 76 | set workers_upload to 0 77 | set interval to 10 78 | set wal to false 79 | set sync to false 80 | open 81 | files 00000000-0000-0000-0000-000000000000 82 | 83 | # test: validate partition 84 | show partitions debug 85 | select 86 | 87 | # test: set compression 88 | alter storage main set (compression 'zstd') 89 | refresh partition 0 90 | 91 | show partitions debug 92 | 93 | # test: close/open 94 | close 95 | 96 | init 97 | set workers to 0 98 | set workers_upload to 0 99 | set interval to 10 100 | set wal to false 101 | set sync to false 102 | open 103 | files 00000000-0000-0000-0000-000000000000 104 | 105 | # test: validate partition 106 | show partitions debug 107 | select 108 | 109 | # test: set compression and encryption 110 | alter storage main set (encryption 'aes') 111 | 112 | drop partition 0 113 | show partitions debug 114 | 115 | alter storage main set (encryption 'aes', encryption_key '01234567890123456789012345678912') 116 | 117 | insert 0 118 | insert 1 119 | insert 2 120 | 121 | refresh partition 0 122 | show partitions debug 123 | 124 | # test: close/open 125 | close 126 | 127 | init 128 | set workers to 0 129 | set workers_upload to 0 130 | set interval to 10 131 | set wal to false 132 | set sync to false 133 | open 134 | files 00000000-0000-0000-0000-000000000000 135 | 136 | # test: validate partition 137 | show partitions debug 138 | select 139 | 140 | close 141 | -------------------------------------------------------------------------------- /test/recovery/recovery_serial.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to true 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: restart (no records) 14 | show ssn 15 | 16 | close 17 | 18 | init 19 | set workers to 0 20 | set workers_upload to 0 21 | set interval to 10 22 | set sync to false 23 | open 24 | 25 | show ssn 26 | 27 | # test: create partition/insert 28 | insert -1 29 | 30 | # test: select 31 | show ssn 32 | select 33 | 34 | # test: restart (restore from wal) 35 | close 36 | 37 | init 38 | set workers to 0 39 | set workers_upload to 0 40 | set interval to 10 41 | set sync to false 42 | open 43 | 44 | show ssn 45 | select 46 | 47 | # test: insert 48 | insert -1 49 | 50 | # test: select 51 | show ssn 52 | select 53 | 54 | # test: refresh/gc 55 | refresh partition 0 56 | debug "wal_create" 57 | debug "wal_gc" 58 | debug "wal_read" 59 | show wal 60 | 61 | show partitions debug 62 | 63 | # test: restart (restore from partition) 64 | close 65 | 66 | init 67 | set workers to 0 68 | set workers_upload to 0 69 | set interval to 10 70 | set sync to false 71 | open 72 | 73 | # test: select 74 | show ssn 75 | select 76 | 77 | # test: insert 78 | insert -1 79 | 80 | # test: select 81 | show ssn 82 | select 83 | 84 | # test: restart (restore from partition and wal) 85 | close 86 | 87 | init 88 | set workers to 0 89 | set workers_upload to 0 90 | set interval to 10 91 | set sync to false 92 | open 93 | 94 | # test: select 95 | show ssn 96 | select 97 | 98 | # test: insert 99 | insert -1 100 | 101 | # test: select 102 | show ssn 103 | select 104 | 105 | close 106 | -------------------------------------------------------------------------------- /test/recovery/recovery_serial.test.ok: -------------------------------------------------------------------------------- 1 | init 2 | set workers to 0 3 | set workers_upload to 0 4 | set interval to 10 5 | set serial to true 6 | set uuid to '00000000-0000-0000-0000-000000000000' 7 | set compression to '' 8 | set sync to false 9 | open 10 | # test: restart (no records) 11 | show ssn 12 | 0 13 | close 14 | init 15 | set workers to 0 16 | set workers_upload to 0 17 | set interval to 10 18 | set sync to false 19 | open 20 | show ssn 21 | 0 22 | # test: create partition/insert 23 | insert -1 24 | # test: select 25 | show ssn 26 | 1 27 | select 28 | [0] 29 | (eof) 30 | # test: restart (restore from wal) 31 | close 32 | init 33 | set workers to 0 34 | set workers_upload to 0 35 | set interval to 10 36 | set sync to false 37 | open 38 | show ssn 39 | 1 40 | select 41 | [0] 42 | (eof) 43 | # test: insert 44 | insert -1 45 | # test: select 46 | show ssn 47 | 2 48 | select 49 | [0] 50 | [1] 51 | (eof) 52 | # test: refresh/gc 53 | refresh partition 0 54 | debug "wal_create" 55 | debug "wal_gc" 56 | debug "wal_read" 57 | show wal 58 | { 59 | "active": true, 60 | "rotate_wm": 104857600, 61 | "sync_on_rotate": true, 62 | "sync_on_write": false, 63 | "crc": false, 64 | "lsn": 2, 65 | "lsn_min": 3, 66 | "files": 1 67 | } 68 | show partitions debug 69 | [{ 70 | "min": 0, 71 | "max": 9, 72 | "events": 2, 73 | "events_heap": 0, 74 | "regions": 1, 75 | "size": 242, 76 | "size_uncompressed": 242, 77 | "size_heap": 0, 78 | "created": "(filtered)", 79 | "refreshed": "(filtered)", 80 | "refreshes": 1, 81 | "on_storage": true, 82 | "on_cloud": false, 83 | "storage": "main", 84 | "index": { 85 | "size": 52, 86 | "size_origin": 52, 87 | "size_regions": 60, 88 | "size_regions_origin": 60, 89 | "size_total": 242, 90 | "size_total_origin": 242, 91 | "regions": 1, 92 | "events": 2, 93 | "refreshes": 1, 94 | "lsn": 2, 95 | "compression": 0, 96 | "encryption": 0 97 | } 98 | }] 99 | # test: restart (restore from partition) 100 | close 101 | init 102 | set workers to 0 103 | set workers_upload to 0 104 | set interval to 10 105 | set sync to false 106 | open 107 | # test: select 108 | show ssn 109 | 2 110 | select 111 | [0] 112 | [1] 113 | (eof) 114 | # test: insert 115 | insert -1 116 | # test: select 117 | show ssn 118 | 3 119 | select 120 | [0] 121 | [1] 122 | [2] 123 | (eof) 124 | # test: restart (restore from partition and wal) 125 | close 126 | init 127 | set workers to 0 128 | set workers_upload to 0 129 | set interval to 10 130 | set sync to false 131 | open 132 | # test: select 133 | show ssn 134 | 3 135 | select 136 | [0] 137 | [1] 138 | [2] 139 | (eof) 140 | # test: insert 141 | insert -1 142 | # test: select 143 | show ssn 144 | 4 145 | select 146 | [0] 147 | [1] 148 | [2] 149 | [3] 150 | (eof) 151 | close 152 | -------------------------------------------------------------------------------- /test/recovery/wal_crc.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | # test: wal crc 4 | init 5 | set workers to 0 6 | set workers_upload to 0 7 | set interval to 10 8 | set serial to false 9 | set wal_crc to true 10 | set uuid to '00000000-0000-0000-0000-000000000000' 11 | set compression to '' 12 | set sync to false 13 | open 14 | 15 | # test: insert 16 | insert 1 17 | 18 | show lsn 19 | show wal 20 | debug 'wal_read' 21 | 22 | insert 2 23 | 24 | show lsn 25 | show wal 26 | debug 'wal_read' 27 | 28 | insert 3 29 | 30 | show lsn 31 | show wal 32 | debug 'wal_read' 33 | 34 | select 35 | 36 | # test: restart (validate crc during replay) 37 | close 38 | 39 | init 40 | set workers to 0 41 | set workers_upload to 0 42 | set interval to 10 43 | set serial to false 44 | set wal_crc to true 45 | set uuid to '00000000-0000-0000-0000-000000000000' 46 | set sync to false 47 | open 48 | 49 | show wal 50 | select 51 | 52 | close 53 | -------------------------------------------------------------------------------- /test/recovery/wal_crc.test.ok: -------------------------------------------------------------------------------- 1 | # test: wal crc 2 | init 3 | set workers to 0 4 | set workers_upload to 0 5 | set interval to 10 6 | set serial to false 7 | set wal_crc to true 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | # test: insert 13 | insert 1 14 | show lsn 15 | 1 16 | show wal 17 | { 18 | "active": true, 19 | "rotate_wm": 104857600, 20 | "sync_on_rotate": true, 21 | "sync_on_write": false, 22 | "crc": true, 23 | "lsn": 1, 24 | "lsn_min": 1, 25 | "files": 1 26 | } 27 | debug 'wal_read' 28 | [1, 0, 1, 35] 29 | 30 | insert 2 31 | show lsn 32 | 2 33 | show wal 34 | { 35 | "active": true, 36 | "rotate_wm": 104857600, 37 | "sync_on_rotate": true, 38 | "sync_on_write": false, 39 | "crc": true, 40 | "lsn": 2, 41 | "lsn_min": 1, 42 | "files": 1 43 | } 44 | debug 'wal_read' 45 | [1, 0, 1, 35] 46 | [2, 0, 1, 35] 47 | 48 | insert 3 49 | show lsn 50 | 3 51 | show wal 52 | { 53 | "active": true, 54 | "rotate_wm": 104857600, 55 | "sync_on_rotate": true, 56 | "sync_on_write": false, 57 | "crc": true, 58 | "lsn": 3, 59 | "lsn_min": 1, 60 | "files": 1 61 | } 62 | debug 'wal_read' 63 | [1, 0, 1, 35] 64 | [2, 0, 1, 35] 65 | [3, 0, 1, 35] 66 | 67 | select 68 | [1] 69 | [2] 70 | [3] 71 | (eof) 72 | # test: restart (validate crc during replay) 73 | close 74 | init 75 | set workers to 0 76 | set workers_upload to 0 77 | set interval to 10 78 | set serial to false 79 | set wal_crc to true 80 | set uuid to '00000000-0000-0000-0000-000000000000' 81 | set sync to false 82 | open 83 | show wal 84 | { 85 | "active": true, 86 | "rotate_wm": 104857600, 87 | "sync_on_rotate": true, 88 | "sync_on_write": false, 89 | "crc": true, 90 | "lsn": 3, 91 | "lsn_min": 1, 92 | "files": 1 93 | } 94 | select 95 | [1] 96 | [2] 97 | [3] 98 | (eof) 99 | close 100 | -------------------------------------------------------------------------------- /test/s3/s3.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: create s3 cloud 14 | create cloud s3 (type 's3') 15 | create cloud s3 (type 's3', url 'localhost:9000') 16 | create cloud s3 (type 's3', url 'localhost:9000', access_key 'minioadmin') 17 | 18 | create cloud s3 (type 's3', url 'localhost:9000', access_key 'minioadmin', secret_key 'minioadmin') 19 | show clouds 20 | 21 | # test: create storage with cloud s3 (create bucket) 22 | create storage test (cloud 's3', sync false, uuid '00000000-0000-0000-0000-000000000123', compression 'zstd', encryption 'aes') 23 | show storages 24 | 25 | alter pipeline set test 26 | 27 | # test: create partition (no file) 28 | insert 0 29 | insert 1 30 | insert 2 31 | show partitions debug 32 | show storages 33 | select 34 | 35 | # test: refresh (upload) 36 | refresh partition 0 37 | show partitions debug 38 | 39 | # test: select (from cloud) 40 | select 41 | 42 | # test: download 43 | download partition 0 44 | show partitions debug 45 | 46 | # test: select (from storage, still on cloud) 47 | select 48 | 49 | # test: upload 50 | upload partition 0 51 | show partitions debug 52 | 53 | # test: select (from cloud) 54 | select 55 | 56 | # test: drop from cloud 57 | drop partition 0 on cloud 58 | show partitions debug 59 | 60 | # test: select 61 | select 62 | 63 | # test: update partition 64 | insert 1 xx 65 | insert 2 yy 66 | 67 | # test: refresh (upload) 68 | refresh partition 0 69 | show partitions debug 70 | 71 | # test: select (from cloud) 72 | select 73 | 74 | # test: create partitions 75 | insert 10 76 | insert 20 77 | insert 30 78 | insert 40 79 | insert 50 80 | insert 60 81 | insert 70 82 | insert 80 83 | insert 90 84 | show partitions debug 85 | 86 | # test: refresh partitions 87 | refresh partitions between 0 and 100 88 | show partitions debug 89 | 90 | # test: update partitions 91 | insert 11 92 | insert 21 93 | insert 31 94 | insert 41 95 | insert 51 96 | insert 61 97 | insert 71 98 | insert 81 99 | insert 91 100 | show partitions debug 101 | 102 | # test: refresh partitions #2 103 | refresh partitions between 0 and 100 104 | show partitions debug 105 | 106 | # test: select 107 | select 108 | 109 | # test: restart (close/open) 110 | close 111 | 112 | init 113 | set workers to 0 114 | set workers_upload to 0 115 | set interval to 10 116 | set serial to false 117 | set sync to false 118 | open 119 | 120 | # test: validate 121 | show clouds 122 | show storages 123 | show partitions debug 124 | select 125 | 126 | # test: drop storage (has partitions) 127 | drop storage test 128 | 129 | # test: drop storage (detach, drop bucket) 130 | 131 | # cleanup 132 | alter pipeline reset 133 | drop partitions between 0 and 9999 134 | 135 | drop storage test 136 | 137 | close 138 | -------------------------------------------------------------------------------- /test/storage/alter_pipeline.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: pipeline is not set by default 14 | show storages debug 15 | show pipeline 16 | 17 | # test: insert (main only) 18 | insert 0 x 19 | show storages debug 20 | 21 | # test: insert (more storages wo pipeline) 22 | create storage hot 23 | create storage cold 24 | insert 0 y 25 | insert 30 y 26 | show storages debug 27 | 28 | # test: alter pipeline parsing 29 | alter 30 | alter pipeline 31 | alter pipeline abc 32 | alter pipeline set 33 | alter pipeline set 123 34 | 35 | # test: alter pipeline set 36 | alter pipeline set hot 37 | show pipeline 38 | 39 | # test: insert (primary changed) 40 | insert 40 z 41 | show storages debug 42 | 43 | # test: select 44 | select 45 | 46 | # test: drop storage (with pipeline dependency) 47 | drop storage hot 48 | 49 | # test: alter pipeline reset 50 | alter pipeline reset 51 | show pipeline 52 | 53 | # test: drop storage #2 54 | drop storage hot 55 | drop partition 40 56 | drop storage hot 57 | show storages debug 58 | 59 | # test: insert (primary changed) 60 | insert 40 v 61 | show storages debug 62 | 63 | # test: alter pipeline set (storage does not exists) 64 | alter pipeline set undef 65 | 66 | # test: alter pipeline set (hot swap) 67 | create storage hot 68 | alter pipeline set hot 69 | show pipeline 70 | 71 | show storages debug 72 | insert 50 73 | 74 | create storage hot_swap 75 | alter pipeline set hot_swap 76 | show pipeline 77 | show storages debug 78 | 79 | insert 60 80 | show storages debug 81 | 82 | # test: select 83 | select 84 | 85 | # test: alter pipeline set partitions (chain) 86 | move partition 60 into hot 87 | alter pipeline reset 88 | drop storage hot_swap 89 | 90 | show storages debug 91 | 92 | alter pipeline set hot (partitions 2), cold 93 | show pipeline 94 | 95 | # test: alter pipeline set partitions (both) 96 | alter pipeline set hot (partitions 2), cold (partitions 0) 97 | show pipeline 98 | 99 | # test: alter pipeline set events 100 | alter pipeline set hot (events 100) 101 | show pipeline 102 | 103 | # test: alter pipeline set partitions, size 104 | alter pipeline set hot (partitions 2, size 100MiB) 105 | show pipeline 106 | 107 | # test: alter pipeline set duration 108 | alter pipeline set hot (duration 1day) 109 | show pipeline 110 | 111 | # test: alter pipeline set (duplicate) 112 | alter pipeline set hot, hot 113 | show pipeline 114 | 115 | # test: alter pipeline set (no condition) 116 | alter pipeline set hot, cold 117 | show pipeline 118 | 119 | close 120 | -------------------------------------------------------------------------------- /test/storage/alter_storage.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: alter storage parsing 14 | alter 15 | alter storage 16 | alter storage if 17 | alter storage if abc 18 | alter storage if not abc 19 | alter storage if exists 20 | alter storage if exists test abc 21 | 22 | # test: alter storage rename (already exists) 23 | create storage test 24 | show storages debug 25 | alter storage test rename 26 | alter storage test rename to 27 | alter storage test rename to test 28 | alter storage test rename to main 29 | 30 | # test: alter storage rename 31 | alter storage test rename to test2 32 | show storages debug 33 | drop storage test2 34 | 35 | # test: alter storage rename if exists 36 | alter storage if exists test rename to test2 37 | show storages debug 38 | 39 | # test: alter storage rename main 40 | alter storage main rename to test 41 | show storages debug 42 | 43 | # test: alter storage set 44 | create storage test 45 | alter storage test set 46 | alter storage test set abc 47 | alter storage test set ( 48 | alter storage test set (sync 49 | alter storage test set (sync, 50 | alter storage test set (sync,) 51 | alter storage test set (sync 123 52 | alter storage test set (sync true, 53 | alter storage test set (sync true,) 54 | 55 | alter storage test set (sync false) 56 | show storages debug 57 | 58 | alter storage test set (sync true) 59 | show storages debug 60 | 61 | alter storage test set (sync false, crc true) 62 | show storages debug 63 | 64 | # test: alter storage set uuid 65 | alter storage test set (uuid '00000000-0000-0000-0000-000000000000') 66 | 67 | # test: alter storage set path 68 | alter storage test set (path '__test__') 69 | show storages debug 70 | 71 | # test: alter storage set crc (must be empty) 72 | alter pipeline set test 73 | insert 0 74 | insert 1 75 | insert 2 76 | refresh partition 0 77 | 78 | alter storage test set (crc false) 79 | show storages debug 80 | 81 | close 82 | -------------------------------------------------------------------------------- /test/storage/compression.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: create partition 14 | insert 0 15 | insert 1 16 | insert 3 17 | show partitions debug 18 | refresh partition 0 19 | select 20 | 21 | # test: alter storage set compression 22 | alter storage main set (compression 'zstd') 23 | show partitions debug 24 | 25 | # test: refresh (compress) 26 | refresh partition 0 27 | show partitions debug 28 | select 29 | 30 | # test: drop partition 31 | drop partition 0 32 | 33 | # test: alter storage set compression, crc 34 | alter storage main set (compression 'zstd', crc true) 35 | insert 0 36 | insert 1 37 | insert 3 38 | show partitions debug 39 | refresh partition 0 40 | show partitions debug 41 | 42 | # test: refresh 43 | refresh partition 0 44 | show partitions debug 45 | select 46 | 47 | # test: alter storage set compression (with crc) 48 | alter storage main set (compression '') 49 | show partitions debug 50 | 51 | # test: refresh 52 | refresh partition 0 53 | show partitions debug 54 | select 55 | drop partition 0 56 | 57 | # test: zstd refresh/select 58 | create storage zstd (compression 'zstd') 59 | alter pipeline set zstd 60 | show storages debug 61 | insert 0 62 | insert 1 63 | insert 2 64 | insert 3 65 | insert 4 66 | insert 5 67 | insert 6 68 | insert 7 69 | insert 8 70 | insert 9 71 | refresh partition 0 72 | show partitions debug 73 | select 74 | drop partition 0 75 | 76 | # test: lz4 refresh/select 77 | create storage lz4 (compression 'lz4') 78 | alter pipeline set lz4 79 | show storages debug 80 | insert 0 81 | insert 1 82 | insert 2 83 | insert 3 84 | insert 4 85 | insert 5 86 | insert 6 87 | insert 7 88 | insert 8 89 | insert 9 90 | refresh partition 0 91 | show storages debug 92 | show partitions debug 93 | select 94 | 95 | close 96 | -------------------------------------------------------------------------------- /test/storage/create.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: create partition parsing 14 | create partition 15 | create partition abc 16 | 17 | # test: create partition (default interval) 18 | create partition 30 19 | show partitions debug 20 | 21 | # test: create partition (prev) 22 | create partition 20 30 23 | show partitions debug 24 | 25 | # test: create partition (next) 26 | create partition 40 60 27 | show partitions debug 28 | 29 | # test: create partition (gap) 30 | create partition 100 200 31 | show partitions debug 32 | 33 | # test: overlap (right) 34 | create partition 0 25 35 | show partitions debug 36 | 37 | # test: overlap (left) 38 | create partition 20 70 39 | show partitions debug 40 | 41 | # test: overlap (right) 42 | create partition 60 220 43 | show partitions debug 44 | 45 | close 46 | -------------------------------------------------------------------------------- /test/storage/drop.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: drop parsing 14 | drop 15 | drop abc 16 | drop partition 17 | drop partition abc 18 | 19 | # test: drop partition does not exists 20 | drop partition 0 21 | 22 | # test: drop partition if exists 23 | drop partition if exists 0 24 | 25 | # test: create partition (no file) 26 | insert 0 27 | insert 1 28 | insert 2 29 | show partitions debug 30 | 31 | # test: drop 32 | drop partition 0 33 | show partitions debug 34 | 35 | # test: create partition 36 | insert 0 37 | insert 1 38 | insert 2 39 | refresh partition 0 40 | show partitions debug 41 | 42 | # test: drop #2 43 | drop partition 0 44 | show partitions debug 45 | show storages debug 46 | 47 | # test: create partitions 48 | insert 10 49 | insert 20 50 | insert 30 51 | insert 40 52 | show partitions debug 53 | 54 | # test: drop partitions parsing 55 | drop partitions 56 | drop partitions abc 57 | drop partitions between 58 | drop partitions between abc 59 | drop partitions between 0 60 | drop partitions between 0 and 61 | drop partitions between 0 and abc 62 | 63 | # test: drop partitions 64 | drop partitions between 0 and 50 65 | show partitions debug 66 | 67 | # test: drop partitions (gap) 68 | insert 100 69 | insert 200 70 | insert 300 71 | insert 400 72 | show partitions debug 73 | show storages debug 74 | 75 | # test: drop partitions 76 | drop partitions between 0 and 500 77 | show partitions debug 78 | show storages debug 79 | 80 | close 81 | -------------------------------------------------------------------------------- /test/storage/drop_storage.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: drop storage parsing 14 | drop 15 | drop storage 16 | drop storage if 17 | drop storage if 123 18 | drop storage if not 19 | drop storage if exists 20 | drop storage if exists 123 21 | drop storage 123 22 | 23 | # test: drop storage 24 | create storage test 25 | show storages debug 26 | 27 | drop storage test 28 | show storages debug 29 | 30 | # test: drop storage (not exists) 31 | drop storage test 32 | 33 | # test: drop storage if exists 34 | drop storage if exists test 35 | 36 | # test: drop storage main 37 | drop storage main 38 | 39 | # test: create storage (with partition) 40 | create storage test 41 | insert 0 42 | move partition 0 into test 43 | 44 | show storages debug 45 | show partitions debug 46 | 47 | # test: drop storage (with partition) 48 | drop storage test 49 | drop partition 0 50 | drop storage test 51 | show storages debug 52 | 53 | close 54 | -------------------------------------------------------------------------------- /test/storage/move.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: move parsing 14 | move 15 | move abc 16 | move partition 17 | move partition abc 18 | 19 | # test: move partition does not exists 20 | move partition 0 into 21 | move partition 0 into main 22 | 23 | # test: move partition if exists 24 | move partition if exists 0 into main 25 | 26 | # test: create partition 27 | insert 0 28 | insert 1 29 | insert 2 30 | show storages debug 31 | 32 | # test: move partition (same storage) 33 | move partition 0 into main 34 | show storages debug 35 | 36 | # test: move partition 37 | create storage test 38 | move partition 0 into test 39 | show storages debug 40 | 41 | # test: select 42 | select 43 | 44 | # test: create partitions 45 | insert 10 46 | insert 20 47 | insert 30 48 | insert 40 49 | show storages debug 50 | 51 | # test: move partitions parsing 52 | move partitions 53 | move partitions abc 54 | move partitions between 55 | move partitions between abc 56 | move partitions between 10 57 | move partitions between 10 and 58 | move partitions between 10 and 50 59 | move partitions between 10 and 50 into 60 | 61 | # test: move partitions 62 | move partitions between 10 and 50 into test 63 | show storages debug 64 | show partitions debug 65 | 66 | # test: select 67 | select 68 | 69 | # test: set compression 70 | alter storage main set (compression 'zstd') 71 | 72 | # test: move partitions #2 73 | move partitions between 0 and 50 into main 74 | show storages debug 75 | show partitions debug 76 | 77 | # test: select 78 | select 79 | 80 | close 81 | -------------------------------------------------------------------------------- /test/storage/rebalance.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: rebalance (no pipeline set) 14 | rebalance 15 | show storages debug 16 | 17 | # test: create storages 18 | create storage hot 19 | create storage cold 20 | 21 | # test: alter pipeline set partitions 22 | alter pipeline set hot (partitions 2), cold 23 | show pipeline 24 | 25 | # test: rebalance #1 (empty, <= partitions) 26 | rebalance 27 | show storages debug 28 | 29 | # test: rebalance #2 (< partitions) 30 | insert 0 31 | rebalance 32 | show storages debug 33 | 34 | # test: rebalance #3 (= partitions) 35 | insert 10 36 | rebalance 37 | show storages debug 38 | 39 | # test: rebalance #4 (> partitions) 40 | insert 20 41 | show storages debug 42 | rebalance 43 | show storages debug 44 | 45 | # test: rebalance #5 (more then one, > partitions) 46 | insert 30 47 | insert 40 48 | insert 500 49 | insert 600 50 | show storages debug 51 | rebalance 52 | show storages debug 53 | 54 | select 55 | 56 | # test: alter pipeline set partitions zero 57 | alter pipeline set hot (partitions 0) 58 | show pipeline 59 | 60 | # test: rebalance (auto drop) 61 | show storages debug 62 | rebalance 63 | show storages debug 64 | 65 | # test: alter pipeline set partitions zero #2 (chain) 66 | alter pipeline set hot (partitions 2), cold (partitions 0) 67 | show pipeline 68 | 69 | # test: rebalance #1 (auto drop existing) 70 | show storages debug 71 | rebalance 72 | show storages debug 73 | 74 | # test: rebalance #2 (auto drop) 75 | insert 0 76 | rebalance 77 | show storages debug 78 | 79 | # test: rebalance #3 (auto drop) 80 | insert 10 81 | rebalance 82 | show storages debug 83 | select 84 | 85 | # test: rebalance #4 (auto drop from cold) 86 | insert 20 87 | rebalance 88 | show storages debug 89 | select 90 | 91 | close 92 | -------------------------------------------------------------------------------- /test/storage/refresh.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: refresh parsing 14 | refresh 15 | refresh abc 16 | refresh partition 17 | refresh partition abc 18 | 19 | # test: refresh partition does not exists 20 | refresh partition 0 21 | 22 | # test: refresh partition if exists 23 | refresh partition if exists 0 24 | 25 | # test: create partition 26 | insert 0 27 | insert 1 28 | insert 2 29 | show storages debug 30 | 31 | # test: refresh (memtable) 32 | refresh partition 0 33 | show storages debug 34 | 35 | # test: select (region) 36 | select 37 | 38 | # test: update 39 | insert 3 40 | insert 4 41 | insert 5 42 | show storages debug 43 | 44 | # test: select (memtable + region) 45 | select 46 | 47 | # test: refresh (memtable + region) 48 | refresh partition 0 49 | show storages debug 50 | show partitions debug 51 | 52 | # test: select (updated region) 53 | select 54 | 55 | # test: refresh (with no updates) 56 | refresh partition 0 57 | show storages debug 58 | show partitions debug 59 | 60 | # test: set compression 61 | alter storage main set (compression 'zstd') 62 | 63 | # test: refresh (compress) 64 | refresh partition 0 65 | show storages debug 66 | show partitions debug 67 | 68 | # test: select (compressed data) 69 | select 70 | 71 | # test: create partitions 72 | insert 20 73 | insert 30 74 | insert 40 75 | show storages debug 76 | 77 | # test: refresh partitions parsing 78 | refresh partitions 79 | refresh partitions abc 80 | refresh partitions between 81 | refresh partitions between abc 82 | refresh partitions between 0 83 | refresh partitions between 0 to 84 | refresh partitions between 0 and 85 | refresh partitions between 0 and abc 86 | 87 | # test: refresh partitions 88 | show partitions debug 89 | refresh partitions between 0 and 40 90 | show storages debug 91 | 92 | # test: select 93 | select 94 | 95 | # test: refresh partitions #2 96 | refresh partitions between 40 and 50 97 | show storages debug 98 | 99 | # test: select 100 | select 101 | 102 | close 103 | -------------------------------------------------------------------------------- /test/storage/service.test: -------------------------------------------------------------------------------- 1 | # 2 | 3 | init 4 | set workers to 0 5 | set workers_upload to 0 6 | set interval to 10 7 | set serial to false 8 | set uuid to '00000000-0000-0000-0000-000000000000' 9 | set compression to '' 10 | set sync to false 11 | open 12 | 13 | # test: create partition 14 | insert 0 15 | insert 1 16 | insert 3 17 | show partitions debug 18 | 19 | # process rebalance events 20 | service 21 | show partitions debug 22 | 23 | # test: checkpoint 24 | checkpoint 25 | show partitions debug 26 | 27 | # test: service #1 (refresh) 28 | service 29 | show partitions debug 30 | 31 | # test: service #2 (noop) 32 | service 33 | show partitions debug 34 | 35 | select 36 | 37 | # test: alter storage set refresh 38 | alter storage main set (refresh_wm 1) 39 | 40 | # test: insert (service refresh) 41 | show partitions debug 42 | insert 0 xxx 43 | show partitions debug 44 | 45 | # test: service #1 (refresh) 46 | service 47 | show partitions debug 48 | 49 | # test: service #2 (noop) 50 | service 51 | show partitions debug 52 | 53 | select 54 | 55 | close 56 | -------------------------------------------------------------------------------- /test/suite/monotone_test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | #include "suite/suite.h" 15 | #include "suite/suite_cmd.h" 16 | #include "suite/test.h" 17 | -------------------------------------------------------------------------------- /test/suite/suite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | typedef struct Test Test; 15 | typedef struct TestCursor TestCursor; 16 | typedef struct TestGroup TestGroup; 17 | typedef struct TestSuite TestSuite; 18 | 19 | struct Test 20 | { 21 | char* name; 22 | char* description; 23 | TestGroup* group; 24 | List link_group; 25 | List link; 26 | }; 27 | 28 | struct TestGroup 29 | { 30 | char* name; 31 | char* directory; 32 | bool optional; 33 | List list_test; 34 | List link; 35 | }; 36 | 37 | struct TestCursor 38 | { 39 | char* name; 40 | monotone_cursor_t* cursor; 41 | List link; 42 | }; 43 | 44 | struct TestSuite 45 | { 46 | void* dlhandle; 47 | char* current_test_options; 48 | char* current_test; 49 | FILE* current_test_result; 50 | int current_test_ok_exists; 51 | char* current_test_ok_file; 52 | char* current_test_result_file; 53 | int current_test_started; 54 | int current_line; 55 | int current_plan_line; 56 | TestGroup* current_group; 57 | Test* current; 58 | monotone_t* env; 59 | int list_cursor_count; 60 | List list_cursor; 61 | char* option_test_dir; 62 | char* option_result_dir; 63 | char* option_plan_file; 64 | char* option_test; 65 | char* option_group; 66 | int option_fix; 67 | List list_test; 68 | List list_group; 69 | }; 70 | 71 | void test_suite_init(TestSuite*); 72 | void test_suite_free(TestSuite*); 73 | void test_suite_cleanup(TestSuite*); 74 | int test_suite_run(TestSuite*); 75 | -------------------------------------------------------------------------------- /test/suite/suite_cmd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | int test_suite_cmd(TestSuite*, char*); 15 | -------------------------------------------------------------------------------- /test/suite/test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // monotone. 5 | // 6 | // embeddable cloud-native storage for events 7 | // and time-series data. 8 | // 9 | // Copyright (c) 2023-2025 Dmitry Simonenko 10 | // 11 | // MIT Licensed. 12 | // 13 | 14 | static inline int 15 | test_sh(TestSuite* self, const char* fmt, ...) 16 | { 17 | (void)self; 18 | va_list args; 19 | va_start(args, fmt); 20 | char cmd[PATH_MAX]; 21 | vsnprintf(cmd, sizeof(cmd), fmt, args); 22 | int rc = system(cmd); 23 | va_end(args); 24 | return rc; 25 | } 26 | 27 | static inline void 28 | test_info(TestSuite* self, const char* fmt, ...) 29 | { 30 | (void)self; 31 | va_list args; 32 | va_start(args, fmt); 33 | vprintf(fmt, args); 34 | va_end(args); 35 | fflush(stdout); 36 | } 37 | 38 | static inline void 39 | test_error(TestSuite* self, const char* fmt, ...) 40 | { 41 | (void)self; 42 | va_list args; 43 | va_start(args, fmt); 44 | printf("\n"); 45 | printf("error: "); 46 | vprintf(fmt, args); 47 | printf("\n"); 48 | va_end(args); 49 | fflush(stdout); 50 | } 51 | 52 | static inline void 53 | test_log(TestSuite* self, const char* fmt, ...) 54 | { 55 | va_list args; 56 | va_start(args, fmt); 57 | vfprintf(self->current_test_result, fmt, args); 58 | va_end(args); 59 | fflush(self->current_test_result); 60 | } 61 | 62 | static inline void 63 | test_log_error(TestSuite* self) 64 | { 65 | if (! self->env) 66 | { 67 | test_log(self, "error: env is not openned\n"); 68 | return; 69 | } 70 | auto error = monotone_error(self->env); 71 | if (error) 72 | test_log(self, "error: %s\n", error); 73 | else 74 | test_log(self, "(null)\n"); 75 | } 76 | 77 | #define test(expr) ({ \ 78 | if (! (expr)) { \ 79 | fprintf(stdout, "fail (%s:%d) %s\n", __FILE__, __LINE__, #expr); \ 80 | fflush(stdout); \ 81 | abort(); \ 82 | } \ 83 | }) 84 | 85 | static inline char* 86 | test_chomp(char* start) 87 | { 88 | if (start == NULL) 89 | return NULL; 90 | char* pos = start; 91 | while (*pos != '\n') 92 | pos++; 93 | *pos = 0; 94 | return start; 95 | } 96 | 97 | static inline char* 98 | test_arg(char** start) 99 | { 100 | if (*start == NULL) 101 | return NULL; 102 | char* pos = *start; 103 | while (*pos == ' ') 104 | pos++; 105 | char* arg = pos; 106 | while (*pos != '\n' && *pos != ' ') 107 | pos++; 108 | int is_eol = *pos == '\n'; 109 | *pos = 0; 110 | pos++; 111 | *start = (is_eol) ? NULL : pos; 112 | if (*arg == 0) 113 | return NULL; 114 | return arg; 115 | } 116 | -------------------------------------------------------------------------------- /test/test.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // monotone. 4 | // 5 | // embeddable cloud-native storage for events 6 | // and time-series data. 7 | // 8 | // Copyright (c) 2023-2025 Dmitry Simonenko 9 | // 10 | // MIT Licensed. 11 | // 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | TestSuite suite; 18 | 19 | int 20 | main(int argc, char *argv[]) 21 | { 22 | test_suite_init(&suite); 23 | suite.option_result_dir = "_output"; 24 | suite.option_plan_file = "plan"; 25 | 26 | int opt; 27 | while ((opt = getopt(argc, argv, "o:t:g:hf")) != -1) { 28 | switch (opt) { 29 | case 'o': 30 | suite.option_result_dir = optarg; 31 | break; 32 | case 'f': 33 | suite.option_fix = 1; 34 | break; 35 | case 't': 36 | suite.option_test = optarg; 37 | break; 38 | case 'g': 39 | suite.option_group = optarg; 40 | break; 41 | case 'h': 42 | default: 43 | printf("usage: %s [-o output_dir] [-t test] [-g group] [-h] [-f]\n", argv[0]); 44 | return 0; 45 | } 46 | } 47 | 48 | int rc; 49 | rc = test_suite_run(&suite); 50 | if (rc == -1) 51 | return -1; 52 | 53 | test_suite_cleanup(&suite); 54 | test_suite_free(&suite); 55 | return 0; 56 | } 57 | --------------------------------------------------------------------------------