OpenKeel: the sovereign French Cloud solution of the inherent group, with a European reach Discover inherent

Reverse-spec · Libraries

oslo.cache — Scenarios

End-to-end scenarios — oslo.cache — branch stable/2026.2

Branch stable/2026.2 @ fc96999a99e4 — repository https://opendev.org/openstack/oslo.cache — analysed on 2026-10-28

The commands shown were recorded (_rewrite/wire_stable-2026.2.json); the scenario numbers refer to 07.

1. Memoized call: miss, then hit (scenario 1)

sequenceDiagram
    participant S as Service (e.g. Keystone)
    participant D as memoization decorator (oslo.cache + dogpile)
    participant M as memcached
    S->>D: get_project("p1")
    D->>D: key = "mod:get_project|p1 default" → sha1 → 40 hex
    D->>M: get <sha1>
    M-->>D: END (miss)
    D->>D: local lock (dogpile mutex, per process)
    D->>M: get <sha1> (second read under the lock)
    M-->>D: END
    D->>S: calls the real function
    alt [cache] enabled and [group] caching
        D->>M: set <sha1> 1 <backend_expiration_time or 0> <n> + pickle(CachedValue(payload, {ct, v:2}))
        M-->>D: STORED
    else caching disabled for the group
        Note over D,M: no set
    end
    S->>D: get_project("p1") again
    D->>M: get <sha1>
    M-->>D: VALUE <sha1> 1 <n> …
    D->>D: now - ct ≤ cache_time or expiration_time? → hit
    D-->>S: payload

2. Expiration decided by the reader (scenarios 6 and 7)

sequenceDiagram
    participant A as Process A (expiration_time 600)
    participant B as Process B ([group] cache_time 1)
    participant M as memcached
    A->>M: set <k> 1 0 … (ct = T)
    Note over M: exptime 0: the item stays until eviction
    B->>M: get <k> at T + 2 s
    M-->>B: VALUE …
    B->>B: now - ct = 2 > 1 → expired
    B->>M: get <k> (under lock), then set <k> … (new ct)
    A->>M: get <k> at T + 5 s
    M-->>A: VALUE … (ct = T + 2)
    A->>A: 3 ≤ 600 → hit

The same item is fresh for A and expired for B: freshness belongs to each reader's configuration.

3. Invalidation (scenario 10, and Keystone)

sequenceDiagram
    participant W as Process W
    participant O as Process O
    participant M as memcached
    W->>M: set <k> … "v1"
    W->>W: region.invalidate() — timestamp in memory, nothing sent
    W->>M: get <k>
    M-->>W: VALUE … (ct older than the invalidation) → treated as a miss
    O->>M: get <k>
    M-->>O: VALUE … → "v1" still served
    Note over W,O: Keystone: invalidation writes a new region id under "<<<region>>>:<name>"<br/>every key carries that id before hashing → all processes miss

4. Unreachable or saturated memcached (scenarios 14 to 16)

sequenceDiagram
    participant S as Service
    participant P as memcache_pool
    participant M as memcached
    S->>P: memoized call
    alt memcached down (python-memcached)
        P-xM: connect refused
        P->>P: server dead for memcache_dead_retry (300 s), shared by the pool
        P-->>S: miss → function computed, no error
    else memcached down (pymemcache, Redis)
        P-->>S: ConnectionRefusedError / redis ConnectionError → the request fails
    else pool saturated (memcache_pool_maxsize clients busy)
        P->>P: waits memcache_pool_connection_get_timeout (10 s)
        P-->>S: QueueEmpty → the request fails
    end

Source: reverse-spec-oslo.cache/04-scenarios_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.