1+ package io .warmup .framework .cache ;
2+
3+ import java .util .*;
4+ import java .util .concurrent .ConcurrentHashMap ;
5+ import java .util .concurrent .atomic .AtomicInteger ;
6+ import java .util .concurrent .atomic .AtomicLong ;
7+ import java .util .concurrent .TimeUnit ;
8+ import java .util .logging .Logger ;
9+
10+ /**
11+ * O(1) Optimized Cache Manager with atomic counters, TTL caches, and cache invalidation.
12+ * Provides production-ready caching performance with comprehensive statistics.
13+ */
14+ public class CacheManager {
15+
16+ private static final Logger log = Logger .getLogger (CacheManager .class .getName ());
17+
18+ // O(1) Atomic Counters for Real-time Statistics
19+ private final AtomicInteger cachePuts = new AtomicInteger (0 );
20+ private final AtomicInteger cacheGets = new AtomicInteger (0 );
21+ private final AtomicInteger cacheHits = new AtomicInteger (0 );
22+ private final AtomicInteger cacheMisses = new AtomicInteger (0 );
23+ private final AtomicInteger cacheRemovals = new AtomicInteger (0 );
24+ private final AtomicInteger cacheExpirations = new AtomicInteger (0 );
25+ private final AtomicLong totalCacheOperations = new AtomicLong (0 );
26+
27+ // O(1) TTL Caches - Cache Data (10s), Cache Stats (30s)
28+ private final Map <String , CacheEntry > cacheData = new ConcurrentHashMap <>();
29+ private final Map <String , Long > cacheDataExpiry = new ConcurrentHashMap <>();
30+ private static final long CACHE_DATA_TTL = TimeUnit .SECONDS .toMillis (10 );
31+
32+ private final Map <String , Object > cacheStatsCache = new ConcurrentHashMap <>();
33+ private final Map <String , Long > cacheStatsExpiry = new ConcurrentHashMap <>();
34+ private static final long CACHE_STATS_TTL = TimeUnit .SECONDS .toMillis (30 );
35+
36+ // O(1) Cache Invalidation Flags
37+ private volatile boolean cacheDataDirty = false ;
38+ private volatile boolean cacheStatsDirty = false ;
39+
40+ // O(1) Performance Monitoring
41+ private final AtomicLong totalCacheOperationTime = new AtomicLong (0 );
42+ private volatile long startTime = System .currentTimeMillis ();
43+
44+ // Backend storage for cache data
45+ private final Map <String , Object > backendStorage = new ConcurrentHashMap <>();
46+
47+ // Configuration
48+ private static final int MAX_CACHE_SIZE = 10000 ; // Maximum cache entries
49+ private static final int CLEANUP_THRESHOLD = 1000 ; // Trigger cleanup when threshold exceeded
50+
51+ /**
52+ * Default constructor
53+ */
54+ public CacheManager () {
55+ log .info ("CacheManager initialized with in-memory backend" );
56+ }
57+
58+ // O(1) Optimized put operation with TTL caching
59+ public void put (String key , Object value ) {
60+ long startTime = System .nanoTime ();
61+
62+ cachePuts .incrementAndGet ();
63+ totalCacheOperations .incrementAndGet ();
64+
65+ // Backend storage operation (O(1))
66+ backendStorage .put (key , value );
67+
68+ // O(1) TTL cache storage
69+ cacheData .put (key , new CacheEntry (value , System .currentTimeMillis () + CACHE_DATA_TTL ));
70+ cacheDataExpiry .put (key , System .currentTimeMillis () + CACHE_DATA_TTL );
71+
72+ // O(1) Cache invalidation
73+ cacheDataDirty = true ;
74+ cacheStatsDirty = true ;
75+
76+ // Trigger cleanup if needed
77+ if (cacheData .size () > CLEANUP_THRESHOLD ) {
78+ cleanupExpiredEntries ();
79+ }
80+
81+ long duration = System .nanoTime () - startTime ;
82+ totalCacheOperationTime .addAndGet (duration );
83+
84+ log .info ("Cache PUT: " + key + " = " + value );
85+ }
86+
87+ // O(1) Optimized get operation with TTL caching and hit/miss tracking
88+ public Object get (String key ) {
89+ long startTime = System .nanoTime ();
90+
91+ cacheGets .incrementAndGet ();
92+ totalCacheOperations .incrementAndGet ();
93+
94+ Object result = null ;
95+
96+ // O(1) TTL cache check first
97+ if (isCacheValid (key , cacheData , cacheDataExpiry )) {
98+ CacheEntry entry = cacheData .get (key );
99+ if (entry != null && entry .value != null ) {
100+ result = entry .value ;
101+ cacheHits .incrementAndGet ();
102+
103+ long duration = System .nanoTime () - startTime ;
104+ totalCacheOperationTime .addAndGet (duration );
105+
106+ return result ;
107+ }
108+ }
109+
110+ // Cache miss - try backend storage (O(1))
111+ result = backendStorage .get (key );
112+
113+ if (result != null ) {
114+ cacheHits .incrementAndGet ();
115+ // Refresh TTL cache
116+ cacheData .put (key , new CacheEntry (result , System .currentTimeMillis () + CACHE_DATA_TTL ));
117+ cacheDataExpiry .put (key , System .currentTimeMillis () + CACHE_DATA_TTL );
118+ } else {
119+ cacheMisses .incrementAndGet ();
120+ }
121+
122+ long duration = System .nanoTime () - startTime ;
123+ totalCacheOperationTime .addAndGet (duration );
124+
125+ log .info ("Cache GET: " + key + " = " + result );
126+ return result ;
127+ }
128+
129+ // O(1) Optimized remove operation with cache invalidation
130+ public void remove (String key ) {
131+ long startTime = System .nanoTime ();
132+
133+ cacheRemovals .incrementAndGet ();
134+ totalCacheOperations .incrementAndGet ();
135+
136+ // Backend storage operation (O(1))
137+ backendStorage .remove (key );
138+
139+ // O(1) TTL cache removal
140+ CacheEntry removed = cacheData .remove (key );
141+ cacheDataExpiry .remove (key );
142+
143+ if (removed != null ) {
144+ cacheDataDirty = true ;
145+ cacheStatsDirty = true ;
146+ }
147+
148+ long duration = System .nanoTime () - startTime ;
149+ totalCacheOperationTime .addAndGet (duration );
150+
151+ log .info ("Cache REMOVE: " + key );
152+ }
153+
154+ // O(1) Optimized info method with TTL caching
155+ public String getInfo () {
156+ String cacheKey = "cacheInfo" ;
157+
158+ // O(1) Cache check
159+ if (!cacheStatsDirty && isCacheValid (cacheKey , cacheStatsCache , cacheStatsExpiry )) {
160+ String cached = (String ) cacheStatsCache .get (cacheKey );
161+ if (cached != null ) return cached ;
162+ }
163+
164+ StringBuilder info = new StringBuilder ();
165+ info .append ("CacheManager with O(1) Optimizations - " );
166+ info .append ("Entries: " ).append (cacheData .size ());
167+ info .append (" | Backend: InMemory" );
168+ info .append (" | Hit Rate: " ).append (getHitRate ()).append ("%" );
169+ info .append (" | Operations: " ).append (totalCacheOperations .get ());
170+
171+ String result = info .toString ();
172+
173+ // O(1) Cache storage
174+ cacheStatsCache .put (cacheKey , result );
175+ cacheStatsExpiry .put (cacheKey , System .currentTimeMillis () + CACHE_STATS_TTL );
176+ cacheStatsDirty = false ;
177+
178+ return result ;
179+ }
180+
181+ // O(1) Helper method for cache validation
182+ private boolean isCacheValid (String key , Map <String , ?> cache , Map <String , Long > expiry ) {
183+ Long expireTime = expiry .get (key );
184+ if (expireTime == null || System .currentTimeMillis () >= expireTime ) {
185+ // Cache expired - count as expiration and clean up
186+ if (cache == cacheData ) {
187+ cacheExpirations .incrementAndGet ();
188+ cacheData .remove (key );
189+ cacheDataExpiry .remove (key );
190+ }
191+ return false ;
192+ }
193+ return true ;
194+ }
195+
196+ // O(1) Cleanup expired entries
197+ private void cleanupExpiredEntries () {
198+ long currentTime = System .currentTimeMillis ();
199+ int expiredCount = 0 ;
200+
201+ Iterator <Map .Entry <String , Long >> iterator = cacheDataExpiry .entrySet ().iterator ();
202+ while (iterator .hasNext ()) {
203+ Map .Entry <String , Long > entry = iterator .next ();
204+ if (currentTime >= entry .getValue ()) {
205+ cacheData .remove (entry .getKey ());
206+ iterator .remove ();
207+ expiredCount ++;
208+ }
209+ }
210+
211+ if (expiredCount > 0 ) {
212+ cacheExpirations .addAndGet (expiredCount );
213+ cacheDataDirty = true ;
214+ cacheStatsDirty = true ;
215+ log .info ("Cache cleanup: " + expiredCount + " expired entries removed" );
216+ }
217+ }
218+
219+ // O(1) Atomic counter getters
220+ public int getCachePuts () {
221+ return cachePuts .get ();
222+ }
223+
224+ public int getCacheGets () {
225+ return cacheGets .get ();
226+ }
227+
228+ public int getCacheHits () {
229+ return cacheHits .get ();
230+ }
231+
232+ public int getCacheMisses () {
233+ return cacheMisses .get ();
234+ }
235+
236+ public int getCacheRemovals () {
237+ return cacheRemovals .get ();
238+ }
239+
240+ public int getCacheExpirations () {
241+ return cacheExpirations .get ();
242+ }
243+
244+ public long getTotalCacheOperations () {
245+ return totalCacheOperations .get ();
246+ }
247+
248+ // O(1) Performance metrics
249+ public double getHitRate () {
250+ int total = cacheHits .get () + cacheMisses .get ();
251+ return total > 0 ? (double ) cacheHits .get () / total * 100 : 0.0 ;
252+ }
253+
254+ public double getAverageOperationTime () {
255+ long total = totalCacheOperations .get ();
256+ return total > 0 ? (double ) totalCacheOperationTime .get () / total / 1_000_000.0 : 0.0 ; // milliseconds
257+ }
258+
259+ public long getUptime () {
260+ return System .currentTimeMillis () - startTime ;
261+ }
262+
263+ // O(1) Cache statistics
264+ public Map <String , Object > getCacheStatistics () {
265+ String cacheKey = "cacheStatistics" ;
266+
267+ // O(1) Cache check
268+ if (!cacheStatsDirty && isCacheValid (cacheKey , cacheStatsCache , cacheStatsExpiry )) {
269+ @ SuppressWarnings ("unchecked" )
270+ Map <String , Object > cached = (Map <String , Object >) cacheStatsCache .get (cacheKey );
271+ if (cached != null ) return cached ;
272+ }
273+
274+ Map <String , Object > stats = new HashMap <>();
275+ stats .put ("cachePuts" , cachePuts .get ());
276+ stats .put ("cacheGets" , cacheGets .get ());
277+ stats .put ("cacheHits" , cacheHits .get ());
278+ stats .put ("cacheMisses" , cacheMisses .get ());
279+ stats .put ("cacheRemovals" , cacheRemovals .get ());
280+ stats .put ("cacheExpirations" , cacheExpirations .get ());
281+ stats .put ("totalOperations" , totalCacheOperations .get ());
282+ stats .put ("hitRate" , getHitRate ());
283+ stats .put ("averageOperationTimeMs" , getAverageOperationTime ());
284+ stats .put ("uptimeMs" , getUptime ());
285+ stats .put ("currentCacheSize" , cacheData .size ());
286+ stats .put ("backendCacheType" , "InMemory" );
287+
288+ // O(1) Cache storage
289+ cacheStatsCache .put (cacheKey , stats );
290+ cacheStatsExpiry .put (cacheKey , System .currentTimeMillis () + CACHE_STATS_TTL );
291+ cacheStatsDirty = false ;
292+
293+ return stats ;
294+ }
295+
296+ // O(1) Force cache invalidation
297+ public void clearAllCaches () {
298+ cacheData .clear ();
299+ cacheDataExpiry .clear ();
300+ cacheStatsCache .clear ();
301+ cacheStatsExpiry .clear ();
302+
303+ cacheDataDirty = false ;
304+ cacheStatsDirty = false ;
305+
306+ log .info ("All caches cleared" );
307+ }
308+
309+ // O(1) Force refresh all cached data
310+ public void refreshCache () {
311+ clearAllCaches ();
312+ // Optionally clear backend cache
313+ // This would need to be implemented in the backend cache service
314+ }
315+
316+ // Internal CacheEntry class
317+ private static class CacheEntry {
318+ final Object value ;
319+ final long expiryTime ;
320+
321+ CacheEntry (Object value , long expiryTime ) {
322+ this .value = value ;
323+ this .expiryTime = expiryTime ;
324+ }
325+
326+ boolean isExpired () {
327+ return System .currentTimeMillis () >= expiryTime ;
328+ }
329+ }
330+ }
0 commit comments