Skip to content

theCoderFromHell/simple-cache

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 

Repository files navigation

# Java TTL Cache

A lightweight, high-performance Time-To-Live (TTL) cache implementation in Java with elegant design patterns and thread-safe operations.

## Features

- **Automatic TTL-based eviction** - Entries automatically expire after specified time
- **Thread-safe** - Built on `ConcurrentHashMap` for concurrent access
- **Statistics tracking** - Monitor cache performance with built-in metrics
- **Design pattern rich** - Builder, Factory, Decorator, and Null Object patterns
- **High performance** - Efficient cleanup with scheduled executor
- **Configurable** - Customizable cleanup intervals and initial capacity
- **Well-tested** - Comprehensive unit test coverage
- **Type-safe** - Generics support for any key-value types

## Architecture

The cache system follows a clean, layered architecture:
- **Cache Interface**: Defines the contract for all cache implementations
- **TTLCache**: Main implementation with TTL eviction
- **CacheEntry**: Wrapper for values with expiration tracking
- **Decorators**: Additional functionality like statistics
- **Factories**: Simplified cache creation
- **Null Object**: Safe no-operation implementation

## Installation

Add the source files to your Java project (requires Java 17+). Copy these files:
- Cache.java
- CacheEntry.java
- TTLCache.java
- CacheFactory.java
- CacheStatisticsDecorator.java
- NullCache.java

## Quick Start

```java
// Simple usage
Cache<String, String> cache = new TTLCache.Builder().build();
cache.put("user:123", "John Doe", 5000); // 5 seconds TTL

String user = cache.get("user:123"); // Returns "John Doe"
```

## Usage Examples

### Basic Cache Operations

```java
// Create cache with default settings
Cache<String, Integer> cache = new TTLCache.Builder().build();

// Store with TTL (3 seconds)
cache.put("counter", 42, 3000);

// Retrieve value
Integer value = cache.get("counter"); // Returns 42

// Check if key exists
boolean exists = cache.containsKey("counter"); // Returns true

// Remove manually
cache.remove("counter");

// Clear all entries
cache.clear();
```

### Advanced Configuration

```java
// Custom cleanup every 2 seconds with larger capacity
Cache<String, User> cache = new TTLCache.Builder()
    .cleanupInterval(2, TimeUnit.SECONDS)
    .initialCapacity(1000)
    .build();
```

### Using Factory Pattern

```java
// Factory-created cache
Cache<String, Double> cache = CacheFactory.createDefaultCache();

// Custom cleanup cache
Cache<String, Double> fastCleanupCache = 
    CacheFactory.createCacheWithCustomCleanup(1, TimeUnit.SECONDS);
```

### Statistics Tracking

```java
// Cache with statistics
CacheStatisticsDecorator<String, String> cache = 
    new CacheStatisticsDecorator<>(new TTLCache.Builder().build());

cache.put("key1", "value1", 1000);
cache.get("key1");
cache.get("nonexistent");

CacheStatisticsDecorator.CacheStatistics stats = cache.getStatistics();
System.out.println("Hit ratio: " + stats.getHitRatio()); // 0.5
System.out.println("Hits: " + stats.getHits()); // 1
System.out.println("Misses: " + stats.getMisses()); // 1
```

### Null Object Pattern

```java
// Useful for testing or disabling caching
Cache<String, String> noOpCache = new NullCache<>();
noOpCache.put("test", "value", 1000); // Does nothing
String result = noOpCache.get("test"); // Returns null
```

## Configuration Options

| Option | Default | Description |
|--------|---------|-------------|
| Cleanup Interval | 5 seconds | How often to clean expired entries |
| Initial Capacity | 16 | Initial size of the internal map |
| Concurrency Level | Default | ConcurrentHashMap concurrency level |

## Testing

Run the included unit tests using JUnit 5 or compile and run manually.

## Design Patterns

This implementation showcases several Gang of Four design patterns:

- **Builder Pattern**: Flexible cache configuration
- **Factory Pattern**: Simplified cache creation
- **Decorator Pattern**: Added functionality without modification
- **Null Object Pattern**: Safe no-operation implementation
- **Strategy Pattern**: Extensible eviction policies

## Performance Considerations

- **Time Complexity**: O(1) for get/put/remove operations
- **Space Complexity**: O(n) where n is number of entries
- **Cleanup Overhead**: Configurable background thread with minimal impact
- **Memory Usage**: Automatic expiration prevents memory leaks

## Extending the Cache

### Adding New Eviction Policies

```java
public class LRUCache<K, V> implements Cache<K, V> {
    // Implement LRU eviction alongside TTL
}
```

### Adding Persistence

```java
public class PersistentCache<K, V> implements Cache<K, V> {
    // Add disk or database persistence
}
```

## Best Practices

1. **Choose appropriate TTL** based on data volatility
2. **Monitor cache statistics** to optimize hit ratios
3. **Use reasonable cleanup intervals** based on expiration patterns
4. **Consider key serialization** for complex objects
5. **Always call shutdown()** when application terminates

## Monitoring

```java
// Monitor cache health
CacheStatisticsDecorator<String, Data> monitoredCache = 
    new CacheStatisticsDecorator<>(cache);

// Periodically check statistics
monitoredCache.getStatistics().getHitRatio();
monitoredCache.getStatistics().getHits();
```

## License

This project is licensed under the MIT License.

## Troubleshooting

**Q: Entries not expiring?**
A: Check your cleanup interval configuration

**Q: High memory usage?**
A: Ensure proper TTL values and consider smaller cleanup intervals

**Q: Thread contention?**
A: The cache uses ConcurrentHashMap, but monitor for specific use cases

## Learning Resources

- Java Concurrency in Practice
- Effective Java
- Design Patterns: Elements of Reusable Object-Oriented Software

Built with Java

About

Simple cache to cache simple things

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages