Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6245518
feat: encapsulate cache replacement strategies into enum
DanielDango Jan 20, 2026
95ecd2d
feat: add cache initialization logic to EvaluationConfiguration and u…
DanielDango Apr 18, 2026
c34b4e5
feat: make LocalCache implement Cache and revamp CacheReplacementStra…
DanielDango Apr 18, 2026
cc8c041
feat: retrieve cache replacement strategy from ModuleConfiguration
DanielDango Apr 18, 2026
5186194
feat: implement HierarchicalCache for multi-layer caching and update …
DanielDango Apr 19, 2026
b239c14
docs: update caching documentation to include HierarchicalCache
DanielDango Apr 20, 2026
9c804e1
Merge remote-tracking branch 'refs/remotes/upstream/main' into featur…
DanielDango Apr 29, 2026
b4aebe6
feat: support environment-based cache configuration
DanielDango Apr 29, 2026
a515e5f
Merge remote-tracking branch 'upstream/main' into fork/DanielDango/fe…
DanielDango May 4, 2026
2135004
revert: remove module config for caches, instead get cache configurat…
DanielDango May 4, 2026
11aa1bb
test: enhance CacheTest with new entry writing, retrieval, serializat…
DanielDango May 4, 2026
68b5c9e
fix: resolve sonar cube issues
DanielDango May 4, 2026
4cadcf7
refactor: streamline cache manager configuration
DanielDango May 4, 2026
53ebb05
refactor: update cache conflict resolution to replacement strategy te…
DanielDango May 4, 2026
8ca6260
revert: remove unused argumentAsEnum method from ModuleConfiguration
DanielDango May 4, 2026
c1ff184
refactor: enhance cache hierarchy parsing to support quoted strings a…
DanielDango May 4, 2026
0940083
refactor: make default cache configuration identical to previous beha…
DanielDango May 5, 2026
1f4b55e
refactor: improve cache inconsistency handling and resolution methods
DanielDango May 5, 2026
c1db4b5
refactor: mark resolveViaInternalKey method as deprecated with clarif…
DanielDango May 5, 2026
0e00965
feat: add test-specific environment configuration and enforce env ove…
DanielDango May 5, 2026
ae89375
refactor: update documentation for CacheManagers reset usage and remo…
DanielDango May 5, 2026
f5aea19
refactor: add deprecated javadoc annotation and standardize dotenv va…
DanielDango May 5, 2026
574d9fa
refactor: simplify cache creation logic and enforce non-null parameters
DanielDango May 26, 2026
b8cb713
test: added Mockito tests for hierarchical cache behaviour
DanielDango May 26, 2026
63380ff
refactor: introduce helper methods for cache value insertion using ap…
DanielDango May 26, 2026
148c2f7
refactor: replace string-based cache type with enum for improved type…
DanielDango Jun 1, 2026
1cfe0c7
refactor: update cache hierarchy configuration to use enum and enforc…
DanielDango Jun 1, 2026
62b0b0c
refactor: unify json serialization
DanielDango Jun 10, 2026
5d1b624
docs: remove resolved comment
DanielDango Jun 14, 2026
d95c0ba
docs: update redis behaviour when unavailable
DanielDango Jun 17, 2026
e0d17be
Potential fix for pull request finding
dfuchss Jun 20, 2026
c2b321d
Fix comments
dfuchss Jun 20, 2026
d9e9c82
docs: fix old references to fallback behaviour if redis is unavailable
DanielDango Jun 23, 2026
62281fd
Potential fix for pull request finding
dfuchss Jun 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 34 additions & 6 deletions docs/caching.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ LiSSA implements a sophisticated caching system to improve performance and ensur
- [`ClassifierCacheParameter`](../src/main/java/edu/kit/kastel/sdq/lissa/ratlr/cache/classifier/ClassifierCacheParameter.java): Configuration for classifier caches (model name, seed, temperature)
- [`EmbeddingCacheParameter`](../src/main/java/edu/kit/kastel/sdq/lissa/ratlr/cache/embedding/EmbeddingCacheParameter.java): Configuration for embedding caches (model name)
2. **Cache Implementations**
- [`Hierarchical Cache`](../src/main/java/edu/kit/kastel/sdq/lissa/ratlr/cache/HierarchicalCache.java): Two cache levels with a synchronization mechanism
- Changes are applied to both levels
- Reads use a Conflict Resolution Strategy to ensure consistent results
- If a cache entry is missing in one level during a read, it is also written to the other level
- [`LocalCache`](../src/main/java/edu/kit/kastel/sdq/lissa/ratlr/cache/LocalCache.java): File-based cache implementation that stores data in JSON format
- Implements dirty tracking to optimize writes
- Automatically saves changes on shutdown
- Supports atomic writes using temporary files
- [`RedisCache`](../src/main/java/edu/kit/kastel/sdq/lissa/ratlr/cache/RedisCache.java): Redis-based cache implementation with fallback to local cache
- [`RedisCache`](../src/main/java/edu/kit/kastel/sdq/lissa/ratlr/cache/RedisCache.java): Redis-based cache implementation
- Uses Redis for high-performance caching
- Falls back to local cache if Redis is unavailable
- Supports both string and object serialization
3. **Cache Management**
- [`CacheManager`](../src/main/java/edu/kit/kastel/sdq/lissa/ratlr/cache/CacheManager.java): Central manager for cache instances
Expand Down Expand Up @@ -59,6 +62,16 @@ Parameters are used to:
2. Create cache keys from content (via `createCacheKey()` method)
3. Validate cache consistency when retrieving existing caches

