tpcache.ini — Enduro/X tpcall caching configuration
[@cachedb/DBNAME_SECTION] cachedb=DBNAME_DB resource=DATABASE_DIRECTORY flags=FLAGS limit=LIMIT expiry=EXPIRY max_readers=MAX_READERS max_dbs=MAX_NAMED_DBS map_size=MAP_SIZE perms=DB_PERMISSIONS [@cachedb/DBNAME_2] ... [@cachedb/DBNAME_N] ... [@cache] svc SERVICE_NAME= { "caches":[ { "cachedb":"CACHE_DBNAME", "flags":"CACHE_FLAGS", "type":"TYPE", "subtype":"SUBTYPE", "rule":"RULE", "keyfmt":"KEYFMT", "save":"SAVE", "delete":"DELETE", "rsprule":"RSPRULE", "refreshrule":"REFRESHRULE", "inval_svc":"INVAL_SVC", "inval_idx":"INVAL_IDX", "keygrpdb":"KEYGRPDB", "keygrpfmt":"KEYGRPFMT", "keygrpmaxtperrno":"KEYGRPMAXTPERRNO", "keygrpmaxtpurcode":"KEYGRPMAXTPURCODE", "keygroupmrej":"KEYGROUPMREJ", "keygroupmax":"KEYGROUPMAX" }, { "cachedb":"DBNAME_2", ... }, ... ] } svc SERVICE_NAME_N= { "caches":[ { "cachedb":"DBNAME_N", ... }, ... ] }
Enduro/X supports tpcall(3) caching, by writing results into LMDB. LMDB is integral par to of the Enduro/X. To avoid conflict with users choice of LMDB version, the embedded version is renamed to "EXDB", so that global C symbols does not conflict. To configure Enduro/x tpcall caching, firstly database must be configured. Enduro/X uses approach, that each database is stored into separate file system directory. On Linux systems (or others which support RAM drivers), the directory can be defined in RAM drive, and thus avoid the cache writing to disk (as the LMDB uses memory mapped files). On Linux for this purpose /dev/shm can be used.
Caching is performed at service level. Thus when software is doing tpcall(3), the client’s call is intercepted, and tested against cache. If saved data is found, then data is directly returned from LMDB and no service invocation is done.
Each cached item must have a key. The key is build from the call data. Key is zero (0x00 byte) terminated string. Key format is given in cache configuration. Before lookup to DB is made, rule expression is tested. This indicates either the call must be cached or not. If rule is true, key is built and with key DB is tested, if result is found, it is returned to caller. If result is not found, then service invocation is performed. When service responds, data is written to cache.
Service can have multiple caches, with different rules. Once request is processed the first cache which matches the rule is used for lookup or data saving.
Each cache references database definition, single database can be use by multiple caches or each cache can have it’s own database. Keeping multiple databases could make better performance for caches were often writes are done. As concurrent writes are synchronized so that only one process writes to the same database.
If writing to the same database, user shall ensure that keys are unique between different service cache definitions. This can be reached by adding different prefixes in key format.
Simple cache - this is cache were data is saved in one cache database. No linked databases are used.
Keygroup is separate database where records can be grouped. For example by user id. The group record holds the UBF buffer with string key occurrences which are linked in the group. Keygroup database name is encoded as
Keyitem is linked record to the group.
For performance reasons, if non persistent cache is required, it is recommended to store data file in RAM driver, for example on GNU/Linux systems it is /dev/shm. It is considered that in such scenario LMDB will use twice the memory. As one is a copy in RAM drive and another is mapped pages in process to the file. It is up to kernel realization to make some optimizations here.
Simple caches
[@cachedb/db02_1] cachedb=db02_1 resource=${TESTDIR_DB}/db02_1 flags=bootreset [@cachedb/db02_2] cachedb=db02_2 resource=${TESTDIR_DB}/db02_2 flags=bootreset [@cache] svc TESTSV02= { "caches":[ { "cachedb":"db02_1", "type":"UBF", "keyfmt":"SV2-$(T_STRING_FLD)", "save":"*", "rule":"T_STRING_2_FLD=='HELLO CACHE 1'" }, { "cachedb":"db02_2", "type":"UBF", "keyfmt":"SV2-$(T_STRING_FLD)", "save":"T_STRING.*|T_FLOAT.*|T_LONG_2_FLD|T_SHORT.*", "flags":"putrex" } ] } svc SOMEOTHERSVC= { "caches":[ { "cachedb":"db02_1", "type":"UBF", "keyfmt":"SVOTHER-$(T_STRING_FLD)", "save":"*", } ] }
Cache with keygroup and buffer reject:
[@cachedb/db15] max_dbs=2 resource=${TESTDIR_DB}/db15 subscr=@C.001/.*/.*|@C.002/.*/.* # # These two inherits settings from above. # [@cachedb/db15/g] cachedb=g@db15 flags=bootreset,bcastput,bcastdel,keygroup expiry=30s [@cachedb/db15/k] cachedb=k@db15 flags=bootreset,bcastput,bcastdel,keyitems expiry=10s [@cache] svc TESTSV15= { "caches":[ { "cachedb":"k@db15", "keygrpdb":"g@db15", "type":"UBF", "keyfmt":"SV15$(T_STRING_FLD)-SV15$(T_SHORT_FLD)", "keygrpfmt":"SV15$(T_STRING_FLD)", "save":"T_STRING_FLD,T_STRING_2_FLD,T_LONG_2_FLD,T_SHORT_FLD", "flags":"getmerge", "keygroupmax":"7", "keygroupmrej":"{\"T_STRING_3_FLD\":\"REJECT\",\"T_LONG_2_FLD\":[\"1\", \"2\"]}", "keygrpmaxtperrno":"11", "keygrpmaxtpurcode":"4" } ] }
For more unit tests please see atmitest/test048_cache unit test folder ini files.