aio-libs / aio-libs/aiocache

`clear(namespace=...)` over-deletes on `SimpleMemoryCache`: prefix match has no boundary, silently clearing sibling namespaces (inconsistent with the Valkey backend)

未关闭
#1,081 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
主要语言
Python
星标
1.4k
派生
181
PR 合并指标
30 天内没有已合并 PR

描述

**Summary**

On `SimpleMemoryCache`, `clear(namespace="foo")` also deletes keys stored under any namespace that *starts with* `"foo"` (e.g. `"foobar"`), silently discarding unrelated cached data. The Valkey backend does not have this problem, so the same `clear(namespace=...)` call behaves differently depending on the backend.

**Reproduction** (in-memory, no external server needed; HEAD `ae5948b`):

```python
import asyncio
from aiocache import SimpleMemoryCache

async def main():
c = SimpleMemoryCache()
await c.set("k", 1, namespace="foo") # stored under key "fook"
await c.set("k", 2, namespace="foobar") # stored under key "foobark"

await c.clear(namespace="foo") # intended: clear only namespace "foo"

print(await c.get("k", namespace="foo")) # None (expected)
print(await c.get("k", namespace="foobar")) # None <-- BUG: expected 2, data silently lost

asyncio.run(main())
```

**Root cause**

`SimpleMemoryBackend._clear` matches by bare prefix, and memory keys are built with no delimiter (`f"{ns}{k}"`):

```python
# aiocache/backends/memory.py
async def _clear(self, namespace=None, _conn=None):
if namespace:
for key in list(self._cache):
if key.startswith(namespace): # no boundary: "foo" also matches "foobar..."
self.__delete(key)
```

The Valkey backend avoids this by isolating namespaces with a `:` delimiter in both key construction and clear (`f"{ns}:{k}"` and a `"{ns}:*"` scan), so `clear(namespace="foo")` is boundary-safe on Valkey but over-deletes on the memory backend (and memcached, which shares the bare-prefix default key builder).

**Why it matters**

Two concerns: (1) **silent data loss** — clearing one namespace can wipe another whose name shares a prefix, with no error; and (2) **backend inconsistency** — the backends are documented as interchangeable, but `clear(namespace=...)` is not consistent across them.

**On intent** — I recognize this may be the intended "prefix" behavior for the memory/memcached backends: `test_clear_namespace` currently asserts `clear("nm")` deletes `"nma"` and `"nmb"`, which codifies bare-prefix matching. That is exactly why I am raising this as an issue rather than opening a PR — the resolution is a design choice for you. (Distinct from #479, which was `clear()` ignoring the instance namespace entirely and was fixed in #562; and from #910, a feature request.)

**Possible resolutions (your call)**

1. **Align the memory (and memcached) backends with Valkey** — use a `:` delimiter in the default key builder and a boundary-aware clear, so `clear(namespace=...)` is consistent across all backends. This changes the memory key format (low risk: memory is ephemeral) and would update `test_clear_namespace`. Happy to send this PR.
2. **Keep the prefix model but document it** — explicitly warn that on prefix-scanning backends, namespaces must not share a prefix, to prevent silent data loss. Also happy to PR the docs.

---
[![verified by Coretexa](https://img.shields.io/badge/verified_by-Coretexa-3b82f6)](https://coretexa.dev)

*Originated and independently verified by Coretexa — an AI-assisted pipeline that reproduces each finding on HEAD and has it adversarially checked by a separate verifier than found it before submission. Here: reproduced on HEAD `ae5948b`, the delimiter fix confirmed to resolve it, and the existing test reviewed.*

**Environment:** aiocache @ HEAD `ae5948b`, Python 3.11.

贡献指南

打开贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。