diff --git a/CPPLINT.cfg b/CPPLINT.cfg new file mode 100644 index 00000000..939b0a6e --- /dev/null +++ b/CPPLINT.cfg @@ -0,0 +1,8 @@ +# cpplint settings. See scripts/check_style.sh and scripts/cpplint +# These settings can be overridden in any subfolder by placing a CPPLINT.cfg file in it + +set noparent + +filter=-build/include_subdir + +linelength=120 diff --git a/src/dict-rados/DictRados.cpp b/src/dict-rados/DictRados.cpp index 32e9252a..448cfc37 100644 --- a/src/dict-rados/DictRados.cpp +++ b/src/dict-rados/DictRados.cpp @@ -1,4 +1,19 @@ -#include "DictRados.hpp" +// Copyright 2017 +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include extern "C" { @@ -15,781 +30,771 @@ extern "C" { #include "DictRados.h" } -#include -#include -#include -#include -#include -#include -#include -#include - -#include - +#include "DictRados.h" #include "DictRados.hpp" -using namespace librados; -using namespace std; +using namespace librados; // NOLINT + +using std::string; +using std::stringstream; +using std::vector; +using std::map; +using std::pair; +using std::set; #define DICT_USERNAME_SEPARATOR '/' static Rados cluster; static int cluster_ref_count; -static const vector explode(const string& str, const char& sep) { - vector v; - stringstream ss(str); // Turn the string into a stream. - string tok; +static const vector explode(const string &str, const char &sep) { + vector v; + stringstream ss(str); // Turn the string into a stream. + string tok; - while (getline(ss, tok, sep)) { - v.push_back(tok); - } + while (getline(ss, tok, sep)) { + v.push_back(tok); + } - return v; + return v; } -DictRados::DictRados() : - pool("librmb") { -} +DictRados::DictRados() : pool("librmb") {} -DictRados::~DictRados() { -} +DictRados::~DictRados() {} int DictRados::init(const string uri, const string &username, string &error_r) { - const char * const *args; - int ret = 0; - int err = 0; - - ret = read_config_from_uri(uri); - - if (cluster_ref_count == 0) { - if (ret >= 0) { - err = cluster.init(nullptr); - i_debug("DictRados::init()=%d", err); - if (err < 0) { - error_r = "Couldn't create the cluster handle! " + string(strerror(-err)); - ret = -1; - } - } - - if (ret >= 0) { - err = cluster.conf_parse_env(nullptr); - i_debug("conf_parse_env()=%d", err); - if (err < 0) { - error_r = "Cannot parse config environment! " + string(strerror(-err)); - ret = -1; - } - } - - if (ret >= 0) { - err = cluster.conf_read_file(nullptr); - i_debug("conf_read_file()=%d", err); - if (err < 0) { - error_r = "Cannot read config file! " + string(strerror(-err)); - ret = -1; - } - } - - if (ret >= 0) { - err = cluster.connect(); - i_debug("connect()=%d", err); - if (err < 0) { - error_r = "Cannot connect to cluster! " + string(strerror(-err)); - ret = -1; - } else { - cluster_ref_count++; - } - } - } - - if (ret >= 0) { - err = cluster.ioctx_create(pool.c_str(), io_ctx); - i_debug("ioctx_create(pool=%s)=%d", pool.c_str(), err); - if (err < 0) { - error_r = t_strdup_printf("Cannot open RADOS pool %s: %s", pool.c_str(), strerror(-err)); - cluster.shutdown(); - cluster_ref_count--; - ret = -1; - } - } - - if (ret < 0) { - i_debug("DictRados::init(uri=%s)=%d/%s, cluster_ref_count=%d", uri.c_str(), -1, error_r.c_str(), cluster_ref_count); - return -1; - } - - set_username(username); - - i_debug("DictRados::init(uri=%s)=%d, cluster_ref_count=%d", uri.c_str(), 0, cluster_ref_count); - return 0; + const char *const *args; + int ret = 0; + int err = 0; + + ret = read_config_from_uri(uri); + + if (cluster_ref_count == 0) { + if (ret >= 0) { + err = cluster.init(nullptr); + i_debug("DictRados::init()=%d", err); + if (err < 0) { + error_r = "Couldn't create the cluster handle! " + string(strerror(-err)); + ret = -1; + } + } + + if (ret >= 0) { + err = cluster.conf_parse_env(nullptr); + i_debug("conf_parse_env()=%d", err); + if (err < 0) { + error_r = "Cannot parse config environment! " + string(strerror(-err)); + ret = -1; + } + } + + if (ret >= 0) { + err = cluster.conf_read_file(nullptr); + i_debug("conf_read_file()=%d", err); + if (err < 0) { + error_r = "Cannot read config file! " + string(strerror(-err)); + ret = -1; + } + } + + if (ret >= 0) { + err = cluster.connect(); + i_debug("connect()=%d", err); + if (err < 0) { + error_r = "Cannot connect to cluster! " + string(strerror(-err)); + ret = -1; + } else { + cluster_ref_count++; + } + } + } + + if (ret >= 0) { + err = cluster.ioctx_create(pool.c_str(), io_ctx); + i_debug("ioctx_create(pool=%s)=%d", pool.c_str(), err); + if (err < 0) { + error_r = t_strdup_printf("Cannot open RADOS pool %s: %s", pool.c_str(), strerror(-err)); + cluster.shutdown(); + cluster_ref_count--; + ret = -1; + } + } + + if (ret < 0) { + i_debug("DictRados::init(uri=%s)=%d/%s, cluster_ref_count=%d", uri.c_str(), -1, error_r.c_str(), cluster_ref_count); + return -1; + } + + set_username(username); + + i_debug("DictRados::init(uri=%s)=%d, cluster_ref_count=%d", uri.c_str(), 0, cluster_ref_count); + return 0; } void DictRados::deinit() { - i_debug("DictRados::deinit(), cluster_ref_count=%d", cluster_ref_count); + i_debug("DictRados::deinit(), cluster_ref_count=%d", cluster_ref_count); - get_io_ctx().close(); + get_io_ctx().close(); - if (cluster_ref_count > 0) { - cluster_ref_count--; - if (cluster_ref_count == 0) { - cluster.shutdown(); - } - } + if (cluster_ref_count > 0) { + cluster_ref_count--; + if (cluster_ref_count == 0) { + cluster.shutdown(); + } + } } -int DictRados::read_config_from_uri(const string & uri) { - int ret = 0; - vector props(explode(uri, ':')); - for (vector::iterator it = props.begin(); it != props.end(); ++it) { - if (it->compare(0, 4, "oid=") == 0) { - oid = it->substr(4); - } else if (it->compare(0, 5, "pool=") == 0) { - pool = it->substr(5); - } else { - ret = -1; - break; - } - } - - return ret; +int DictRados::read_config_from_uri(const string &uri) { + int ret = 0; + vector props(explode(uri, ':')); + for (vector::iterator it = props.begin(); it != props.end(); ++it) { + if (it->compare(0, 4, "oid=") == 0) { + oid = it->substr(4); + } else if (it->compare(0, 5, "pool=") == 0) { + pool = it->substr(5); + } else { + ret = -1; + break; + } + } + + return ret; } -void DictRados::set_username(const std::string& username) { - if (username.find( DICT_USERNAME_SEPARATOR) == string::npos) { - this->username = username; - } else { - /* escape the username */ - this->username = dict_escape_string(username.c_str()); - } +void DictRados::set_username(const std::string &username) { + if (username.find(DICT_USERNAME_SEPARATOR) == string::npos) { + this->username = username; + } else { + /* escape the username */ + this->username = dict_escape_string(username.c_str()); + } } -const string DictRados::get_full_oid(const std::string& key) { - if (key.find(DICT_PATH_SHARED) == 0) { - return get_shared_oid(); - } else if (key.find(DICT_PATH_PRIVATE) == 0) { - return get_private_oid(); - } else { - i_unreached(); - } - return ""; +const string DictRados::get_full_oid(const std::string &key) { + if (key.find(DICT_PATH_SHARED) == 0) { + return get_shared_oid(); + } else if (key.find(DICT_PATH_PRIVATE) == 0) { + return get_private_oid(); + } else { + i_unreached(); + } + return ""; } -const string DictRados::get_shared_oid() { - return this->oid + DICT_USERNAME_SEPARATOR + "shared"; -} +const string DictRados::get_shared_oid() { return this->oid + DICT_USERNAME_SEPARATOR + "shared"; } -const string DictRados::get_private_oid() { - return this->oid + DICT_USERNAME_SEPARATOR + this->username; -} +const string DictRados::get_private_oid() { return this->oid + DICT_USERNAME_SEPARATOR + this->username; } ///////////////////////////// C API ////////////////////////////// struct rados_dict { - struct dict dict; - DictRados *d; + struct dict dict; + DictRados *d; }; int rados_dict_init(struct dict *driver, const char *uri, const struct dict_settings *set, struct dict **dict_r, - const char **error_r) { - struct rados_dict *dict; - const char * const *args; + const char **error_r) { + struct rados_dict *dict; + const char *const *args; - i_debug("rados_dict_init(uri=%s), cluster_ref_count=%d", uri, cluster_ref_count); + i_debug("rados_dict_init(uri=%s), cluster_ref_count=%d", uri, cluster_ref_count); - dict = i_new(struct rados_dict, 1); - dict->d = new DictRados(); - DictRados *d = dict->d; + dict = i_new(struct rados_dict, 1); + dict->d = new DictRados(); + DictRados *d = dict->d; - string error_msg; - int ret = d->init(uri, set->username, error_msg); + string error_msg; + int ret = d->init(uri, set->username, error_msg); - if (ret < 0) { - delete dict->d; - dict->d = nullptr; - i_free(dict); - *error_r = t_strdup_printf("%s", error_msg.c_str()); - return -1; - } + if (ret < 0) { + delete dict->d; + dict->d = nullptr; + i_free(dict); + *error_r = t_strdup_printf("%s", error_msg.c_str()); + return -1; + } - dict->dict = *driver; - *dict_r = &dict->dict; + dict->dict = *driver; + *dict_r = &dict->dict; - return 0; + return 0; } void rados_dict_deinit(struct dict *_dict) { - struct rados_dict *dict = (struct rados_dict *) _dict; - DictRados *d = ((struct rados_dict *) _dict)->d; + struct rados_dict *dict = (struct rados_dict *)_dict; + DictRados *d = ((struct rados_dict *)_dict)->d; - i_debug("rados_dict_deinit(), cluster_ref_count=%d", cluster_ref_count); + i_debug("rados_dict_deinit(), cluster_ref_count=%d", cluster_ref_count); - d->deinit(); - delete dict->d; - dict->d = nullptr; + d->deinit(); + delete dict->d; + dict->d = nullptr; - i_free(_dict); + i_free(_dict); } int rados_dict_wait(struct dict *_dict) { - struct rados_dict *dict = (struct rados_dict *) _dict; - DictRados *d = ((struct rados_dict *) _dict)->d; + struct rados_dict *dict = (struct rados_dict *)_dict; + DictRados *d = ((struct rados_dict *)_dict)->d; - i_debug("rados_dict_wait(), n=%lu", d->completions.size()); + i_debug("rados_dict_wait(), n=%lu", d->completions.size()); - // TODO timeout? - while (!d->completions.empty()) { - auto c = d->completions.front(); - if (c.get() != nullptr) - c->wait_for_complete_and_cb(); - } + // TODO(p.mauritius): wait timeout? + while (!d->completions.empty()) { + auto c = d->completions.front(); + if (c.get() != nullptr) + c->wait_for_complete_and_cb(); + } - return 0; + return 0; } -static void rados_lookup_complete_callback(rados_completion_t comp, void* arg); +static void rados_lookup_complete_callback(rados_completion_t comp, void *arg); class rados_dict_lookup_context { -public: - DictRados *dict; - ObjectReadOperation read_op; - map result_map; - int r_val = -1; - bufferlist bl; - - AioCompletionPtr completion; - string key; - string value; - void *context = nullptr; - dict_lookup_callback_t *callback; - - rados_dict_lookup_context(DictRados *dict) : - callback(nullptr) { - this->dict = dict; - completion = std::make_shared( - *librados::Rados::aio_create_completion(this, rados_lookup_complete_callback, nullptr)); - } - - ~rados_dict_lookup_context() { - i_debug("~rados_dict_lookup_context()"); - // completion->release(); - // completion = nullptr; - } - + public: + DictRados *dict; + ObjectReadOperation read_op; + map result_map; + int r_val = -1; + bufferlist bl; + + AioCompletionPtr completion; + string key; + string value; + void *context = nullptr; + dict_lookup_callback_t *callback; + + rados_dict_lookup_context(DictRados *dict) : callback(nullptr) { + this->dict = dict; + completion = std::make_shared( + *librados::Rados::aio_create_completion(this, rados_lookup_complete_callback, nullptr)); + } + + ~rados_dict_lookup_context() { + i_debug("~rados_dict_lookup_context()"); + // completion->release(); + // completion = nullptr; + } }; -static void rados_lookup_complete_callback(rados_completion_t comp, void* arg) { - rados_dict_lookup_context *lc = (rados_dict_lookup_context *) arg; - - struct dict_lookup_result result; - result.value = nullptr; - result.values = nullptr; - result.error = nullptr; - result.ret = DICT_COMMIT_RET_OK; - - const char *values[2]; - - i_debug("rados_lookup_complete_callback(%s): ret=%d(%s)", lc->key.c_str(), lc->completion->get_return_value(), - strerror(-lc->completion->get_return_value())); - i_debug("rados_lookup_complete_callback(%s): r_val=%d(%s)", lc->key.c_str(), lc->r_val, strerror(-lc->r_val)); - - lc->dict->completions.remove(lc->completion); - - int ret = lc->completion->get_return_value(); - - if (ret == 0) { - auto it = lc->result_map.find(lc->key); - if (it != lc->result_map.end()) { - lc->value = it->second.to_str(); - i_debug("rados_lookup_complete_callback('%s')='%s'", it->first.c_str(), lc->value.c_str()); - result.value = lc->value.c_str(); - result.values = values; - values[0] = lc->value.c_str(); - values[1] = nullptr; - result.ret = DICT_COMMIT_RET_OK; - } - } else { - if (ret == -ENOENT) { - result.ret = DICT_COMMIT_RET_NOTFOUND; - } else { - result.ret = DICT_COMMIT_RET_FAILED; - } - } - - if (lc->callback != nullptr) { - i_debug("rados_lookup_complete_callback(%s) call callback result=%d", lc->key.c_str(), result.ret); - lc->callback(&result, lc->context); - } - - delete lc; +static void rados_lookup_complete_callback(rados_completion_t comp, void *arg) { + rados_dict_lookup_context *lc = reinterpret_cast(arg); + + struct dict_lookup_result result; + result.value = nullptr; + result.values = nullptr; + result.error = nullptr; + result.ret = DICT_COMMIT_RET_OK; + + const char *values[2]; + + i_debug("rados_lookup_complete_callback(%s): ret=%d(%s)", lc->key.c_str(), lc->completion->get_return_value(), + strerror(-lc->completion->get_return_value())); + i_debug("rados_lookup_complete_callback(%s): r_val=%d(%s)", lc->key.c_str(), lc->r_val, strerror(-lc->r_val)); + + lc->dict->completions.remove(lc->completion); + + int ret = lc->completion->get_return_value(); + + if (ret == 0) { + auto it = lc->result_map.find(lc->key); + if (it != lc->result_map.end()) { + lc->value = it->second.to_str(); + i_debug("rados_lookup_complete_callback('%s')='%s'", it->first.c_str(), lc->value.c_str()); + result.value = lc->value.c_str(); + result.values = values; + values[0] = lc->value.c_str(); + values[1] = nullptr; + result.ret = DICT_COMMIT_RET_OK; + } + } else { + if (ret == -ENOENT) { + result.ret = DICT_COMMIT_RET_NOTFOUND; + } else { + result.ret = DICT_COMMIT_RET_FAILED; + } + } + + if (lc->callback != nullptr) { + i_debug("rados_lookup_complete_callback(%s) call callback result=%d", lc->key.c_str(), result.ret); + lc->callback(&result, lc->context); + } + + delete lc; } void rados_dict_lookup_async(struct dict *_dict, const char *key, dict_lookup_callback_t *callback, void *context) { - DictRados *d = ((struct rados_dict *) _dict)->d; - set keys; - keys.insert(key); - auto lc = new rados_dict_lookup_context(d); - - i_debug("rados_dict_lookup_async(%s)", key); - - lc->key = key; - lc->context = context; - lc->callback = callback; - lc->read_op.omap_get_vals_by_keys(keys, &lc->result_map, &lc->r_val); - - int err = d->get_io_ctx().aio_operate(d->get_full_oid(key), lc->completion.get(), &lc->read_op, LIBRADOS_OPERATION_NOFLAG, - &lc->bl); - - if (err < 0) { - if (lc->callback != nullptr) { - struct dict_lookup_result result; - result.value = nullptr; - result.error = nullptr; - result.ret = DICT_COMMIT_RET_FAILED; - - i_debug("rados_dict_lookup_async() call callback func..."); - lc->callback(&result, context); - } - delete lc; - } else { - d->completions.push_back(lc->completion); - } + DictRados *d = ((struct rados_dict *)_dict)->d; + set keys; + keys.insert(key); + auto lc = new rados_dict_lookup_context(d); + + i_debug("rados_dict_lookup_async(%s)", key); + + lc->key = key; + lc->context = context; + lc->callback = callback; + lc->read_op.omap_get_vals_by_keys(keys, &lc->result_map, &lc->r_val); + + int err = d->get_io_ctx().aio_operate(d->get_full_oid(key), lc->completion.get(), &lc->read_op, + LIBRADOS_OPERATION_NOFLAG, &lc->bl); + + if (err < 0) { + if (lc->callback != nullptr) { + struct dict_lookup_result result; + result.value = nullptr; + result.error = nullptr; + result.ret = DICT_COMMIT_RET_FAILED; + + i_debug("rados_dict_lookup_async() call callback func..."); + lc->callback(&result, context); + } + delete lc; + } else { + d->completions.push_back(lc->completion); + } } static void rados_dict_lookup_sync_callback(const struct dict_lookup_result *result, void *ctx) { - struct dict_lookup_result *res = (struct dict_lookup_result *) ctx; - res->ret = result->ret; - res->value = t_strdup(result->value); - res->error = t_strdup(result->error); - i_debug("rados_dict_lookup_sync_callback() ret=%d value=%s", result->ret, result->value); + struct dict_lookup_result *res = (struct dict_lookup_result *)ctx; + res->ret = result->ret; + res->value = t_strdup(result->value); + res->error = t_strdup(result->error); + i_debug("rados_dict_lookup_sync_callback() ret=%d value=%s", result->ret, result->value); } int rados_dict_lookup(struct dict *dict, pool_t pool, const char *key, const char **value_r) { - pool_t orig_pool = pool; - struct dict_lookup_result res; - int ret; + pool_t orig_pool = pool; + struct dict_lookup_result res; + int ret; - i_debug("rados_dict_lookup(%s)", key); + i_debug("rados_dict_lookup(%s)", key); - rados_dict_lookup_async(dict, key, rados_dict_lookup_sync_callback, &res); + rados_dict_lookup_async(dict, key, rados_dict_lookup_sync_callback, &res); - if ((ret = rados_dict_wait(dict)) == 0) { - ret = res.ret; - if (res.ret > 0) { - *value_r = p_strdup(orig_pool, res.value); - } - } + if ((ret = rados_dict_wait(dict)) == 0) { + ret = res.ret; + if (res.ret > 0) { + *value_r = p_strdup(orig_pool, res.value); + } + } - i_debug("rados_dict_lookup(%s)=%s", key, *value_r); + i_debug("rados_dict_lookup(%s)=%s", key, *value_r); - return ret; + return ret; } class rados_dict_transaction_context { -public: - struct dict_transaction_context ctx; - bool atomic_inc_not_found; - - ObjectWriteOperation write_op_private; - AioCompletionPtr completion_private; - bool dirty_private; - - ObjectWriteOperation write_op_shared; - AioCompletionPtr completion_shared; - bool dirty_shared; - - void *context = nullptr; - dict_transaction_commit_callback_t *callback; - - rados_dict_transaction_context() { - dirty_private = false; - dirty_shared = false; - completion_private = std::make_shared(*librados::Rados::aio_create_completion()); - completion_shared = std::make_shared(*librados::Rados::aio_create_completion()); - callback = nullptr; - atomic_inc_not_found = false; - } - - ~rados_dict_transaction_context() { - i_debug("~rados_dict_transaction_context()"); -// completion_private->release(); -// completion_shared->release(); - } - - ObjectWriteOperation &get_op(const std::string& key) { - if (key.find(DICT_PATH_SHARED) == 0) { - dirty_shared |= true; - return write_op_shared; - } else if (key.find(DICT_PATH_PRIVATE) == 0) { - dirty_private |= true; - return write_op_private; - } - i_unreached(); - } - + public: + struct dict_transaction_context ctx; + bool atomic_inc_not_found; + + ObjectWriteOperation write_op_private; + AioCompletionPtr completion_private; + bool dirty_private; + + ObjectWriteOperation write_op_shared; + AioCompletionPtr completion_shared; + bool dirty_shared; + + void *context = nullptr; + dict_transaction_commit_callback_t *callback; + + rados_dict_transaction_context() { + dirty_private = false; + dirty_shared = false; + completion_private = std::make_shared(*librados::Rados::aio_create_completion()); + completion_shared = std::make_shared(*librados::Rados::aio_create_completion()); + callback = nullptr; + atomic_inc_not_found = false; + } + + ~rados_dict_transaction_context() { + i_debug("~rados_dict_transaction_context()"); + // completion_private->release(); + // completion_shared->release(); + } + + ObjectWriteOperation &get_op(const std::string &key) { + if (key.find(DICT_PATH_SHARED) == 0) { + dirty_shared |= true; + return write_op_shared; + } else if (key.find(DICT_PATH_PRIVATE) == 0) { + dirty_private |= true; + return write_op_private; + } + i_unreached(); + } }; struct dict_transaction_context *rados_transaction_init(struct dict *_dict) { - struct rados_dict_transaction_context *ctx; + struct rados_dict_transaction_context *ctx; - ctx = new rados_dict_transaction_context(); - ctx->ctx.dict = _dict; + ctx = new rados_dict_transaction_context(); + ctx->ctx.dict = _dict; - ctx->ctx.timestamp.tv_sec = 0; - ctx->ctx.timestamp.tv_nsec = 0; + ctx->ctx.timestamp.tv_sec = 0; + ctx->ctx.timestamp.tv_nsec = 0; - return &ctx->ctx; + return &ctx->ctx; } void rados_dict_set_timestamp(struct dict_transaction_context *_ctx, const struct timespec *ts) { - struct rados_dict_transaction_context *ctx = (struct rados_dict_transaction_context *) _ctx; - DictRados *d = ((struct rados_dict *) _ctx->dict)->d; + struct rados_dict_transaction_context *ctx = (struct rados_dict_transaction_context *)_ctx; + DictRados *d = ((struct rados_dict *)_ctx->dict)->d; - struct timespec t = { ts->tv_sec, ts->tv_nsec }; + struct timespec t = {ts->tv_sec, ts->tv_nsec}; - if (ts != NULL) { - _ctx->timestamp.tv_sec = t.tv_sec; - _ctx->timestamp.tv_nsec = t.tv_nsec; - ctx->write_op_private.mtime2(&t); - ctx->write_op_shared.mtime2(&t); - } + if (ts != NULL) { + _ctx->timestamp.tv_sec = t.tv_sec; + _ctx->timestamp.tv_nsec = t.tv_nsec; + ctx->write_op_private.mtime2(&t); + ctx->write_op_shared.mtime2(&t); + } } -static void rados_transaction_private_complete_callback(rados_completion_t comp, void* arg) { - rados_dict_transaction_context *c = (rados_dict_transaction_context *) arg; - DictRados *d = ((struct rados_dict *) c->ctx.dict)->d; +static void rados_transaction_private_complete_callback(rados_completion_t comp, void *arg) { + rados_dict_transaction_context *c = reinterpret_cast(arg); + DictRados *d = ((struct rados_dict *)c->ctx.dict)->d; - i_debug("rados_transaction_private_complete_callback() %d %d", c->completion_private->is_complete_and_cb(), - c->completion_shared->is_complete_and_cb()); + i_debug("rados_transaction_private_complete_callback() %d %d", c->completion_private->is_complete_and_cb(), + c->completion_shared->is_complete_and_cb()); - bool failed = c->completion_private->get_return_value() < 0; - bool finished = !c->dirty_shared; + bool failed = c->completion_private->get_return_value() < 0; + bool finished = !c->dirty_shared; - d->completions.remove(c->completion_private); + d->completions.remove(c->completion_private); - if (finished || c->completion_shared->is_complete_and_cb()) { - failed |= c->completion_shared->get_return_value() < 0; - finished = true; - } + if (finished || c->completion_shared->is_complete_and_cb()) { + failed |= c->completion_shared->get_return_value() < 0; + finished = true; + } - if (finished) { - if (c->callback != nullptr) { - i_debug("rados_transaction_private_complete_callback() call callback func..."); - c->callback(failed ? DICT_COMMIT_RET_FAILED : DICT_COMMIT_RET_OK, c->context); - } + if (finished) { + if (c->callback != nullptr) { + i_debug("rados_transaction_private_complete_callback() call callback func..."); + c->callback(failed ? DICT_COMMIT_RET_FAILED : DICT_COMMIT_RET_OK, c->context); + } - delete c; - } + delete c; + } } -static void rados_transaction_shared_complete_callback(rados_completion_t comp, void* arg) { - rados_dict_transaction_context *c = (rados_dict_transaction_context *) arg; - DictRados *d = ((struct rados_dict *) c->ctx.dict)->d; +static void rados_transaction_shared_complete_callback(rados_completion_t comp, void *arg) { + rados_dict_transaction_context *c = reinterpret_cast(arg); + DictRados *d = ((struct rados_dict *)c->ctx.dict)->d; - i_debug("rados_transaction_shared_complete_callback() %d %d", c->completion_private->is_complete_and_cb(), - c->completion_shared->is_complete_and_cb()); + i_debug("rados_transaction_shared_complete_callback() %d %d", c->completion_private->is_complete_and_cb(), + c->completion_shared->is_complete_and_cb()); - bool failed = c->completion_shared->get_return_value() < 0; - bool finished = !c->dirty_private; + bool failed = c->completion_shared->get_return_value() < 0; + bool finished = !c->dirty_private; - d->completions.remove(c->completion_shared); + d->completions.remove(c->completion_shared); - if (finished || c->completion_private->is_complete_and_cb()) { - failed |= c->completion_private->get_return_value() < 0; - finished = true; - } + if (finished || c->completion_private->is_complete_and_cb()) { + failed |= c->completion_private->get_return_value() < 0; + finished = true; + } - if (finished) { - if (c->callback != nullptr) { - i_debug("rados_transaction_shared_complete_callback() call callback func..."); - c->callback(failed ? DICT_COMMIT_RET_FAILED : DICT_COMMIT_RET_OK, c->context); - } + if (finished) { + if (c->callback != nullptr) { + i_debug("rados_transaction_shared_complete_callback() call callback func..."); + c->callback(failed ? DICT_COMMIT_RET_FAILED : DICT_COMMIT_RET_OK, c->context); + } - delete c; - } + delete c; + } } -int rados_transaction_commit(struct dict_transaction_context *_ctx, bool async, dict_transaction_commit_callback_t *callback, - void *context) { - struct rados_dict_transaction_context *ctx = (struct rados_dict_transaction_context *) _ctx; - DictRados *d = ((struct rados_dict *) _ctx->dict)->d; - - bool failed = false; - - if (_ctx->changed) { - ctx->context = context; - ctx->callback = callback; - - if (async) { - ctx->completion_private->set_complete_callback(ctx, rados_transaction_private_complete_callback); - ctx->completion_shared->set_complete_callback(ctx, rados_transaction_shared_complete_callback); - } - - if (!failed && ctx->dirty_private) { - i_debug("rados_transaction_commit() operate(%s)", d->get_private_oid().c_str()); - failed = d->get_io_ctx().aio_operate(d->get_private_oid(), ctx->completion_private.get(), &ctx->write_op_private) < 0; - if (async) - d->completions.push_back(ctx->completion_private); - } - - if (!failed && ctx->dirty_shared) { - i_debug("rados_transaction_commit() operate(%s)", d->get_shared_oid().c_str()); - failed = d->get_io_ctx().aio_operate(d->get_shared_oid(), ctx->completion_shared.get(), &ctx->write_op_shared) < 0; - if (async) - d->completions.push_back(ctx->completion_shared); - } - - if (!failed && !async) { - if (ctx->dirty_private) { - failed |= ctx->completion_private->wait_for_complete_and_cb() < 0; - failed |= ctx->completion_private->get_return_value() < 0; - } - if (ctx->dirty_shared) { - failed |= ctx->completion_shared->wait_for_complete_and_cb() < 0; - failed |= ctx->completion_shared->get_return_value() < 0; - } - if (callback != NULL) - callback(failed ? DICT_COMMIT_RET_FAILED : DICT_COMMIT_RET_OK, context); - } - - if (!async) { - delete ctx; - } - - } - - return failed ? DICT_COMMIT_RET_FAILED : DICT_COMMIT_RET_OK; +int rados_transaction_commit(struct dict_transaction_context *_ctx, bool async, + dict_transaction_commit_callback_t *callback, void *context) { + rados_dict_transaction_context *ctx = reinterpret_cast(_ctx); + DictRados *d = ((struct rados_dict *)_ctx->dict)->d; + + bool failed = false; + + if (_ctx->changed) { + ctx->context = context; + ctx->callback = callback; + + if (async) { + ctx->completion_private->set_complete_callback(ctx, rados_transaction_private_complete_callback); + ctx->completion_shared->set_complete_callback(ctx, rados_transaction_shared_complete_callback); + } + + if (!failed && ctx->dirty_private) { + i_debug("rados_transaction_commit() operate(%s)", d->get_private_oid().c_str()); + failed = + d->get_io_ctx().aio_operate(d->get_private_oid(), ctx->completion_private.get(), &ctx->write_op_private) < 0; + if (async) + d->completions.push_back(ctx->completion_private); + } + + if (!failed && ctx->dirty_shared) { + i_debug("rados_transaction_commit() operate(%s)", d->get_shared_oid().c_str()); + failed = + d->get_io_ctx().aio_operate(d->get_shared_oid(), ctx->completion_shared.get(), &ctx->write_op_shared) < 0; + if (async) + d->completions.push_back(ctx->completion_shared); + } + + if (!failed && !async) { + if (ctx->dirty_private) { + failed |= ctx->completion_private->wait_for_complete_and_cb() < 0; + failed |= ctx->completion_private->get_return_value() < 0; + } + if (ctx->dirty_shared) { + failed |= ctx->completion_shared->wait_for_complete_and_cb() < 0; + failed |= ctx->completion_shared->get_return_value() < 0; + } + if (callback != NULL) + callback(failed ? DICT_COMMIT_RET_FAILED : DICT_COMMIT_RET_OK, context); + } + + if (!async) { + delete ctx; + } + } + + return failed ? DICT_COMMIT_RET_FAILED : DICT_COMMIT_RET_OK; } void rados_transaction_rollback(struct dict_transaction_context *_ctx) { - struct rados_dict_transaction_context *ctx = (struct rados_dict_transaction_context *) _ctx; + struct rados_dict_transaction_context *ctx = (struct rados_dict_transaction_context *)_ctx; - i_debug("rados_transaction_rollback()"); + i_debug("rados_transaction_rollback()"); - delete ctx; + delete ctx; } void rados_set(struct dict_transaction_context *_ctx, const char *key, const char *value) { - struct rados_dict_transaction_context *ctx = (struct rados_dict_transaction_context *) _ctx; - DictRados *d = ((struct rados_dict *) _ctx->dict)->d; + struct rados_dict_transaction_context *ctx = (struct rados_dict_transaction_context *)_ctx; + DictRados *d = ((struct rados_dict *)_ctx->dict)->d; - i_debug("rados_set(%s,%s)", key, value); + i_debug("rados_set(%s,%s)", key, value); - _ctx->changed = TRUE; + _ctx->changed = TRUE; - std::map map; - bufferlist bl; - bl.append(value); - map.insert(pair(key, bl)); - ctx->get_op(key).omap_set(map); + std::map map; + bufferlist bl; + bl.append(value); + map.insert(pair(key, bl)); + ctx->get_op(key).omap_set(map); } void rados_unset(struct dict_transaction_context *_ctx, const char *key) { - struct rados_dict_transaction_context *ctx = (struct rados_dict_transaction_context *) _ctx; - DictRados *d = ((struct rados_dict *) _ctx->dict)->d; + struct rados_dict_transaction_context *ctx = (struct rados_dict_transaction_context *)_ctx; + DictRados *d = ((struct rados_dict *)_ctx->dict)->d; - i_debug("rados_unset(%s)", key); + i_debug("rados_unset(%s)", key); - _ctx->changed = TRUE; + _ctx->changed = TRUE; - set keys; - keys.insert(key); - ctx->get_op(key).omap_rm_keys(keys); + set keys; + keys.insert(key); + ctx->get_op(key).omap_rm_keys(keys); } void rados_atomic_inc(struct dict_transaction_context *_ctx, const char *key, long long diff) { - struct rados_dict_transaction_context *ctx = (struct rados_dict_transaction_context *) _ctx; - DictRados *d = ((struct rados_dict *) _ctx->dict)->d; + struct rados_dict_transaction_context *ctx = (struct rados_dict_transaction_context *)_ctx; + DictRados *d = ((struct rados_dict *)_ctx->dict)->d; - i_debug("rados_atomic_inc(%s,%lld)", key, diff); + i_debug("rados_atomic_inc(%s,%lld)", key, diff); - _ctx->changed = TRUE; + _ctx->changed = TRUE; - set keys; - keys.insert(key); + set keys; + keys.insert(key); -// TODO implement + // TODO(p.mauritius): implement } class kv_map { -public: - int rval = -1; - std::string key; - std::map map; - typename std::map::iterator map_iter; + public: + int rval = -1; + std::string key; + std::map map; + typename std::map::iterator map_iter; }; class rados_dict_iterate_context { -public: - struct dict_iterate_context ctx; - enum dict_iterate_flags flags; - bool failed = FALSE; + public: + struct dict_iterate_context ctx; + enum dict_iterate_flags flags; + bool failed = FALSE; - std::vector results; - typename std::vector::iterator results_iter; + std::vector results; + typename std::vector::iterator results_iter; }; -struct dict_iterate_context * -rados_dict_iterate_init(struct dict *_dict, const char * const *paths, enum dict_iterate_flags flags) { - DictRados *d = ((struct rados_dict *) _dict)->d; - - i_debug("rados_dict_iterate_init()"); - - /* these flags are not supported for now */ - i_assert((flags & DICT_ITERATE_FLAG_SORT_BY_VALUE) == 0); - i_assert((flags & DICT_ITERATE_FLAG_SORT_BY_KEY) == 0); - i_assert((flags & DICT_ITERATE_FLAG_ASYNC) == 0); - - auto iter = new rados_dict_iterate_context(); - - iter->ctx.dict = _dict; - iter->flags = flags; - - set private_keys; - set shared_keys; - while (*paths) { - string key = *paths++; - if (key.find(DICT_PATH_SHARED) == 0) { - shared_keys.insert(key); - } else if (key.find(DICT_PATH_PRIVATE) == 0) { - private_keys.insert(key); - } - } - - if (private_keys.size() + shared_keys.size() > 0) { - AioCompletion *private_read_completion = librados::Rados::aio_create_completion(); - ObjectReadOperation private_read_op; - AioCompletion *shared_read_completion = librados::Rados::aio_create_completion(); - ObjectReadOperation shared_read_op; - - if (flags & DICT_ITERATE_FLAG_EXACT_KEY) { - iter->results.reserve(2); - } else { - iter->results.reserve(private_keys.size() + shared_keys.size()); - } - - if (private_keys.size() > 0) { - i_debug("rados_dict_iterate_init() private query"); - - if (flags & DICT_ITERATE_FLAG_EXACT_KEY) { - iter->results.emplace_back(); - private_read_op.omap_get_vals_by_keys(private_keys, &iter->results.back().map, &iter->results.back().rval); - } else { - int i = 0; - for (auto k : private_keys) { - iter->results.emplace_back(); - iter->results.back().key = k; - private_read_op.omap_get_vals2("", k, LONG_MAX, &iter->results.back().map, nullptr, &iter->results.back().rval); - } - } - - bufferlist bl; - int err = d->get_io_ctx().aio_operate(d->get_full_oid(DICT_PATH_PRIVATE), private_read_completion, &private_read_op, - &bl); - i_debug("rados_dict_iterate_init(): private err=%d(%s)", err, strerror(-err)); - iter->failed = err < 0; - } - - if (!iter->failed && shared_keys.size() > 0) { - i_debug("rados_dict_iterate_init() shared query"); - - if (flags & DICT_ITERATE_FLAG_EXACT_KEY) { - iter->results.emplace_back(); - shared_read_op.omap_get_vals_by_keys(shared_keys, &iter->results.back().map, &iter->results.back().rval); - } else { - int i = 0; - for (auto k : shared_keys) { - iter->results.emplace_back(); - iter->results.back().key = k; - shared_read_op.omap_get_vals2("", k, LONG_MAX, &iter->results.back().map, nullptr, &iter->results.back().rval); - } - } - - bufferlist bl; - int err = d->get_io_ctx().aio_operate(d->get_full_oid(DICT_PATH_SHARED), shared_read_completion, &shared_read_op, &bl); - i_debug("rados_dict_iterate_init(): shared err=%d(%s)", err, strerror(-err)); - iter->failed = err < 0; - } - - if (!iter->failed) { - int err = private_read_completion->wait_for_complete_and_cb(); - err = private_read_completion->get_return_value(); - iter->failed = err < 0; - } - - if (!iter->failed) { - int err = shared_read_completion->wait_for_complete(); - shared_read_completion->get_return_value(); - iter->failed = err < 0; - } - - private_read_completion->release(); - shared_read_completion->release(); - - if (!iter->failed) { - for (auto r : iter->results) { - i_debug("rados_dict_iterate_init(): r_val=%d(%s)", r.rval, strerror(-r.rval)); - iter->failed |= (r.rval < 0); - } - } - - if (!iter->failed) { - auto ri = iter->results_iter = iter->results.begin(); - iter->results_iter->map_iter = iter->results_iter->map.begin(); - } else { - i_debug("rados_dict_iterate_init() failed"); - } - } else { - i_debug("rados_dict_iterate_init() no keys"); - iter->failed = true; - } - - return &iter->ctx; +struct dict_iterate_context *rados_dict_iterate_init(struct dict *_dict, const char *const *paths, + enum dict_iterate_flags flags) { + DictRados *d = ((struct rados_dict *)_dict)->d; + + i_debug("rados_dict_iterate_init()"); + + /* these flags are not supported for now */ + i_assert((flags & DICT_ITERATE_FLAG_SORT_BY_VALUE) == 0); + i_assert((flags & DICT_ITERATE_FLAG_SORT_BY_KEY) == 0); + i_assert((flags & DICT_ITERATE_FLAG_ASYNC) == 0); + + auto iter = new rados_dict_iterate_context(); + + iter->ctx.dict = _dict; + iter->flags = flags; + + set private_keys; + set shared_keys; + while (*paths) { + string key = *paths++; + if (key.find(DICT_PATH_SHARED) == 0) { + shared_keys.insert(key); + } else if (key.find(DICT_PATH_PRIVATE) == 0) { + private_keys.insert(key); + } + } + + if (private_keys.size() + shared_keys.size() > 0) { + AioCompletion *private_read_completion = librados::Rados::aio_create_completion(); + ObjectReadOperation private_read_op; + AioCompletion *shared_read_completion = librados::Rados::aio_create_completion(); + ObjectReadOperation shared_read_op; + + if (flags & DICT_ITERATE_FLAG_EXACT_KEY) { + iter->results.reserve(2); + } else { + iter->results.reserve(private_keys.size() + shared_keys.size()); + } + + if (private_keys.size() > 0) { + i_debug("rados_dict_iterate_init() private query"); + + if (flags & DICT_ITERATE_FLAG_EXACT_KEY) { + iter->results.emplace_back(); + private_read_op.omap_get_vals_by_keys(private_keys, &iter->results.back().map, &iter->results.back().rval); + } else { + int i = 0; + for (auto k : private_keys) { + iter->results.emplace_back(); + iter->results.back().key = k; + private_read_op.omap_get_vals2("", k, LONG_MAX, &iter->results.back().map, nullptr, + &iter->results.back().rval); + } + } + + bufferlist bl; + int err = d->get_io_ctx().aio_operate(d->get_full_oid(DICT_PATH_PRIVATE), private_read_completion, + &private_read_op, &bl); + i_debug("rados_dict_iterate_init(): private err=%d(%s)", err, strerror(-err)); + iter->failed = err < 0; + } + + if (!iter->failed && shared_keys.size() > 0) { + i_debug("rados_dict_iterate_init() shared query"); + + if (flags & DICT_ITERATE_FLAG_EXACT_KEY) { + iter->results.emplace_back(); + shared_read_op.omap_get_vals_by_keys(shared_keys, &iter->results.back().map, &iter->results.back().rval); + } else { + int i = 0; + for (auto k : shared_keys) { + iter->results.emplace_back(); + iter->results.back().key = k; + shared_read_op.omap_get_vals2("", k, LONG_MAX, &iter->results.back().map, nullptr, + &iter->results.back().rval); + } + } + + bufferlist bl; + int err = + d->get_io_ctx().aio_operate(d->get_full_oid(DICT_PATH_SHARED), shared_read_completion, &shared_read_op, &bl); + i_debug("rados_dict_iterate_init(): shared err=%d(%s)", err, strerror(-err)); + iter->failed = err < 0; + } + + if (!iter->failed) { + int err = private_read_completion->wait_for_complete_and_cb(); + err = private_read_completion->get_return_value(); + iter->failed = err < 0; + } + + if (!iter->failed) { + int err = shared_read_completion->wait_for_complete(); + shared_read_completion->get_return_value(); + iter->failed = err < 0; + } + + private_read_completion->release(); + shared_read_completion->release(); + + if (!iter->failed) { + for (auto r : iter->results) { + i_debug("rados_dict_iterate_init(): r_val=%d(%s)", r.rval, strerror(-r.rval)); + iter->failed |= (r.rval < 0); + } + } + + if (!iter->failed) { + auto ri = iter->results_iter = iter->results.begin(); + iter->results_iter->map_iter = iter->results_iter->map.begin(); + } else { + i_debug("rados_dict_iterate_init() failed"); + } + } else { + i_debug("rados_dict_iterate_init() no keys"); + iter->failed = true; + } + + return &iter->ctx; } bool rados_dict_iterate(struct dict_iterate_context *ctx, const char **key_r, const char **value_r) { - struct rados_dict_iterate_context *iter = (struct rados_dict_iterate_context *) ctx; - i_debug("rados_dict_iterate()"); + struct rados_dict_iterate_context *iter = (struct rados_dict_iterate_context *)ctx; + i_debug("rados_dict_iterate()"); - *key_r = NULL; - *value_r = NULL; + *key_r = NULL; + *value_r = NULL; - if (iter->failed) - return FALSE; + if (iter->failed) + return FALSE; - while (iter->results_iter->map_iter == iter->results_iter->map.end()) { - if (++iter->results_iter == iter->results.end()) - return FALSE; - iter->results_iter->map_iter = iter->results_iter->map.begin(); - } + while (iter->results_iter->map_iter == iter->results_iter->map.end()) { + if (++iter->results_iter == iter->results.end()) + return FALSE; + iter->results_iter->map_iter = iter->results_iter->map.begin(); + } - auto map_iter = iter->results_iter->map_iter++; + auto map_iter = iter->results_iter->map_iter++; - if ((iter->flags & DICT_ITERATE_FLAG_RECURSE) != 0) { -// match everything - } else if ((iter->flags & DICT_ITERATE_FLAG_EXACT_KEY) != 0) { -// prefiltered by query, match everything - } else { - if (map_iter->first.find('/', iter->results_iter->key.length()) != string::npos) { - return rados_dict_iterate(ctx, key_r, value_r); - } - } + if ((iter->flags & DICT_ITERATE_FLAG_RECURSE) != 0) { + // match everything + } else if ((iter->flags & DICT_ITERATE_FLAG_EXACT_KEY) != 0) { + // prefiltered by query, match everything + } else { + if (map_iter->first.find('/', iter->results_iter->key.length()) != string::npos) { + return rados_dict_iterate(ctx, key_r, value_r); + } + } - i_debug("Iterator found key = '%s', value = '%s'", map_iter->first.c_str(), map_iter->second.to_str().c_str()); - *key_r = i_strdup(map_iter->first.c_str()); + i_debug("Iterator found key = '%s', value = '%s'", map_iter->first.c_str(), map_iter->second.to_str().c_str()); + *key_r = i_strdup(map_iter->first.c_str()); - if ((iter->flags & DICT_ITERATE_FLAG_NO_VALUE) == 0) { - *value_r = i_strdup(map_iter->second.to_str().c_str()); - } + if ((iter->flags & DICT_ITERATE_FLAG_NO_VALUE) == 0) { + *value_r = i_strdup(map_iter->second.to_str().c_str()); + } - return TRUE; + return TRUE; } int rados_dict_iterate_deinit(struct dict_iterate_context *ctx) { - struct rados_dict_iterate_context *iter = (struct rados_dict_iterate_context *) ctx; + struct rados_dict_iterate_context *iter = (struct rados_dict_iterate_context *)ctx; - int ret = iter->failed ? -1 : 0; - i_debug("rados_dict_iterate_deinit()=%d", ret); + int ret = iter->failed ? -1 : 0; + i_debug("rados_dict_iterate_deinit()=%d", ret); - delete iter; + delete iter; - return ret; + return ret; } diff --git a/src/dict-rados/DictRados.h b/src/dict-rados/DictRados.h index 0bfcbe18..6c0721e6 100644 --- a/src/dict-rados/DictRados.h +++ b/src/dict-rados/DictRados.h @@ -1,5 +1,7 @@ -#ifndef DOVECOT_RADOS_PLUGIN_DICT_RADOS_DICTRADOS_H_ -#define DOVECOT_RADOS_PLUGIN_DICT_RADOS_DICTRADOS_H_ +// Copyright 2017 + +#ifndef SRC_DICT_RADOS_DICTRADOS_H_ +#define SRC_DICT_RADOS_DICTRADOS_H_ #include "lib.h" #include "dict-private.h" @@ -30,4 +32,4 @@ extern int rados_dict_iterate_deinit(struct dict_iterate_context *ctx); extern void rados_dict_set_timestamp(struct dict_transaction_context *ctx, const struct timespec *ts); -#endif /* DOVECOT_RADOS_PLUGIN_DICT_RADOS_DICTRADOS_H_ */ +#endif // SRC_DICT_RADOS_DICTRADOS_H_ diff --git a/src/storage-rbox/rbox-save.c b/src/storage-rbox/rbox-save.c index f24619db..fb338a79 100644 --- a/src/storage-rbox/rbox-save.c +++ b/src/storage-rbox/rbox-save.c @@ -21,441 +21,437 @@ #include "rbox-sync.h" #include "debug-helper.h" - struct rbox_save_context { - struct dbox_save_context ctx; + struct dbox_save_context ctx; - struct rbox_mailbox *mbox; - struct rbox_sync_context *sync_ctx; + struct rbox_mailbox *mbox; + struct rbox_sync_context *sync_ctx; - struct dbox_file *cur_file; - struct dbox_file_append_context *append_ctx; + struct dbox_file *cur_file; + struct dbox_file_append_context *append_ctx; - uint32_t first_saved_seq; - ARRAY(struct dbox_file *) - files; + uint32_t first_saved_seq; + ARRAY(struct dbox_file *) + files; }; -struct dbox_file * -rbox_save_file_get_file(struct mailbox_transaction_context *t, uint32_t seq) { - FUNC_START(); - struct rbox_save_context *ctx = (struct rbox_save_context *) t->save_ctx; - struct dbox_file * const *files, *file; - unsigned int count; +struct dbox_file *rbox_save_file_get_file(struct mailbox_transaction_context *t, uint32_t seq) { + FUNC_START(); + struct rbox_save_context *ctx = (struct rbox_save_context *)t->save_ctx; + struct dbox_file *const *files, *file; + unsigned int count; - i_assert(seq >= ctx->first_saved_seq); + i_assert(seq >= ctx->first_saved_seq); - files = array_get(&ctx->files, &count); - i_assert(count > 0); - i_assert(seq - ctx->first_saved_seq < count); + files = array_get(&ctx->files, &count); + i_assert(count > 0); + i_assert(seq - ctx->first_saved_seq < count); - file = files[seq - ctx->first_saved_seq]; - i_assert(((struct rbox_file * )file)->written_to_disk); + file = files[seq - ctx->first_saved_seq]; + i_assert(((struct rbox_file *)file)->written_to_disk); - i_debug("rbox_save_file_get_file: seq = %u", seq); - rbox_dbg_print_mail_save_context(&ctx->ctx.ctx, "rbox_save_file_get_file", NULL); - rbox_dbg_print_dbox_file(file, "rbox_save_file_get_file", NULL); - FUNC_END(); - return file; + i_debug("rbox_save_file_get_file: seq = %u", seq); + rbox_dbg_print_mail_save_context(&ctx->ctx.ctx, "rbox_save_file_get_file", NULL); + rbox_dbg_print_dbox_file(file, "rbox_save_file_get_file", NULL); + FUNC_END(); + return file; } -struct mail_save_context * -rbox_save_alloc(struct mailbox_transaction_context *t) { - FUNC_START(); - struct rbox_mailbox *mbox = (struct rbox_mailbox *) t->box; - struct rbox_save_context *ctx = (struct rbox_save_context *) t->save_ctx; - - i_assert((t->flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0); - - if (ctx != NULL) { - /* use the existing allocated structure */ - ctx->cur_file = NULL; - ctx->ctx.failed = FALSE; - ctx->ctx.finished = FALSE; - ctx->ctx.dbox_output = NULL; - rbox_dbg_print_mail_save_context(&ctx->ctx.ctx, "rbox_save_file_get_file", NULL); - FUNC_END_RET("ret = &ctx->ctx.ctx; use the existing allocated structure"); - return &ctx->ctx.ctx; - } - - ctx = i_new(struct rbox_save_context, 1); - ctx->ctx.ctx.transaction = t; - ctx->ctx.trans = t->itrans; - ctx->mbox = mbox; - i_array_init(&ctx->files, 32); - t->save_ctx = &ctx->ctx.ctx; - rbox_dbg_print_mail_save_context(&ctx->ctx.ctx, "rbox_save_file_get_file", NULL); - FUNC_END(); - return t->save_ctx; +struct mail_save_context *rbox_save_alloc(struct mailbox_transaction_context *t) { + FUNC_START(); + struct rbox_mailbox *mbox = (struct rbox_mailbox *)t->box; + struct rbox_save_context *ctx = (struct rbox_save_context *)t->save_ctx; + + i_assert((t->flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0); + + if (ctx != NULL) { + /* use the existing allocated structure */ + ctx->cur_file = NULL; + ctx->ctx.failed = FALSE; + ctx->ctx.finished = FALSE; + ctx->ctx.dbox_output = NULL; + rbox_dbg_print_mail_save_context(&ctx->ctx.ctx, "rbox_save_file_get_file", NULL); + FUNC_END_RET("ret = &ctx->ctx.ctx; use the existing allocated structure"); + return &ctx->ctx.ctx; + } + + ctx = i_new(struct rbox_save_context, 1); + ctx->ctx.ctx.transaction = t; + ctx->ctx.trans = t->itrans; + ctx->mbox = mbox; + i_array_init(&ctx->files, 32); + t->save_ctx = &ctx->ctx.ctx; + rbox_dbg_print_mail_save_context(&ctx->ctx.ctx, "rbox_save_file_get_file", NULL); + FUNC_END(); + return t->save_ctx; } void rbox_save_add_file(struct mail_save_context *_ctx, struct dbox_file *file) { - FUNC_START(); - struct rbox_save_context *ctx = (struct rbox_save_context *) _ctx; - struct dbox_file * const *files; - unsigned int count; - - if (ctx->first_saved_seq == 0) - ctx->first_saved_seq = ctx->ctx.seq; - - files = array_get(&ctx->files, &count); - if (count > 0) { - /* a plugin may leave a previously saved file open. - we'll close it here to avoid eating too many fds. */ - dbox_file_close(files[count - 1]); - } - array_append(&ctx->files, &file, 1); - rbox_dbg_print_mail_save_context(_ctx, "rbox_save_add_file", NULL); - rbox_dbg_print_dbox_file(file, "rbox_save_add_file", NULL); - FUNC_END(); + FUNC_START(); + struct rbox_save_context *ctx = (struct rbox_save_context *)_ctx; + struct dbox_file *const *files; + unsigned int count; + + if (ctx->first_saved_seq == 0) + ctx->first_saved_seq = ctx->ctx.seq; + + files = array_get(&ctx->files, &count); + if (count > 0) { + /* a plugin may leave a previously saved file open. + we'll close it here to avoid eating too many fds. */ + dbox_file_close(files[count - 1]); + } + array_append(&ctx->files, &file, 1); + rbox_dbg_print_mail_save_context(_ctx, "rbox_save_add_file", NULL); + rbox_dbg_print_dbox_file(file, "rbox_save_add_file", NULL); + FUNC_END(); } int rbox_save_begin(struct mail_save_context *_ctx, struct istream *input) { - FUNC_START(); - struct rbox_save_context *ctx = (struct rbox_save_context *) _ctx; - struct dbox_file *file; - int ret; - - rbox_dbg_print_mail_save_context(_ctx, "rbox_save_begin", NULL); - - file = rbox_file_create(ctx->mbox); - ctx->append_ctx = dbox_file_append_init(file); - ret = dbox_file_get_append_stream(ctx->append_ctx, &ctx->ctx.dbox_output); - if (ret <= 0) { - i_assert(ret != 0); - dbox_file_append_rollback(&ctx->append_ctx); - dbox_file_unref(&file); - ctx->ctx.failed = TRUE; - FUNC_END_RET("ret = -1; get_append_stream failed"); - return -1; - } - ctx->cur_file = file; - dbox_save_begin(&ctx->ctx, input); - - rbox_save_add_file(_ctx, file); - FUNC_END(); - return ctx->ctx.failed ? -1 : 0; + FUNC_START(); + struct rbox_save_context *ctx = (struct rbox_save_context *)_ctx; + struct dbox_file *file; + int ret; + + rbox_dbg_print_mail_save_context(_ctx, "rbox_save_begin", NULL); + + file = rbox_file_create(ctx->mbox); + ctx->append_ctx = dbox_file_append_init(file); + ret = dbox_file_get_append_stream(ctx->append_ctx, &ctx->ctx.dbox_output); + if (ret <= 0) { + i_assert(ret != 0); + dbox_file_append_rollback(&ctx->append_ctx); + dbox_file_unref(&file); + ctx->ctx.failed = TRUE; + FUNC_END_RET("ret = -1; get_append_stream failed"); + return -1; + } + ctx->cur_file = file; + dbox_save_begin(&ctx->ctx, input); + + rbox_save_add_file(_ctx, file); + FUNC_END(); + return ctx->ctx.failed ? -1 : 0; } int rbox_save_continue(struct mail_save_context *_ctx) { - FUNC_START(); - struct dbox_save_context *ctx = (struct dbox_save_context *) _ctx; - struct mail_storage *storage = _ctx->transaction->box->storage; - - rbox_dbg_print_mail_save_context(_ctx, "rbox_save_continue", NULL); - - if (ctx->failed) { - FUNC_END_RET("ret == -1; ctx failed"); - return -1; - } - - if (_ctx->data.attach != NULL) { - FUNC_END_RET("ret == index_attachment_save_continue"); - return index_attachment_save_continue(_ctx); - } - - do { - if (o_stream_send_istream(_ctx->data.output, ctx->input) < 0) { - if (!mail_storage_set_error_from_errno(storage)) { - mail_storage_set_critical(storage, "write(%s) failed: %m", o_stream_get_name(_ctx->data.output)); - } - ctx->failed = TRUE; - FUNC_END_RET("ret == -1; o_stream_send_istream failed"); - return -1; - } - index_mail_cache_parse_continue(_ctx->dest_mail); - - /* both tee input readers may consume data from our primary - input stream. we'll have to make sure we don't return with - one of the streams still having data in them. */ - } while (i_stream_read(ctx->input) > 0); - FUNC_END(); - return 0; + FUNC_START(); + struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx; + struct mail_storage *storage = _ctx->transaction->box->storage; + + rbox_dbg_print_mail_save_context(_ctx, "rbox_save_continue", NULL); + + if (ctx->failed) { + FUNC_END_RET("ret == -1; ctx failed"); + return -1; + } + if (_ctx->data.attach != NULL) { + FUNC_END_RET("ret == index_attachment_save_continue"); + return index_attachment_save_continue(_ctx); + } + + do { + if (o_stream_send_istream(_ctx->data.output, ctx->input) < 0) { + if (!mail_storage_set_error_from_errno(storage)) { + mail_storage_set_critical(storage, "write(%s) failed: %m", o_stream_get_name(_ctx->data.output)); + } + ctx->failed = TRUE; + FUNC_END_RET("ret == -1; o_stream_send_istream failed"); + return -1; + } + index_mail_cache_parse_continue(_ctx->dest_mail); + + /* both tee input readers may consume data from our primary + input stream. we'll have to make sure we don't return with + one of the streams still having data in them. */ + } while (i_stream_read(ctx->input) > 0); + FUNC_END(); + return 0; } static int dbox_save_mail_write_metadata(struct dbox_save_context *ctx, struct dbox_file *file) { - FUNC_START(); - struct rbox_file *sfile = (struct rbox_file *) file; - const ARRAY_TYPE(mail_attachment_extref) *extrefs_arr; - const struct mail_attachment_extref *extrefs; - struct dbox_message_header dbox_msg_hdr; - uoff_t message_size; - guid_128_t guid_128; - unsigned int i, count; - - rbox_dbg_print_dbox_file(file, "dbox_save_mail_write_metadata", NULL); - rbox_dbg_print_mail_save_context(&ctx->ctx, "dbox_save_mail_write_metadata", NULL); - - i_assert(file->msg_header_size == sizeof(dbox_msg_hdr)); - - message_size = ctx->dbox_output->offset - file->msg_header_size - file->file_header_size; - - dbox_save_write_metadata(&ctx->ctx, ctx->dbox_output, message_size, NULL, guid_128); - dbox_msg_header_fill(&dbox_msg_hdr, message_size); - if (o_stream_pwrite(ctx->dbox_output, &dbox_msg_hdr, sizeof(dbox_msg_hdr), file->file_header_size) < 0) { - dbox_file_set_syscall_error(file, "pwrite()"); - FUNC_END_RET("ret == -1; o_stream_pwrite failed"); - return -1; - } - sfile->written_to_disk = TRUE; - - /* remember the attachment paths until commit time */ - extrefs_arr = index_attachment_save_get_extrefs(&ctx->ctx); - if (extrefs_arr != NULL) - extrefs = array_get(extrefs_arr, &count); - else { - extrefs = NULL; - count = 0; - } - if (count > 0) { - sfile->attachment_pool = pool_alloconly_create("rbox attachment paths", 512); - p_array_init(&sfile->attachment_paths, sfile->attachment_pool, count); - for (i = 0; i < count; i++) { - const char *path = p_strdup(sfile->attachment_pool, extrefs[i].path); - array_append(&sfile->attachment_paths, &path, 1); - } - } - FUNC_END(); - return 0; + FUNC_START(); + struct rbox_file *sfile = (struct rbox_file *)file; + const ARRAY_TYPE(mail_attachment_extref) * extrefs_arr; + const struct mail_attachment_extref *extrefs; + struct dbox_message_header dbox_msg_hdr; + uoff_t message_size; + guid_128_t guid_128; + unsigned int i, count; + + rbox_dbg_print_dbox_file(file, "dbox_save_mail_write_metadata", NULL); + rbox_dbg_print_mail_save_context(&ctx->ctx, "dbox_save_mail_write_metadata", NULL); + + i_assert(file->msg_header_size == sizeof(dbox_msg_hdr)); + + message_size = ctx->dbox_output->offset - file->msg_header_size - file->file_header_size; + + dbox_save_write_metadata(&ctx->ctx, ctx->dbox_output, message_size, NULL, guid_128); + dbox_msg_header_fill(&dbox_msg_hdr, message_size); + if (o_stream_pwrite(ctx->dbox_output, &dbox_msg_hdr, sizeof(dbox_msg_hdr), file->file_header_size) < 0) { + dbox_file_set_syscall_error(file, "pwrite()"); + FUNC_END_RET("ret == -1; o_stream_pwrite failed"); + return -1; + } + sfile->written_to_disk = TRUE; + + /* remember the attachment paths until commit time */ + extrefs_arr = index_attachment_save_get_extrefs(&ctx->ctx); + if (extrefs_arr != NULL) + extrefs = array_get(extrefs_arr, &count); + else { + extrefs = NULL; + count = 0; + } + if (count > 0) { + sfile->attachment_pool = pool_alloconly_create("rbox attachment paths", 512); + p_array_init(&sfile->attachment_paths, sfile->attachment_pool, count); + for (i = 0; i < count; i++) { + const char *path = p_strdup(sfile->attachment_pool, extrefs[i].path); + array_append(&sfile->attachment_paths, &path, 1); + } + } + FUNC_END(); + return 0; } static int dbox_save_finish_write(struct mail_save_context *_ctx) { - FUNC_START(); - struct rbox_save_context *ctx = (struct rbox_save_context *) _ctx; - struct dbox_file **files; - - rbox_dbg_print_mail_save_context(_ctx, "dbox_save_finish_write", NULL); - - ctx->ctx.finished = TRUE; - if (ctx->ctx.dbox_output == NULL) { - FUNC_END_RET("ret == -1; ctx.dbox_output == NULL"); - return -1; - } - - if (_ctx->data.save_date != (time_t) -1) { - /* we can't change ctime, but we can add the date to cache */ - struct index_mail *mail = (struct index_mail *) _ctx->dest_mail; - uint32_t t = _ctx->data.save_date; - - index_mail_cache_add(mail, MAIL_CACHE_SAVE_DATE, &t, sizeof(t)); - } - dbox_save_end(&ctx->ctx); - - files = array_idx_modifiable(&ctx->files, array_count(&ctx->files) - 1); - if (!ctx->ctx.failed) - T_BEGIN { - if (dbox_save_mail_write_metadata(&ctx->ctx, *files) < 0) - ctx->ctx.failed = TRUE; - }T_END; - - if (ctx->ctx.failed) { - mail_index_expunge(ctx->ctx.trans, ctx->ctx.seq); - mail_cache_transaction_reset(ctx->ctx.ctx.transaction->cache_trans); - dbox_file_append_rollback(&ctx->append_ctx); - dbox_file_unlink(*files); - dbox_file_unref(files); - array_delete(&ctx->files, array_count(&ctx->files) - 1, 1); - } else { - dbox_file_append_checkpoint(ctx->append_ctx); - if (dbox_file_append_commit(&ctx->append_ctx) < 0) - ctx->ctx.failed = TRUE; - dbox_file_close(*files); - } - - i_stream_unref(&ctx->ctx.input); - ctx->ctx.dbox_output = NULL; - - FUNC_END(); - return ctx->ctx.failed ? -1 : 0; + FUNC_START(); + struct rbox_save_context *ctx = (struct rbox_save_context *)_ctx; + struct dbox_file **files; + + rbox_dbg_print_mail_save_context(_ctx, "dbox_save_finish_write", NULL); + + ctx->ctx.finished = TRUE; + if (ctx->ctx.dbox_output == NULL) { + FUNC_END_RET("ret == -1; ctx.dbox_output == NULL"); + return -1; + } + + if (_ctx->data.save_date != (time_t)-1) { + /* we can't change ctime, but we can add the date to cache */ + struct index_mail *mail = (struct index_mail *)_ctx->dest_mail; + uint32_t t = _ctx->data.save_date; + + index_mail_cache_add(mail, MAIL_CACHE_SAVE_DATE, &t, sizeof(t)); + } + dbox_save_end(&ctx->ctx); + + files = array_idx_modifiable(&ctx->files, array_count(&ctx->files) - 1); + if (!ctx->ctx.failed) + T_BEGIN { + if (dbox_save_mail_write_metadata(&ctx->ctx, *files) < 0) + ctx->ctx.failed = TRUE; + } + T_END; + + if (ctx->ctx.failed) { + mail_index_expunge(ctx->ctx.trans, ctx->ctx.seq); + mail_cache_transaction_reset(ctx->ctx.ctx.transaction->cache_trans); + dbox_file_append_rollback(&ctx->append_ctx); + dbox_file_unlink(*files); + dbox_file_unref(files); + array_delete(&ctx->files, array_count(&ctx->files) - 1, 1); + } else { + dbox_file_append_checkpoint(ctx->append_ctx); + if (dbox_file_append_commit(&ctx->append_ctx) < 0) + ctx->ctx.failed = TRUE; + dbox_file_close(*files); + } + + i_stream_unref(&ctx->ctx.input); + ctx->ctx.dbox_output = NULL; + + FUNC_END(); + return ctx->ctx.failed ? -1 : 0; } int rbox_save_finish(struct mail_save_context *ctx) { - FUNC_START(); - int ret; + FUNC_START(); + int ret; - ret = dbox_save_finish_write(ctx); - index_save_context_free(ctx); - FUNC_END(); - return ret; + ret = dbox_save_finish_write(ctx); + index_save_context_free(ctx); + FUNC_END(); + return ret; } void rbox_save_cancel(struct mail_save_context *_ctx) { - FUNC_START(); - struct dbox_save_context *ctx = (struct dbox_save_context *) _ctx; + FUNC_START(); + struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx; - ctx->failed = TRUE; - (void) rbox_save_finish(_ctx); - FUNC_END(); + ctx->failed = TRUE; + (void)rbox_save_finish(_ctx); + FUNC_END(); } -static int dbox_save_assign_uids(struct rbox_save_context *ctx, const ARRAY_TYPE(seq_range) *uids) -{ - FUNC_START(); - struct dbox_file *const *files; - struct seq_range_iter iter; - unsigned int i, count, n = 0; - uint32_t uid; - bool ret; - - rbox_dbg_print_mail_save_context(ctx, "dbox_save_assign_uids", NULL); - - seq_range_array_iter_init(&iter, uids); - files = array_get(&ctx->files, &count); - for (i = 0; i < count; i++) { - struct rbox_file *sfile = (struct rbox_file *)files[i]; - - ret = seq_range_array_iter_nth(&iter, n++, &uid); - i_assert(ret); - if (rbox_file_assign_uid(sfile, uid, FALSE) < 0) { - FUNC_END_RET("ret == -1; file_assign_uid failed"); - return -1; - } - if (ctx->ctx.highest_pop3_uidl_seq == i+1) { - index_pop3_uidl_set_max_uid(&ctx->mbox->box, - ctx->ctx.trans, uid); - } - } - i_assert(!seq_range_array_iter_nth(&iter, n, &uid)); - FUNC_END(); - return 0; +static int dbox_save_assign_uids(struct rbox_save_context *ctx, const ARRAY_TYPE(seq_range) * uids) { + FUNC_START(); + struct dbox_file *const *files; + struct seq_range_iter iter; + unsigned int i, count, n = 0; + uint32_t uid; + bool ret; + + rbox_dbg_print_mail_save_context(ctx, "dbox_save_assign_uids", NULL); + + seq_range_array_iter_init(&iter, uids); + files = array_get(&ctx->files, &count); + for (i = 0; i < count; i++) { + struct rbox_file *sfile = (struct rbox_file *)files[i]; + + ret = seq_range_array_iter_nth(&iter, n++, &uid); + i_assert(ret); + if (rbox_file_assign_uid(sfile, uid, FALSE) < 0) { + FUNC_END_RET("ret == -1; file_assign_uid failed"); + return -1; + } + if (ctx->ctx.highest_pop3_uidl_seq == i + 1) { + index_pop3_uidl_set_max_uid(&ctx->mbox->box, ctx->ctx.trans, uid); + } + } + i_assert(!seq_range_array_iter_nth(&iter, n, &uid)); + FUNC_END(); + return 0; } static int dbox_save_assign_stub_uids(struct rbox_save_context *ctx) { - FUNC_START(); - struct dbox_file * const *files; - unsigned int i, count; + FUNC_START(); + struct dbox_file *const *files; + unsigned int i, count; - rbox_dbg_print_mail_save_context(&ctx->ctx.ctx, "dbox_save_assign_uids", NULL); + rbox_dbg_print_mail_save_context(&ctx->ctx.ctx, "dbox_save_assign_uids", NULL); - files = array_get(&ctx->files, &count); - for (i = 0; i < count; i++) { - struct rbox_file *sfile = (struct rbox_file *) files[i]; - uint32_t uid; + files = array_get(&ctx->files, &count); + for (i = 0; i < count; i++) { + struct rbox_file *sfile = (struct rbox_file *)files[i]; + uint32_t uid; - mail_index_lookup_uid(ctx->ctx.trans->view, ctx->first_saved_seq + i, &uid); - i_assert(uid != 0); + mail_index_lookup_uid(ctx->ctx.trans->view, ctx->first_saved_seq + i, &uid); + i_assert(uid != 0); - if (rbox_file_assign_uid(sfile, uid, TRUE) < 0) { - FUNC_END_RET("ret == -1; file_assign_uid failed"); - return -1; - } - } + if (rbox_file_assign_uid(sfile, uid, TRUE) < 0) { + FUNC_END_RET("ret == -1; file_assign_uid failed"); + return -1; + } + } - FUNC_END(); - return 0; + FUNC_END(); + return 0; } static void dbox_save_unref_files(struct rbox_save_context *ctx) { - FUNC_START(); - struct dbox_file **files; - unsigned int i, count; - - rbox_dbg_print_mail_save_context(&ctx->ctx.ctx, "dbox_save_assign_uids", NULL); - - files = array_get_modifiable(&ctx->files, &count); - for (i = 0; i < count; i++) { - if (ctx->ctx.failed) { - struct rbox_file *sfile = (struct rbox_file *) files[i]; - - (void) rbox_file_unlink_aborted_save(sfile); - } - dbox_file_unref(&files[i]); - } - array_free(&ctx->files); - FUNC_END(); + FUNC_START(); + struct dbox_file **files; + unsigned int i, count; + + rbox_dbg_print_mail_save_context(&ctx->ctx.ctx, "dbox_save_assign_uids", NULL); + + files = array_get_modifiable(&ctx->files, &count); + for (i = 0; i < count; i++) { + if (ctx->ctx.failed) { + struct rbox_file *sfile = (struct rbox_file *)files[i]; + + (void)rbox_file_unlink_aborted_save(sfile); + } + dbox_file_unref(&files[i]); + } + array_free(&ctx->files); + FUNC_END(); } int rbox_transaction_save_commit_pre(struct mail_save_context *_ctx) { - FUNC_START(); - struct rbox_save_context *ctx = (struct rbox_save_context *) _ctx; - struct mailbox_transaction_context *_t = _ctx->transaction; - const struct mail_index_header *hdr; - - rbox_dbg_print_mail_save_context(_ctx, "rbox_transaction_save_commit_pre", NULL); - - i_assert(ctx->ctx.finished); - - if (array_count(&ctx->files) == 0) { - /* the mail must be freed in the commit_pre() */ - FUNC_END_RET("ret == 0; array_count == 0"); - return 0; - } - - if (rbox_sync_begin(ctx->mbox, RBOX_SYNC_FLAG_FORCE | RBOX_SYNC_FLAG_FSYNC, &ctx->sync_ctx) < 0) { - rbox_transaction_save_rollback(_ctx); - FUNC_END_RET("ret == -1; sync_begin failed"); - return -1; - } - - /* update dbox header flags */ - dbox_save_update_header_flags(&ctx->ctx, ctx->sync_ctx->sync_view, ctx->mbox->hdr_ext_id, - offsetof(struct rbox_index_header, flags)); - - hdr = mail_index_get_header(ctx->sync_ctx->sync_view); - - if ((_ctx->transaction->flags & MAILBOX_TRANSACTION_FLAG_FILL_IN_STUB) == 0) { - /* assign UIDs for new messages */ - mail_index_append_finish_uids(ctx->ctx.trans, hdr->next_uid, &_t->changes->saved_uids); - if (dbox_save_assign_uids(ctx, &_t->changes->saved_uids) < 0) { - rbox_transaction_save_rollback(_ctx); - FUNC_END_RET("ret == -1; assign_uids failed"); - return -1; - } - } else { - /* assign UIDs that we stashed away */ - if (dbox_save_assign_stub_uids(ctx) < 0) { - rbox_transaction_save_rollback(_ctx); - FUNC_END_RET("ret == -1; assign_stub_uids failed"); - return -1; - } - } - - _t->changes->uid_validity = hdr->uid_validity; - FUNC_END(); - return 0; + FUNC_START(); + struct rbox_save_context *ctx = (struct rbox_save_context *)_ctx; + struct mailbox_transaction_context *_t = _ctx->transaction; + const struct mail_index_header *hdr; + + rbox_dbg_print_mail_save_context(_ctx, "rbox_transaction_save_commit_pre", NULL); + + i_assert(ctx->ctx.finished); + + if (array_count(&ctx->files) == 0) { + /* the mail must be freed in the commit_pre() */ + FUNC_END_RET("ret == 0; array_count == 0"); + return 0; + } + + if (rbox_sync_begin(ctx->mbox, RBOX_SYNC_FLAG_FORCE | RBOX_SYNC_FLAG_FSYNC, &ctx->sync_ctx) < 0) { + rbox_transaction_save_rollback(_ctx); + FUNC_END_RET("ret == -1; sync_begin failed"); + return -1; + } + + /* update dbox header flags */ + dbox_save_update_header_flags(&ctx->ctx, ctx->sync_ctx->sync_view, ctx->mbox->hdr_ext_id, + offsetof(struct rbox_index_header, flags)); + + hdr = mail_index_get_header(ctx->sync_ctx->sync_view); + + if ((_ctx->transaction->flags & MAILBOX_TRANSACTION_FLAG_FILL_IN_STUB) == 0) { + /* assign UIDs for new messages */ + mail_index_append_finish_uids(ctx->ctx.trans, hdr->next_uid, &_t->changes->saved_uids); + if (dbox_save_assign_uids(ctx, &_t->changes->saved_uids) < 0) { + rbox_transaction_save_rollback(_ctx); + FUNC_END_RET("ret == -1; assign_uids failed"); + return -1; + } + } else { + /* assign UIDs that we stashed away */ + if (dbox_save_assign_stub_uids(ctx) < 0) { + rbox_transaction_save_rollback(_ctx); + FUNC_END_RET("ret == -1; assign_stub_uids failed"); + return -1; + } + } + + _t->changes->uid_validity = hdr->uid_validity; + FUNC_END(); + return 0; } -void rbox_transaction_save_commit_post(struct mail_save_context *_ctx, struct mail_index_transaction_commit_result *result) { - FUNC_START(); - struct rbox_save_context *ctx = (struct rbox_save_context *) _ctx; - struct mail_storage *storage = _ctx->transaction->box->storage; +void rbox_transaction_save_commit_post(struct mail_save_context *_ctx, + struct mail_index_transaction_commit_result *result) { + FUNC_START(); + struct rbox_save_context *ctx = (struct rbox_save_context *)_ctx; + struct mail_storage *storage = _ctx->transaction->box->storage; - _ctx->transaction = NULL; /* transaction is already freed */ + _ctx->transaction = NULL; /* transaction is already freed */ - rbox_dbg_print_mail_save_context(_ctx, "rbox_transaction_save_commit_post", NULL); + rbox_dbg_print_mail_save_context(_ctx, "rbox_transaction_save_commit_post", NULL); - if (array_count(&ctx->files) == 0) { - rbox_transaction_save_rollback(_ctx); - FUNC_END_RET("array_count == 0"); - return; - } + if (array_count(&ctx->files) == 0) { + rbox_transaction_save_rollback(_ctx); + FUNC_END_RET("array_count == 0"); + return; + } - mail_index_sync_set_commit_result(ctx->sync_ctx->index_sync_ctx, result); + mail_index_sync_set_commit_result(ctx->sync_ctx->index_sync_ctx, result); - if (rbox_sync_finish(&ctx->sync_ctx, TRUE) < 0) - ctx->ctx.failed = TRUE; + if (rbox_sync_finish(&ctx->sync_ctx, TRUE) < 0) + ctx->ctx.failed = TRUE; - if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) { - const char *box_path = mailbox_get_path(&ctx->mbox->box); + if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) { + const char *box_path = mailbox_get_path(&ctx->mbox->box); - if (fdatasync_path(box_path) < 0) { - mail_storage_set_critical(storage, "fdatasync_path(%s) failed: %m", box_path); - } - } - rbox_transaction_save_rollback(_ctx); - FUNC_END(); + if (fdatasync_path(box_path) < 0) { + mail_storage_set_critical(storage, "fdatasync_path(%s) failed: %m", box_path); + } + } + rbox_transaction_save_rollback(_ctx); + FUNC_END(); } void rbox_transaction_save_rollback(struct mail_save_context *_ctx) { - FUNC_START(); - struct rbox_save_context *ctx = (struct rbox_save_context *) _ctx; + FUNC_START(); + struct rbox_save_context *ctx = (struct rbox_save_context *)_ctx; - if (!ctx->ctx.finished) - rbox_save_cancel(_ctx); - dbox_save_unref_files(ctx); + if (!ctx->ctx.finished) + rbox_save_cancel(_ctx); + dbox_save_unref_files(ctx); - if (ctx->sync_ctx != NULL) - (void) rbox_sync_finish(&ctx->sync_ctx, FALSE); - i_free(ctx); - FUNC_END(); + if (ctx->sync_ctx != NULL) + (void)rbox_sync_finish(&ctx->sync_ctx, FALSE); + i_free(ctx); + FUNC_END(); }