### Cache Replacement Strategies

When using hierarchical caches with multiple layers (e.g., Redis and local cache), the system detects and resolves conflicts between layers:

- **NONE** (default): Does not replace conflicting values; leaves both cache layers as they are. Primary value is returned on read.
- **ERROR**: Throws an exception if a cache conflict is detected, ensuring data consistency by failing fast.
- **OVERWRITE**: Automatically overwrites the secondary cache value with the primary cache value when a conflict is detected, and logs a warning.

The replacement strategy for cache conflicts is configured via the `CACHE_REPLACEMENT_STRATEGY` environment variable.

### Cache API

The `Cache` interface provides two API levels:
Expand All @@ -81,7 +94,20 @@ The `Cache` interface provides two API levels:
"cache_dir": "./cache/path" // Directory for cache storage
}
```
2. **Redis Setup**
2. **Environment Variables**

The caching system supports the following environment variables:
- **CACHE_HIERARCHY**: Comma-separated list of cache types in order (e.g., "LOCAL,REDIS")
- Default: "LOCAL"
- Supported values: "LOCAL", "REDIS"
- **CACHE_REPLACEMENT_STRATEGY**: Strategy for handling conflicts between cache layers
- Default: "NONE"
- Supported values: "NONE", "ERROR", "OVERWRITE"
- **REDIS_URL**: Redis connection URL for RedisCache
- Default: "redis://localhost:6379"
- Example: "redis://redis-server:6379"

3. **Redis Setup**
To use Redis for caching, you need to set up a Redis server. Here's a recommended Docker Compose configuration:

```yaml
Expand All @@ -101,10 +127,12 @@ The `Cache` interface provides two API levels:

To use Redis with LiSSA:
1. Start the Redis server using Docker Compose
2. The system will automatically use Redis if available
3. If Redis is unavailable, it will fall back to local file-based caching (useful for replication packages)
2. Set environment variables if needed:
- `CACHE_HIERARCHY=REDIS,LOCAL` to use Redis with local fallback
- `REDIS_URL=redis://your-redis-host:6379` if not using the default
3. If Redis is unavailable, but configured to be used the system will fail.

3. **Best Practices**
4. **Best Practices**

- Use the cache directory specified in the configuration
- Clear the cache directory if you encounter issues
Expand Down
39 changes: 26 additions & 13 deletions env-template
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
OPENWEBUI_URL=https://domain.tldr/api
OPENWEBUI_API_KEY=

OLLAMA_EMBEDDING_HOST=
#OLLAMA_EMBEDDING_PASSWORD=
#OLLAMA_EMBEDDING_USER=

OLLAMA_HOST=
#OLLAMA_PASSWORD=
#OLLAMA_USER=

OPENAI_ORGANIZATION_ID=
OPENAI_API_KEY=
OPENWEBUI_URL=https://domain.tldr/api
OPENWEBUI_API_KEY=

OLLAMA_EMBEDDING_HOST=
#OLLAMA_EMBEDDING_PASSWORD=
#OLLAMA_EMBEDDING_USER=

OLLAMA_HOST=
#OLLAMA_PASSWORD=
#OLLAMA_USER=

OPENAI_ORGANIZATION_ID=
OPENAI_API_KEY=

# Cache strategy for handling conflicts between different cache levels
# Valid values: NONE, ERROR, OVERWRITE
#CACHE_REPLACEMENT_STRATEGY=ERROR

