Skip to content

cocache-api ​

cocache-api defines every contract in CoCache: the API your application calls and the SPI that storage and channel implementations provide. It has no runtime dependencies beyond the Kotlin standard library. A new L1 store or event channel therefore needs only this module, plus cocache-test to verify it against the TCK.

Package Map ​

mermaid
graph TB
    subgraph api ["me.ahoo.cache.api"]
        Cache["Cache / CacheGetter / CacheSetter"]
        CV["CacheValue (sealed)<br>PresentValue | MissingValue"]
        TtlAt["TtlAt"]
        Store["CacheStore"]
        Named["NamedCache"]
    end
    subgraph spi ["SPI packages"]
        Client["client.ClientSideCache"]
        Dist["distributed.DistributedCache"]
        Src["source.CacheSource"]
        Conv["converter.KeyConverter"]
        Filt["filter.KeyFilter"]
        Cons["consistency.CacheEvictedEventBus<br>CacheEvictedSubscriber / CacheEvictedEvent"]
        Join["join.JoinCache / JoinValue / JoinKeyExtractor"]
    end
    Ann["annotation.@CoCache / @CaffeineCache / @JoinCacheable"]

    Client --> Store
    Dist --> Store
    Store --> CV
    CV --> TtlAt

    style Cache fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style CV fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style TtlAt fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Store fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Named fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Client fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Dist fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Src fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Conv fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Filt fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Cons fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Join fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Ann fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style api fill:#161b22,stroke:#8b949e,color:#e6edf3
    style spi fill:#161b22,stroke:#8b949e,color:#e6edf3

Contracts ​

TypeKindContractSource
Cache<K, V>APIgetCache, get, getTtlAt, setCache, set, evictCache.kt
CacheValue<V>ValueSealed: PresentValue(value, ttlAt) / MissingValue(ttlAt); of(null, …) is missingCacheValue.kt
TtlAtValueAbsolute epoch-second expiry, FOREVER, at(ttl, amplitude)TtlAt.kt
CacheStore<V>SPIPure string-key storage of CacheValue; no policyCacheStore.kt
ClientSideCache<V>SPIL2 store + size, clear()ClientSideCache.kt
DistributedCache<V>SPIL1 store + close(); null from getCache means missDistributedCache.kt
CacheSource<K, V>SPIloadCacheValue(key); null → negative cacheCacheSource.kt
KeyConverter<K>SPIBusiness key → storage keyKeyConverter.kt
KeyFilterSPInotExist(key) short-circuits to a negative resultKeyFilter.kt
CacheEvictedEventBusSPIpublish / register / unregister; must call onReset on (re)subscriptionCacheEvictedEventBus.kt
CacheEvictedSubscriberSPIonEvicted(event), onReset()CacheEvictedSubscriber.kt
JoinCache / JoinValue / JoinKeyExtractorAPIComposition of two cachesjoin/

Negative Cache ​

mermaid
stateDiagram-v2
    [*] --> Absent
    Absent --> Present: source returns value
    Absent --> Missing: source returns null
    Missing --> Absent: missingTtl elapses / evict
    Present --> Absent: ttl elapses / evict
    Missing --> Present: set(key, value)

The negative cache is an explicit type, so it cannot collide with business data: CacheValue.forever("_nil_").isMissing is false. The Redis sentinel (_nil_ by default) is purely a wire encoding inside the Redis codecs.

Annotations ​

AnnotationPurposeSource
@CoCachename, keyPrefix, keyExpression, ttl (3600), ttlAmplitude (60), missingTtl (60)CoCache.kt
@CaffeineCacheL2 maximumSize (10000), initialCapacity, expireAfterAccessCaffeineCache.kt
@JoinCacheablefirstCacheName, joinCacheName, joinKeyExpressionJoinCacheable.kt

Implementing an SPI ​

mermaid
sequenceDiagram
autonumber
    participant Dev as Implementer
    participant API as cocache-api
    participant TCK as cocache-test
    Dev->>API: implement DistributedCache<V>
    Dev->>TCK: extend DistributedCacheSpec<V>
    TCK-->>Dev: store contract verified
    Dev->>TCK: extend DefaultCoherentCacheSpec / MultipleInstanceSyncSpec
    TCK-->>Dev: coherence verified end-to-end

Released under the Apache License 2.0.