common/dbinterface.h (67 lines of code) (raw):

#pragma once #include <stdint.h> #include <unistd.h> #include <stdexcept> #include <memory> #include "dbconnector.h" #include "logger.h" namespace swss { class UnavailableDataError : public std::runtime_error { public: UnavailableDataError(const std::string& message, const std::string& data) : std::runtime_error(message) , m_data(data) { } const char *getData() const { return m_data.c_str(); } private: const std::string m_data; }; class DBInterface { public: void connect(int dbId, const std::string& dbName, bool retry = true); void close(const std::string& dbName); void close(); int64_t del(const std::string& dbName, const std::string& key, bool blocking = false); // Delete all keys which match %pattern from DB void delete_all_by_pattern(const std::string& dbName, const std::string& pattern); bool exists(const std::string& dbName, const std::string& key); std::shared_ptr<std::string> get(const std::string& dbName, const std::string& hash, const std::string& key, bool blocking = false); bool hexists(const std::string& dbName, const std::string& hash, const std::string& key); std::map<std::string, std::string> get_all(const std::string& dbName, const std::string& hash, bool blocking = false); std::vector<std::string> keys(const std::string& dbName, const char *pattern = "*", bool blocking = false); std::pair<int, std::vector<std::string>> scan(const std::string& db_name, int cursor, const char *match, uint32_t count); int64_t publish(const std::string& dbName, const std::string& channel, const std::string& message); void hmset(const std::string& dbName, const std::string &hash, const std::map<std::string, std::string> &values); int64_t set(const std::string& dbName, const std::string& hash, const std::string& key, const std::string& value, bool blocking = false); DBConnector& get_redis_client(const std::string& dbName); void set_redis_kwargs(std::string unix_socket_path, std::string host, int port); static const int BLOCKING_ATTEMPT_ERROR_THRESHOLD = 10; static const int BLOCKING_ATTEMPT_SUPPRESSION = BLOCKING_ATTEMPT_ERROR_THRESHOLD + 5; // Wait period in seconds before attempting to reconnect to Redis. static const int CONNECT_RETRY_WAIT_TIME = 10; // Wait period in seconds to wait before attempting to retrieve missing data. static const int DATA_RETRIEVAL_WAIT_TIME = 3; // Time to wait for any given message to arrive via pub-sub. static const int PUB_SUB_NOTIFICATION_TIMEOUT = 10; // seconds // Maximum allowable time to wait on a specific pub-sub notification. static constexpr double PUB_SUB_MAXIMUM_DATA_WAIT = 60.0; // seconds private: template <typename T, typename FUNC> T blockable(FUNC f, const std::string& dbName, bool blocking = false); // Unsubscribe the chosent client from keyspace event notifications void _unsubscribe_keyspace_notification(const std::string& dbName); bool _unavailable_data_handler(const std::string& dbName, const char *data); // Subscribe the chosent client to keyspace event notifications void _subscribe_keyspace_notification(const std::string& dbName); // In the event Redis is unavailable, close existing connections, and try again. void _connection_error_handler(const std::string& dbName); void _onetime_connect(int dbId, const std::string& dbName); // Keep reconnecting to Database 'dbId' until success void _persistent_connect(int dbId, const std::string& dbName); // Pub-sub keyspace pattern static constexpr const char *KEYSPACE_PATTERN = "__key*__:*"; // In Redis, by default keyspace events notifications are disabled because while not // very sensible the feature uses some CPU power. Notifications are enabled using // the notify-keyspace-events of redis.conf or via the CONFIG SET. // In order to enable the feature a non-empty string is used, composed of multiple characters, // where every character has a special meaning according to the following table: // K - Keyspace events, published with __keyspace@<db>__ prefix. // E - Keyevent events, published with __keyevent@<db>__ prefix. // g - Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ... // $ - String commands // l - List commands // s - Set commands // h - Hash commands // z - Sorted set commands // x - Expired events (events generated every time a key expires) // e - Evicted events (events generated when a key is evicted for maxmemory) // A - Alias for g$lshzxe, so that the "AKE" string means all the events. // ACS Redis db mainly uses hash, therefore h is selected. static constexpr const char *KEYSPACE_EVENTS = "KEA"; std::unordered_map<std::string, std::shared_ptr<DBConnector>> keyspace_notification_channels; std::unordered_map<std::string, DBConnector> m_redisClient; std::string m_unix_socket_path; std::string m_host = "127.0.0.1"; int m_port = 6379; }; }