1+ package picoded .dstack .struct .cache ;
2+
3+ import picoded .core .struct .GenericConvertMap ;
4+
5+ import java .util .concurrent .TimeUnit ;
6+
7+ // Cache2k implmentation
8+ import org .cache2k .Cache2kBuilder ;
9+ import org .cache2k .Cache ;
10+
11+ class StructCacheUtil {
12+
13+ /**
14+ * Utility function used to build a new Cache2k cache instance
15+ * This handles all the various common config settings, and set it up accordingly
16+ */
17+ static <V > Cache <String , V > setupCache2kMap (Cache2kBuilder <String ,V > builder , String name , GenericConvertMap <String , Object > config ) {
18+
19+ //
20+ // Get Config
21+ //-----------------------------------------------------------------------
22+
23+ //
24+ // Alright, time to build a new cache
25+ // We are in the era of GB ram computing, 10k cache would
26+ // be a good sane default in server environment. Even if there are
27+ // multiple sets of StructCache, as it would take ~60MB each
28+ //
29+ // That means, with 10 data set being cached, that would be about ~600MB
30+ //
31+ // to consider : auto detect RAM size in KB - and use that?
32+ // a good rough guideline would be 1/4 of free ram space divided by 6kb
33+ // as a capcity size auto detction
34+ //
35+ // # DataObjectMap caching napkin math assumptions
36+ // - Assume a hashmap object with 30 parameters (including system keys)
37+ // - Because its hard to predict the capacity/size ratio it is assumed to be 1:1
38+ // - Keys and value storage are assumed to be a 22 character string
39+ //
40+ // > The above assumptions was designed to somewhat be the upper limit of
41+ // > ram storage cost for a data object map. Rather then an average.
42+ //
43+ // # References
44+ // - http://java-performance.info/memory-consumption-of-java-data-types-2/
45+ // - https://www.javamex.com/tutorials/memory/string_memory_usage.shtml
46+ //
47+ // # The Math
48+ //
49+ // 36 bytes : 32+4 bytes - HashMap space on primary cache map
50+ // 108 bytes : 3 x overhead for cache mapping
51+ // 62 bytes : 40 overhead + 22 oid string key
52+ // 1080 bytes : 30 x (32+4) HashMap overhead
53+ // 1860 bytes : 30 x (40+22) ObjectMap key strings
54+ // 1860 bytes : 30 x (40+22) ObjectMap value strings
55+ // ----------
56+ // 5006 bytes : Total bytes per object map
57+ // ~ 6 kilo bytes : Rounded up
58+ //
59+ // # RAM cost for 10k objects
60+ //
61+ // 10,000 * 6 KB = 60 MB
62+ //
63+ // > So yea, we are ok to assume a 10k objects for most parts
64+ //
65+ int capacity = config .getInt ("capacity" , 10000 );
66+
67+ // Disable monitoring statistics by default
68+ boolean monitoring = config .getBoolean ("monitoring" , false );
69+
70+ // Optimize for high concurrency mode, not recommended unless its
71+ // >100k size, and 8 vCPU that is constantly under heavy load
72+ boolean boostConcurrency = config .getBoolean ("boostConcurrency" , false );
73+
74+ // Enable / Disable statistics, because we do not provide any API interface for this
75+ // there is almost no use case, unless you are bypassing our api and modifying cach2k directly
76+ boolean statistics = config .getBoolean ("statistics" , false );
77+
78+ // Number of milliseconds to cache the values up to, note that this should operate independent of
79+ // any expiry logic that is used for KeyValueMap, defaults to 3 days (in seconds)
80+ //
81+ // If you want to disable expiry (which makes no sense), use -1
82+ long valueLifespan = config .getLong ("valueLifespan" , 3 * 24 * 60 * 60 * 1000L );
83+
84+ //
85+ // Setup the builder
86+ //-----------------------------------------------------------------------
87+
88+ // Configure cache name and capacity
89+ builder = builder .name (name ).entryCapacity (capacity );
90+
91+ // Disable monitoring
92+ if (monitoring == false ) {
93+ builder = builder .disableMonitoring (true );
94+ }
95+ // boostConcurrency if configured
96+ if (boostConcurrency == true ) {
97+ builder = builder .boostConcurrency (true );
98+ }
99+ if (statistics == false ) {
100+ builder = builder .disableStatistics (true );
101+ }
102+ if (valueLifespan >= 0 ) {
103+ builder = builder .expireAfterWrite (valueLifespan , TimeUnit .MILLISECONDS );
104+ } else {
105+ builder = builder .eternal (true );
106+ }
107+
108+ //
109+ // Build and return the built cache
110+ //-----------------------------------------------------------------------
111+ return builder .build ();
112+ }
113+ }
0 commit comments