mirror of
https://github.com/isar/libmdbx.git
synced 2025-02-01 10:58:20 +08:00
mdbx: refine mdbx_is_dirty().
This commit is contained in:
parent
f4bf454298
commit
c2fda6be5a
52
mdbx.c
52
mdbx.c
@ -11484,7 +11484,7 @@ int mdbx_is_dirty(const MDB_txn *txn, const void *ptr) {
|
|||||||
return MDBX_EBADSIGN;
|
return MDBX_EBADSIGN;
|
||||||
|
|
||||||
if (unlikely(txn->mt_flags & MDB_TXN_RDONLY))
|
if (unlikely(txn->mt_flags & MDB_TXN_RDONLY))
|
||||||
return MDB_BAD_TXN;
|
return MDBX_RESULT_FALSE;
|
||||||
|
|
||||||
const MDB_env *env = txn->mt_env;
|
const MDB_env *env = txn->mt_env;
|
||||||
const uintptr_t mask = ~(uintptr_t)(env->me_psize - 1);
|
const uintptr_t mask = ~(uintptr_t)(env->me_psize - 1);
|
||||||
@ -11495,50 +11495,38 @@ int mdbx_is_dirty(const MDB_txn *txn, const void *ptr) {
|
|||||||
* что было исходно задумано, детали см в логике кода mdbx_page_touch().
|
* что было исходно задумано, детали см в логике кода mdbx_page_touch().
|
||||||
*
|
*
|
||||||
* Более того, в режиме БЕЗ WRITEMAP грязные страницы выделяются через
|
* Более того, в режиме БЕЗ WRITEMAP грязные страницы выделяются через
|
||||||
* malloc(), т.е. находятся вне mmap-диаппазона.
|
* malloc(), т.е. находятся вне mmap-диапазона.
|
||||||
*
|
*
|
||||||
* Тем не менее, однозначно страница "не грязная" если:
|
* Тем не менее, однозначно страница "не грязная" если адрес находится
|
||||||
* - адрес находится внутри mmap-диаппазона и в заголовке страницы
|
* внутри mmap-диапазона и в заголовке страницы нет флажка P_DIRTY. */
|
||||||
* нет флажка P_DIRTY, то однозначно страница "не грязная".
|
|
||||||
* - адрес вне mmap-диаппазона и его нет среди списка "грязных" страниц.
|
|
||||||
*/
|
|
||||||
if (env->me_map < (char *)page) {
|
if (env->me_map < (char *)page) {
|
||||||
const size_t used_size = env->me_psize * txn->mt_next_pgno;
|
const size_t used_size = env->me_psize * txn->mt_next_pgno;
|
||||||
if (env->me_map + used_size > (char *)page) {
|
if ((char *)page < env->me_map + used_size) {
|
||||||
/* страница внутри диапазона */
|
/* страница внутри диапазона, смотрим на флажки */
|
||||||
if (page->mp_flags & P_DIRTY)
|
if ((page->mp_flags & (P_DIRTY | P_LOOSE | P_KEEP)) == 0)
|
||||||
return MDBX_RESULT_TRUE;
|
|
||||||
return MDBX_RESULT_FALSE;
|
return MDBX_RESULT_FALSE;
|
||||||
}
|
}
|
||||||
/* Гипотетически здесь возможна ситуация, когда указатель адресует что-то
|
/* Гипотетически здесь возможна ситуация, когда указатель адресует что-то
|
||||||
* в пределах mmap, но за границей распределенных страниц. Это тяжелая
|
* в пределах mmap, но за границей распределенных страниц. Это тяжелая
|
||||||
* ошибка, которой не возможно добиться без каких-то мега-нарушений.
|
* ошибка, к которой не возможно прийти без каких-то больших нарушений.
|
||||||
* Поэтому не проверяем этот случай кроме как assert-ом, ибо бестолку. */
|
* Поэтому не проверяем этот случай кроме как assert-ом, ибо бестолку. */
|
||||||
mdbx_tassert(txn, env->me_map + env->me_mapsize > (char *)page);
|
mdbx_tassert(txn, env->me_map + env->me_mapsize > (char *)page);
|
||||||
}
|
}
|
||||||
/* Страница вне mmap-диаппазона */
|
|
||||||
|
|
||||||
if (env->me_flags & MDB_WRITEMAP)
|
/* Страница вне используемого mmap-диапазона, т.е. либо в функцию был
|
||||||
/* Если MDB_WRITEMAP, то результат уже ясен. */
|
* передан некорректный адрес, либо адрес в теневой странице, которая была
|
||||||
return MDBX_RESULT_FALSE;
|
* выделена посредством malloc().
|
||||||
|
*
|
||||||
/* Смотрим список грязных страниц у заданной транзакции. */
|
* Поэтому всегда считаем что страница вне mmap-диапазона "грязная",
|
||||||
MDB_ID2 *list = txn->mt_u.dirty_list;
|
* не просматривая при этом списки грязных и spilled страниц у каких-либо
|
||||||
if (list) {
|
* транзакций. Такая логика имеет ряд преимуществ:
|
||||||
unsigned i, n = list[0].mid;
|
* - не тратим время на просмотр списков;
|
||||||
for (i = 1; i <= n; i++) {
|
* - результат всегда безопасен (может быть ложно-положительным, но
|
||||||
const MDB_page *dirty = list[i].mptr;
|
* не ложно-отрицательным);
|
||||||
if (dirty == page)
|
* - результат не зависит от вложенности транзакций и от относительного
|
||||||
|
* положения переданной транзакции в этой рекурсии. */
|
||||||
return MDBX_RESULT_TRUE;
|
return MDBX_RESULT_TRUE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* При вложенных транзакциях, страница может быть в dirty-списке
|
|
||||||
* родительской транзакции, но в этом случае она будет скопирована перед
|
|
||||||
* изменением в текущей транзакции, т.е. относительно заданной транзакции
|
|
||||||
* проверяемый адрес "не грязный". */
|
|
||||||
return MDBX_RESULT_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mdbx_dbi_open_ex(MDB_txn *txn, const char *name, unsigned flags,
|
int mdbx_dbi_open_ex(MDB_txn *txn, const char *name, unsigned flags,
|
||||||
MDB_dbi *pdbi, MDB_cmp_func *keycmp,
|
MDB_dbi *pdbi, MDB_cmp_func *keycmp,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user