From 0a9d96affdd4d4c555522904400f6ca7db680b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 1 Aug 2024 22:03:45 +0300 Subject: [PATCH] =?UTF-8?q?mdbx:=20=D1=83=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BB=D0=BE=D0=B6=D0=BD=D0=BE=D0=B9?= =?UTF-8?q?=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8=20=D0=BD=D0=B5-=D0=BA?= =?UTF-8?q?=D0=BE=D0=B3=D0=B5=D1=80=D0=B5=D0=BD=D1=82=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B8=20=D0=BF=D1=80=D0=B8=20=D0=B8=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B8=20mdbx?= =?UTF-8?q?=5Fdbi=5Fsequence(MAIN=5FDBI)=20=D0=B1=D0=B5=D0=B7=20=D0=B4?= =?UTF-8?q?=D1=80=D1=83=D0=B3=D0=B8=D1=85=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Временная подпорка для coherency_check(), которую в перспективе следует заменить вместе с переделкой установки mod_txnid. Суть проблемы: - coherency_check() в качестве одного из критериев "когерентности" проверяет условие meta.maindb.mod_txnid == maindb.root->txnid; - при обновлении maindb.sequence высталяется DBI_DIRTY, что приведет к обновлению meta.maindb.mod_txnid = current_txnid; - однако, если в само дерево maindb обновление не вносились и оно не пустое, то корневая страницы останеться с прежним txnid и из-за этого ложно сработает coherency_check(). Временное (текущее) решение: Принудительно обновляем корневую страницу в описанной выше ситуации. Это устраняет проблему, но и не создает рисков регресса. Итоговое решение, которое предстоит реализовать: - изменить семантику установки/обновления mod_txnid, привязав его строго к изменению b-tree, но не атрибутов; - обновлять mod_txnid при фиксации вложенных транзакций; - для dbi-хендлов пользовательских subDb (видимо) можно оставить DBI_DIRTY в качестве признака необходимости обновления записи subDb в MainDB, при этом взводить DBI_DIRTY вместе с обновлением mod_txnid, в том числе при обновлении sequence. - для MAIN_DBI при обновлении sequence не следует взводить DBI_DIRTY и/или обновлять mod_txnid, а только взводить MDBX_TXN_DIRTY. - альтернативно, можно перераспределить флажки-признаки dbi_state, чтобы различать состояние dirty-tree и dirty-attributes. --- src/misc.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/misc.c b/src/misc.c index b6839c11..415eee1c 100644 --- a/src/misc.c +++ b/src/misc.c @@ -60,9 +60,48 @@ int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result, return MDBX_RESULT_TRUE; tASSERT(txn, new > dbs->sequence); + if ((txn->dbi_state[dbi] & DBI_DIRTY) == 0) { + txn->flags |= MDBX_TXN_DIRTY; + txn->dbi_state[dbi] |= DBI_DIRTY; + if (unlikely(dbi == MAIN_DBI) && txn->dbs[MAIN_DBI].root != P_INVALID) { + /* LY: Временная подпорка для coherency_check(), которую в перспективе + * следует заменить вместе с переделкой установки mod_txnid. + * + * Суть проблемы: + * - coherency_check() в качестве одного из критериев "когерентности" + * проверяет условие meta.maindb.mod_txnid == maindb.root->txnid; + * - при обновлении maindb.sequence высталяется DBI_DIRTY, что приведет + * к обновлению meta.maindb.mod_txnid = current_txnid; + * - однако, если в само дерево maindb обновление не вносились и оно + * не пустое, то корневая страницы останеться с прежним txnid и из-за + * этого ложно сработает coherency_check(). + * + * Временное (текущее) решение: Принудительно обновляем корневую + * страницу в описанной выше ситуации. Это устраняет проблему, но и + * не создает рисков регресса. + * + * FIXME: Итоговое решение, которое предстоит реализовать: + * - изменить семантику установки/обновления mod_txnid, привязав его + * строго к изменению b-tree, но не атрибутов; + * - обновлять mod_txnid при фиксации вложенных транзакций; + * - для dbi-хендлов пользовательских subDb (видимо) можно оставить + * DBI_DIRTY в качестве признака необходимости обновления записи + * subDb в MainDB, при этом взводить DBI_DIRTY вместе с обновлением + * mod_txnid, в том числе при обновлении sequence. + * - для MAIN_DBI при обновлении sequence не следует взводить DBI_DIRTY + * и/или обновлять mod_txnid, а только взводить MDBX_TXN_DIRTY. + * - альтернативно, можно перераспределить флажки-признаки dbi_state, + * чтобы различать состояние dirty-tree и dirty-attributes. */ + cursor_couple_t cx; + rc = cursor_init(&cx.outer, txn, MAIN_DBI); + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + rc = tree_search(&cx.outer, nullptr, Z_MODIFY | Z_ROOTONLY); + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + } + } dbs->sequence = new; - txn->flags |= MDBX_TXN_DIRTY; - txn->dbi_state[dbi] |= DBI_DIRTY; } return MDBX_SUCCESS;