mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-08 05:24:12 +08:00
mdbx: fix/refine mdbx_is_dirty().
Change-Id: I70bb46b47e7c313fdfd0b130ee55b82dd75e92d2
This commit is contained in:
parent
b84bb4f805
commit
0f3994d506
@ -15669,35 +15669,30 @@ int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) {
|
|||||||
return MDBX_RESULT_FALSE;
|
return MDBX_RESULT_FALSE;
|
||||||
|
|
||||||
const MDBX_env *env = txn->mt_env;
|
const MDBX_env *env = txn->mt_env;
|
||||||
const uintptr_t mask = ~(uintptr_t)(env->me_psize - 1);
|
const ptrdiff_t offset = (uint8_t *)ptr - env->me_map;
|
||||||
const MDBX_page *page = (const MDBX_page *)((uintptr_t)ptr & mask);
|
if (offset >= 0) {
|
||||||
|
const pgno_t pgno = bytes2pgno(env, offset);
|
||||||
/* LY: Тут не всё хорошо с абсолютной достоверностью результата,
|
if (likely(pgno < txn->mt_next_pgno)) {
|
||||||
* так как флажок P_DIRTY может означать не совсем то,
|
const MDBX_page *page = pgno2page(env, pgno);
|
||||||
* что было исходно задумано, детали см в логике кода mdbx_page_touch().
|
if (unlikely(page->mp_pgno != pgno)) {
|
||||||
*
|
/* The ptr pointed into middle of a large page,
|
||||||
* Более того, в режиме БЕЗ WRITEMAP грязные страницы выделяются через
|
* not to the beginning of a data. */
|
||||||
* malloc(), т.е. находятся вне mmap-диапазона и тогда чтобы отличить
|
return MDBX_EINVAL;
|
||||||
* действительно грязную страницу от указателя на данные пользователя
|
}
|
||||||
* следует сканировать dirtylist, что накладно.
|
if (unlikely(page->mp_flags & (P_DIRTY | P_LOOSE | P_KEEP)))
|
||||||
*
|
return MDBX_RESULT_TRUE;
|
||||||
* Тем не менее, однозначно страница "не грязная" (не будет переписана
|
if (likely(txn->tw.spill_pages == nullptr))
|
||||||
* во время транзакции) если адрес находится внутри mmap-диапазона
|
return MDBX_RESULT_FALSE;
|
||||||
* и в заголовке страницы нет флажка P_DIRTY. */
|
return mdbx_pnl_exist(txn->tw.spill_pages, pgno << 1) ? MDBX_RESULT_TRUE
|
||||||
if (env->me_map < (uint8_t *)page) {
|
: MDBX_RESULT_FALSE;
|
||||||
const size_t usedbytes = pgno2bytes(env, txn->mt_next_pgno);
|
}
|
||||||
if ((uint8_t *)page < env->me_map + usedbytes) {
|
if ((size_t)offset < env->me_mapsize) {
|
||||||
/* страница внутри диапазона, смотрим на флажки */
|
/* Указатель адресует что-то в пределах mmap, но за границей
|
||||||
return (page->mp_flags & (P_DIRTY | P_LOOSE | P_KEEP))
|
* распределенных страниц. Такое может случится если mdbx_is_dirty()
|
||||||
? MDBX_RESULT_TRUE
|
* вызывает после операции, в ходе которой гразная страница попала
|
||||||
: MDBX_RESULT_FALSE;
|
* в loose и затем была возвращена в нераспределенное пространство. */
|
||||||
|
return MDBX_RESULT_TRUE;
|
||||||
}
|
}
|
||||||
/* Гипотетически здесь возможна ситуация, когда указатель адресует что-то
|
|
||||||
* в пределах mmap, но за границей распределенных страниц. Это тяжелая
|
|
||||||
* ошибка, к которой не возможно прийти без каких-то больших нарушений.
|
|
||||||
* Поэтому не проверяем этот случай кроме как assert-ом, на то что
|
|
||||||
* страница вне mmap-диаппазона. */
|
|
||||||
mdbx_tassert(txn, (uint8_t *)page >= env->me_map + env->me_mapsize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Страница вне используемого mmap-диапазона, т.е. либо в функцию был
|
/* Страница вне используемого mmap-диапазона, т.е. либо в функцию был
|
||||||
|
Loading…
x
Reference in New Issue
Block a user