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.
- pysciqlop_cache-0.1.0/.bumpversion.cfg +13 -0
- pysciqlop_cache-0.1.0/.clang-format +32 -0
- pysciqlop_cache-0.1.0/.github/workflows/CI.yml +213 -0
- pysciqlop_cache-0.1.0/.github/workflows/tests-with-coverage.yml +37 -0
- pysciqlop_cache-0.1.0/.gitignore +17 -0
- pysciqlop_cache-0.1.0/CLAUDE.md +88 -0
- pysciqlop_cache-0.1.0/COPYING +21 -0
- pysciqlop_cache-0.1.0/PKG-INFO +318 -0
- pysciqlop_cache-0.1.0/README.md +274 -0
- pysciqlop_cache-0.1.0/benchmark/batch_chart.png +0 -0
- pysciqlop_cache-0.1.0/benchmark/batch_per_op_chart.png +0 -0
- pysciqlop_cache-0.1.0/benchmark/bench_valuesize.py +106 -0
- pysciqlop_cache-0.1.0/benchmark/main.py +109 -0
- pysciqlop_cache-0.1.0/benchmark/plot_scaling.py +165 -0
- pysciqlop_cache-0.1.0/benchmark/plot_valuesize.py +199 -0
- pysciqlop_cache-0.1.0/benchmark/scaling.py +166 -0
- pysciqlop_cache-0.1.0/benchmark/scaling_chart.png +0 -0
- pysciqlop_cache-0.1.0/benchmark/scaling_violin.png +0 -0
- pysciqlop_cache-0.1.0/benchmark/valuesize_chart.png +0 -0
- pysciqlop_cache-0.1.0/docs/plans/2026-03-09-bugfixes-and-perf.md +476 -0
- pysciqlop_cache-0.1.0/docs/superpowers/plans/2026-03-10-fanout-store.md +1002 -0
- pysciqlop_cache-0.1.0/docs/superpowers/plans/2026-03-11-check-command.md +892 -0
- pysciqlop_cache-0.1.0/docs/superpowers/specs/2026-03-10-fanout-store-design.md +81 -0
- pysciqlop_cache-0.1.0/docs/superpowers/specs/2026-03-11-torture-tests-design.md +64 -0
- pysciqlop_cache-0.1.0/include/sciqlop_cache/Profiling.hpp +51 -0
- pysciqlop_cache-0.1.0/include/sciqlop_cache/database.hpp +536 -0
- pysciqlop_cache-0.1.0/include/sciqlop_cache/disk_storage.hpp +193 -0
- pysciqlop_cache-0.1.0/include/sciqlop_cache/fanout_store.hpp +342 -0
- pysciqlop_cache-0.1.0/include/sciqlop_cache/policies.hpp +63 -0
- pysciqlop_cache-0.1.0/include/sciqlop_cache/sciqlop_cache.hpp +18 -0
- pysciqlop_cache-0.1.0/include/sciqlop_cache/store.hpp +1491 -0
- pysciqlop_cache-0.1.0/include/sciqlop_cache/utils/buffer.hpp +121 -0
- pysciqlop_cache-0.1.0/include/sciqlop_cache/utils/concepts.hpp +26 -0
- pysciqlop_cache-0.1.0/include/sciqlop_cache/utils/time.hpp +23 -0
- pysciqlop_cache-0.1.0/meson.build +196 -0
- pysciqlop_cache-0.1.0/meson_options.txt +6 -0
- pysciqlop_cache-0.1.0/pyproject.toml +46 -0
- pysciqlop_cache-0.1.0/pysciqlop_cache/__init__.py +598 -0
- pysciqlop_cache-0.1.0/pysciqlop_cache/meson.build +26 -0
- pysciqlop_cache-0.1.0/pysciqlop_cache/migrate.py +181 -0
- pysciqlop_cache-0.1.0/pysciqlop_cache/pysciqlop_cache.cpp +343 -0
- pysciqlop_cache-0.1.0/pysciqlop_cache/serializers.py +129 -0
- pysciqlop_cache-0.1.0/scripts/version.py +46 -0
- pysciqlop_cache-0.1.0/subprojects/catch2.wrap +11 -0
- pysciqlop_cache-0.1.0/subprojects/cpp_utils.wrap +7 -0
- pysciqlop_cache-0.1.0/subprojects/fmt.wrap +13 -0
- pysciqlop_cache-0.1.0/subprojects/google-benchmark.wrap +13 -0
- pysciqlop_cache-0.1.0/subprojects/hedley.wrap +12 -0
- pysciqlop_cache-0.1.0/subprojects/nanobind.wrap +14 -0
- pysciqlop_cache-0.1.0/subprojects/robin-map.wrap +13 -0
- pysciqlop_cache-0.1.0/subprojects/sqlite3.wrap +13 -0
- pysciqlop_cache-0.1.0/subprojects/stduuid.wrap +13 -0
- pysciqlop_cache-0.1.0/subprojects/tracy.wrap +7 -0
- pysciqlop_cache-0.1.0/tests/basic/main.cpp +920 -0
- pysciqlop_cache-0.1.0/tests/basic_index/main.cpp +192 -0
- pysciqlop_cache-0.1.0/tests/bench_perf/main.cpp +175 -0
- pysciqlop_cache-0.1.0/tests/check/main.cpp +288 -0
- pysciqlop_cache-0.1.0/tests/common.hpp +77 -0
- pysciqlop_cache-0.1.0/tests/concurrency_bugs/main.cpp +106 -0
- pysciqlop_cache-0.1.0/tests/database/main.cpp +108 -0
- pysciqlop_cache-0.1.0/tests/fanout/main.cpp +309 -0
- pysciqlop_cache-0.1.0/tests/intermediate/main.cpp +209 -0
- pysciqlop_cache-0.1.0/tests/multithreads/main.cpp +157 -0
- pysciqlop_cache-0.1.0/tests/python/test_concurrency_bugs.py +569 -0
- pysciqlop_cache-0.1.0/tests/python/test_hypothesis.py +247 -0
- pysciqlop_cache-0.1.0/tests/python/test_perf_vs_diskcache.py +163 -0
- pysciqlop_cache-0.1.0/tests/python/test_python_interface.py +999 -0
- pysciqlop_cache-0.1.0/tests/python/test_python_multiprocess.py +84 -0
- pysciqlop_cache-0.1.0/tests/python/test_serializers.py +243 -0
- pysciqlop_cache-0.1.0/tests/python/test_torture.py +280 -0
- pysciqlop_cache-0.1.0/tests/torture/main.cpp +246 -0
- 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,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.
|