mirror of
				https://github.com/isar/libmdbx.git
				synced 2025-11-04 05:08:57 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			137 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			137 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/// \copyright SPDX-License-Identifier: Apache-2.0
 | 
						||
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2024
 | 
						||
 | 
						||
#pragma once
 | 
						||
 | 
						||
#include "essentials.h"
 | 
						||
 | 
						||
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION MDBX_INTERNAL size_t
 | 
						||
dbi_bitmap_ctz_fallback(const MDBX_txn *txn, intptr_t bmi);
 | 
						||
 | 
						||
#if MDBX_ENABLE_DBI_SPARSE
 | 
						||
 | 
						||
static inline size_t dbi_bitmap_ctz(const MDBX_txn *txn, intptr_t bmi) {
 | 
						||
  tASSERT(txn, bmi > 0);
 | 
						||
  STATIC_ASSERT(sizeof(bmi) >= sizeof(txn->dbi_sparse[0]));
 | 
						||
#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl)
 | 
						||
  if (sizeof(txn->dbi_sparse[0]) <= sizeof(int))
 | 
						||
    return __builtin_ctz((int)bmi);
 | 
						||
  if (sizeof(txn->dbi_sparse[0]) == sizeof(long))
 | 
						||
    return __builtin_ctzl((long)bmi);
 | 
						||
#if (defined(__SIZEOF_LONG_LONG__) && __SIZEOF_LONG_LONG__ == 8) ||            \
 | 
						||
    __has_builtin(__builtin_ctzll)
 | 
						||
  return __builtin_ctzll(bmi);
 | 
						||
#endif /* have(long long) && long long == uint64_t */
 | 
						||
#endif /* GNU C */
 | 
						||
 | 
						||
#if defined(_MSC_VER)
 | 
						||
  unsigned long index;
 | 
						||
  if (sizeof(txn->dbi_sparse[0]) > 4) {
 | 
						||
#if defined(_M_AMD64) || defined(_M_ARM64) || defined(_M_X64)
 | 
						||
    _BitScanForward64(&index, bmi);
 | 
						||
    return index;
 | 
						||
#else
 | 
						||
    if (bmi > UINT32_MAX) {
 | 
						||
      _BitScanForward(&index, (uint32_t)((uint64_t)bmi >> 32));
 | 
						||
      return index;
 | 
						||
    }
 | 
						||
#endif
 | 
						||
  }
 | 
						||
  _BitScanForward(&index, (uint32_t)bmi);
 | 
						||
  return index;
 | 
						||
#endif /* MSVC */
 | 
						||
 | 
						||
  return dbi_bitmap_ctz_fallback(txn, bmi);
 | 
						||
}
 | 
						||
 | 
						||
/* LY: Макрос целенаправленно сделан с одним циклом, чтобы сохранить возможность
 | 
						||
 * использования оператора break */
 | 
						||
#define TXN_FOREACH_DBI_FROM(TXN, I, FROM)                                     \
 | 
						||
  for (size_t bitmap_chunk = CHAR_BIT * sizeof(TXN->dbi_sparse[0]),            \
 | 
						||
              bitmap_item = TXN->dbi_sparse[0] >> FROM, I = FROM;              \
 | 
						||
       I < TXN->n_dbi; ++I)                                                    \
 | 
						||
    if (bitmap_item == 0) {                                                    \
 | 
						||
      I = (I - 1) | (bitmap_chunk - 1);                                        \
 | 
						||
      bitmap_item = TXN->dbi_sparse[(1 + I) / bitmap_chunk];                   \
 | 
						||
      if (!bitmap_item)                                                        \
 | 
						||
        I += bitmap_chunk;                                                     \
 | 
						||
      continue;                                                                \
 | 
						||
    } else if ((bitmap_item & 1) == 0) {                                       \
 | 
						||
      size_t bitmap_skip = dbi_bitmap_ctz(txn, bitmap_item);                   \
 | 
						||
      bitmap_item >>= bitmap_skip;                                             \
 | 
						||
      I += bitmap_skip - 1;                                                    \
 | 
						||
      continue;                                                                \
 | 
						||
    } else if (bitmap_item >>= 1, TXN->dbi_state[I])
 | 
						||
 | 
						||
#else
 | 
						||
 | 
						||
#define TXN_FOREACH_DBI_FROM(TXN, I, SKIP)                                     \
 | 
						||
  for (size_t I = SKIP; I < TXN->n_dbi; ++I)                                   \
 | 
						||
    if (TXN->dbi_state[I])
 | 
						||
 | 
						||
