pysciqlop-cache 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. pysciqlop_cache-0.1.0/.bumpversion.cfg +13 -0
  2. pysciqlop_cache-0.1.0/.clang-format +32 -0
  3. pysciqlop_cache-0.1.0/.github/workflows/CI.yml +213 -0
  4. pysciqlop_cache-0.1.0/.github/workflows/tests-with-coverage.yml +37 -0
  5. pysciqlop_cache-0.1.0/.gitignore +17 -0
  6. pysciqlop_cache-0.1.0/CLAUDE.md +88 -0
  7. pysciqlop_cache-0.1.0/COPYING +21 -0
  8. pysciqlop_cache-0.1.0/PKG-INFO +318 -0
  9. pysciqlop_cache-0.1.0/README.md +274 -0
  10. pysciqlop_cache-0.1.0/benchmark/batch_chart.png +0 -0
  11. pysciqlop_cache-0.1.0/benchmark/batch_per_op_chart.png +0 -0
  12. pysciqlop_cache-0.1.0/benchmark/bench_valuesize.py +106 -0
  13. pysciqlop_cache-0.1.0/benchmark/main.py +109 -0
  14. pysciqlop_cache-0.1.0/benchmark/plot_scaling.py +165 -0
  15. pysciqlop_cache-0.1.0/benchmark/plot_valuesize.py +199 -0
  16. pysciqlop_cache-0.1.0/benchmark/scaling.py +166 -0
  17. pysciqlop_cache-0.1.0/benchmark/scaling_chart.png +0 -0
  18. pysciqlop_cache-0.1.0/benchmark/scaling_violin.png +0 -0
  19. pysciqlop_cache-0.1.0/benchmark/valuesize_chart.png +0 -0
  20. pysciqlop_cache-0.1.0/docs/plans/2026-03-09-bugfixes-and-perf.md +476 -0
  21. pysciqlop_cache-0.1.0/docs/superpowers/plans/2026-03-10-fanout-store.md +1002 -0
  22. pysciqlop_cache-0.1.0/docs/superpowers/plans/2026-03-11-check-command.md +892 -0
  23. pysciqlop_cache-0.1.0/docs/superpowers/specs/2026-03-10-fanout-store-design.md +81 -0
  24. pysciqlop_cache-0.1.0/docs/superpowers/specs/2026-03-11-torture-tests-design.md +64 -0
  25. pysciqlop_cache-0.1.0/include/sciqlop_cache/Profiling.hpp +51 -0
  26. pysciqlop_cache-0.1.0/include/sciqlop_cache/database.hpp +536 -0
  27. pysciqlop_cache-0.1.0/include/sciqlop_cache/disk_storage.hpp +193 -0
  28. pysciqlop_cache-0.1.0/include/sciqlop_cache/fanout_store.hpp +342 -0
  29. pysciqlop_cache-0.1.0/include/sciqlop_cache/policies.hpp +63 -0
  30. pysciqlop_cache-0.1.0/include/sciqlop_cache/sciqlop_cache.hpp +18 -0
  31. pysciqlop_cache-0.1.0/include/sciqlop_cache/store.hpp +1491 -0
  32. pysciqlop_cache-0.1.0/include/sciqlop_cache/utils/buffer.hpp +121 -0
  33. pysciqlop_cache-0.1.0/include/sciqlop_cache/utils/concepts.hpp +26 -0
  34. pysciqlop_cache-0.1.0/include/sciqlop_cache/utils/time.hpp +23 -0
  35. pysciqlop_cache-0.1.0/meson.build +196 -0
  36. pysciqlop_cache-0.1.0/meson_options.txt +6 -0
  37. pysciqlop_cache-0.1.0/pyproject.toml +46 -0
  38. pysciqlop_cache-0.1.0/pysciqlop_cache/__init__.py +598 -0
  39. pysciqlop_cache-0.1.0/pysciqlop_cache/meson.build +26 -0
  40. pysciqlop_cache-0.1.0/pysciqlop_cache/migrate.py +181 -0
  41. pysciqlop_cache-0.1.0/pysciqlop_cache/pysciqlop_cache.cpp +343 -0
  42. pysciqlop_cache-0.1.0/pysciqlop_cache/serializers.py +129 -0
  43. pysciqlop_cache-0.1.0/scripts/version.py +46 -0
  44. pysciqlop_cache-0.1.0/subprojects/catch2.wrap +11 -0
  45. pysciqlop_cache-0.1.0/subprojects/cpp_utils.wrap +7 -0
  46. pysciqlop_cache-0.1.0/subprojects/fmt.wrap +13 -0
  47. pysciqlop_cache-0.1.0/subprojects/google-benchmark.wrap +13 -0
  48. pysciqlop_cache-0.1.0/subprojects/hedley.wrap +12 -0
  49. pysciqlop_cache-0.1.0/subprojects/nanobind.wrap +14 -0
  50. pysciqlop_cache-0.1.0/subprojects/robin-map.wrap +13 -0
  51. pysciqlop_cache-0.1.0/subprojects/sqlite3.wrap +13 -0
  52. pysciqlop_cache-0.1.0/subprojects/stduuid.wrap +13 -0
  53. pysciqlop_cache-0.1.0/subprojects/tracy.wrap +7 -0
  54. pysciqlop_cache-0.1.0/tests/basic/main.cpp +920 -0
  55. pysciqlop_cache-0.1.0/tests/basic_index/main.cpp +192 -0
  56. pysciqlop_cache-0.1.0/tests/bench_perf/main.cpp +175 -0
  57. pysciqlop_cache-0.1.0/tests/check/main.cpp +288 -0
  58. pysciqlop_cache-0.1.0/tests/common.hpp +77 -0
  59. pysciqlop_cache-0.1.0/tests/concurrency_bugs/main.cpp +106 -0
  60. pysciqlop_cache-0.1.0/tests/database/main.cpp +108 -0
  61. pysciqlop_cache-0.1.0/tests/fanout/main.cpp +309 -0
  62. pysciqlop_cache-0.1.0/tests/intermediate/main.cpp +209 -0
  63. pysciqlop_cache-0.1.0/tests/multithreads/main.cpp +157 -0
  64. pysciqlop_cache-0.1.0/tests/python/test_concurrency_bugs.py +569 -0
  65. pysciqlop_cache-0.1.0/tests/python/test_hypothesis.py +247 -0
  66. pysciqlop_cache-0.1.0/tests/python/test_perf_vs_diskcache.py +163 -0
  67. pysciqlop_cache-0.1.0/tests/python/test_python_interface.py +999 -0
  68. pysciqlop_cache-0.1.0/tests/python/test_python_multiprocess.py +84 -0
  69. pysciqlop_cache-0.1.0/tests/python/test_serializers.py +243 -0
  70. pysciqlop_cache-0.1.0/tests/python/test_torture.py +280 -0
  71. pysciqlop_cache-0.1.0/tests/torture/main.cpp +246 -0
  72. pysciqlop_cache-0.1.0/version.txt +1 -0
