A typical components::PostgreCache usage consists of trait definition:
struct PostgresTrivialPolicy {
static constexpr std::string_view kName = "my-pg-cache" ;
using ValueType = MyStructure;
static constexpr auto kKeyMember = &MyStructure::id;
static constexpr const char * kQuery = "SELECT a, b, updated FROM test.data" ;
static constexpr const char * kUpdatedField = "updated" ;
using UpdatedFieldType = storages::postgres::TimePointTz;
};
and registration of the component in components::ComponentList :
See Basics of Caches for introduction into caches.
Configuration
components::PostgreCache static configuration file should have a PostgreSQL component name specified in pgcomponent
configuration parameter.
Optionally the operation timeouts for cache loading can be specified.
For avoiding "memory leaks", see the respective section in components::CachingComponentBase .
Name Description Default value
full-update-op-timeout timeout for a full update 1m
incremental-update-op-timeout timeout for an incremental update 1s
update-correction incremental update window adjustment - (0 for caches with defined GetLastKnownUpdated)
chunk-size number of rows to request from PostgreSQL via portals, 0 to fetch all rows in one request without portals 1000
Cache policy
Cache policy is the template argument of components::PostgreCache component. Please see the following code snippet for documentation.
namespace example {
struct MyStructure {
int id = 0;
std::string bar{};
storages::postgres::TimePointWithoutTz updated;
int get_id() const { return id; }
};
struct PostgresExamplePolicy {
static constexpr std::string_view kName = "my-pg-cache" ;
using ValueType = MyStructure;
static constexpr auto kKeyMember = &MyStructure::id;
static constexpr const char * kQuery = "select id, bar, updated from test.my_data" ;
static constexpr const char * kUpdatedField = "updated" ;
using UpdatedFieldType = storages::postgres::TimePointTz;
static constexpr const char * kWhere = "id > 10" ;
using CacheContainer = std::unordered_map<int, MyStructure>;
static constexpr bool kMayReturnNull = false ;
static constexpr const char * kOrderBy = "updated asc" ;
};
}
The query can be a std::string. But due to non-guaranteed order of static data members initialization, std::string should be returned from a static member function, please see the following code snippet.
struct PostgresExamplePolicy4 {
static constexpr std::string_view kName = "my-pg-cache" ;
using ValueType = MyStructure;
static constexpr auto kKeyMember = &MyStructure::id;
static std::string GetQuery() { return "select id, bar, updated from test.my_data" ; }
static constexpr const char * kUpdatedField = "updated" ;
using UpdatedFieldType = storages::postgres::TimePointWithoutTz;
};
Policy may have static function GetLastKnownUpdated. It should be used when new entries from database are taken via revision, identifier, or anything else, but not timestamp of the last update. If this function is supplied, new entries are taken from db with condition 'WHERE kUpdatedField > GetLastKnownUpdated(cache_container)'. Otherwise, condition is 'WHERE kUpdatedField > last_update - correction_'. See the following code snippet for an example of usage
struct MyStructureWithRevision {
int id = 0;
std::string bar{};
storages::postgres::TimePointWithoutTz updated;
int32_t revision = 0;
int get_id() const { return id; }
};
class UserSpecificCache {
public :
void insert_or_assign(int , MyStructureWithRevision&& item) {
latest_revision_ = std::max(latest_revision_, item.revision);
}
static size_t size() { return 0; }
int GetLatestRevision() const { return latest_revision_; }
private :
int latest_revision_ = 0;
};
struct PostgresExamplePolicy3 {
using ValueType = MyStructureWithRevision;
static constexpr std::string_view kName = "my-pg-cache" ;
static constexpr const char * kQuery = "select id, bar, revision from test.my_data" ;
using CacheContainer = UserSpecificCache;
static constexpr const char * kUpdatedField = "revision" ;
using UpdatedFieldType = int32_t;
static constexpr auto kKeyMember = &MyStructureWithRevision::get_id;
static int32_t GetLastKnownUpdated(const UserSpecificCache& container) { return container.GetLatestRevision(); }
};
Cache can also store only subset of data. For example for the database that is is defined in the following way:
CREATE TABLE IF NOT EXISTS key_value_table (
key VARCHAR ,
value VARCHAR ,
updated TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
it is possible to create a cache that stores only the latest value
:
struct KeyValue {
std::string key;
std::string value;
};
struct LastCachePolicy {
static constexpr std::string_view kName = "last-pg-cache" ;
using ValueType = KeyValue;
static constexpr auto kKeyMember = &KeyValue::key;
static constexpr const char * kQuery = "SELECT DISTINCT ON (key) key, value FROM key_value_table" ;
static constexpr const char * kUpdatedField = "updated" ;
using UpdatedFieldType = storages::postgres::TimePointTz;
static constexpr const char * kOrderBy = "key, updated DESC" ;
};
using LastCache = components::PostgreCache<LastCachePolicy>;
In case one provides a custom CacheContainer within Policy, it is notified of Update completion via its public member function OnWritesDone, if any. See the following code snippet for an example of usage:
class UserSpecificCacheWithWriteNotification {
public :
void insert_or_assign(int , MyStructure&&) {}
static size_t size() { return 0; }
void OnWritesDone() {}
};
Forward Declaration
To forward declare a cache you can forward declare a trait and include userver/cache/base_postgres_cache_fwd.hpp header. It is also useful to forward declare the cache value type.
#pragma once
#include <memory>
USERVER_NAMESPACE_BEGIN
namespace example {
struct PostgresExamplePolicy;
struct MyStructure;
}
namespace caches {
using MyCache1 = components::PostgreCache<example::PostgresExamplePolicy>;
using MyCache1Data = std::shared_ptr<const example::MyStructure>;
}