#endif /* MDBX_ENABLE_DBI_SPARSE */
 | 
						||
 | 
						||
#define TXN_FOREACH_DBI_ALL(TXN, I) TXN_FOREACH_DBI_FROM(TXN, I, 0)
 | 
						||
#define TXN_FOREACH_DBI_USER(TXN, I) TXN_FOREACH_DBI_FROM(TXN, I, CORE_DBS)
 | 
						||
 | 
						||
MDBX_INTERNAL int dbi_import(MDBX_txn *txn, const size_t dbi);
 | 
						||
 | 
						||
struct dbi_snap_result {
 | 
						||
  uint32_t sequence;
 | 
						||
  unsigned flags;
 | 
						||
};
 | 
						||
MDBX_INTERNAL struct dbi_snap_result dbi_snap(const MDBX_env *env,
 | 
						||
                                              const size_t dbi);
 | 
						||
 | 
						||
MDBX_INTERNAL int dbi_update(MDBX_txn *txn, int keep);
 | 
						||
 | 
						||
static inline uint8_t dbi_state(const MDBX_txn *txn, const size_t dbi) {
 | 
						||
  STATIC_ASSERT(
 | 
						||
      (int)DBI_DIRTY == MDBX_DBI_DIRTY && (int)DBI_STALE == MDBX_DBI_STALE &&
 | 
						||
      (int)DBI_FRESH == MDBX_DBI_FRESH && (int)DBI_CREAT == MDBX_DBI_CREAT);
 | 
						||
 | 
						||
#if MDBX_ENABLE_DBI_SPARSE
 | 
						||
  const size_t bitmap_chunk = CHAR_BIT * sizeof(txn->dbi_sparse[0]);
 | 
						||
  const size_t bitmap_indx = dbi / bitmap_chunk;
 | 
						||
  const size_t bitmap_mask = (size_t)1 << dbi % bitmap_chunk;
 | 
						||
  return likely(dbi < txn->n_dbi &&
 | 
						||
                (txn->dbi_sparse[bitmap_indx] & bitmap_mask) != 0)
 | 
						||
             ? txn->dbi_state[dbi]
 | 
						||
             : 0;
 | 
						||
#else
 | 
						||
  return likely(dbi < txn->n_dbi) ? txn->dbi_state[dbi] : 0;
 | 
						||
#endif /* MDBX_ENABLE_DBI_SPARSE */
 | 
						||
}
 | 
						||
 | 
						||
static inline bool dbi_changed(const MDBX_txn *txn, const size_t dbi) {
 | 
						||
  const MDBX_env *const env = txn->env;
 | 
						||
  eASSERT(env, dbi_state(txn, dbi) & DBI_LINDO);
 | 
						||
  const uint32_t snap_seq =
 | 
						||
      atomic_load32(&env->dbi_seqs[dbi], mo_AcquireRelease);
 | 
						||
  return snap_seq != txn->dbi_seqs[dbi];
 | 
						||
}
 | 
						||
 | 
						||
static inline int dbi_check(const MDBX_txn *txn, const size_t dbi) {
 | 
						||
  const uint8_t state = dbi_state(txn, dbi);
 | 
						||
  if (likely((state & DBI_LINDO) != 0 && !dbi_changed(txn, dbi)))
 | 
						||
    return (state & DBI_VALID) ? MDBX_SUCCESS : MDBX_BAD_DBI;
 | 
						||
 | 
						||
  /* Медленный путь: ленивая до-инициализацяи и импорт */
 | 
						||
  return dbi_import((MDBX_txn *)txn, dbi);
 | 
						||
}
 | 
						||
 | 
						||
static inline uint32_t dbi_seq_next(const MDBX_env *const env, size_t dbi) {
 | 
						||
  uint32_t v = atomic_load32(&env->dbi_seqs[dbi], mo_AcquireRelease) + 1;
 | 
						||
  return v ? v : 1;
 | 
						||
}
 | 
						||
 | 
						||
MDBX_INTERNAL int dbi_open(MDBX_txn *txn, const MDBX_val *const name,
 | 
						||
                           unsigned user_flags, MDBX_dbi *dbi,
 | 
						||
                           MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp);
 | 
						||
 | 
						||
MDBX_INTERNAL int dbi_bind(MDBX_txn *txn, const size_t dbi, unsigned user_flags,
 | 
						||
                           MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp);
 | 
						||
 | 
						||
MDBX_INTERNAL const tree_t *dbi_dig(const MDBX_txn *txn, const size_t dbi,
 | 
						||
                                    tree_t *fallback);
 |