@@ -0,0 +1,13 @@
1
+ [bumpversion]
2
+ current_version = 0.1.0
3
+ commit = True
4
+ tag = True
5
+
6
+ [bumpversion:file:version.txt]
7
+ parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
8
+ search = {current_version}
9
+ replace = {new_version}
10
+
11
+ [bumpversion:file:docs/conf.py]
12
+ search = version = '{current_version}'
13
+ replace = version = '{new_version}'
@@ -0,0 +1,32 @@
1
+ ---
2
+ # See http://clang.llvm.org/docs/ClangFormatStyleOptions.html for a definition
3
+ # of the options
4
+ Language: Cpp
5
+ BasedOnStyle: WebKit
6
+
7
+ # Line length
8
+ ColumnLimit: 100
9
+
10
+ # Indent with 4 spaces
11
+ IndentWidth: 4
12
+ AccessModifierOffset: -4 # -IndentWidth
13
+ ConstructorInitializerIndentWidth: 8 # 2 * IndentWidth
14
+
15
+ BreakBeforeBraces: Allman
16
+ SeparateDefinitionBlocks: Always
17
+ EmptyLineBeforeAccessModifier: Always
18
+
19
+ AllowShortFunctionsOnASingleLine: Inline
20
+ AlwaysBreakTemplateDeclarations: true
21
+ AlwaysBreakBeforeMultilineStrings: true
22
+ BreakBeforeBinaryOperators: true
23
+ ConstructorInitializerAllOnOneLineOrOnePerLine: true
24
+ IndentCaseLabels: true
25
+ MaxEmptyLinesToKeep: 2
26
+ Standard: Cpp11
27
+ UseTab: Never
28
+
29
+ ContinuationIndentWidth: 4
30
+ AlignAfterOpenBracket: true
31
+ LambdaBodyIndentation: Signature
32
+
@@ -0,0 +1,213 @@
1
+ name: GH Actions
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ push:
7
+ pull_request:
8
+
9
+ # Auto-cancel superseded runs of the same branch/PR. Releases never
10
+ # cancel each other (the tag ref is unique).
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.event_name == 'release' && github.ref || (github.head_ref || github.ref_name) }}
13
+ cancel-in-progress: ${{ github.event_name != 'release' }}
14
+
15
+ jobs:
16
+ build_sdist:
17
+ name: Build source distribution
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - name: Build sdist
22
+ run: pipx run build --sdist
23
+ - name: Upload artifact
24
+ uses: actions/upload-artifact@v4
25
+ with:
26
+ name: cibw-sdist
27
+ path: dist/*.tar.gz
28
+
29
+ build_wheels:
30
+ name: ${{ matrix.os }} ${{ matrix.CIBW_ARCHS }} wheels
31
+ runs-on: ${{ matrix.os }}
32
+ strategy:
33
+ matrix:
34
+ include:
35
+ - os: ubuntu-latest
36
+ CIBW_ENVIRONMENT: ''
37
+ CIBW_ARCHS: "x86_64"
38
+ - os: ubuntu-24.04-arm
39
+ CIBW_ENVIRONMENT: ''
40
+ CIBW_ARCHS: "aarch64"
41
+ - os: windows-latest
42
+ CIBW_ENVIRONMENT: ''
43
+ CIBW_ARCHS: "AMD64"
44
+ - os: macos-15-intel
45
+ CIBW_ENVIRONMENT: >
46
+ MACOSX_DEPLOYMENT_TARGET='13.0'
47
+ CIBW_ARCHS: "x86_64"
48
+ - os: macos-14 # Apple Silicon
49
+ CIBW_ENVIRONMENT: >
50
+ MACOSX_DEPLOYMENT_TARGET='13.0'
51
+ CIBW_ARCHS: "arm64"
52
+ env:
53
+ CIBW_ENVIRONMENT: ${{ matrix.CIBW_ENVIRONMENT }}
54
+ CIBW_SKIP: "*-win32 *i686"
55
+ CIBW_ARCHS: ${{ matrix.CIBW_ARCHS }}
56
+ CIBW_PRERELEASE_PYTHONS: "True"
57
+ # see https://github.com/matplotlib/matplotlib/pull/28687/files#diff-504e739c530d50b780e9a09ae8fd0c3ea8258ea7553be06afb06f03f95b1ee0aR103
58
+ CIBW_CONFIG_SETTINGS_WINDOWS: >-
59
+ setup-args="--vsenv"
60
+ setup-args="-Db_vscrt=mt"
61
+ setup-args="-Dcpp_link_args=['ucrt.lib','vcruntime.lib','/nodefaultlib:libucrt.lib','/nodefaultlib:libvcruntime.lib']"
62
+ steps:
63
+ - uses: actions/checkout@v4
64
+
65
+ # ccache for Linux wheels: cibuildwheel runs the build inside the
66
+ # manylinux/musllinux container, so we mount a host-side ccache dir
67
+ # into it (CIBW_CONTAINER_ENGINE), install ccache inside the
68
+ # container (CIBW_BEFORE_ALL_LINUX), and point CC/CXX at it. The
69
+ # cache mostly hits on stable subprojects (sqlite3.c is the big
70
+ # one — ~60s per build) across the 6 Python builds for one platform
71
+ # and across runs that don't bump subproject versions.
72
+ - name: Restore ccache (Linux)
73
+ if: runner.os == 'Linux'
74
+ uses: actions/cache@v4
75
+ with:
76
+ path: ${{ github.workspace }}/.ccache
77
+ key: ccache-${{ matrix.os }}-${{ matrix.CIBW_ARCHS }}-${{ hashFiles('subprojects/*.wrap', 'meson.build') }}
78
+ restore-keys: |
79
+ ccache-${{ matrix.os }}-${{ matrix.CIBW_ARCHS }}-
80
+
81
+ - name: Configure ccache for cibuildwheel (Linux)
82
+ if: runner.os == 'Linux'
83
+ run: |
84
+ mkdir -p ${{ github.workspace }}/.ccache
85
+ chmod -R 777 ${{ github.workspace }}/.ccache
86
+ # Try every package manager / repo combo we might land in:
87
+ # musllinux (Alpine: apk), manylinux_2_28 (AlmaLinux 8: PowerTools),
88
+ # manylinux_2_34 (AlmaLinux 9: CRB), manylinux2014 (CentOS 7: EPEL).
89
+ INSTALL_CCACHE='( command -v apk && apk add --no-cache ccache ) || ( dnf install -y --enablerepo=powertools ccache 2>/dev/null ) || ( dnf install -y --enablerepo=crb ccache 2>/dev/null ) || ( yum install -y epel-release && yum install -y ccache )'
90
+ echo "CIBW_BEFORE_ALL_LINUX=$INSTALL_CCACHE" >> $GITHUB_ENV
91
+ echo 'CIBW_ENVIRONMENT_LINUX=CCACHE_DIR=/host_ccache CCACHE_MAXSIZE=500M CC="ccache gcc" CXX="ccache g++"' >> $GITHUB_ENV
92
+ echo 'CIBW_CONTAINER_ENGINE=docker; create_args: --volume=${{ github.workspace }}/.ccache:/host_ccache' >> $GITHUB_ENV
93
+
94
+ - name: Build wheels
95
+ uses: pypa/cibuildwheel@v3.1.4
96
+
97
+ - name: Show ccache size (Linux)
98
+ if: runner.os == 'Linux' && always()
99
+ run: du -sh ${{ github.workspace }}/.ccache 2>/dev/null || true
100
+
101
+ - uses: actions/upload-artifact@v4
102
+ with:
103
+ name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
104
+ path: ./wheelhouse/*.whl
105
+
106
+ test_wheels:
107
+ needs: [build_wheels]
108
+ strategy:
109
+ fail-fast: false
110
+ matrix:
111
+ os: [macos-15-intel, macos-14, windows-latest, ubuntu-latest, ubuntu-24.04-arm]
112
+ python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.14t']
113
+ runs-on: ${{ matrix.os }}
114
+ steps:
115
+ - name: Setup Python
116
+ uses: actions/setup-python@v5
117
+ with:
118
+ python-version: ${{ matrix.python-version }}
119
+ allow-prereleases: true
120
+ #architecture: x64
121
+ - uses: actions/download-artifact@v4
122
+ with:
123
+ pattern: cibw-wheels-*
124
+ path: dist
125
+ merge-multiple: true
126
+ - name: install wheel (Unix)
127
+ if: runner.os != 'Windows'
128
+ run: |
129
+ pip install numpy
130
+ pip install --no-index --find-links $GITHUB_WORKSPACE/dist pysciqlop-cache
131
+ - name: install wheel (Windows)
132
+ if: runner.os == 'Windows'
133
+ run: |
134
+ pip install numpy
135
+ pip install --no-index --find-links $env:GITHUB_WORKSPACE\dist pysciqlop-cache
136
+ - uses: actions/checkout@v4
137
+ - name: run tests
138
+ # Two interacting issues, fixed together:
139
+ #
140
+ # 1. multiprocessing.Pool workers under spawn (macOS/Windows always)
141
+ # or forkserver (Linux Python 3.14+ default) re-import the
142
+ # function's module by name. pytest assigns name
143
+ # 'tests.python.test_concurrency_bugs', so workers need to be able
144
+ # to `import tests`. Add repo root to PYTHONPATH for that.
145
+ #
146
+ # 2. But the source `pysciqlop_cache/` directory is at the repo root
147
+ # and shadows the installed wheel: its __init__.py does
148
+ # `from ._pysciqlop_cache import …` and the compiled .so only
149
+ # exists in site-packages. Remove the source dir from the
150
+ # workspace before running tests so the installed wheel wins.
151
+ # (Cross-platform via Python's shutil.)
152
+ env:
153
+ PYTHONPATH: ${{ github.workspace }}
154
+ run: |
155
+ pip install pytest pytest-timeout ddt requests hypothesis diskcache
156
+ python -c "import shutil; shutil.rmtree('pysciqlop_cache', ignore_errors=True)"
157
+ # --timeout=300 (5 min) so a hang fails fast with a stack trace
158
+ # instead of running until the GitHub job timeout. Real tests on
159
+ # Windows can be slow (cross-process SQLite + fcntl emulation) but
160
+ # 5 min is a generous ceiling — if anything exceeds it, that's a
161
+ # bug to investigate, not a number to bump.
162
+ # --timeout-method=thread so threaded/multiproc tests can be killed
163
+ # cleanly on Windows (the default 'signal' method needs SIGALRM
164
+ # which Windows doesn't have).
165
+ python -m pytest --import-mode=importlib --tb=short --disable-warnings -v --timeout=300 --timeout-method=thread tests/python --ignore=tests/python/test_torture.py --ignore=tests/python/test_hypothesis.py
166
+
167
+ upload_pypi:
168
+ needs: [build_sdist, build_wheels, test_wheels]
169
+ runs-on: ubuntu-latest
170
+ # upload to PyPI only on github releases
171
+ if: github.event_name == 'release' && github.event.action == 'published' && github.repository_owner == 'SciQLop'
172
+ # PyPI Trusted Publisher (OIDC). The `pypi` environment matches the
173
+ # publisher config registered on https://pypi.org/manage/project/PySciQLop_cache/
174
+ # — no API token needed; the action exchanges the OIDC ID token from
175
+ # GitHub for a short-lived PyPI upload token.
176
+ environment:
177
+ name: pypi
178
+ url: https://pypi.org/p/PySciQLop_cache
179
+ permissions:
180
+ id-token: write
181
+ steps:
182
+ - uses: actions/download-artifact@v4
183
+ with:
184
+ pattern: cibw-*
185
+ path: dist
186
+ merge-multiple: true
187
+ - uses: pypa/gh-action-pypi-publish@release/v1
188
+ with:
189
+ skip-existing: true
190
+
191
+ upload_test_pypi:
192
+ needs: [build_sdist, build_wheels, test_wheels]
193
+ runs-on: ubuntu-latest
194
+ # upload to test PyPI on github pushes
195
+ if: github.event_name == 'push' && github.repository_owner == 'SciQLop'
196
+ # TestPyPI Trusted Publisher (OIDC). Matches the publisher config on
197
+ # https://test.pypi.org/manage/project/PySciQLop_cache/ via the
198
+ # `testpypi` environment.
199
+ environment:
200
+ name: testpypi
201
+ url: https://test.pypi.org/p/PySciQLop_cache
202
+ permissions:
203
+ id-token: write
204
+ steps:
205
+ - uses: actions/download-artifact@v4
206
+ with:
207
+ pattern: cibw-*
208
+ path: dist
209
+ merge-multiple: true
210
+ - uses: pypa/gh-action-pypi-publish@release/v1
211
+ with:
212
+ repository-url: https://test.pypi.org/legacy/
213
+ skip-existing: true
@@ -0,0 +1,37 @@
1
+ name: Tests Linux with coverage
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+ name: build an tests with coverage
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+ with:
12
+ submodules: true
13
+ - name: Install dependencies
14
+ run: |
15
+ sudo apt update
16
+ sudo apt install -y python3-pip python3-dev lcov g++ meson ninja-build git catch2
17
+ pip install --upgrade meson ninja numpy meson-python>=0.14.0 build wheel ddt requests
18
+ - name: Configure with meson
19
+ run: meson -Db_coverage=true -Dwith_tests=true . build
20
+ - name: Build (meson)
21
+ run: ninja -C build
22
+ - name: Run tests (meson)
23
+ run: ninja test -C build
24
+ - name: Generate Coverage report
25
+ run: |
26
+ lcov --capture --ignore-errors=inconsistent,mismatch --directory . --output-file coverage.info
27
+ lcov --remove coverage.info '/usr/*' --ignore-errors=unused --output-file coverage.info
28
+ lcov --remove coverage.info '*/catch*' --ignore-errors=unused --output-file coverage.info
29
+ lcov --list coverage.info
30
+ - name: Upload coverage to Codecov
31
+ uses: codecov/codecov-action@v4
32
+ with:
33
+ token: ${{ secrets.CODECOV_TOKEN }}
34
+ file: ./coverage.info
35
+ flags: unittests
36
+ name: codecov-cdfpp
37
+ fail_ci_if_error: true
@@ -0,0 +1,17 @@
1
+ build/
2
+ subprojects/*
3
+ !subprojects/*.wrap
4
+ *.kdev4
5
+ CMakeLists.txt.user
6
+ .cache/*
7
+ .cmake/*
8
+ *.user
9
+ *.user.*
10
+ *.ipynb_check*
11
+ *__pycache__*
12
+ version.txt
13
+ docs/_build/*
14
+ docs/generated/*
15
+ dist/*
16
+ tmp*
17
+ .vscode/*
@@ -0,0 +1,88 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ Sciqlop-cache is a C++20 caching library with Python bindings. It uses SQLite for metadata and a hybrid storage strategy: values ≤ 8KB stored as BLOBs in SQLite, larger values stored as files on disk. Thread-safe via per-instance database connections and WAL mode.
8
+
9
+ ## Build Commands
10
+
11
+ ```bash
12
+ # Configure with tests
13
+ meson setup build -Dwith_tests=true
14
+
15
+ # Build
16
+ meson compile -C build
17
+
18
+ # Run all tests
19
+ meson test -C build
20
+
21
+ # Run a single test suite
22
+ meson test -C build sciqlop-cache:basic
23
+
24
+ # Available test suites:
25
+ # C++ (always-on): sciqlop-cache:basic, sciqlop-cache:basic_index,
26
+ # sciqlop-cache:database, sciqlop-cache:intermediate,
27
+ # sciqlop-cache:multithreads, sciqlop-cache:fanout,
28
+ # sciqlop-cache:check
29
+ # C++ (with_torture_tests=true):
30
+ # sciqlop-cache:torture, sciqlop-cache:concurrency_bugs
31
+ # Python (always-on if Python wrapper enabled):
32
+ # sciqlop-cache:test_python_interface,
33
+ # sciqlop-cache:test_serializers,
34
+ # sciqlop-cache:test_python_multiprocess,
35
+ # sciqlop-cache:test_perf_vs_diskcache,
36
+ # sciqlop-cache:test_concurrency_bugs
37
+ # Python (with_torture_tests=true):
38
+ # sciqlop-cache:test_torture, sciqlop-cache:test_hypothesis
39
+
40
+ # Build Python wheel
41
+ pip install meson-python numpy && python -m build --wheel
42
+ ```
43
+
44
+ ### Meson Options
45
+
46
+ - `with_tests` (false) — build C++ tests
47
+ - `with_benchmarks` (false) — build benchmarks
48
+ - `disable_python_wrapper` (false) — skip Python bindings
49
+ - `tracy_enable` (false) — enable Tracy profiling
50
+
51
+ ## Architecture
52
+
53
+ **Core layer** (`include/sciqlop_cache/`):
54
+
55
+ - `store.hpp` — `_Store<Storage, Policies...>` template class, the main engine. Uses zero-cost policy-based design: policies are inherited as mixins, SQL and behavior composed via `if constexpr` + fold expressions. No virtual dispatch.
56
+ - `policies.hpp` — Policy structs: `WithExpiration`, `WithEviction`, `WithTags`, `WithStats`. Each contributes schema columns, WHERE clause fragments, and runtime hooks. `has_policy_v` trait for compile-time branching.
57
+ - `sciqlop_cache.hpp` — Type aliases: `Cache = _Store<DiskStorage, WithExpiration, WithEviction, WithTags, WithStats>`, `Index = _Store<DiskStorage>`, `FanoutCache = FanoutStore<Cache>`, `FanoutIndex = FanoutStore<Index>`.
58
+ - `fanout_store.hpp` — `FanoutStore<StoreType>` template. Shards keys across N independent `_Store` instances via `hash(key) % shard_count` for write concurrency. Per-key ops dispatch to one shard; cross-shard ops aggregate.
59
+ - `database.hpp` — SQLite wrapper: `Database`, `CompiledStatement`, `BindedCompiledStatement`, `Transaction`. Uses SQLITE_NOMUTEX with manual transaction control. `~Transaction()` rolls back if `commit()` was never called (RAII rollback-by-default).
60
+ - `disk_storage.hpp` — `DiskStorage` class. UUID-based two-level directory hierarchy for file storage.
61
+ - `utils/concepts.hpp` — C++20 concepts: `DurationConcept`, `TimePoint`, `Bytes`
62
+ - `utils/buffer.hpp` — Polymorphic buffer with memory-mapped file support
63
+ - `utils/time.hpp` — Epoch/TimePoint conversions for SQLite
64
+
65
+ **Python bindings** (`pysciqlop_cache/`): nanobind-based, exposes `Cache`, `Index`, `FanoutCache`, and `FanoutIndex` with dict-like interface and `Buffer` with `.memoryview()`.
66
+
67
+ **Tests** (`tests/`): Catch2 BDD-style. Seven always-on C++ suites (basic, basic_index, database, intermediate, multithreads, fanout, check) plus Python tests. Two more suites (`torture`, `concurrency_bugs`) plus the Python `test_torture` and `test_hypothesis` are gated by `-Dwith_torture_tests=true` (designed for sanitizer / long-running runs).
68
+
69
+ ## Dependencies
70
+
71
+ All vendored in `subprojects/`: SQLite amalgamation, fmt, nanobind, Catch2, stduuid, cpp_utils, tracy, robin-map, hedley.
72
+
73
+ ## Key Design Decisions
74
+
75
+ - **Policy-based Store** — `_Store<Storage, Policies...>` composes features at compile time. `Cache` has expiration, LRU eviction, tags, and stats. `Index` is a bare key-value store with no overhead.
76
+ - **FanoutStore** — `FanoutStore<StoreType>` shards keys across N independent stores (default 8) for write concurrency. `max_size` is per shard. `transact(key)` scoped to one shard. No cross-shard transactions.
77
+ - Per-instance `Database` + `std::recursive_mutex` for thread safety
78
+ - WAL mode + 600s busy_timeout for multi-process safety
79
+ - **`_NestedTxn` (private RAII helper in `_Store`)** — every internal write path (`_set_impl`, `del`, `pop`, `incr`, `evict_tag`) wraps in a `BEGIN EXCLUSIVE` only at the outermost level (depth-counted via `_txn_depth`). Inner levels are no-ops. Both for cross-process atomicity (read-modify-write inside one txn) and to compose cleanly inside a user `transact()`.
80
+ - **`TransactionGuard` is reentrant on the same thread** (depth-counted same as `_NestedTxn`). Nested `with cache.transact():` is supported; outer rollback discards inner work (no real SAVEPOINTs — same semantics as diskcache).
81
+ - **BG checkpoint thread takes `_mtx`** around `_bg_evict` + `_resync_counters` so it can't clobber atomic counters mid-update on the user-thread side.
82
+ - `size()` and `count()` use in-memory atomic counters (O(1)) for types without expiration; `count()` queries DB when expiration filtering needed (deliberate — see `tier2_perf_decisions.md` in the auto-memory)
83
+ - Expiration handled at query time via SQL (`WHERE expire IS NULL OR expire > unixepoch('now')`) — only present in types with `WithExpiration`
84
+ - No-expiry default: `set()`/`add()` without expire stores NULL (never expires)
85
+ - LRU eviction: `max_size` in bytes (0 = unlimited, default). Background thread evicts using monotonic access counter — only present with `WithEviction`
86
+ - Tags: optional `tag` parameter on `set()`/`add()`, indexed for fast `evict_tag()` bulk removal — only present with `WithTags`
87
+ - C++20 concepts enforce type safety at compile time
88
+ - `requires` clauses on methods ensure policy-specific API (e.g. `touch()`, `evict()`) is only available on types that support it
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Laboratory of Plasma Physics, Ecole Polytechnique, CNRS, Sorbonne Université, Université Paris-Saclay
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, 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,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.