c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen#ifndef DICT_H
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen#define DICT_H
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen#define DICT_PATH_PRIVATE "priv/"
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen#define DICT_PATH_SHARED "shared/"
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
7c4ff436f9c6daa09ac052ad05505601605b3ebdTimo Sirainenstruct timespec;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainenstruct dict;
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainenstruct dict_iterate_context;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainenenum dict_iterate_flags {
76b4207273534f71365bc7f900c23a5160692802Timo Sirainen /* Recurse to all the sub-hierarchies (e.g. iterating "foo/" will
76b4207273534f71365bc7f900c23a5160692802Timo Sirainen return "foo/a", but should it return "foo/a/b"?) */
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen DICT_ITERATE_FLAG_RECURSE = 0x01,
76b4207273534f71365bc7f900c23a5160692802Timo Sirainen /* Sort returned results by key */
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen DICT_ITERATE_FLAG_SORT_BY_KEY = 0x02,
76b4207273534f71365bc7f900c23a5160692802Timo Sirainen /* Sort returned results by value */
63b938821926c2b21fc6f98909e8a81571a682eeTimo Sirainen DICT_ITERATE_FLAG_SORT_BY_VALUE = 0x04,
76b4207273534f71365bc7f900c23a5160692802Timo Sirainen /* Don't return values, only keys */
76b4207273534f71365bc7f900c23a5160692802Timo Sirainen DICT_ITERATE_FLAG_NO_VALUE = 0x08,
76b4207273534f71365bc7f900c23a5160692802Timo Sirainen /* Don't recurse at all. This is basically the same as dict_lookup(),
76b4207273534f71365bc7f900c23a5160692802Timo Sirainen but it'll return all the rows instead of only the first one. */
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen DICT_ITERATE_FLAG_EXACT_KEY = 0x10,
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen /* Perform iteration asynchronously. */
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen DICT_ITERATE_FLAG_ASYNC = 0x20
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen};
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainenenum dict_data_type {
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen DICT_DATA_TYPE_STRING = 0,
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch DICT_DATA_TYPE_UINT32,
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch DICT_DATA_TYPE_LAST
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen};
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainenstruct dict_settings {
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen enum dict_data_type value_type;
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen const char *username;
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen const char *base_dir;
a6a6ad107e509cf8952a28f740eb2023284497b9Timo Sirainen /* home directory for the user, if known */
a6a6ad107e509cf8952a28f740eb2023284497b9Timo Sirainen const char *home_dir;
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen};
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainenstruct dict_lookup_result {
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen int ret;
85b234661baa110e046d3d9ad22f59e69fa75c69Timo Sirainen
85b234661baa110e046d3d9ad22f59e69fa75c69Timo Sirainen /* First returned value (ret > 0) */
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen const char *value;
85b234661baa110e046d3d9ad22f59e69fa75c69Timo Sirainen /* NULL-terminated list of all returned values (ret > 0) */
85b234661baa110e046d3d9ad22f59e69fa75c69Timo Sirainen const char *const *values;
85b234661baa110e046d3d9ad22f59e69fa75c69Timo Sirainen
85b234661baa110e046d3d9ad22f59e69fa75c69Timo Sirainen /* Error message for a failed lookup (ret < 0) */
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen const char *error;
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen};
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainenenum dict_commit_ret {
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen DICT_COMMIT_RET_OK = 1,
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen DICT_COMMIT_RET_NOTFOUND = 0,
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen DICT_COMMIT_RET_FAILED = -1,
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen /* write may or may not have succeeded (e.g. write timeout or
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen disconnected from server) */
c5d27aee77dad4b10d6dd915b9cb4c8757c0e988Timo Sirainen DICT_COMMIT_RET_WRITE_UNCERTAIN = -2,
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen};
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenstruct dict_commit_result {
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen enum dict_commit_ret ret;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen const char *error;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen};
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainentypedef void dict_lookup_callback_t(const struct dict_lookup_result *result,
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen void *context);
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainentypedef void dict_iterate_callback_t(void *context);
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainentypedef void
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainendict_transaction_commit_callback_t(const struct dict_commit_result *result,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen void *context);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainenvoid dict_driver_register(struct dict *driver);
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainenvoid dict_driver_unregister(struct dict *driver);
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainen
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainenvoid dict_drivers_register_builtin(void);
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainenvoid dict_drivers_unregister_builtin(void);
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainenvoid dict_drivers_register_all(void);
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainenvoid dict_drivers_unregister_all(void);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen/* Open dictionary with given URI (type:data).
10399559650f552a23949772be79eb6a80198c5aTimo Sirainen Returns 0 if ok, -1 if URI is invalid. */
20e04227229970d148801c507946666e2a9bd838Timo Sirainenint dict_init(const char *uri, const struct dict_settings *set,
20e04227229970d148801c507946666e2a9bd838Timo Sirainen struct dict **dict_r, const char **error_r);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen/* Close dictionary. */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid dict_deinit(struct dict **dict);
c4478af52de63804efef2055580adf1dfc8679c6Timo Sirainen/* Wait for all pending asynchronous operations to finish. */
c4478af52de63804efef2055580adf1dfc8679c6Timo Sirainenvoid dict_wait(struct dict *dict);
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen/* Switch the dict to the current ioloop. This can be used to do dict_wait()
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen among other IO work. Returns TRUE if there is actually some work that can
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen be waited on. */
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainenbool dict_switch_ioloop(struct dict *dict) ATTR_NOWARN_UNUSED_RESULT;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
f8ead0942a9b7c8fcf91414ed1b534d5807ca555Timo Sirainen/* Lookup value for key. Set it to NULL if it's not found.
f8ead0942a9b7c8fcf91414ed1b534d5807ca555Timo Sirainen Returns 1 if found, 0 if not found and -1 if lookup failed. */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenint dict_lookup(struct dict *dict, pool_t pool,
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen const char *key, const char **value_r, const char **error_r);
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainenvoid dict_lookup_async(struct dict *dict, const char *key,
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen dict_lookup_callback_t *callback, void *context);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen/* Iterate through all values in a path. flag indicates how iteration
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen is carried out */
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainenstruct dict_iterate_context *
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainendict_iterate_init(struct dict *dict, const char *path,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen enum dict_iterate_flags flags);
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainenstruct dict_iterate_context *
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainendict_iterate_init_multiple(struct dict *dict, const char *const *paths,
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen enum dict_iterate_flags flags);
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen/* Set async callback. Note that if dict_iterate_init() already did all the
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen work, this callback may never be called. So after dict_iterate_init() you
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen should call dict_iterate() in any case to see if all the results are
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen already available. */
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainenvoid dict_iterate_set_async_callback(struct dict_iterate_context *ctx,
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen dict_iterate_callback_t *callback,
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen void *context);
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen/* Limit how many rows will be returned by the iteration (0 = unlimited).
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen This allows backends to optimize the query (e.g. use LIMIT 1 with SQL). */
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainenvoid dict_iterate_set_limit(struct dict_iterate_context *ctx,
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen uint64_t max_rows);
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen/* If dict_iterate() returns FALSE, the iteration may be finished or if this
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen is an async iteration it may be waiting for more data. If this function
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen returns TRUE, the dict callback is called again with more data. */
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainenbool dict_iterate_has_more(struct dict_iterate_context *ctx);
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainenbool dict_iterate(struct dict_iterate_context *ctx,
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen const char **key_r, const char **value_r);
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen/* Returns 0 = ok, -1 = iteration failed */
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainenint dict_iterate_deinit(struct dict_iterate_context **ctx, const char **error_r);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen/* Start a new dictionary transaction. */
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainenstruct dict_transaction_context *dict_transaction_begin(struct dict *dict);
aef407f147034a569591c0f59593342a8c7b39eaTimo Sirainen/* Don't log a warning if the transaction commit took a long time.
aef407f147034a569591c0f59593342a8c7b39eaTimo Sirainen This is needed if there are no guarantees that an asynchronous commit will
aef407f147034a569591c0f59593342a8c7b39eaTimo Sirainen finish up anytime soon. Mainly useful for transactions which aren't
aef407f147034a569591c0f59593342a8c7b39eaTimo Sirainen especially important whether they finish or not. */
aef407f147034a569591c0f59593342a8c7b39eaTimo Sirainenvoid dict_transaction_no_slowness_warning(struct dict_transaction_context *ctx);
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen/* Set write timestamp for the entire transaction. This must be set before
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen any changes are done and can't be changed afterwards. Currently only
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen dict-sql with Cassandra backend does anything with this. */
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainenvoid dict_transaction_set_timestamp(struct dict_transaction_context *ctx,
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen const struct timespec *ts);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen/* Commit the transaction. Returns 1 if ok, 0 if dict_atomic_inc() was used
7fc0f80480063a9d4cb9e8c07b50db2a5627799eTimo Sirainen on a nonexistent key, -1 if failed. */
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenint dict_transaction_commit(struct dict_transaction_context **ctx,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen const char **error_r);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen/* Commit the transaction, but don't wait to see if it finishes successfully.
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen If callback isn't NULL, it's called eventually. If it's not called by the
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen time you want to deinitialize dict, call dict_flush() to wait for the
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen result. */
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenvoid dict_transaction_commit_async(struct dict_transaction_context **ctx,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen dict_transaction_commit_callback_t *callback,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen void *context) ATTR_NULL(2, 3);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen/* Rollback all changes made in transaction. */
1dc6f277f5ac6a3dd5cd6aa75a7ef691de9acb7aTimo Sirainenvoid dict_transaction_rollback(struct dict_transaction_context **ctx);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen/* Set key=value in dictionary. */
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainenvoid dict_set(struct dict_transaction_context *ctx,
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen const char *key, const char *value);
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen/* Unset a record in dictionary, identified by key*/
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainenvoid dict_unset(struct dict_transaction_context *ctx,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen const char *key);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen/* Increase/decrease a numeric value in dictionary. Note that the value is
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen changed when transaction is being committed, so you can't know beforehand
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen what the value will become. The value is updated only if it already exists,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen otherwise commit() will return 0. */
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainenvoid dict_atomic_inc(struct dict_transaction_context *ctx,
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen const char *key, long long diff);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen/* Escape/unescape '/' characters in a string, so that it can be safely added
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen into path components in dict keys. */
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainenconst char *dict_escape_string(const char *str);
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainenconst char *dict_unescape_string(const char *str);
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen#endif