cachebox 6.2.6__tar.gz → 6.2.7__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.
- {cachebox-6.2.6 → cachebox-6.2.7}/.github/workflows/CI.yml +22 -16
- {cachebox-6.2.6 → cachebox-6.2.7}/Cargo.lock +1 -1
- {cachebox-6.2.6 → cachebox-6.2.7}/Cargo.toml +1 -1
- {cachebox-6.2.6 → cachebox-6.2.7}/PKG-INFO +1 -1
- {cachebox-6.2.6 → cachebox-6.2.7}/src/policies/fifopolicy.rs +2 -2
- {cachebox-6.2.6 → cachebox-6.2.7}/src/policies/lfupolicy.rs +2 -2
- {cachebox-6.2.6 → cachebox-6.2.7}/src/policies/lrupolicy.rs +2 -2
- {cachebox-6.2.6 → cachebox-6.2.7}/src/policies/nopolicy.rs +2 -2
- {cachebox-6.2.6 → cachebox-6.2.7}/src/policies/rrpolicy.rs +2 -2
- {cachebox-6.2.6 → cachebox-6.2.7}/src/policies/traits.rs +1 -1
- {cachebox-6.2.6 → cachebox-6.2.7}/src/policies/ttlpolicy.rs +2 -2
- {cachebox-6.2.6 → cachebox-6.2.7}/src/policies/vttlpolicy.rs +2 -2
- {cachebox-6.2.6 → cachebox-6.2.7}/src/policies/wrapped.rs +12 -2
- {cachebox-6.2.6 → cachebox-6.2.7}/src/pyclasses/cache.rs +3 -1
- {cachebox-6.2.6 → cachebox-6.2.7}/src/pyclasses/fifocache.rs +3 -1
- {cachebox-6.2.6 → cachebox-6.2.7}/src/pyclasses/lfucache.rs +3 -1
- {cachebox-6.2.6 → cachebox-6.2.7}/src/pyclasses/lrucache.rs +3 -1
- {cachebox-6.2.6 → cachebox-6.2.7}/src/pyclasses/rrcache.rs +3 -1
- {cachebox-6.2.6 → cachebox-6.2.7}/src/pyclasses/ttlcache.rs +3 -1
- {cachebox-6.2.6 → cachebox-6.2.7}/src/pyclasses/vttlcache.rs +3 -1
- cachebox-6.2.7/tests/__init__.py +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/tests/mixins.py +82 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/typos.toml +1 -7
- {cachebox-6.2.6 → cachebox-6.2.7}/.github/dependabot.yaml +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/.github/workflows/docs.yml +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/.github/workflows/python-test.yml +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/.gitignore +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/LICENSE +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/LICENSE-THIRD-PARTY +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/README.md +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/build.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/cachebox/__init__.py +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/cachebox/_cachebox.py +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/cachebox/_core.pyi +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/cachebox/_wrappers.py +0 -0
- /cachebox-6.2.6/tests/__init__.py → /cachebox-6.2.7/cachebox/py.typed +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/cachebox/utils.py +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/docs/docs/algorithms.md +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/docs/docs/api/impls.md +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/docs/docs/api/index.md +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/docs/docs/api/utils.md +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/docs/docs/faq.md +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/docs/docs/getting-started.md +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/docs/docs/index.md +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/docs/docs/installation.md +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/docs/docs/migration.md +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/docs/docs/tips.md +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/docs/mkdocs.yml +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/pyproject.toml +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/rust-toolchain.toml +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/rustfmt.toml +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/alloc.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/control/bitmask.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/control/group/generic.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/control/group/lsx.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/control/group/mod.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/control/group/neon.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/control/group/sse2.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/control/mod.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/control/tag.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/mod.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/raw.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/scopeguard.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/hashbrown/util.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/internal/alias.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/internal/lazyheap.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/internal/linked_list.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/internal/mod.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/internal/onceinit.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/internal/pickle.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/internal/utils.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/lib.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/macro_rules.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/policies/common.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/policies/mod.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/pyclasses/base.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/pyclasses/mod.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/src/typeref.rs +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/tests/conftest.py +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/tests/test_impls.py +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/tests/test_utils.py +0 -0
- {cachebox-6.2.6 → cachebox-6.2.7}/uv.lock +0 -0
|
@@ -58,21 +58,24 @@ jobs:
|
|
|
58
58
|
strategy:
|
|
59
59
|
matrix:
|
|
60
60
|
platform:
|
|
61
|
-
- { target: x86_64, interpreter: *interpreters }
|
|
62
|
-
- { target: x86, interpreter: *interpreters }
|
|
63
|
-
- { target: aarch64, interpreter: *interpreters }
|
|
64
|
-
- { target: armv7, interpreter: *interpreters }
|
|
65
|
-
- { target: s390x, interpreter: *interpreters }
|
|
66
|
-
- { target: ppc64le, interpreter: *interpreters }
|
|
61
|
+
- { target: x86_64-unknown-linux-gnu, arch: x86_64, interpreter: *interpreters }
|
|
62
|
+
- { target: i686-unknown-linux-gnu, arch: x86, interpreter: *interpreters }
|
|
63
|
+
- { target: aarch64-unknown-linux-gnu, arch: aarch64, interpreter: *interpreters }
|
|
64
|
+
- { target: armv7-unknown-linux-gnueabihf, arch: armv7, interpreter: *interpreters }
|
|
65
|
+
- { target: s390x-unknown-linux-gnu, arch: s390x, interpreter: *interpreters }
|
|
66
|
+
- { target: powerpc64le-unknown-linux-gnu, arch: ppc64le, interpreter: *interpreters }
|
|
67
|
+
- { target: riscv64gc-unknown-linux-gnu, arch: riscv64, interpreter: *interpreters }
|
|
67
68
|
|
|
68
69
|
steps:
|
|
69
70
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
70
71
|
with:
|
|
71
72
|
persist-credentials: false
|
|
72
73
|
|
|
73
|
-
- uses:
|
|
74
|
+
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
74
75
|
with:
|
|
75
|
-
|
|
76
|
+
activate-environment: true
|
|
77
|
+
enable-cache: false
|
|
78
|
+
python-version: "3"
|
|
76
79
|
|
|
77
80
|
- uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
|
|
78
81
|
# zizmor: ignore[cache-poisoning]
|
|
@@ -88,7 +91,7 @@ jobs:
|
|
|
88
91
|
|
|
89
92
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
90
93
|
with:
|
|
91
|
-
name: wheels-linux-${{ matrix.platform.
|
|
94
|
+
name: wheels-linux-${{ matrix.platform.arch }}
|
|
92
95
|
path: dist
|
|
93
96
|
|
|
94
97
|
build-musllinux:
|
|
@@ -96,19 +99,22 @@ jobs:
|
|
|
96
99
|
strategy:
|
|
97
100
|
matrix:
|
|
98
101
|
platform:
|
|
99
|
-
- { target: x86_64, interpreter: *interpreters }
|
|
100
|
-
- { target: x86, interpreter: *interpreters }
|
|
101
|
-
- { target: aarch64, interpreter: *interpreters }
|
|
102
|
-
- { target: armv7, interpreter: *interpreters }
|
|
102
|
+
- { target: x86_64-unknown-linux-musl, arch: x86_64, interpreter: *interpreters }
|
|
103
|
+
- { target: i686-unknown-linux-musl, arch: x86, interpreter: *interpreters }
|
|
104
|
+
- { target: aarch64-unknown-linux-musl, arch: aarch64, interpreter: *interpreters }
|
|
105
|
+
- { target: armv7-unknown-linux-musleabihf, arch: armv7, interpreter: *interpreters }
|
|
106
|
+
- { target: riscv64gc-unknown-linux-musl, arch: riscv64, interpreter: *interpreters }
|
|
103
107
|
|
|
104
108
|
steps:
|
|
105
109
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
106
110
|
with:
|
|
107
111
|
persist-credentials: false
|
|
108
112
|
|
|
109
|
-
- uses:
|
|
113
|
+
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
110
114
|
with:
|
|
111
|
-
|
|
115
|
+
activate-environment: true
|
|
116
|
+
enable-cache: false
|
|
117
|
+
python-version: "3"
|
|
112
118
|
|
|
113
119
|
- uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
|
|
114
120
|
# zizmor: ignore[cache-poisoning]
|
|
@@ -124,7 +130,7 @@ jobs:
|
|
|
124
130
|
|
|
125
131
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
126
132
|
with:
|
|
127
|
-
name: wheels-musllinux-${{ matrix.platform.
|
|
133
|
+
name: wheels-musllinux-${{ matrix.platform.arch }}
|
|
128
134
|
path: dist
|
|
129
135
|
|
|
130
136
|
build-windows:
|
|
@@ -419,13 +419,13 @@ impl PolicyExt for FIFOPolicy {
|
|
|
419
419
|
maxsize: usize,
|
|
420
420
|
getsizeof: Option<alias::PyObject>,
|
|
421
421
|
_global_ttl: Option<std::time::Duration>,
|
|
422
|
-
|
|
422
|
+
built: pyo3::Bound<'_, pyo3::types::PyTuple>,
|
|
423
423
|
) -> pyo3::PyResult<(Self::Shared, Self)> {
|
|
424
424
|
use pyo3::types::PyAnyMethods;
|
|
425
425
|
use pyo3::types::PyListMethods;
|
|
426
426
|
use pyo3::types::PyTupleMethods;
|
|
427
427
|
|
|
428
|
-
let list =
|
|
428
|
+
let list = built.get_item(0)?.cast_into::<pyo3::types::PyList>()?;
|
|
429
429
|
let list_length = list.len();
|
|
430
430
|
|
|
431
431
|
if list_length > maxsize {
|
|
@@ -501,13 +501,13 @@ impl PolicyExt for LFUPolicy {
|
|
|
501
501
|
maxsize: usize,
|
|
502
502
|
getsizeof: Option<alias::PyObject>,
|
|
503
503
|
_global_ttl: Option<std::time::Duration>,
|
|
504
|
-
|
|
504
|
+
built: pyo3::Bound<'_, pyo3::types::PyTuple>,
|
|
505
505
|
) -> pyo3::PyResult<(Self::Shared, Self)> {
|
|
506
506
|
use pyo3::types::PyAnyMethods;
|
|
507
507
|
use pyo3::types::PyListMethods;
|
|
508
508
|
use pyo3::types::PyTupleMethods;
|
|
509
509
|
|
|
510
|
-
let list =
|
|
510
|
+
let list = built.get_item(0)?.cast_into::<pyo3::types::PyList>()?;
|
|
511
511
|
let list_length = list.len();
|
|
512
512
|
|
|
513
513
|
if list_length > maxsize {
|
|
@@ -347,13 +347,13 @@ impl PolicyExt for LRUPolicy {
|
|
|
347
347
|
maxsize: usize,
|
|
348
348
|
getsizeof: Option<alias::PyObject>,
|
|
349
349
|
_global_ttl: Option<std::time::Duration>,
|
|
350
|
-
|
|
350
|
+
built: pyo3::Bound<'_, pyo3::types::PyTuple>,
|
|
351
351
|
) -> pyo3::PyResult<(Self::Shared, Self)> {
|
|
352
352
|
use pyo3::types::PyAnyMethods;
|
|
353
353
|
use pyo3::types::PyListMethods;
|
|
354
354
|
use pyo3::types::PyTupleMethods;
|
|
355
355
|
|
|
356
|
-
let list =
|
|
356
|
+
let list = built.get_item(0)?.cast_into::<pyo3::types::PyList>()?;
|
|
357
357
|
let list_length = list.len();
|
|
358
358
|
|
|
359
359
|
if list_length > maxsize {
|
|
@@ -266,12 +266,12 @@ impl PolicyExt for NoPolicy {
|
|
|
266
266
|
maxsize: usize,
|
|
267
267
|
getsizeof: Option<alias::PyObject>,
|
|
268
268
|
_global_ttl: Option<std::time::Duration>,
|
|
269
|
-
|
|
269
|
+
built: pyo3::Bound<'_, pyo3::types::PyTuple>,
|
|
270
270
|
) -> pyo3::PyResult<(Self::Shared, Self)> {
|
|
271
271
|
use pyo3::types::PyDictMethods;
|
|
272
272
|
use pyo3::types::PyTupleMethods;
|
|
273
273
|
|
|
274
|
-
let dict =
|
|
274
|
+
let dict = built.get_item(0)?.cast_into::<pyo3::types::PyDict>()?;
|
|
275
275
|
let dict_length = dict.len();
|
|
276
276
|
|
|
277
277
|
if dict_length > maxsize {
|
|
@@ -277,12 +277,12 @@ impl PolicyExt for RRPolicy {
|
|
|
277
277
|
maxsize: usize,
|
|
278
278
|
getsizeof: Option<alias::PyObject>,
|
|
279
279
|
_global_ttl: Option<std::time::Duration>,
|
|
280
|
-
|
|
280
|
+
built: pyo3::Bound<'_, pyo3::types::PyTuple>,
|
|
281
281
|
) -> pyo3::PyResult<(Self::Shared, Self)> {
|
|
282
282
|
use pyo3::types::PyDictMethods;
|
|
283
283
|
use pyo3::types::PyTupleMethods;
|
|
284
284
|
|
|
285
|
-
let dict =
|
|
285
|
+
let dict = built.get_item(0)?.cast_into::<pyo3::types::PyDict>()?;
|
|
286
286
|
let dict_length = dict.len();
|
|
287
287
|
|
|
288
288
|
if dict_length > maxsize {
|
|
@@ -152,6 +152,6 @@ pub trait PolicyExt: Sized {
|
|
|
152
152
|
maxsize: usize,
|
|
153
153
|
getsizeof: Option<alias::PyObject>,
|
|
154
154
|
global_ttl: Option<std::time::Duration>,
|
|
155
|
-
|
|
155
|
+
built: pyo3::Bound<'_, pyo3::types::PyTuple>,
|
|
156
156
|
) -> pyo3::PyResult<(Self::Shared, Self)>;
|
|
157
157
|
}
|
|
@@ -556,7 +556,7 @@ impl PolicyExt for TTLPolicy {
|
|
|
556
556
|
maxsize: usize,
|
|
557
557
|
getsizeof: Option<alias::PyObject>,
|
|
558
558
|
global_ttl: Option<std::time::Duration>,
|
|
559
|
-
|
|
559
|
+
built: pyo3::Bound<'_, pyo3::types::PyTuple>,
|
|
560
560
|
) -> pyo3::PyResult<(Self::Shared, Self)> {
|
|
561
561
|
use pyo3::types::PyAnyMethods;
|
|
562
562
|
use pyo3::types::PyListMethods;
|
|
@@ -566,7 +566,7 @@ impl PolicyExt for TTLPolicy {
|
|
|
566
566
|
return Err(new_py_error!(PyValueError, "global_ttl is zero"));
|
|
567
567
|
}
|
|
568
568
|
|
|
569
|
-
let list =
|
|
569
|
+
let list = built.get_item(0)?.cast_into::<pyo3::types::PyList>()?;
|
|
570
570
|
let list_length = list.len();
|
|
571
571
|
|
|
572
572
|
if list_length > maxsize {
|
|
@@ -505,13 +505,13 @@ impl PolicyExt for VTTLPolicy {
|
|
|
505
505
|
maxsize: usize,
|
|
506
506
|
getsizeof: Option<alias::PyObject>,
|
|
507
507
|
_global_ttl: Option<std::time::Duration>,
|
|
508
|
-
|
|
508
|
+
built: pyo3::Bound<'_, pyo3::types::PyTuple>,
|
|
509
509
|
) -> pyo3::PyResult<(Self::Shared, Self)> {
|
|
510
510
|
use pyo3::types::PyAnyMethods;
|
|
511
511
|
use pyo3::types::PyListMethods;
|
|
512
512
|
use pyo3::types::PyTupleMethods;
|
|
513
513
|
|
|
514
|
-
let list =
|
|
514
|
+
let list = built.get_item(0)?.cast_into::<pyo3::types::PyList>()?;
|
|
515
515
|
let list_length = list.len();
|
|
516
516
|
|
|
517
517
|
if list_length > maxsize {
|
|
@@ -53,6 +53,16 @@ impl<P: PolicyExt> Wrapped<P> {
|
|
|
53
53
|
pub fn policy(&self) -> parking_lot::MutexGuard<'_, P> {
|
|
54
54
|
self.inner.lock()
|
|
55
55
|
}
|
|
56
|
+
|
|
57
|
+
/// Acquires the mutex only if it is free, returning `None` otherwise.
|
|
58
|
+
///
|
|
59
|
+
/// For callers that must never wait for the lock, such as `__traverse__`:
|
|
60
|
+
/// the thread holding the lock may be running Python code, and a garbage
|
|
61
|
+
/// collection pass landing there would deadlock the whole process.
|
|
62
|
+
#[inline(always)]
|
|
63
|
+
pub fn try_policy(&self) -> Option<parking_lot::MutexGuard<'_, P>> {
|
|
64
|
+
self.inner.try_lock()
|
|
65
|
+
}
|
|
56
66
|
}
|
|
57
67
|
|
|
58
68
|
#[inline(always)]
|
|
@@ -298,13 +308,13 @@ impl<P: PolicyExt> Wrapped<P> {
|
|
|
298
308
|
return Err(new_py_error!(PyValueError, "global_ttl is negative"));
|
|
299
309
|
}
|
|
300
310
|
|
|
301
|
-
let
|
|
311
|
+
let built = tuple.get_item(3)?.cast_into::<pyo3::types::PyTuple>()?;
|
|
302
312
|
|
|
303
313
|
let (shared, inner) = P::from_pickle(
|
|
304
314
|
maxsize,
|
|
305
315
|
getsizeof,
|
|
306
316
|
global_ttl.map(std::time::Duration::from_secs_f64),
|
|
307
|
-
|
|
317
|
+
built,
|
|
308
318
|
)?;
|
|
309
319
|
|
|
310
320
|
Ok(Self {
|
|
@@ -651,7 +651,9 @@ impl PyCache {
|
|
|
651
651
|
}
|
|
652
652
|
|
|
653
653
|
let inner = self.0.get();
|
|
654
|
-
let policy = inner.
|
|
654
|
+
let Some(policy) = inner.try_policy() else {
|
|
655
|
+
return Ok(());
|
|
656
|
+
};
|
|
655
657
|
|
|
656
658
|
for handle_ref in unsafe { policy.table().iter() } {
|
|
657
659
|
let handle = unsafe { handle_ref.as_ref() };
|
|
@@ -679,7 +679,9 @@ impl PyFIFOCache {
|
|
|
679
679
|
}
|
|
680
680
|
|
|
681
681
|
let inner = self.0.get();
|
|
682
|
-
let policy = inner.
|
|
682
|
+
let Some(policy) = inner.try_policy() else {
|
|
683
|
+
return Ok(());
|
|
684
|
+
};
|
|
683
685
|
|
|
684
686
|
for handle in policy.entries().iter() {
|
|
685
687
|
visit.call(handle.key().as_ref())?;
|
|
@@ -744,7 +744,9 @@ impl PyLFUCache {
|
|
|
744
744
|
}
|
|
745
745
|
|
|
746
746
|
let inner = self.0.get();
|
|
747
|
-
let policy = inner.
|
|
747
|
+
let Some(policy) = inner.try_policy() else {
|
|
748
|
+
return Ok(());
|
|
749
|
+
};
|
|
748
750
|
|
|
749
751
|
for cursor in unsafe { policy.table().iter() } {
|
|
750
752
|
let handle = unsafe { cursor.as_ref().element() };
|
|
@@ -725,7 +725,9 @@ impl PyLRUCache {
|
|
|
725
725
|
}
|
|
726
726
|
|
|
727
727
|
let inner = self.0.get();
|
|
728
|
-
let policy = inner.
|
|
728
|
+
let Some(policy) = inner.try_policy() else {
|
|
729
|
+
return Ok(());
|
|
730
|
+
};
|
|
729
731
|
|
|
730
732
|
for cursor in unsafe { policy.list().iter() } {
|
|
731
733
|
let handle = unsafe { cursor.element() };
|
|
@@ -671,7 +671,9 @@ impl PyRRCache {
|
|
|
671
671
|
}
|
|
672
672
|
|
|
673
673
|
let inner = self.0.get();
|
|
674
|
-
let policy = inner.
|
|
674
|
+
let Some(policy) = inner.try_policy() else {
|
|
675
|
+
return Ok(());
|
|
676
|
+
};
|
|
675
677
|
|
|
676
678
|
for handle_ref in unsafe { policy.table().iter() } {
|
|
677
679
|
let handle = unsafe { handle_ref.as_ref() };
|
|
@@ -816,7 +816,9 @@ impl PyTTLCache {
|
|
|
816
816
|
}
|
|
817
817
|
|
|
818
818
|
let inner = self.0.get();
|
|
819
|
-
let policy = inner.
|
|
819
|
+
let Some(policy) = inner.try_policy() else {
|
|
820
|
+
return Ok(());
|
|
821
|
+
};
|
|
820
822
|
|
|
821
823
|
for handle in policy.entries().iter() {
|
|
822
824
|
visit.call(handle.key().as_ref())?;
|
|
@@ -776,7 +776,9 @@ impl PyVTTLCache {
|
|
|
776
776
|
}
|
|
777
777
|
|
|
778
778
|
let inner = self.0.get();
|
|
779
|
-
let policy = inner.
|
|
779
|
+
let Some(policy) = inner.try_policy() else {
|
|
780
|
+
return Ok(());
|
|
781
|
+
};
|
|
780
782
|
|
|
781
783
|
for cursor in unsafe { policy.table().iter() } {
|
|
782
784
|
let handle = unsafe { cursor.as_ref().element() };
|
|
File without changes
|
|
@@ -101,6 +101,23 @@ class InitializeMixin(BaseMixin):
|
|
|
101
101
|
|
|
102
102
|
|
|
103
103
|
class InsertAndGetMixin(BaseMixin):
|
|
104
|
+
def test_key_eq_may_trigger_the_gc(self):
|
|
105
|
+
# __eq__ runs in the middle of a probe, with the lock held; a deadlock
|
|
106
|
+
# here would keep the GIL, so the call runs in a child process
|
|
107
|
+
name = type(self.create_cache()).__name__
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
done = subprocess.run(
|
|
111
|
+
[sys.executable, "-c", EQ_TRIGGERING_GC, name],
|
|
112
|
+
capture_output=True,
|
|
113
|
+
text=True,
|
|
114
|
+
timeout=60,
|
|
115
|
+
)
|
|
116
|
+
except subprocess.TimeoutExpired:
|
|
117
|
+
pytest.fail(f"{name}.get() with a colliding key never returned")
|
|
118
|
+
|
|
119
|
+
assert done.stdout.strip() == "ok", done.stderr
|
|
120
|
+
|
|
104
121
|
def test_insert_returns_none_on_new_key(self):
|
|
105
122
|
cache = self.create_cache()
|
|
106
123
|
|
|
@@ -205,6 +222,55 @@ class SetDefaultMixin(BaseMixin):
|
|
|
205
222
|
assert cache.get("k") == "existing"
|
|
206
223
|
|
|
207
224
|
|
|
225
|
+
DROPPED_VALUE_TRIGGERING_GC = """
|
|
226
|
+
import gc
|
|
227
|
+
import sys
|
|
228
|
+
|
|
229
|
+
import cachebox
|
|
230
|
+
|
|
231
|
+
name = sys.argv[1]
|
|
232
|
+
cls = getattr(cachebox, name)
|
|
233
|
+
cache = cls(10, global_ttl=60) if name == "TTLCache" else cls(10)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class Boom:
|
|
237
|
+
def __del__(self):
|
|
238
|
+
gc.collect()
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
cache.insert("k", Boom())
|
|
242
|
+
cache.clear()
|
|
243
|
+
print("ok")
|
|
244
|
+
"""
|
|
245
|
+
|
|
246
|
+
EQ_TRIGGERING_GC = """
|
|
247
|
+
import gc
|
|
248
|
+
import sys
|
|
249
|
+
|
|
250
|
+
import cachebox
|
|
251
|
+
|
|
252
|
+
name = sys.argv[1]
|
|
253
|
+
cls = getattr(cachebox, name)
|
|
254
|
+
cache = cls(10, global_ttl=60) if name == "TTLCache" else cls(10)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class Key:
|
|
258
|
+
def __init__(self, name):
|
|
259
|
+
self.name = name
|
|
260
|
+
|
|
261
|
+
def __hash__(self):
|
|
262
|
+
return 42 # same hash for every key, so lookups have to call __eq__
|
|
263
|
+
|
|
264
|
+
def __eq__(self, other):
|
|
265
|
+
gc.collect()
|
|
266
|
+
return self.name == other.name
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
cache.insert(Key("a"), 1)
|
|
270
|
+
assert cache.get(Key("b")) is None
|
|
271
|
+
print("ok")
|
|
272
|
+
"""
|
|
273
|
+
|
|
208
274
|
FACTORY_TOUCHING_CACHE = """
|
|
209
275
|
import gc
|
|
210
276
|
import sys
|
|
@@ -635,6 +701,22 @@ class IterationMixin(BaseMixin):
|
|
|
635
701
|
|
|
636
702
|
|
|
637
703
|
class DrainClearShrinkMixin(BaseMixin):
|
|
704
|
+
def test_dropping_a_value_may_trigger_the_gc(self):
|
|
705
|
+
# a deadlock here would keep the GIL, so the call runs in a child process
|
|
706
|
+
name = type(self.create_cache()).__name__
|
|
707
|
+
|
|
708
|
+
try:
|
|
709
|
+
done = subprocess.run(
|
|
710
|
+
[sys.executable, "-c", DROPPED_VALUE_TRIGGERING_GC, name],
|
|
711
|
+
capture_output=True,
|
|
712
|
+
text=True,
|
|
713
|
+
timeout=60,
|
|
714
|
+
)
|
|
715
|
+
except subprocess.TimeoutExpired:
|
|
716
|
+
pytest.fail(f"{name}.clear() never returned")
|
|
717
|
+
|
|
718
|
+
assert done.stdout.strip() == "ok", done.stderr
|
|
719
|
+
|
|
638
720
|
def test_clear_removes_all_items(self):
|
|
639
721
|
cache = self.create_cache()
|
|
640
722
|
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
[default.extend-words]
|
|
2
|
-
# error: `builded` should be `built`
|
|
3
|
-
# --> .\src\policies\ttlpolicy.rs:569:20
|
|
4
|
-
# |
|
|
5
|
-
# 569 | let list = builded.get_item(0)?.cast_into::<pyo3::types::PyList>()?;
|
|
6
|
-
# | ^^^^^^^
|
|
7
|
-
builded = "builded"
|
|
8
2
|
# error: `fo` should be `of`, `for`, `do`, `go`, `to`
|
|
9
3
|
# --> .\src\policies\fifopolicy.rs:212:66
|
|
10
4
|
# |
|
|
11
5
|
# 212 | // - All others: (vd_idx + fo) - fo = vd_idx
|
|
12
6
|
# | ^^
|
|
13
|
-
fo = "fo"
|
|
7
|
+
fo = "fo"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|