Caching Remote Tables

This explains what a cached remote table is and how to configure a remote database table to be cached locally.

Overview

Caching a table locally takes a copy of a remote database table and stores it in an InMemory datastore store.

This is useful for tables where you want to perform GetByKey queries or datastore lookups. Essentially, if you need to retrieve specific facts (that is, rows) from the table, then it will be more performant to cache the table InMemory.

Out of the box, the FXRates table is cached locally. This allows us to perform GetByKey queries in PostProcessors without any performance penalty of having to query the remote database and send the results for a single value back to Atoti.

How it works

In the ADirectQueryDatabaseSchema we define tables that we want to cache locally. The FXRates is one of these by default. When the application starts we create an InMemory datastore store of the same name as the remote table. We then rename the remote table (the name Atoti uses to reference the remote table) to contain a suffix of “CACHE_SOURCE”. So our remote FXRates table will be renamed to “FXRates_CACHE_SOURCE” and we will have an InMemory datastore store “FXRates”. We then run a complete list query on the remote table “FXRates_CACHE_SOURCE” and write all the results into the InMemory “FXRates” store.

All existing references to the “FXRates” store (for datastore lookups or use in measures) within the application will query the InMemory store rather than the remote one.

This same process can be applied to any side store.

note

Only isolated tables can be cached InMemory.

We cannot cache referenced stores as the reference would be between InMemory and remote tables, which is not supported.

Defining Cached Table

To define a cached table we must register it as a table to cache InMemory and expose the table as a bean with a qualifier of SideStoresToCache.

Registering the Table to Cache

First we must define our table in our datastore description. See Create Datastore Definition on how to add new Tables/Stores to the application.

Once our store is defined in our datastore configuration, we can add this Table as a table we want to cache locally. This is done in an implementation of ADirectQueryDatabaseSchema. To add our Table we can simply extend one of the classes that extends ADirectQueryDatabaseSchema such as DirectQueryDatabaseConfig and override the getTablesToCacheLocally() method and mark our class as primary with the @Primary annotation.

We also need to mark our method as a Bean with the Qualifier set to SideStoresToCache. This will register these tables and our DirectQueryInitialDataLoadConfig will populate the InMemory stores with the contents of the remote tables.

Furthermore, when converting our datastore store description into a database Table description, we need to tell the migrator that this is a store to cache locally InMemory. We need to tell the migrator this is a table to cache locally, so it can set the database Table’s name to include “_CACHE_SOURCE” as well as mark the datastore store as an InMemory store to use.

This will leave us with our custom class defining the table to cache locally:

@Primary
public class CustomCachedTableClickHouseDatabaseConfig extends DirectQueryDatabaseConfig {

    @Bean
    @Qualifier("SideStoresToCache")
	@Override
	public List<Table> getTablesToCacheLocally(){
		// Get all default tables from the parent
		List<Table> existingTables = super.getTablesToCacheLocally();

		// Add the table we want to cache locally:
		existingTables.add(getMyCustomTable());

		return existingTables;
	}

    // Migrate from datastore description to database Table definition
	public Table getMyCustomTable(){
		return migrator.migrateToDirectQueryTable(
				getStoreDescriptionFor(
						"MyCustomTable"
				),
				true    // Specifying that this is a table to cache locally
		);
	}
}

Conclusion

Now you can query your cached table in measures just as you would with any other Atoti InMemory datastore store. We can validate that our table was cached by taking a look in the AdminUI. We should see that we have one store with the “_CACHE_SOURCE” suffix - this is the remote table. The InMemory table is the one without the suffix.

Here we can see the Table “MyCustomTable” as both an InMemory store (named “MyCustomTable”) and as a remote DirectQuery database Table (named “MyCustomTable_CACHE_SOURCE”). This can also be seen for the FXRates store. Both these stores will contain the same data.

Cached Table as seen in AdminUI

Application Refresh

When the Application is Refreshed through the DirectQuery REST Service, the InMemory Stores will be completely re-populated with the content of the remote Tables.