# Cache hierarchy - ascending comma-separated list of cache types to use
# Examples:
# LOCAL - only local file-based cache
# LOCAL,REDIS - local cache as primary, Redis as secondary fallback
# REDIS,LOCAL - Redis as primary, local cache as secondary fallback
# Valid cache types: LOCAL, REDIS
#CACHE_HIERARCHY=REDIS,LOCAL

6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
Expand Down
72 changes: 63 additions & 9 deletions src/main/java/edu/kit/kastel/sdq/lissa/ratlr/cache/Cache.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

import org.jspecify.annotations.Nullable;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
* Interface for cache implementations in the LiSSA framework.
* This interface defines the contract for caching mechanisms that store and retrieve
Expand All @@ -14,8 +17,8 @@ public interface Cache<K extends CacheKey> {
/**
* Retrieves a value from the cache and deserializes it to the specified type.
*
* @param <T> The type to deserialize the cached value to
* @param key The cache key to look up
* @param <T> The type to deserialize the cached value to
* @param key The cache key to look up
* @param clazz The class of the type to deserialize to
* @return The deserialized value, or null if not found
*/
Expand All @@ -25,8 +28,8 @@ public interface Cache<K extends CacheKey> {
* Retrieves a value from the cache and deserializes it to the specified type.
* <b>DO NOT USE UNLESS YOU KNOW WHAT YOU ARE DOING.</b>
*
* @param <T> The type to deserialize the cached value to
* @param key The cache key to look up
* @param <T> The type to deserialize the cached value to
* @param key The cache key to look up
* @param clazz The class of the type to deserialize to
* @return The deserialized value, or null if not found
* @deprecated This method exposes internal cache key handling and should not be used in general code.
Expand All @@ -37,16 +40,16 @@ public interface Cache<K extends CacheKey> {
/**
* Stores a string value in the cache.
*
* @param key The cache key to store the value under
* @param key The cache key to store the value under
* @param value The string value to store
*/
void put(String key, String value);

/**
* Stores a string value in the cache.
*
* @param <T> The type of the value to store
* @param key The cache key to store the value under
* @param <T> The type of the value to store
* @param key The cache key to store the value under
* @param value The value to store
* @deprecated This method exposes internal cache key handling and should not be used in general code.
*/
Expand All @@ -57,8 +60,8 @@ public interface Cache<K extends CacheKey> {
* Stores an object value in the cache.
* The object will be serialized before storage.
*
* @param <T> The type of the value to store
* @param key The cache key to store the value under
* @param <T> The type of the value to store
* @param key The cache key to store the value under
* @param value The object value to store
*/
<T> void put(String key, T value);
Expand All @@ -85,4 +88,55 @@ public interface Cache<K extends CacheKey> {
* @return The cache parameters
*/
CacheParameter<K> getCacheParameter();

/**
* Converts a JSON string to an object of the specified type.
* If the target type is String, the JSON string is returned as is.
*
* @param <T> The type to convert to
* @param jsonData The JSON string to convert
* @param clazz The class of the target type
* @param mapper The ObjectMapper instance to use for deserialization
* @return The converted object, or null if jsonData is null
* @throws IllegalArgumentException If the JSON cannot be deserialized to the target type
*/
@SuppressWarnings("unchecked")
static <T> @Nullable T convert(@Nullable String jsonData, Class<T> clazz, ObjectMapper mapper) {
if (jsonData == null) {
return null;
}
try {
return mapper.readValue(jsonData, clazz);
} catch (JsonProcessingException e) {
// Backward compatibility for unserialized String values
if (clazz == String.class) {
return (T) jsonData;
}
throw new IllegalArgumentException("Could not deserialize object", e);
}
}

/**
* Factory method to create a cache instance by type name.
* Supported types:
* <ul>
* <li>"local" - LocalCache for file-based storage</li>
* <li>"redis" - RedisCache for Redis-based storage</li>
* </ul>
*
* @param <K> The type of cache key
* @param type The cache type name (case-insensitive)
* @param cacheDir The directory for local cache storage
* @param parameters The cache parameters
* @param mapper The ObjectMapper for JSON operations
* @return A cache instance of the specified type
* @throws IllegalArgumentException If the type is not recognized or the cache cannot be created
*/
static <K extends CacheKey> Cache<K> createByType(
CacheType type, CacheParameter<K> parameters, @Nullable String cacheDir, @Nullable ObjectMapper mapper) {
return switch (type) {
case LOCAL -> new LocalCache<>(cacheDir, parameters);
case REDIS -> new RedisCache<>(parameters, mapper);
};
}
}
Loading
Loading