github.com/moontrade/mdbx-go@v0.4.0/mdbx.go (about)

     1  package mdbx
     2  
     3  /*
     4  //#cgo !windows CFLAGS: -O2 -g -DMDBX_BUILD_FLAGS='' -DMDBX_DEBUG=0 -DNDEBUG=1 -DMDBX_FORCE_ASSERTIONS=1 -std=gnu11 -fvisibility=hidden -ffast-math  -fPIC -pthread -Wno-error=attributes -W -Wall -Werror -Wextra -Wpedantic -Wno-deprecated-declarations -Wno-format -Wno-implicit-fallthrough -Wno-unused-parameter -Wno-format-extra-args -Wno-missing-field-initializers
     5  #cgo !windows CFLAGS: -O2 -g -DMDBX_BUILD_FLAGS='' -DMDBX_DEBUG=0 -DNDEBUG=1 -fPIC -ffast-math -std=gnu11 -fvisibility=hidden -pthread
     6  #cgo linux LDFLAGS: -lrt
     7  
     8  #include <stdlib.h>
     9  #include <string.h>
    10  #include <inttypes.h>
    11  #include "mdbx.h"
    12  #include "mdbx_utils.h"
    13  
    14  #ifndef likely
    15  #   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
    16  #       define likely(cond) __builtin_expect(!!(cond), 1)
    17  #   else
    18  #       define likely(x) (!!(x))
    19  #   endif
    20  #endif
    21  
    22  #ifndef unlikely
    23  #   if (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
    24  #       define unlikely(cond) __builtin_expect(!!(cond), 0)
    25  #   else
    26  #       define unlikely(x) (!!(x))
    27  #   endif
    28  #endif
    29  
    30  static int cmp_lexical(const MDBX_val *a, const MDBX_val *b) {
    31    if (a->iov_len == b->iov_len)
    32      return a->iov_len ? memcmp(a->iov_base, b->iov_base, a->iov_len) : 0;
    33  
    34    const int diff_len = (a->iov_len < b->iov_len) ? -1 : 1;
    35    const size_t shortest = (a->iov_len < b->iov_len) ? a->iov_len : b->iov_len;
    36    int diff_data = shortest ? memcmp(a->iov_base, b->iov_base, shortest) : 0;
    37    return likely(diff_data) ? diff_data : diff_len;
    38  }
    39  
    40  int mdbx_cmp_u16(const MDBX_val *a, const MDBX_val *b) {
    41    if (unlikely(a->iov_len < 2 || b->iov_len < 2)) {
    42      return cmp_lexical(a, b);
    43    }
    44    uint16_t aa = *((uint16_t*)a->iov_base);
    45    uint16_t bb = *((uint16_t*)b->iov_base);
    46    return bb > aa ? -1 : aa > bb;
    47  }
    48  
    49  int mdbx_cmp_u32(const MDBX_val *a, const MDBX_val *b) {
    50    if (unlikely(a->iov_len < 4 || b->iov_len < 4)) {
    51      return cmp_lexical(a, b);
    52    }
    53    uint32_t aa = *((uint32_t*)a->iov_base);
    54    uint32_t bb = *((uint32_t*)b->iov_base);
    55    return bb > aa ? -1 : aa > bb;
    56  }
    57  
    58  int mdbx_cmp_u64(const MDBX_val *a, const MDBX_val *b) {
    59    if (unlikely(a->iov_len < 8 || b->iov_len < 8)) {
    60      return cmp_lexical(a, b);
    61    }
    62    uint64_t aa = *((uint64_t*)a->iov_base);
    63    uint64_t bb = *((uint64_t*)b->iov_base);
    64    return bb > aa ? -1 : aa > bb;
    65  }
    66  
    67  int mdbx_cmp_u16_prefix_lexical(const MDBX_val *a, const MDBX_val *b) {
    68    if (unlikely(a->iov_len < 2 || b->iov_len < 2)) {
    69      return cmp_lexical(a, b);
    70    }
    71    uint16_t aa = *((uint16_t*)a->iov_base);
    72    uint16_t bb = *((uint16_t*)a->iov_base);
    73    if (aa < bb) {
    74  	return -1;
    75    }
    76    if (aa > bb) {
    77      return 1;
    78    }
    79    if (a->iov_len == b->iov_len)
    80      return a->iov_len ? memcmp(a->iov_base+2, b->iov_base+2, a->iov_len-2) : 0;
    81  
    82    const int diff_len = (a->iov_len < b->iov_len) ? -1 : 1;
    83    const size_t shortest = (a->iov_len < b->iov_len) ? a->iov_len : b->iov_len;
    84    int diff_data = shortest ? memcmp(a->iov_base+2, b->iov_base+2, shortest-2) : 0;
    85    return likely(diff_data) ? diff_data : diff_len;
    86  }
    87  
    88  int mdbx_cmp_u16_prefix_u64(const MDBX_val *a, const MDBX_val *b) {
    89    if (unlikely(a->iov_len < 10 || b->iov_len < 10)) {
    90      return cmp_lexical(a, b);
    91    }
    92    uint16_t aa = *((uint16_t*)a->iov_base);
    93    uint16_t bb = *((uint16_t*)a->iov_base);
    94    if (aa < bb) return -1;
    95    if (aa > bb) return 1;
    96    uint64_t aa2 = *((uint64_t*)a->iov_base+2);
    97    uint64_t bb2 = *((uint64_t*)b->iov_base+2);
    98    if (aa2 < bb2) return -1;
    99    if (aa2 > bb2) return 1;
   100    return 0;
   101  }
   102  
   103  int mdbx_cmp_u32_prefix_u64_dup_lexical(const MDBX_val *a, const MDBX_val *b) {
   104    if (unlikely(a->iov_len < 12 || b->iov_len < 12)) {
   105      return cmp_lexical(a, b);
   106    }
   107    uint32_t aa = *((uint32_t*)a->iov_base);
   108    uint32_t bb = *((uint32_t*)a->iov_base);
   109    if (aa < bb) {
   110  	return -1;
   111    }
   112    if (aa > bb) {
   113      return 1;
   114    }
   115    if (a->iov_len == b->iov_len) {
   116      int result = a->iov_len ? memcmp(a->iov_base+12, b->iov_base+12, a->iov_len-12) : 0;
   117  	if (result != 0) return result;
   118  
   119  	uint64_t aaa = *((uint64_t*)a->iov_base+4);
   120  	uint64_t bbb = *((uint64_t*)a->iov_base+4);
   121  	if (aaa < bbb) {
   122  	  return -1;
   123  	}
   124  	if (aaa > bbb) {
   125  	  return 1;
   126  	}
   127  	return 0;
   128    }
   129  
   130    const int diff_len = (a->iov_len < b->iov_len) ? -1 : 1;
   131    const size_t shortest = (a->iov_len < b->iov_len) ? a->iov_len : b->iov_len;
   132    int diff_data = shortest ? memcmp(a->iov_base+12, b->iov_base+12, shortest-12) : 0;
   133    return likely(diff_data) ? diff_data : diff_len;
   134  }
   135  
   136  int mdbx_cmp_u64_prefix_u64_dup_lexical(const MDBX_val *a, const MDBX_val *b) {
   137    if (unlikely(a->iov_len < 16 || b->iov_len < 16)) {
   138      return cmp_lexical(a, b);
   139    }
   140    uint32_t aa = *((uint32_t*)a->iov_base);
   141    uint32_t bb = *((uint32_t*)a->iov_base);
   142    if (aa < bb) {
   143  	return -1;
   144    }
   145    if (aa > bb) {
   146      return 1;
   147    }
   148    if (a->iov_len == b->iov_len) {
   149      int result = a->iov_len ? memcmp(a->iov_base+16, b->iov_base+16, a->iov_len-16) : 0;
   150  	if (result != 0) return result;
   151  
   152  	uint64_t aaa = *((uint64_t*)a->iov_base+8);
   153  	uint64_t bbb = *((uint64_t*)a->iov_base+8);
   154  	if (aaa < bbb) {
   155  	  return -1;
   156  	}
   157  	if (aaa > bbb) {
   158  	  return 1;
   159  	}
   160  	return 0;
   161    }
   162  
   163    const int diff_len = (a->iov_len < b->iov_len) ? -1 : 1;
   164    const size_t shortest = (a->iov_len < b->iov_len) ? a->iov_len : b->iov_len;
   165    int diff_data = shortest ? memcmp(a->iov_base+16, b->iov_base+16, shortest-16) : 0;
   166    return likely(diff_data) ? diff_data : diff_len;
   167  }
   168  
   169  int mdbx_cmp_u32_prefix_u64_dup_u64(const MDBX_val *a, const MDBX_val *b) {
   170    if (unlikely(a->iov_len < 20 || b->iov_len < 20)) {
   171      return cmp_lexical(a, b);
   172    }
   173    uint32_t aa = *((uint32_t*)a->iov_base);
   174    uint32_t bb = *((uint32_t*)a->iov_base);
   175    if (aa < bb) {
   176  	return -1;
   177    }
   178    if (aa > bb) {
   179      return 1;
   180    }
   181    uint64_t av = *((uint64_t*)a->iov_base+12);
   182    uint64_t bv = *((uint64_t*)a->iov_base+12);
   183    if (av < bv) {
   184  	return -1;
   185    }
   186    if (av > bv) {
   187      return 1;
   188    }
   189    av = *((uint64_t*)a->iov_base+4);
   190    bv = *((uint64_t*)a->iov_base+4);
   191    if (av < bv) {
   192      return -1;
   193    }
   194    if (av > bv) {
   195      return 1;
   196    }
   197    return 0;
   198  }
   199  
   200  int mdbx_cmp_u64_prefix_u64_dup_u64(const MDBX_val *a, const MDBX_val *b) {
   201    if (unlikely(a->iov_len < 24 || b->iov_len < 24)) {
   202      return cmp_lexical(a, b);
   203    }
   204    uint32_t aa = *((uint32_t*)a->iov_base);
   205    uint32_t bb = *((uint32_t*)a->iov_base);
   206    if (aa < bb) {
   207  	return -1;
   208    }
   209    if (aa > bb) {
   210      return 1;
   211    }
   212    uint64_t av = *((uint64_t*)a->iov_base+16);
   213    uint64_t bv = *((uint64_t*)a->iov_base+16);
   214    if (av < bv) {
   215  	return -1;
   216    }
   217    if (av > bv) {
   218      return 1;
   219    }
   220    av = *((uint64_t*)a->iov_base+8);
   221    bv = *((uint64_t*)a->iov_base+8);
   222    if (av < bv) {
   223      return -1;
   224    }
   225    if (av > bv) {
   226      return 1;
   227    }
   228    return 0;
   229  }
   230  
   231  int mdbx_cmp_u32_prefix_lexical(const MDBX_val *a, const MDBX_val *b) {
   232    if (unlikely(a->iov_len < 4 || b->iov_len < 4)) {
   233      return cmp_lexical(a, b);
   234    }
   235    uint32_t aa = *((uint32_t*)a->iov_base);
   236    uint32_t bb = *((uint32_t*)a->iov_base);
   237    if (aa < bb) {
   238  	return -1;
   239    }
   240    if (aa > bb) {
   241      return 1;
   242    }
   243    if (a->iov_len == b->iov_len)
   244      return a->iov_len ? memcmp(a->iov_base+4, b->iov_base+4, a->iov_len-4) : 0;
   245  
   246    const int diff_len = (a->iov_len < b->iov_len) ? -1 : 1;
   247    const size_t shortest = (a->iov_len < b->iov_len) ? a->iov_len : b->iov_len;
   248    int diff_data = shortest ? memcmp(a->iov_base+4, b->iov_base+4, shortest-4) : 0;
   249    return likely(diff_data) ? diff_data : diff_len;
   250  }
   251  
   252  int mdbx_cmp_u32_prefix_u64(const MDBX_val *a, const MDBX_val *b) {
   253    if (unlikely(a->iov_len < 12 || b->iov_len < 12)) {
   254     return cmp_lexical(a, b);
   255    }
   256    uint32_t aa = *((uint32_t*)a->iov_base);
   257    uint32_t bb = *((uint32_t*)a->iov_base);
   258    if (aa < bb) return -1;
   259    if (aa > bb) return 1;
   260    uint64_t aa2 = *((uint64_t*)a->iov_base+4);
   261    uint64_t bb2 = *((uint64_t*)b->iov_base+4);
   262    if (aa2 < bb2) return -1;
   263    if (aa2 > bb2) return 1;
   264    return 0;
   265  }
   266  
   267  int mdbx_cmp_u64_prefix_lexical(const MDBX_val *a, const MDBX_val *b) {
   268    if (unlikely(a->iov_len < 8 || b->iov_len < 8)) {
   269      return cmp_lexical(a, b);
   270    }
   271    uint64_t aa = *((uint64_t*)a->iov_base);
   272    uint64_t bb = *((uint64_t*)a->iov_base);
   273    if (aa < bb) {
   274  	return -1;
   275    }
   276    if (aa > bb) {
   277      return 1;
   278    }
   279    if (a->iov_len == b->iov_len)
   280      return a->iov_len ? memcmp(a->iov_base+8, b->iov_base+8, a->iov_len-8) : 0;
   281  
   282    const int diff_len = (a->iov_len < b->iov_len) ? -1 : 1;
   283    const size_t shortest = (a->iov_len < b->iov_len) ? a->iov_len : b->iov_len;
   284    int diff_data = shortest ? memcmp(a->iov_base+8, b->iov_base+8, shortest-8) : 0;
   285    return likely(diff_data) ? diff_data : diff_len;
   286  }
   287  
   288  int mdbx_cmp_u64_prefix_u64(const MDBX_val *a, const MDBX_val *b) {
   289    if (unlikely(a->iov_len < 16 || b->iov_len < 16)) {
   290     return cmp_lexical(a, b);
   291    }
   292    uint64_t aa = *((uint32_t*)a->iov_base);
   293    uint64_t bb = *((uint32_t*)a->iov_base);
   294    if (aa < bb) return -1;
   295    if (aa > bb) return 1;
   296    aa = *((uint64_t*)a->iov_base+8);
   297    bb = *((uint64_t*)b->iov_base+8);
   298    if (aa < bb) return -1;
   299    if (aa > bb) return 1;
   300    return 0;
   301  }
   302  
   303  typedef struct mdbx_strerror_t {
   304  	size_t result;
   305  	int32_t code;
   306  } mdbx_strerror_t;
   307  
   308  void do_mdbx_strerror(size_t arg0, size_t arg1) {
   309  	mdbx_strerror_t* args = (mdbx_strerror_t*)(void*)arg0;
   310  	args->result = (size_t)(void*)mdbx_strerror((int)args->code);
   311  }
   312  
   313  typedef struct mdbx_env_set_geometry_t {
   314  	size_t env;
   315  	size_t size_lower;
   316  	size_t size_now;
   317  	size_t size_upper;
   318  	size_t growth_step;
   319  	size_t shrink_threshold;
   320  	size_t page_size;
   321  	int32_t result;
   322  } mdbx_env_set_geometry_t;
   323  
   324  void do_mdbx_env_set_geometry(size_t arg0, size_t arg1) {
   325  	mdbx_env_set_geometry_t* args = (mdbx_env_set_geometry_t*)(void*)arg0;
   326  	args->result = (int32_t)mdbx_env_set_geometry(
   327  		(MDBX_env*)(void*)args->env,
   328  		args->size_lower,
   329  		args->size_now,
   330  		args->size_upper,
   331  		args->growth_step,
   332  		args->shrink_threshold,
   333  		args->page_size
   334  	);
   335  }
   336  
   337  typedef struct mdbx_env_info_t {
   338  	size_t env;
   339  	size_t txn;
   340  	size_t info;
   341  	size_t size;
   342  	int32_t result;
   343  } mdbx_env_info_t;
   344  
   345  void do_mdbx_env_info_ex(size_t arg0, size_t arg1) {
   346  	mdbx_env_info_t* args = (mdbx_env_info_t*)(void*)arg0;
   347  	args->result = (int32_t)mdbx_env_info_ex(
   348  		(MDBX_env*)(void*)args->env,
   349  		(MDBX_txn*)(void*)args->txn,
   350  		(MDBX_envinfo*)(void*)args->info,
   351  		args->size
   352  	);
   353  }
   354  
   355  typedef struct mdbx_txn_info_t {
   356  	size_t txn;
   357  	size_t info;
   358  	int32_t scan_rlt;
   359  	int32_t result;
   360  } mdbx_txn_info_t;
   361  
   362  void do_mdbx_txn_info(size_t arg0, size_t arg1) {
   363  	mdbx_txn_info_t* args = (mdbx_txn_info_t*)(void*)arg0;
   364  	args->result = (int32_t)mdbx_txn_info(
   365  		(MDBX_txn*)(void*)args->txn,
   366  		(MDBX_txn_info*)(void*)args->info,
   367  		args->scan_rlt >= 0
   368  	);
   369  }
   370  
   371  typedef struct mdbx_txn_flags_t {
   372  	size_t txn;
   373  	int32_t flags;
   374  } mdbx_txn_flags_t;
   375  
   376  void do_mdbx_txn_flags(size_t arg0, size_t arg1) {
   377  	mdbx_txn_flags_t* args = (mdbx_txn_flags_t*)(void*)arg0;
   378  	args->flags = (int32_t)mdbx_txn_flags(
   379  		(MDBX_txn*)(void*)args->txn
   380  	);
   381  }
   382  
   383  typedef struct mdbx_txn_id_t {
   384  	size_t txn;
   385  	uint64_t id;
   386  } mdbx_txn_id_t;
   387  
   388  void do_mdbx_txn_id(size_t arg0, size_t arg1) {
   389  	mdbx_txn_id_t* args = (mdbx_txn_id_t*)(void*)arg0;
   390  	args->id = mdbx_txn_id(
   391  		(MDBX_txn*)(void*)args->txn
   392  	);
   393  }
   394  
   395  typedef struct mdbx_txn_commit_ex_t {
   396  	size_t txn;
   397  	size_t latency;
   398  	int32_t result;
   399  } mdbx_txn_commit_ex_t;
   400  
   401  void do_mdbx_txn_commit_ex(size_t arg0, size_t arg1) {
   402  	mdbx_txn_commit_ex_t* args = (mdbx_txn_commit_ex_t*)(void*)arg0;
   403  	args->result = (int32_t)mdbx_txn_commit_ex(
   404  		(MDBX_txn*)(void*)args->txn,
   405  		(MDBX_commit_latency*)(void*)args->latency
   406  	);
   407  }
   408  
   409  typedef struct mdbx_txn_result_t {
   410  	size_t txn;
   411  	int32_t result;
   412  } mdbx_txn_result_t;
   413  
   414  void do_mdbx_txn_abort(size_t arg0, size_t arg1) {
   415  	mdbx_txn_result_t* args = (mdbx_txn_result_t*)(void*)arg0;
   416  	args->result = (int32_t)mdbx_txn_abort(
   417  		(MDBX_txn*)(void*)args->txn
   418  	);
   419  }
   420  
   421  void do_mdbx_txn_break(size_t arg0, size_t arg1) {
   422  	mdbx_txn_result_t* args = (mdbx_txn_result_t*)(void*)arg0;
   423  	args->result = (int32_t)mdbx_txn_break(
   424  		(MDBX_txn*)(void*)args->txn
   425  	);
   426  }
   427  
   428  void do_mdbx_txn_reset(size_t arg0, size_t arg1) {
   429  	mdbx_txn_result_t* args = (mdbx_txn_result_t*)(void*)arg0;
   430  	args->result = (int32_t)mdbx_txn_reset(
   431  		(MDBX_txn*)(void*)args->txn
   432  	);
   433  }
   434  
   435  void do_mdbx_txn_renew(size_t arg0, size_t arg1) {
   436  	mdbx_txn_result_t* args = (mdbx_txn_result_t*)(void*)arg0;
   437  	args->result = (int32_t)mdbx_txn_renew(
   438  		(MDBX_txn*)(void*)args->txn
   439  	);
   440  }
   441  
   442  typedef struct mdbx_txn_canary_t {
   443  	size_t txn;
   444  	size_t canary;
   445  	int32_t result;
   446  } mdbx_txn_canary_t;
   447  
   448  void do_mdbx_canary_put(size_t arg0, size_t arg1) {
   449  	mdbx_txn_canary_t* args = (mdbx_txn_canary_t*)(void*)arg0;
   450  	args->result = (int32_t)mdbx_canary_put(
   451  		(MDBX_txn*)(void*)args->txn,
   452  		(MDBX_canary*)(void*)args->canary
   453  	);
   454  }
   455  
   456  void do_mdbx_canary_get(size_t arg0, size_t arg1) {
   457  	mdbx_txn_canary_t* args = (mdbx_txn_canary_t*)(void*)arg0;
   458  	args->result = (int32_t)mdbx_canary_get(
   459  		(MDBX_txn*)(void*)args->txn,
   460  		(MDBX_canary*)(void*)args->canary
   461  	);
   462  }
   463  
   464  typedef struct mdbx_dbi_stat_t {
   465  	size_t txn;
   466  	size_t stat;
   467  	size_t size;
   468  	uint32_t dbi;
   469  	int32_t result;
   470  } mdbx_dbi_stat_t;
   471  
   472  void do_mdbx_dbi_stat(size_t arg0, size_t arg1) {
   473  	mdbx_dbi_stat_t* args = (mdbx_dbi_stat_t*)(void*)arg0;
   474  	args->result = (int32_t)mdbx_dbi_stat(
   475  		(MDBX_txn*)(void*)args->txn,
   476  		(MDBX_dbi)args->dbi,
   477  		(MDBX_stat*)(void*)args->stat,
   478  		args->size
   479  	);
   480  }
   481  
   482  typedef struct mdbx_dbi_flags_t {
   483  	size_t txn;
   484  	size_t flags;
   485  	size_t state;
   486  	uint32_t dbi;
   487  	int32_t result;
   488  } mdbx_dbi_flags_t;
   489  
   490  void do_mdbx_dbi_flags_ex(size_t arg0, size_t arg1) {
   491  	mdbx_dbi_flags_t* args = (mdbx_dbi_flags_t*)(void*)arg0;
   492  	args->result = (int32_t)mdbx_dbi_flags_ex(
   493  		(MDBX_txn*)(void*)args->txn,
   494  		(MDBX_dbi)args->dbi,
   495  		(unsigned*)(void*)args->flags,
   496  		(unsigned*)(void*)args->state
   497  	);
   498  }
   499  
   500  typedef struct mdbx_drop_t {
   501  	size_t txn;
   502  	size_t del;
   503  	uint32_t dbi;
   504  	int32_t result;
   505  } mdbx_drop_t;
   506  
   507  void do_mdbx_drop(size_t arg0, size_t arg1) {
   508  	mdbx_drop_t* args = (mdbx_drop_t*)(void*)arg0;
   509  	args->result = (int32_t)mdbx_drop(
   510  		(MDBX_txn*)(void*)args->txn,
   511  		(MDBX_dbi)args->dbi,
   512  		args->del > 0
   513  	);
   514  }
   515  
   516  typedef struct mdbx_get_t {
   517  	size_t txn;
   518  	size_t key;
   519  	size_t data;
   520  	uint32_t dbi;
   521  	int32_t result;
   522  } mdbx_get_t;
   523  
   524  void do_mdbx_get(size_t arg0, size_t arg1) {
   525  	mdbx_get_t* args = (mdbx_get_t*)(void*)arg0;
   526  	args->result = (int32_t)mdbx_get(
   527  		(MDBX_txn*)(void*)args->txn,
   528  		(MDBX_dbi)args->dbi,
   529  		(MDBX_val*)(void*)args->key,
   530  		(MDBX_val*)(void*)args->data
   531  	);
   532  }
   533  
   534  void do_mdbx_get_equal_or_great(size_t arg0, size_t arg1) {
   535  	mdbx_get_t* args = (mdbx_get_t*)(void*)arg0;
   536  	args->result = (int32_t)mdbx_get_equal_or_great(
   537  		(MDBX_txn*)(void*)args->txn,
   538  		(MDBX_dbi)args->dbi,
   539  		(MDBX_val*)(void*)args->key,
   540  		(MDBX_val*)(void*)args->data
   541  	);
   542  }
   543  
   544  typedef struct mdbx_get_ex_t {
   545  	size_t txn;
   546  	size_t key;
   547  	size_t data;
   548  	size_t values_count;
   549  	uint32_t dbi;
   550  	int32_t result;
   551  } mdbx_get_ex_t;
   552  
   553  void do_mdbx_get_ex(size_t arg0, size_t arg1) {
   554  	mdbx_get_ex_t* args = (mdbx_get_ex_t*)(void*)arg0;
   555  	args->result = (int32_t)mdbx_get_ex(
   556  		(MDBX_txn*)(void*)args->txn,
   557  		(MDBX_dbi)args->dbi,
   558  		(MDBX_val*)(void*)args->key,
   559  		(MDBX_val*)(void*)args->data,
   560  		(size_t*)(void*)args->values_count
   561  	);
   562  }
   563  
   564  typedef struct mdbx_put_t {
   565  	size_t txn;
   566  	size_t key;
   567  	size_t data;
   568  	uint32_t dbi;
   569  	uint32_t flags;
   570  	int32_t result;
   571  } mdbx_put_t;
   572  
   573  void do_mdbx_put(size_t arg0, size_t arg1) {
   574  	mdbx_put_t* args = (mdbx_put_t*)(void*)arg0;
   575  	args->result = (int32_t)mdbx_put(
   576  		(MDBX_txn*)(void*)args->txn,
   577  		(MDBX_dbi)args->dbi,
   578  		(MDBX_val*)(void*)args->key,
   579  		(MDBX_val*)(void*)args->data,
   580  		(MDBX_put_flags_t)args->flags
   581  	);
   582  }
   583  
   584  typedef struct mdbx_replace_t {
   585  	size_t txn;
   586  	size_t key;
   587  	size_t data;
   588  	size_t old_data;
   589  	uint32_t dbi;
   590  	uint32_t flags;
   591  	int32_t result;
   592  } mdbx_replace_t;
   593  
   594  void do_mdbx_replace(size_t arg0, size_t arg1) {
   595  	mdbx_replace_t* args = (mdbx_replace_t*)(void*)arg0;
   596  	args->result = (int32_t)mdbx_replace(
   597  		(MDBX_txn*)(void*)args->txn,
   598  		(MDBX_dbi)args->dbi,
   599  		(MDBX_val*)(void*)args->key,
   600  		(MDBX_val*)(void*)args->data,
   601  		(MDBX_val*)(void*)args->old_data,
   602  		(MDBX_put_flags_t)args->flags
   603  	);
   604  }
   605  
   606  typedef struct mdbx_del_t {
   607  	size_t txn;
   608  	size_t key;
   609  	size_t data;
   610  	uint32_t dbi;
   611  	int32_t result;
   612  } mdbx_del_t;
   613  
   614  void do_mdbx_del(size_t arg0, size_t arg1) {
   615  	mdbx_del_t* args = (mdbx_del_t*)(void*)arg0;
   616  	args->result = (int32_t)mdbx_del(
   617  		(MDBX_txn*)(void*)args->txn,
   618  		(MDBX_dbi)args->dbi,
   619  		(MDBX_val*)(void*)args->key,
   620  		(MDBX_val*)(void*)args->data
   621  	);
   622  }
   623  
   624  typedef struct mdbx_txn_begin_t {
   625  	size_t env;
   626  	size_t parent;
   627  	size_t txn;
   628  	size_t context;
   629  	uint32_t flags;
   630  	int32_t result;
   631  } mdbx_txn_begin_t;
   632  
   633  void do_mdbx_txn_begin_ex(size_t arg0, size_t arg1) {
   634  	mdbx_txn_begin_t* args = (mdbx_txn_begin_t*)(void*)arg0;
   635  	args->result = (int32_t)mdbx_txn_begin_ex(
   636  		(MDBX_env*)(void*)args->env,
   637  		//(MDBX_txn*)(void*)args->parent,
   638  		NULL,
   639  		(MDBX_txn_flags_t)args->flags,
   640  		(MDBX_txn**)(void*)args->txn,
   641  		(void*)args->context
   642  	);
   643  }
   644  
   645  typedef struct mdbx_cursor_create_t {
   646  	size_t context;
   647  	size_t cursor;
   648  } mdbx_cursor_create_t;
   649  
   650  void do_mdbx_cursor_create(size_t arg0, size_t arg1) {
   651  	mdbx_cursor_create_t* args = (mdbx_cursor_create_t*)(void*)arg0;
   652  	args->cursor = (size_t)mdbx_cursor_create(
   653  		(void*)args->context
   654  	);
   655  }
   656  
   657  typedef struct mdbx_cursor_bind_t {
   658  	size_t txn;
   659  	size_t cursor;
   660  	uint32_t dbi;
   661  	int32_t result;
   662  } mdbx_cursor_bind_t;
   663  
   664  void do_mdbx_cursor_bind(size_t arg0, size_t arg1) {
   665  	mdbx_cursor_bind_t* args = (mdbx_cursor_bind_t*)(void*)arg0;
   666  	args->result = (int32_t)mdbx_cursor_bind(
   667  		(MDBX_txn*)(void*)args->txn,
   668  		(MDBX_cursor*)(void*)args->cursor,
   669  		(MDBX_dbi)args->dbi
   670  	);
   671  }
   672  
   673  typedef struct mdbx_cursor_open_t {
   674  	size_t txn;
   675  	size_t cursor;
   676  	uint32_t dbi;
   677  	int32_t result;
   678  } mdbx_cursor_open_t;
   679  
   680  void do_mdbx_cursor_open(size_t arg0, size_t arg1) {
   681  	mdbx_cursor_open_t* args = (mdbx_cursor_open_t*)(void*)arg0;
   682  	args->result = (int32_t)mdbx_cursor_open(
   683  		(MDBX_txn*)(void*)args->txn,
   684  		(MDBX_dbi)args->dbi,
   685  		(MDBX_cursor**)(void*)args->cursor
   686  	);
   687  }
   688  
   689  void do_mdbx_cursor_close(size_t arg0, size_t arg1) {
   690  	mdbx_cursor_close((MDBX_cursor*)(void*)arg0);
   691  }
   692  
   693  typedef struct mdbx_cursor_renew_t {
   694  	size_t txn;
   695  	size_t cursor;
   696  	int32_t result;
   697  } mdbx_cursor_renew_t;
   698  
   699  void do_mdbx_cursor_renew(size_t arg0, size_t arg1) {
   700  	mdbx_cursor_renew_t* args = (mdbx_cursor_renew_t*)(void*)arg0;
   701  	args->result = (int32_t)mdbx_cursor_renew(
   702  		(MDBX_txn*)(void*)args->txn,
   703  		(MDBX_cursor*)(void*)args->cursor
   704  	);
   705  }
   706  
   707  typedef struct mdbx_cursor_txn_t {
   708  	size_t cursor;
   709  	size_t txn;
   710  } mdbx_cursor_txn_t;
   711  
   712  void do_mdbx_cursor_txn(size_t arg0, size_t arg1) {
   713  	mdbx_cursor_txn_t* args = (mdbx_cursor_txn_t*)(void*)arg0;
   714  	args->txn = (size_t)mdbx_cursor_txn(
   715  		(MDBX_cursor*)(void*)args->cursor
   716  	);
   717  }
   718  
   719  typedef struct mdbx_cursor_dbi_t {
   720  	size_t cursor;
   721  	uint32_t dbi;
   722  } mdbx_cursor_dbi_t;
   723  
   724  void do_mdbx_cursor_dbi(size_t arg0, size_t arg1) {
   725  	mdbx_cursor_dbi_t* args = (mdbx_cursor_dbi_t*)(void*)arg0;
   726  	args->dbi = (uint32_t)mdbx_cursor_dbi(
   727  		(MDBX_cursor*)(void*)args->cursor
   728  	);
   729  }
   730  
   731  typedef struct mdbx_cursor_copy_t {
   732  	size_t src;
   733  	size_t dest;
   734  	int32_t result;
   735  } mdbx_cursor_copy_t;
   736  
   737  void do_mdbx_cursor_copy(size_t arg0, size_t arg1) {
   738  	mdbx_cursor_copy_t* args = (mdbx_cursor_copy_t*)(void*)arg0;
   739  	args->result = (int32_t)mdbx_cursor_copy(
   740  		(MDBX_cursor*)(void*)args->src,
   741  		(MDBX_cursor*)(void*)args->dest
   742  	);
   743  }
   744  
   745  typedef struct mdbx_cursor_get_t {
   746  	size_t cursor;
   747  	size_t key;
   748  	size_t data;
   749  	uint32_t op;
   750  	int32_t result;
   751  } mdbx_cursor_get_t;
   752  
   753  void do_mdbx_cursor_get(size_t arg0, size_t arg1) {
   754  	mdbx_cursor_get_t* args = (mdbx_cursor_get_t*)(void*)arg0;
   755  	args->result = (int32_t)mdbx_cursor_get(
   756  		(MDBX_cursor*)(void*)args->cursor,
   757  		(MDBX_val*)(void*)args->key,
   758  		(MDBX_val*)(void*)args->data,
   759  		(MDBX_cursor_op)args->op
   760  	);
   761  }
   762  
   763  typedef struct mdbx_cursor_put_t {
   764  	size_t cursor;
   765  	size_t key;
   766  	size_t data;
   767  	uint32_t flags;
   768  	int32_t result;
   769  } mdbx_cursor_put_t;
   770  
   771  void do_mdbx_cursor_put(size_t arg0, size_t arg1) {
   772  	mdbx_cursor_put_t* args = (mdbx_cursor_put_t*)(void*)arg0;
   773  	args->result = (int32_t)mdbx_cursor_put(
   774  		(MDBX_cursor*)(void*)args->cursor,
   775  		(MDBX_val*)(void*)args->key,
   776  		(MDBX_val*)(void*)args->data,
   777  		(MDBX_put_flags_t)args->flags
   778  	);
   779  }
   780  
   781  typedef struct mdbx_cursor_del_t {
   782  	size_t cursor;
   783  	uint32_t flags;
   784  	int32_t result;
   785  } mdbx_cursor_del_t;
   786  
   787  void do_mdbx_cursor_del(size_t arg0, size_t arg1) {
   788  	mdbx_cursor_del_t* args = (mdbx_cursor_del_t*)(void*)arg0;
   789  	args->result = (int32_t)mdbx_cursor_del(
   790  		(MDBX_cursor*)(void*)args->cursor,
   791  		(MDBX_put_flags_t)args->flags
   792  	);
   793  }
   794  
   795  typedef struct mdbx_cursor_count_t {
   796  	size_t cursor;
   797  	size_t count;
   798  	int32_t result;
   799  } mdbx_cursor_count_t;
   800  
   801  void do_mdbx_cursor_count(size_t arg0, size_t arg1) {
   802  	mdbx_cursor_count_t* args = (mdbx_cursor_count_t*)(void*)arg0;
   803  	args->result = (int32_t)mdbx_cursor_count(
   804  		(MDBX_cursor*)(void*)args->cursor,
   805  		(size_t*)(void*)args->count
   806  	);
   807  }
   808  
   809  typedef struct mdbx_cursor_eof_t {
   810  	size_t cursor;
   811  	int32_t result;
   812  } mdbx_cursor_eof_t;
   813  
   814  void do_mdbx_cursor_eof(size_t arg0, size_t arg1) {
   815  	mdbx_cursor_eof_t* args = (mdbx_cursor_eof_t*)(void*)arg0;
   816  	args->result = (int32_t)mdbx_cursor_eof(
   817  		(MDBX_cursor*)(void*)args->cursor
   818  	);
   819  }
   820  
   821  typedef struct mdbx_cursor_on_first_t {
   822  	size_t cursor;
   823  	int32_t result;
   824  } mdbx_cursor_on_first_t;
   825  
   826  void do_mdbx_cursor_on_first(size_t arg0, size_t arg1) {
   827  	mdbx_cursor_on_first_t* args = (mdbx_cursor_on_first_t*)(void*)arg0;
   828  	args->result = (int32_t)mdbx_cursor_on_first(
   829  		(MDBX_cursor*)(void*)args->cursor
   830  	);
   831  }
   832  
   833  typedef struct mdbx_cursor_on_last_t {
   834  	size_t cursor;
   835  	int32_t result;
   836  } mdbx_cursor_on_last_t;
   837  
   838  void do_mdbx_cursor_on_last(size_t arg0, size_t arg1) {
   839  	mdbx_cursor_on_last_t* args = (mdbx_cursor_on_last_t*)(void*)arg0;
   840  	args->result = (int32_t)mdbx_cursor_on_last(
   841  		(MDBX_cursor*)(void*)args->cursor
   842  	);
   843  }
   844  
   845  typedef struct mdbx_estimate_distance_t {
   846  	size_t first;
   847  	size_t last;
   848  	int64_t distance_items;
   849  	int32_t result;
   850  } mdbx_estimate_distance_t;
   851  
   852  void do_mdbx_estimate_distance(size_t arg0, size_t arg1) {
   853  	mdbx_estimate_distance_t* args = (mdbx_estimate_distance_t*)(void*)arg0;
   854  	args->result = (int32_t)mdbx_estimate_distance(
   855  		(MDBX_cursor*)(void*)args->first,
   856  		(MDBX_cursor*)(void*)args->last,
   857  		(ptrdiff_t*)(void*)args->distance_items
   858  	);
   859  }
   860  
   861  //typedef struct mdbx_estimate_move_t {
   862  //	size_t txn;
   863  //	size_t last;
   864  //	int64_t distance_items;
   865  //	int32_t result;
   866  //} mdbx_estimate_move_t;
   867  
   868  */
   869  import "C"
   870  import (
   871  	"github.com/moontrade/mdbx-go/internal/capture"
   872  	"github.com/moontrade/mdbx-go/internal/unsafecgo"
   873  	"os"
   874  	"reflect"
   875  	"sync"
   876  	"syscall"
   877  	"time"
   878  	"unsafe"
   879  )
   880  
   881  const (
   882  	MaxDBI      = uint32(C.MDBX_MAX_DBI)
   883  	MaxDataSize = uint32(C.MDBX_MAXDATASIZE)
   884  	MinPageSize = int(C.MDBX_MIN_PAGESIZE)
   885  	MaxPageSize = int(C.MDBX_MAX_PAGESIZE)
   886  )
   887  
   888  func init() {
   889  	sz0 := unsafe.Sizeof(C.MDBX_envinfo{})
   890  	sz1 := unsafe.Sizeof(EnvInfo{})
   891  	if sz0 != sz1 {
   892  		panic("sizeof(C.MDBX_envinfo) != sizeof(EnvInfo{})")
   893  	}
   894  }
   895  
   896  type Cmp C.MDBX_cmp_func
   897  
   898  var (
   899  	CmpU16                    = (*Cmp)(C.mdbx_cmp_u16)
   900  	CmpU32                    = (*Cmp)(C.mdbx_cmp_u32)
   901  	CmpU64                    = (*Cmp)(C.mdbx_cmp_u64)
   902  	CmpU16PrefixLexical       = (*Cmp)(C.mdbx_cmp_u16_prefix_lexical)
   903  	CmpU16PrefixU64           = (*Cmp)(C.mdbx_cmp_u16_prefix_u64)
   904  	CmpU32PrefixLexical       = (*Cmp)(C.mdbx_cmp_u32_prefix_lexical)
   905  	CmpU32PrefixU64           = (*Cmp)(C.mdbx_cmp_u32_prefix_u64)
   906  	CmpU64PrefixLexical       = (*Cmp)(C.mdbx_cmp_u64_prefix_lexical)
   907  	CmpU64PrefixU64           = (*Cmp)(C.mdbx_cmp_u64_prefix_u64)
   908  	CmpU32PrefixU64DupLexical = (*Cmp)(C.mdbx_cmp_u32_prefix_u64_dup_lexical)
   909  	CmpU32PrefixU64DupU64     = (*Cmp)(C.mdbx_cmp_u32_prefix_u64_dup_u64)
   910  	CmpU64PrefixU64DupLexical = (*Cmp)(C.mdbx_cmp_u64_prefix_u64_dup_lexical)
   911  	CmpU64PrefixU64DupU64     = (*Cmp)(C.mdbx_cmp_u64_prefix_u64_dup_u64)
   912  )
   913  
   914  // Chk invokes the embedded mdbx_chk utility
   915  // usage: mdbx_chk [-V] [-v] [-q] [-c] [-0|1|2] [-w] [-d] [-i] [-s subdb] dbpath
   916  //
   917  //	-V            print version and exit
   918  //	-v            more verbose, could be used multiple times
   919  //	-q            be quiet
   920  //	-c            force cooperative mode (don't try exclusive)
   921  //	-w            write-mode checking
   922  //	-d            disable page-by-page traversal of B-tree
   923  //	-i            ignore wrong order errors (for custom comparators case)
   924  //	-s subdb      process a specific subdatabase only
   925  //	-0|1|2        force using specific meta-page 0, or 2 for checking
   926  //	-t            turn to a specified meta-page on successful check
   927  //	-T            turn to a specified meta-page EVEN ON UNSUCCESSFUL CHECK!
   928  func Chk(args ...string) (result int32, output []byte, err error) {
   929  	argv := make([]*C.char, len(args)+1)
   930  	argv[0] = C.CString("mdbx_chk")
   931  	for i, arg := range args {
   932  		argv[i+1] = C.CString(arg)
   933  	}
   934  	defer func() {
   935  		for _, arg := range argv {
   936  			C.free(unsafe.Pointer(arg))
   937  		}
   938  	}()
   939  
   940  	//	ch := make(chan string)
   941  	//	go func() {
   942  	//		defer close(ch)
   943  	//		err = capture.CaptureWithCGoChan(ch, func() {
   944  	//			result = int32(C.mdbx_chk((C.int)(len(argv)), (**C.char)(unsafe.Pointer(&argv[0]))))
   945  	//		})
   946  	//	}()
   947  	//
   948  	//	var lines []string
   949  	//LOOP:
   950  	//	for {
   951  	//		select {
   952  	//		case line, ok := <-ch:
   953  	//			if !ok {
   954  	//				break LOOP
   955  	//			}
   956  	//			//fmt.Fprintf(out, "%s\n", line)
   957  	//			lines = append(lines, line)
   958  	//		}
   959  	//	}
   960  	//	for _, line := range lines {
   961  	//		println(line)
   962  	//	}
   963  
   964  	output, err = capture.CaptureWithCGo(func() {
   965  		result = int32(C.mdbx_chk((C.int)(len(argv)), (**C.char)(unsafe.Pointer(&argv[0]))))
   966  	})
   967  	return
   968  }
   969  
   970  // ChkMain invokes the embedded mdbx_chk utility and exits the program.
   971  // usage: mdbx_chk [-V] [-v] [-q] [-c] [-0|1|2] [-w] [-d] [-i] [-s subdb] dbpath
   972  //
   973  //	-V            print version and exit
   974  //	-v            more verbose, could be used multiple times
   975  //	-q            be quiet
   976  //	-c            force cooperative mode (don't try exclusive)
   977  //	-w            write-mode checking
   978  //	-d            disable page-by-page traversal of B-tree
   979  //	-i            ignore wrong order errors (for custom comparators case)
   980  //	-s subdb      process a specific subdatabase only
   981  //	-0|1|2        force using specific meta-page 0, or 2 for checking
   982  //	-t            turn to a specified meta-page on successful check
   983  //	-T            turn to a specified meta-page EVEN ON UNSUCCESSFUL CHECK!
   984  func ChkMain(args ...string) {
   985  	argv := make([]*C.char, len(args)+1)
   986  	argv[0] = C.CString("mdbx_chk")
   987  	for i, arg := range args {
   988  		argv[i+1] = C.CString(arg)
   989  	}
   990  	defer func() {
   991  		for _, arg := range argv {
   992  			C.free(unsafe.Pointer(arg))
   993  		}
   994  	}()
   995  
   996  	os.Exit(int(C.mdbx_chk((C.int)(len(argv)), (**C.char)(unsafe.Pointer(&argv[0])))))
   997  }
   998  
   999  // Stat invokes the embedded mdbx_stat utility.
  1000  // usage: mdbx_stat [-V] [-q] [-e] [-f[f[f]]] [-r[r]] [-a|-s name] dbpath
  1001  //
  1002  //	-V            print version and exit
  1003  //	-q            be quiet
  1004  //	-p            show statistics of page operations for current session
  1005  //	-e            show whole DB info
  1006  //	-f            show GC info
  1007  //	-r            show readers
  1008  //	-a            print stat of main DB and all subDBs
  1009  //	-s name       print stat of only the specified named subDB
  1010  //	              by default print stat of only the main DB
  1011  func Stat(args ...string) (result int32, output []byte, err error) {
  1012  	argv := make([]*C.char, len(args)+1)
  1013  	argv[0] = C.CString("mdbx_stat")
  1014  	for i, arg := range args {
  1015  		argv[i+1] = C.CString(arg)
  1016  	}
  1017  	defer func() {
  1018  		for _, arg := range argv {
  1019  			C.free(unsafe.Pointer(arg))
  1020  		}
  1021  	}()
  1022  	output, err = capture.CaptureWithCGo(func() {
  1023  		result = int32(C.mdbx_stat((C.int)(len(argv)), (**C.char)(unsafe.Pointer(&argv[0]))))
  1024  	})
  1025  	return
  1026  }
  1027  
  1028  // StatMain invokes the embedded mdbx_stat utility and exits the program.
  1029  // usage: mdbx_stat [-V] [-q] [-e] [-f[f[f]]] [-r[r]] [-a|-s name] dbpath
  1030  //
  1031  //	-V            print version and exit
  1032  //	-q            be quiet
  1033  //	-p            show statistics of page operations for current session
  1034  //	-e            show whole DB info
  1035  //	-f            show GC info
  1036  //	-r            show readers
  1037  //	-a            print stat of main DB and all subDBs
  1038  //	-s name       print stat of only the specified named subDB
  1039  //	              by default print stat of only the main DB
  1040  func StatMain(args ...string) {
  1041  	argv := make([]*C.char, len(args)+1)
  1042  	argv[0] = C.CString("mdbx_chk")
  1043  	for i, arg := range args {
  1044  		argv[i+1] = C.CString(arg)
  1045  	}
  1046  	defer func() {
  1047  		for _, arg := range argv {
  1048  			C.free(unsafe.Pointer(arg))
  1049  		}
  1050  	}()
  1051  
  1052  	os.Exit(int(C.mdbx_stat((C.int)(len(argv)), (**C.char)(unsafe.Pointer(&argv[0])))))
  1053  }
  1054  
  1055  type LogLevel int32
  1056  
  1057  const (
  1058  	// LogFatal Critical conditions, i.e. assertion failures
  1059  	LogFatal = LogLevel(C.MDBX_LOG_FATAL)
  1060  
  1061  	// LogError Enables logging for error conditions and \ref MDBX_LOG_FATAL
  1062  	LogError = LogLevel(C.MDBX_LOG_ERROR)
  1063  
  1064  	// LogWarn Enables logging for warning conditions and \ref MDBX_LOG_ERROR ...
  1065  	// \ref MDBX_LOG_FATAL
  1066  	LogWarn = LogLevel(C.MDBX_LOG_WARN)
  1067  
  1068  	// LogNotice Enables logging for normal but significant condition and
  1069  	// \ref MDBX_LOG_WARN ... \ref MDBX_LOG_FATAL
  1070  	LogNotice = LogLevel(C.MDBX_LOG_NOTICE)
  1071  
  1072  	// LogVerbose Enables logging for verbose informational and \ref MDBX_LOG_NOTICE ...
  1073  	// \ref MDBX_LOG_FATAL
  1074  	LogVerbose = LogLevel(C.MDBX_LOG_VERBOSE)
  1075  
  1076  	// LogDebug Enables logging for debug-level messages and \ref MDBX_LOG_VERBOSE ...
  1077  	// \ref MDBX_LOG_FATAL
  1078  	LogDebug = LogLevel(C.MDBX_LOG_DEBUG)
  1079  
  1080  	// LogTrace Enables logging for trace debug-level messages and \ref MDBX_LOG_DEBUG ...
  1081  	// \ref MDBX_LOG_FATAL
  1082  	LogTrace = LogLevel(C.MDBX_LOG_TRACE)
  1083  
  1084  	// LogExtra Enables extra debug-level messages (dump pgno lists) and all other log-messages
  1085  	LogExtra = LogLevel(C.MDBX_LOG_EXTRA)
  1086  	LogMax   = LogLevel(7)
  1087  
  1088  	// LogDontChange for \ref mdbx_setup_debug() only: Don't change current settings
  1089  	LogDontChange = LogLevel(C.MDBX_LOG_DONTCHANGE)
  1090  )
  1091  
  1092  type Error int32
  1093  
  1094  func (e Error) Error() string {
  1095  	args := struct {
  1096  		result uintptr
  1097  		code   int32
  1098  	}{
  1099  		code: int32(e),
  1100  	}
  1101  	ptr := uintptr(unsafe.Pointer(&args))
  1102  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_strerror), ptr, 0)
  1103  	str := C.GoString((*C.char)(unsafe.Pointer(args.result)))
  1104  	return str
  1105  }
  1106  
  1107  const (
  1108  	ErrSuccess     = Error(C.MDBX_SUCCESS)
  1109  	ErrResultFalse = ErrSuccess
  1110  
  1111  	// ErrResultTrue Successful result with special meaning or a flag
  1112  	ErrResultTrue = Error(C.MDBX_RESULT_TRUE)
  1113  
  1114  	// ErrKeyExist key/data pair already exist
  1115  	ErrKeyExist = Error(C.MDBX_KEYEXIST)
  1116  
  1117  	// ErrFirstLMDBErrCode The first LMDB-compatible defined error code
  1118  	ErrFirstLMDBErrCode = ErrKeyExist
  1119  
  1120  	// ErrNotFound key/data pair not found (EOF)
  1121  	ErrNotFound = Error(C.MDBX_NOTFOUND)
  1122  
  1123  	// ErrPageNotFound Requested page not found -this usually indicates corruption
  1124  	ErrPageNotFound = Error(C.MDBX_PAGE_NOTFOUND)
  1125  
  1126  	// ErrCorrupted Database is corrupted (page was wrong type and so on)
  1127  	ErrCorrupted = Error(C.MDBX_CORRUPTED)
  1128  
  1129  	// ErrPanic Environment had fatal error, i.e. update of meta page failed and so on.
  1130  	ErrPanic = Error(C.MDBX_PANIC)
  1131  
  1132  	// ErrVersionMismatch DB file version mismatch with libmdbx
  1133  	ErrVersionMismatch = Error(C.MDBX_VERSION_MISMATCH)
  1134  
  1135  	// ErrInvalid File is not a valid MDBX file
  1136  	ErrInvalid = Error(C.MDBX_INVALID)
  1137  
  1138  	// ErrMapFull Environment mapsize reached
  1139  	ErrMapFull = Error(C.MDBX_MAP_FULL)
  1140  
  1141  	// ErrDBSFull Environment maxdbs reached
  1142  	ErrDBSFull = Error(C.MDBX_DBS_FULL)
  1143  
  1144  	// ErrReadersFull Environment maxreaders reached
  1145  	ErrReadersFull = Error(C.MDBX_READERS_FULL)
  1146  
  1147  	// ErrTXNFull Transaction has too many dirty pages, i.e transaction too big
  1148  	ErrTXNFull = Error(C.MDBX_TXN_FULL)
  1149  
  1150  	// ErrCursorFull Cursor stack too deep -this usually indicates corruption, i.e branchC.pages loop
  1151  	ErrCursorFull = Error(C.MDBX_CURSOR_FULL)
  1152  
  1153  	// ErrPageFull Page has not enough space -internal error
  1154  	ErrPageFull = Error(C.MDBX_PAGE_FULL)
  1155  
  1156  	// ErrUnableExtendMapSize Database engine was unable to extend mapping, e.g. since address space
  1157  	// is unavailable or busy. This can mean:
  1158  	//  - Database size extended by other process beyond to environment mapsize
  1159  	//    and engine was unable to extend mapping while starting read
  1160  	//    transaction. Environment should be reopened to continue.
  1161  	//  - Engine was unable to extend mapping during write transaction
  1162  	//    or explicit call of \ref mdbx_env_set_geometry().
  1163  	ErrUnableExtendMapSize = Error(C.MDBX_UNABLE_EXTEND_MAPSIZE)
  1164  
  1165  	// ErrIncompatible Environment or database is not compatible with the requested operation
  1166  	// or the specified flags. This can mean:
  1167  	//  - The operation expects an \ref MDBX_DUPSORT / \ref MDBX_DUPFIXED
  1168  	//    database.
  1169  	//  - Opening a named DB when the unnamed DB has \ref MDBX_DUPSORT /
  1170  	//    \ref MDBX_INTEGERKEY.
  1171  	//  - Accessing a data record as a database, or vice versa.
  1172  	//  - The database was dropped and recreated with different flags.
  1173  	ErrIncompatible = Error(C.MDBX_INCOMPATIBLE)
  1174  
  1175  	// ErrBadRSlot Invalid reuse of reader locktable slot
  1176  	// e.g. readC.transaction already run for current thread
  1177  	ErrBadRSlot = Error(C.MDBX_BAD_RSLOT)
  1178  
  1179  	// ErrBadTXN Transaction is not valid for requested operation,
  1180  	// e.g. had errored and be must aborted, has a child, or is invalid
  1181  	ErrBadTXN = Error(C.MDBX_BAD_TXN)
  1182  
  1183  	// ErrBadValSize Invalid size or alignment of key or data for target database,
  1184  	// either invalid subDB name
  1185  	ErrBadValSize = Error(C.MDBX_BAD_VALSIZE)
  1186  
  1187  	// ErrBadDBI The specified DBIC.handle is invalid
  1188  	// or changed by another thread/transaction.
  1189  	ErrBadDBI = Error(C.MDBX_BAD_DBI)
  1190  
  1191  	// ErrProblem Unexpected internal error, transaction should be aborted
  1192  	ErrProblem = Error(C.MDBX_PROBLEM)
  1193  
  1194  	// ErrLastLMDBErrCode The last LMDBC.compatible defined error code
  1195  	ErrLastLMDBErrCode = ErrProblem
  1196  
  1197  	// ErrBusy Another write transaction is running or environment is already used while
  1198  	// opening with \ref MDBX_EXCLUSIVE flag
  1199  	ErrBusy              = Error(C.MDBX_BUSY)
  1200  	ErrFirstAddedErrCode = ErrBusy                 // The first of MDBXC.added error codes
  1201  	ErrEMultiVal         = Error(C.MDBX_EMULTIVAL) // The specified key has more than one associated value
  1202  
  1203  	// ErrEBadSign Bad signature of a runtime object(s), this can mean:
  1204  	//  - memory corruption or doubleC.free;
  1205  	//  - ABI version mismatch (rare case);
  1206  	ErrEBadSign = Error(C.MDBX_EBADSIGN)
  1207  
  1208  	// ErrWannaRecovery Database should be recovered, but this could NOT be done for now
  1209  	// since it opened in readC.only mode.
  1210  	ErrWannaRecovery = Error(C.MDBX_WANNA_RECOVERY)
  1211  
  1212  	// ErrEKeyMismatch The given key value is mismatched to the current cursor position
  1213  	ErrEKeyMismatch = Error(C.MDBX_EKEYMISMATCH)
  1214  
  1215  	// ErrTooLarge Database is too large for current system,
  1216  	// e.g. could NOT be mapped into RAM.
  1217  	ErrTooLarge = Error(C.MDBX_TOO_LARGE)
  1218  
  1219  	// ErrThreadMismatch A thread has attempted to use a not owned object,
  1220  	// e.g. a transaction that started by another thread.
  1221  	ErrThreadMismatch = Error(C.MDBX_THREAD_MISMATCH)
  1222  
  1223  	// ErrTXNOverlapping Overlapping read and write transactions for the current thread
  1224  	ErrTXNOverlapping = Error(C.MDBX_TXN_OVERLAPPING)
  1225  
  1226  	ErrLastAddedErrcode = ErrTXNOverlapping
  1227  
  1228  	ErrENODAT  = Error(C.MDBX_ENODATA)
  1229  	ErrEINVAL  = Error(C.MDBX_EINVAL)
  1230  	ErrEACCESS = Error(C.MDBX_EACCESS)
  1231  	ErrENOMEM  = Error(C.MDBX_ENOMEM)
  1232  	ErrEROFS   = Error(C.MDBX_EROFS)
  1233  	ErrENOSYS  = Error(C.MDBX_ENOSYS)
  1234  	ErrEIO     = Error(C.MDBX_EIO)
  1235  	ErrEPERM   = Error(C.MDBX_EPERM)
  1236  	ErrEINTR   = Error(C.MDBX_EINTR)
  1237  	ErrENOENT  = Error(C.MDBX_ENOFILE)
  1238  	ErrENOTBLK = Error(C.MDBX_EREMOTE)
  1239  )
  1240  
  1241  type EnvFlags uint32
  1242  
  1243  const (
  1244  	EnvEnvDefaults EnvFlags = 0
  1245  
  1246  	// EnvNoSubDir No environment directory.
  1247  	//
  1248  	// By default, MDBX creates its environment in a directory whose pathname is
  1249  	// given in path, and creates its data and lock files under that directory.
  1250  	// With this option, path is used as-is for the database rootDB data file.
  1251  	// The database lock file is the path with "-lck" appended.
  1252  	//
  1253  	// - with `MDBX_NOSUBDIR` = in a filesystem we have the pair of MDBX-files
  1254  	//   which names derived from given pathname by appending predefined suffixes.
  1255  	//
  1256  	// - without `MDBX_NOSUBDIR` = in a filesystem we have the MDBX-directory with
  1257  	//   given pathname, within that a pair of MDBX-files with predefined names.
  1258  	//
  1259  	// This flag affects only at new environment creating by \ref mdbx_env_open(),
  1260  	// otherwise at opening an existing environment libmdbx will choice this
  1261  	// automatically.
  1262  	EnvNoSubDir = EnvFlags(C.MDBX_NOSUBDIR)
  1263  
  1264  	// EnvReadOnly Read only mode.
  1265  	//
  1266  	// Open the environment in read-only mode. No write operations will be
  1267  	// allowed. MDBX will still modify the lock file - except on read-only
  1268  	// filesystems, where MDBX does not use locks.
  1269  	//
  1270  	// - with `MDBX_RDONLY` = open environment in read-only mode.
  1271  	//   MDBX supports pure read-only mode (i.e. without opening LCK-file) only
  1272  	//   when environment directory and/or both files are not writable (and the
  1273  	//   LCK-file may be missing). In such case allowing file(s) to be placed
  1274  	//   on a network read-only share.
  1275  	//
  1276  	// - without `MDBX_RDONLY` = open environment in read-write mode.
  1277  	//
  1278  	// This flag affects only at environment opening but can't be changed after.
  1279  	EnvReadOnly = EnvFlags(C.MDBX_RDONLY)
  1280  
  1281  	// EnvExclusive Open environment in exclusive/monopolistic mode.
  1282  	//
  1283  	// `MDBX_EXCLUSIVE` flag can be used as a replacement for `MDB_NOLOCK`,
  1284  	// which don't supported by MDBX.
  1285  	// In this way, you can get the minimal overhead, but with the correct
  1286  	// multi-process and multi-thread locking.
  1287  	//
  1288  	// - with `MDBX_EXCLUSIVE` = open environment in exclusive/monopolistic mode
  1289  	//   or return \ref MDBX_BUSY if environment already used by other process.
  1290  	//   The rootDB feature of the exclusive mode is the ability to open the
  1291  	//   environment placed on a network share.
  1292  	//
  1293  	// - without `MDBX_EXCLUSIVE` = open environment in cooperative mode,
  1294  	//   i.e. for multi-process access/interaction/cooperation.
  1295  	//   The rootDB requirements of the cooperative mode are:
  1296  	//
  1297  	//   1. data files MUST be placed in the LOCAL file system,
  1298  	//      but NOT on a network share.
  1299  	//   2. environment MUST be opened only by LOCAL processes,
  1300  	//      but NOT over a network.
  1301  	//   3. OS kernel (i.e. file system and memory mapping implementation) and
  1302  	//      all processes that open the given environment MUST be running
  1303  	//      in the physically single RAM with cache-coherency. The only
  1304  	//      exception for cache-consistency requirement is Linux on MIPS
  1305  	//      architecture, but this case has not been tested for a long time).
  1306  	//
  1307  	// This flag affects only at environment opening but can't be changed after.
  1308  	EnvExclusive = EnvFlags(C.MDBX_EXCLUSIVE)
  1309  
  1310  	// EnvAccede Using database/environment which already opened by another process(es).
  1311  	//
  1312  	// The `MDBX_ACCEDE` flag is useful to avoid \ref MDBX_INCOMPATIBLE error
  1313  	// while opening the database/environment which is already used by another
  1314  	// process(es) with unknown mode/flags. In such cases, if there is a
  1315  	// difference in the specified flags (\ref MDBX_NOMETASYNC,
  1316  	// \ref MDBX_SAFE_NOSYNC, \ref MDBX_UTTERLY_NOSYNC, \ref MDBX_LIFORECLAIM,
  1317  	// \ref MDBX_COALESCE and \ref MDBX_NORDAHEAD), instead of returning an error,
  1318  	// the database will be opened in a compatibility with the already used mode.
  1319  	//
  1320  	// `MDBX_ACCEDE` has no effect if the current process is the only one either
  1321  	// opening the DB in read-only mode or other process(es) uses the DB in
  1322  	// read-only mode.
  1323  	EnvAccede = EnvFlags(C.MDBX_ACCEDE)
  1324  
  1325  	// EnvWriteMap Map data into memory with write permission.
  1326  	//
  1327  	// Use a writeable memory map unless \ref MDBX_RDONLY is set. This uses fewer
  1328  	// mallocs and requires much less work for tracking database pages, but
  1329  	// loses protection from application bugs like wild pointer writes and other
  1330  	// bad updates into the database. This may be slightly faster for DBs that
  1331  	// fit entirely in RAM, but is slower for DBs larger than RAM. Also adds the
  1332  	// possibility for stray application writes thru pointers to silently
  1333  	// corrupt the database.
  1334  	//
  1335  	// - with `MDBX_WRITEMAP` = all data will be mapped into memory in the
  1336  	//   read-write mode. This offers a significant performance benefit, since the
  1337  	//   data will be modified directly in mapped memory and then flushed to disk
  1338  	//   by single system call, without any memory management nor copying.
  1339  	//
  1340  	// - without `MDBX_WRITEMAP` = data will be mapped into memory in the
  1341  	//   read-only mode. This requires stocking all modified database pages in
  1342  	//   memory and then writing them to disk through file operations.
  1343  	//
  1344  	// \warning On the other hand, `MDBX_WRITEMAP` adds the possibility for stray
  1345  	// application writes thru pointers to silently corrupt the database.
  1346  	//
  1347  	// \note The `MDBX_WRITEMAP` mode is incompatible with nested transactions,
  1348  	// since this is unreasonable. I.e. nested transactions requires mallocation
  1349  	// of database pages and more work for tracking ones, which neuters a
  1350  	// performance boost caused by the `MDBX_WRITEMAP` mode.
  1351  	//
  1352  	// This flag affects only at environment opening but can't be changed after.
  1353  	EnvWriteMap = EnvFlags(C.MDBX_WRITEMAP)
  1354  
  1355  	// EnvNoTLS Tie reader locktable slots to read-only transactions
  1356  	// instead of to threads.
  1357  	//
  1358  	// Don't use Thread-Local Storage, instead tie reader locktable slots to
  1359  	// \ref MDBX_txn objects instead of to threads. So, \ref mdbx_txn_reset()
  1360  	// keeps the slot reserved for the \ref MDBX_txn object. A thread may use
  1361  	// parallel read-only transactions. And a read-only transaction may span
  1362  	// threads if you synchronizes its use.
  1363  	//
  1364  	// Applications that multiplex many user threads over individual OS threads
  1365  	// need this option. Such an application must also serialize the write
  1366  	// transactions in an OS thread, since MDBX's write locking is unaware of
  1367  	// the user threads.
  1368  	//
  1369  	// \note Regardless to `MDBX_NOTLS` flag a write transaction entirely should
  1370  	// always be used in one thread from start to finish. MDBX checks this in a
  1371  	// reasonable manner and return the \ref MDBX_THREAD_MISMATCH error in rules
  1372  	// violation.
  1373  	//
  1374  	// This flag affects only at environment opening but can't be changed after.
  1375  	EnvNoTLS = EnvFlags(C.MDBX_NOTLS)
  1376  	//MDBX_NOTLS = UINT32_C(0x200000)
  1377  
  1378  	// EnvNoReadAhead Don't do readahead.
  1379  	//
  1380  	// Turn off readahead. Most operating systems perform readahead on read
  1381  	// requests by default. This option turns it off if the OS supports it.
  1382  	// Turning it off may help random read performance when the DB is larger
  1383  	// than RAM and system RAM is full.
  1384  	//
  1385  	// By default libmdbx dynamically enables/disables readahead depending on
  1386  	// the actual database size and currently available memory. On the other
  1387  	// hand, such automation has some limitation, i.e. could be performed only
  1388  	// when DB size changing but can't tracks and reacts changing a free RAM
  1389  	// availability, since it changes independently and asynchronously.
  1390  	//
  1391  	// \note The mdbx_is_readahead_reasonable() function allows to quickly find
  1392  	// out whether to use readahead or not based on the size of the data and the
  1393  	// amount of available memory.
  1394  	//
  1395  	// This flag affects only at environment opening and can't be changed after.
  1396  	EnvNoReadAhead = EnvFlags(C.MDBX_NORDAHEAD)
  1397  
  1398  	// EnvNoMemInit Don't initialize malloc'ed memory before writing to datafile.
  1399  	//
  1400  	// Don't initialize malloc'ed memory before writing to unused spaces in the
  1401  	// data file. By default, memory for pages written to the data file is
  1402  	// obtained using malloc. While these pages may be reused in subsequent
  1403  	// transactions, freshly malloc'ed pages will be initialized to zeroes before
  1404  	// use. This avoids persisting leftover data from other code (that used the
  1405  	// heap and subsequently freed the memory) into the data file.
  1406  	//
  1407  	// Note that many other system libraries may allocate and free memory from
  1408  	// the heap for arbitrary uses. E.g., stdio may use the heap for file I/O
  1409  	// buffers. This initialization step has a modest performance cost so some
  1410  	// applications may want to disable it using this flag. This option can be a
  1411  	// problem for applications which handle sensitive data like passwords, and
  1412  	// it makes memory checkers like Valgrind noisy. This flag is not needed
  1413  	// with \ref MDBX_WRITEMAP, which writes directly to the mmap instead of using
  1414  	// malloc for pages. The initialization is also skipped if \ref MDBX_RESERVE
  1415  	// is used; the caller is expected to overwrite all of the memory that was
  1416  	// reserved in that case.
  1417  	//
  1418  	// This flag may be changed at any time using `mdbx_env_set_flags()`.
  1419  	EnvNoMemInit = EnvFlags(C.MDBX_NOMEMINIT)
  1420  
  1421  	// EnvCoalesce Aims to coalesce a Garbage Collection items.
  1422  	//
  1423  	// With `MDBX_COALESCE` flag MDBX will aims to coalesce items while recycling
  1424  	// a Garbage Collection. Technically, when possible short lists of pages
  1425  	// will be combined into longer ones, but to fit on one database page. As a
  1426  	// result, there will be fewer items in Garbage Collection and a page lists
  1427  	// are longer, which slightly increases the likelihood of returning pages to
  1428  	// Unallocated space and reducing the database file.
  1429  	//
  1430  	// This flag may be changed at any time using mdbx_env_set_flags().
  1431  	EnvCoalesce = EnvFlags(C.MDBX_COALESCE)
  1432  
  1433  	// EnvLIFOReclaim LIFO policy for recycling a Garbage Collection items.
  1434  	//
  1435  	// `MDBX_LIFORECLAIM` flag turns on LIFO policy for recycling a Garbage
  1436  	// Collection items, instead of FIFO by default. On systems with a disk
  1437  	// write-back cache, this can significantly increase write performance, up
  1438  	// to several times in a best case scenario.
  1439  	//
  1440  	// LIFO recycling policy means that for reuse pages will be taken which became
  1441  	// unused the lastest (i.e. just now or most recently). Therefore the loop of
  1442  	// database pages circulation becomes as short as possible. In other words,
  1443  	// the number of pages, that are overwritten in memory and on disk during a
  1444  	// series of write transactions, will be as small as possible. Thus creates
  1445  	// ideal conditions for the efficient operation of the disk write-back cache.
  1446  	//
  1447  	// \ref MDBX_LIFORECLAIM is compatible with all no-sync flags, but gives NO
  1448  	// noticeable impact in combination with \ref MDBX_SAFE_NOSYNC or
  1449  	// \ref MDBX_UTTERLY_NOSYN-Because MDBX will reused pages only before the
  1450  	// last "steady" MVCC-snapshot, i.e. the loop length of database pages
  1451  	// circulation will be mostly defined by frequency of calling
  1452  	// \ref mdbx_env_sync() rather than LIFO and FIFO difference.
  1453  	//
  1454  	// This flag may be changed at any time using mdbx_env_set_flags().
  1455  	EnvLIFOReclaim = EnvFlags(C.MDBX_LIFORECLAIM)
  1456  
  1457  	// EnvPagPerTurb Debugging option, fill/perturb released pages.
  1458  	EnvPagePerTurb = EnvFlags(C.MDBX_PAGEPERTURB)
  1459  
  1460  	// SYNC MODES
  1461  
  1462  	// \defgroup sync_modes SYNC MODES
  1463  	//
  1464  	// \attention Using any combination of \ref MDBX_SAFE_NOSYNC, \ref
  1465  	// MDBX_NOMETASYNC and especially \ref MDBX_UTTERLY_NOSYNC is always a deal to
  1466  	// reduce durability for gain write performance. You must know exactly what
  1467  	// you are doing and what risks you are taking!
  1468  	//
  1469  	// \note for LMDB users: \ref MDBX_SAFE_NOSYNC is NOT similar to LMDB_NOSYNC,
  1470  	// but \ref MDBX_UTTERLY_NOSYNC is exactly match LMDB_NOSYN-See details
  1471  	// below.
  1472  	//
  1473  	// THE SCENE:
  1474  	// - The DAT-file contains several MVCC-snapshots of B-tree at same time,
  1475  	//   each of those B-tree has its own root page.
  1476  	// - Each of meta pages at the beginning of the DAT file contains a
  1477  	//   pointer to the root page of B-tree which is the result of the particular
  1478  	//   transaction, and a number of this transaction.
  1479  	// - For data durability, MDBX must first write all MVCC-snapshot data
  1480  	//   pages and ensure that are written to the disk, then update a meta page
  1481  	//   with the new transaction number and a pointer to the corresponding new
  1482  	//   root page, and flush any buffers yet again.
  1483  	// - Thus during commit a I/O buffers should be flushed to the disk twice;
  1484  	//   i.e. fdatasync(), FlushFileBuffers() or similar syscall should be
  1485  	//   called twice for each commit. This is very expensive for performance,
  1486  	//   but guaranteed durability even on unexpected system failure or power
  1487  	//   outage. Of course, provided that the operating system and the
  1488  	//   underlying hardware (e.g. disk) work correctly.
  1489  	//
  1490  	// TRADE-OFF:
  1491  	// By skipping some stages described above, you can significantly benefit in
  1492  	// speed, while partially or completely losing in the guarantee of data
  1493  	// durability and/or consistency in the event of system or power failure.
  1494  	// Moreover, if for any reason disk write order is not preserved, then at
  1495  	// moment of a system crash, a meta-page with a pointer to the new B-tree may
  1496  	// be written to disk, while the itself B-tree not yet. In that case, the
  1497  	// database will be corrupted!
  1498  	//
  1499  	// \see MDBX_SYNC_DURABLE \see MDBX_NOMETASYNC \see MDBX_SAFE_NOSYNC
  1500  	// \see MDBX_UTTERLY_NOSYNC
  1501  	//
  1502  	// @{
  1503  
  1504  	// EnvSyncDurable Default robust and durable sync mode.
  1505  	//
  1506  	// Metadata is written and flushed to disk after a data is written and
  1507  	// flushed, which guarantees the integrity of the database in the event
  1508  	// of a crash at any time.
  1509  	//
  1510  	// \attention Please do not use other modes until you have studied all the
  1511  	// details and are sure. Otherwise, you may lose your users' data, as happens
  1512  	// in [Miranda NG](https://www.miranda-ng.org/) messenger.
  1513  	EnvSyncDurable = EnvFlags(C.MDBX_SYNC_DURABLE)
  1514  
  1515  	// EnvNoMetaSync Don't sync the meta-page after commit.
  1516  	//
  1517  	// Flush system buffers to disk only once per transaction commit, omit the
  1518  	// metadata flush. Defer that until the system flushes files to disk,
  1519  	// or next non-\ref MDBX_RDONLY commit or \ref mdbx_env_sync(). Depending on
  1520  	// the platform and hardware, with \ref MDBX_NOMETASYNC you may get a doubling
  1521  	// of write performance.
  1522  	//
  1523  	// This trade-off maintains database integrity, but a system crash may
  1524  	// undo the last committed transaction. I.e. it preserves the ACI
  1525  	// (atomicity, consistency, isolation) but not D (durability) database
  1526  	// property.
  1527  	//
  1528  	// `MDBX_NOMETASYNC` flag may be changed at any time using
  1529  	// \ref mdbx_env_set_flags() or by passing to \ref mdbx_txn_begin() for
  1530  	// particular write transaction. \see sync_modes
  1531  	EnvNoMetaSync = EnvFlags(C.MDBX_NOMETASYNC)
  1532  
  1533  	// EnvSafeNoSync Don't sync anything but keep previous steady commits.
  1534  	//
  1535  	// Like \ref MDBX_UTTERLY_NOSYNC the `MDBX_SAFE_NOSYNC` flag disable similarly
  1536  	// flush system buffers to disk when committing a transaction. But there is a
  1537  	// huge difference in how are recycled the MVCC snapshots corresponding to
  1538  	// previous "steady" transactions (see below).
  1539  	//
  1540  	// With \ref MDBX_WRITEMAP the `MDBX_SAFE_NOSYNC` instructs MDBX to use
  1541  	// asynchronous mmap-flushes to disk. Asynchronous mmap-flushes means that
  1542  	// actually all writes will scheduled and performed by operation system on it
  1543  	// own manner, i.e. unordered. MDBX itself just notify operating system that
  1544  	// it would be nice to write data to disk, but no more.
  1545  	//
  1546  	// Depending on the platform and hardware, with `MDBX_SAFE_NOSYNC` you may get
  1547  	// a multiple increase of write performance, even 10 times or more.
  1548  	//
  1549  	// In contrast to \ref MDBX_UTTERLY_NOSYNC mode, with `MDBX_SAFE_NOSYNC` flag
  1550  	// MDBX will keeps untouched pages within B-tree of the last transaction
  1551  	// "steady" which was synced to disk completely. This has big implications for
  1552  	// both data durability and (unfortunately) performance:
  1553  	//  - a system crash can't corrupt the database, but you will lose the last
  1554  	//    transactions; because MDBX will rollback to last steady commit since it
  1555  	//    kept explicitly.
  1556  	//  - the last steady transaction makes an effect similar to "long-lived" read
  1557  	//    transaction (see above in the \ref restrictions section) since prevents
  1558  	//    reuse of pages freed by newer write transactions, thus the any data
  1559  	//    changes will be placed in newly allocated pages.
  1560  	//  - to avoid rapid database growth, the system will sync data and issue
  1561  	//    a steady commit-point to resume reuse pages, each time there is
  1562  	//    insufficient space and before increasing the size of the file on disk.
  1563  	//
  1564  	// In other words, with `MDBX_SAFE_NOSYNC` flag MDBX insures you from the
  1565  	// whole database corruption, at the cost increasing database size and/or
  1566  	// number of disk IOPs. So, `MDBX_SAFE_NOSYNC` flag could be used with
  1567  	// \ref mdbx_env_sync() as alternatively for batch committing or nested
  1568  	// transaction (in some cases). As well, auto-sync feature exposed by
  1569  	// \ref mdbx_env_set_syncbytes() and \ref mdbx_env_set_syncperiod() functions
  1570  	// could be very useful with `MDBX_SAFE_NOSYNC` flag.
  1571  	//
  1572  	// The number and volume of of disk IOPs with MDBX_SAFE_NOSYNC flag will
  1573  	// exactly the as without any no-sync flags. However, you should expect a
  1574  	// larger process's [work set](https://bit.ly/2kA2tFX) and significantly worse
  1575  	// a [locality of reference](https://bit.ly/2mbYq2J), due to the more
  1576  	// intensive allocation of previously unused pages and increase the size of
  1577  	// the database.
  1578  	//
  1579  	// `MDBX_SAFE_NOSYNC` flag may be changed at any time using
  1580  	// \ref mdbx_env_set_flags() or by passing to \ref mdbx_txn_begin() for
  1581  	// particular write transaction.
  1582  	EnvSafeNoSync = EnvFlags(C.MDBX_SAFE_NOSYNC)
  1583  
  1584  	// EnvUtterlyNoSync Don't sync anything and wipe previous steady commits.
  1585  	//
  1586  	// Don't flush system buffers to disk when committing a transaction. This
  1587  	// optimization means a system crash can corrupt the database, if buffers are
  1588  	// not yet flushed to disk. Depending on the platform and hardware, with
  1589  	// `MDBX_UTTERLY_NOSYNC` you may get a multiple increase of write performance,
  1590  	// even 100 times or more.
  1591  	//
  1592  	// If the filesystem preserves write order (which is rare and never provided
  1593  	// unless explicitly noted) and the \ref MDBX_WRITEMAP and \ref
  1594  	// MDBX_LIFORECLAIM flags are not used, then a system crash can't corrupt the
  1595  	// database, but you can lose the last transactions, if at least one buffer is
  1596  	// not yet flushed to disk. The risk is governed by how often the system
  1597  	// flushes dirty buffers to disk and how often \ref mdbx_env_sync() is called.
  1598  	// So, transactions exhibit ACI (atomicity, consistency, isolation) properties
  1599  	// and only lose `D` (durability). I.e. database integrity is maintained, but
  1600  	// a system crash may undo the final transactions.
  1601  	//
  1602  	// Otherwise, if the filesystem not preserves write order (which is
  1603  	// typically) or \ref MDBX_WRITEMAP or \ref MDBX_LIFORECLAIM flags are used,
  1604  	// you should expect the corrupted database after a system crash.
  1605  	//
  1606  	// So, most important thing about `MDBX_UTTERLY_NOSYNC`:
  1607  	//  - a system crash immediately after commit the write transaction
  1608  	//    high likely lead to database corruption.
  1609  	//  - successful completion of mdbx_env_sync(force = true) after one or
  1610  	//    more committed transactions guarantees consistency and durability.
  1611  	//  - BUT by committing two or more transactions you back database into
  1612  	//    a weak state, in which a system crash may lead to database corruption!
  1613  	//    In case single transaction after mdbx_env_sync, you may lose transaction
  1614  	//    itself, but not a whole database.
  1615  	//
  1616  	// Nevertheless, `MDBX_UTTERLY_NOSYNC` provides "weak" durability in case
  1617  	// of an application crash (but no durability on system failure), and
  1618  	// therefore may be very useful in scenarios where data durability is
  1619  	// not required over a system failure (e.g for short-lived data), or if you
  1620  	// can take such risk.
  1621  	//
  1622  	// `MDBX_UTTERLY_NOSYNC` flag may be changed at any time using
  1623  	// \ref mdbx_env_set_flags(), but don't has effect if passed to
  1624  	// \ref mdbx_txn_begin() for particular write transaction. \see sync_modes
  1625  	EnvUtterlyNoSync = EnvFlags(C.MDBX_UTTERLY_NOSYNC)
  1626  )
  1627  
  1628  type TxFlags uint32
  1629  
  1630  const (
  1631  	// TxReadWrite Start read-write transaction.
  1632  	//
  1633  	// Only one write transaction may be active at a time. Writes are fully
  1634  	// serialized, which guarantees that writers can never deadlock.
  1635  	TxReadWrite = TxFlags(C.MDBX_TXN_READWRITE)
  1636  
  1637  	// TxReadOnly Start read-only transaction.
  1638  	//
  1639  	// There can be multiple read-only transactions simultaneously that do not
  1640  	// block each other and a write transactions.
  1641  	TxReadOnly = TxFlags(C.MDBX_TXN_RDONLY)
  1642  
  1643  	// TxReadOnlyPrepare Prepare but not start read-only transaction.
  1644  	//
  1645  	// Transaction will not be started immediately, but created transaction handle
  1646  	// will be ready for use with \ref mdbx_txn_renew(). This flag allows to
  1647  	// preallocate memory and assign a reader slot, thus avoiding these operations
  1648  	// at the next start of the transaction.
  1649  	TxReadOnlyPrepare = TxFlags(C.MDBX_TXN_RDONLY_PREPARE)
  1650  
  1651  	// TxTry Do not block when starting a write transaction.
  1652  	TxTry = TxFlags(C.MDBX_TXN_TRY)
  1653  
  1654  	// TxNoMetaSync Exactly the same as \ref MDBX_NOMETASYNC,
  1655  	// but for this transaction only
  1656  	TxNoMetaSync = TxFlags(C.MDBX_TXN_NOMETASYNC)
  1657  
  1658  	// TxNoSync Exactly the same as \ref MDBX_SAFE_NOSYNC,
  1659  	// but for this transaction only
  1660  	TxNoSync = TxFlags(C.MDBX_TXN_NOSYNC)
  1661  )
  1662  
  1663  type DBFlags uint32
  1664  
  1665  const (
  1666  	DBDefaults = DBFlags(C.MDBX_DB_DEFAULTS)
  1667  
  1668  	// DBReverseKey Use reverse string keys
  1669  	DBReverseKey = DBFlags(C.MDBX_REVERSEKEY)
  1670  
  1671  	// DBDupSort Use sorted duplicates, i.e. allow multi-values
  1672  	DBDupSort = DBFlags(C.MDBX_DUPSORT)
  1673  
  1674  	// DBIntegerKey Numeric keys in native byte order either uint32_t or uint64_t. The keys
  1675  	// must all be of the same size and must be aligned while passing as
  1676  	// arguments.
  1677  	DBIntegerKey = DBFlags(C.MDBX_INTEGERKEY)
  1678  
  1679  	// DBDupFixed With \ref MDBX_DUPSORT; sorted dup items have fixed size
  1680  	DBDupFixed = DBFlags(C.MDBX_DUPFIXED)
  1681  
  1682  	// DBIntegerGroup With \ref MDBX_DUPSORT and with \ref MDBX_DUPFIXED; dups are fixed size
  1683  	// \ref MDBX_INTEGERKEY -style integers. The data values must all be of the
  1684  	// same size and must be aligned while passing as arguments.
  1685  	DBIntegerGroup = DBFlags(C.MDBX_INTEGERDUP)
  1686  
  1687  	// DBReverseDup With \ref MDBX_DUPSORT; use reverse string comparison
  1688  	DBReverseDup = DBFlags(C.MDBX_REVERSEDUP)
  1689  
  1690  	// DBCreate Create DB if not already existing
  1691  	DBCreate = DBFlags(C.MDBX_CREATE)
  1692  
  1693  	// DBAccede Opens an existing sub-database created with unknown flags.
  1694  	//
  1695  	// The `MDBX_DB_ACCEDE` flag is intend to open a existing sub-database which
  1696  	// was created with unknown flags (\ref MDBX_REVERSEKEY, \ref MDBX_DUPSORT,
  1697  	// \ref MDBX_INTEGERKEY, \ref MDBX_DUPFIXED, \ref MDBX_INTEGERDUP and
  1698  	// \ref MDBX_REVERSEDUP).
  1699  	//
  1700  	// In such cases, instead of returning the \ref MDBX_INCOMPATIBLE error, the
  1701  	// sub-database will be opened with flags which it was created, and then an
  1702  	// application could determine the actual flags by \ref mdbx_dbi_flags().
  1703  	DBAccede = DBFlags(C.MDBX_DB_ACCEDE)
  1704  )
  1705  
  1706  type PutFlags uint32
  1707  
  1708  const (
  1709  	// PutUpsert Upsertion by default (without any other flags)
  1710  	PutUpsert = PutFlags(C.MDBX_UPSERT)
  1711  
  1712  	// PutNoOverwrite For insertion: Don't write if the key already exists.
  1713  	PutNoOverwrite = PutFlags(C.MDBX_NOOVERWRITE)
  1714  
  1715  	// PutNoDupData Has effect only for \ref MDBX_DUPSORT databases.
  1716  	// For upsertion: don't write if the key-value pair already exist.
  1717  	// For deletion: remove all values for key.
  1718  	PutNoDupData = PutFlags(C.MDBX_NODUPDATA)
  1719  
  1720  	// PutCurrent For upsertion: overwrite the current key/data pair.
  1721  	// MDBX allows this flag for \ref mdbx_put() for explicit overwrite/update
  1722  	// without insertion.
  1723  	// For deletion: remove only single entry at the current cursor position.
  1724  	PutCurrent = PutFlags(C.MDBX_CURRENT)
  1725  
  1726  	// PutAllDups Has effect only for \ref MDBX_DUPSORT databases.
  1727  	// For deletion: remove all multi-values (aka duplicates) for given key.
  1728  	// For upsertion: replace all multi-values for given key with a new one.
  1729  	PutAllDups = PutFlags(C.MDBX_ALLDUPS)
  1730  
  1731  	// PutReserve For upsertion: Just reserve space for data, don't copy it.
  1732  	// Return a pointer to the reserved space.
  1733  	PutReserve = PutFlags(C.MDBX_RESERVE)
  1734  
  1735  	// PutAppend Data is being appended.
  1736  	// Don't split full pages, continue on a new instead.
  1737  	PutAppend = PutFlags(C.MDBX_APPEND)
  1738  
  1739  	// PutAppendDup Has effect only for \ref MDBX_DUPSORT databases.
  1740  	// Duplicate data is being appended.
  1741  	// Don't split full pages, continue on a new instead.
  1742  	PutAppendDup = PutFlags(C.MDBX_APPENDDUP)
  1743  
  1744  	// PutMultiple Only for \ref MDBX_DUPFIXED.
  1745  	// Store multiple data items in one call.
  1746  	PutMultiple = PutFlags(C.MDBX_MULTIPLE)
  1747  )
  1748  
  1749  type CopyFlags uint32
  1750  
  1751  const (
  1752  	CopyDefaults = CopyFlags(C.MDBX_CP_DEFAULTS)
  1753  
  1754  	// CopyCompact Copy and compact: Omit free space from copy and renumber all
  1755  	// pages sequentially
  1756  	CopyCompact = CopyFlags(C.MDBX_CP_COMPACT)
  1757  
  1758  	// CopyForceDynamicSize Force to make resizeable copy, i.e. dynamic size instead of fixed
  1759  	CopyForceDynamicSize = CopyFlags(C.MDBX_CP_FORCE_DYNAMIC_SIZE)
  1760  )
  1761  
  1762  type CursorOp int32
  1763  
  1764  const (
  1765  	// CursorFirst Position at first key/data item
  1766  	CursorFirst = CursorOp(C.MDBX_FIRST)
  1767  
  1768  	// CursorFirstDup \ref MDBX_DUPSORT -only: Position at first data item of current key.
  1769  	CursorFirstDup = CursorOp(C.MDBX_FIRST_DUP)
  1770  
  1771  	// CursorGetBoth \ref MDBX_DUPSORT -only: Position at key/data pair.
  1772  	CursorGetBoth = CursorOp(C.MDBX_GET_BOTH)
  1773  
  1774  	// CursorGetBothRange \ref MDBX_DUPSORT -only: Position at given key and at first data greater
  1775  	// than or equal to specified data.
  1776  	CursorGetBothRange = CursorOp(C.MDBX_GET_BOTH_RANGE)
  1777  
  1778  	// CursorGetCurrent Return key/data at current cursor position
  1779  	CursorGetCurrent = CursorOp(C.MDBX_GET_CURRENT)
  1780  
  1781  	// CursorGetMultiple \ref MDBX_DUPFIXED -only: Return up to a page of duplicate data items
  1782  	// from current cursor position. Move cursor to prepare
  1783  	// for \ref MDBX_NEXT_MULTIPLE.
  1784  	CursorGetMultiple = CursorOp(C.MDBX_GET_MULTIPLE)
  1785  
  1786  	// CursorLast Position at last key/data item
  1787  	CursorLast = CursorOp(C.MDBX_LAST)
  1788  
  1789  	// CursorLastDup \ref MDBX_DUPSORT -only: Position at last data item of current key.
  1790  	CursorLastDup = CursorOp(C.MDBX_LAST_DUP)
  1791  
  1792  	// CursorNext Position at next data item
  1793  	CursorNext = CursorOp(C.MDBX_NEXT)
  1794  
  1795  	// CursorNextDup \ref MDBX_DUPSORT -only: Position at next data item of current key.
  1796  	CursorNextDup = CursorOp(C.MDBX_NEXT_DUP)
  1797  
  1798  	// CursorNextMultiple \ref MDBX_DUPFIXED -only: Return up to a page of duplicate data items
  1799  	// from next cursor position. Move cursor to prepare
  1800  	// for `MDBX_NEXT_MULTIPLE`.
  1801  	CursorNextMultiple = CursorOp(C.MDBX_NEXT_MULTIPLE)
  1802  
  1803  	// CursorNextNoDup Position at first data item of next key
  1804  	CursorNextNoDup = CursorOp(C.MDBX_NEXT_NODUP)
  1805  
  1806  	// CursorPrev Position at previous data item
  1807  	CursorPrev = CursorOp(C.MDBX_PREV)
  1808  
  1809  	// CursorPrevDup \ref MDBX_DUPSORT -only: Position at previous data item of current key.
  1810  	CursorPrevDup = CursorOp(C.MDBX_PREV_DUP)
  1811  
  1812  	// CursorPrevNoDup Position at last data item of previous key
  1813  	CursorPrevNoDup = CursorOp(C.MDBX_PREV_NODUP)
  1814  
  1815  	// CursorSet Position at specified key
  1816  	CursorSet = CursorOp(C.MDBX_SET)
  1817  
  1818  	// CursorSetKey Position at specified key, return both key and data
  1819  	CursorSetKey = CursorOp(C.MDBX_SET_KEY)
  1820  
  1821  	// CursorSetRange Position at first key greater than or equal to specified key.
  1822  	CursorSetRange = CursorOp(C.MDBX_SET_RANGE)
  1823  
  1824  	// CursorPrevMultiple \ref MDBX_DUPFIXED -only: Position at previous page and return up to
  1825  	// a page of duplicate data items.
  1826  	CursorPrevMultiple = CursorOp(C.MDBX_PREV_MULTIPLE)
  1827  
  1828  	// CursorSetLowerBound Positions cursor at first key-value pair greater than or equal to
  1829  	// specified, return both key and data, and the return code depends on whether
  1830  	// a exact match.
  1831  	//
  1832  	// For non DUPSORT-ed collections this work the same to \ref MDBX_SET_RANGE,
  1833  	// but returns \ref MDBX_SUCCESS if key found exactly or
  1834  	// \ref MDBX_RESULT_TRUE if greater key was found.
  1835  	//
  1836  	// For DUPSORT-ed a data value is taken into account for duplicates,
  1837  	// i.e. for a pairs/tuples of a key and an each data value of duplicates.
  1838  	// Returns \ref MDBX_SUCCESS if key-value pair found exactly or
  1839  	// \ref MDBX_RESULT_TRUE if the next pair was returned.///
  1840  	CursorSetLowerBound = CursorOp(C.MDBX_SET_LOWERBOUND)
  1841  
  1842  	// CursorSetUpperBound Positions cursor at first key-value pair greater than specified,
  1843  	// return both key and data, and the return code depends on whether a
  1844  	// upper-bound was found.
  1845  	//
  1846  	// For non DUPSORT-ed collections this work the same to \ref MDBX_SET_RANGE,
  1847  	// but returns \ref MDBX_SUCCESS if the greater key was found or
  1848  	// \ref MDBX_NOTFOUND otherwise.
  1849  	//
  1850  	// For DUPSORT-ed a data value is taken into account for duplicates,
  1851  	// i.e. for a pairs/tuples of a key and an each data value of duplicates.
  1852  	// Returns \ref MDBX_SUCCESS if the greater pair was returned or
  1853  	// \ref MDBX_NOTFOUND otherwise.///
  1854  	CursorSetUpperBound = CursorOp(C.MDBX_SET_UPPERBOUND)
  1855  )
  1856  
  1857  type Opt int32
  1858  
  1859  const (
  1860  	// OptMaxDB \brief Controls the maximum number of named databases for the environment.
  1861  	//
  1862  	// \details By default only unnamed key-value database could used and
  1863  	// appropriate value should set by `MDBX_opt_max_db` to using any more named
  1864  	// subDB(s). To reduce overhead, use the minimum sufficient value. This option
  1865  	// may only set after \ref mdbx_env_create() and before \ref mdbx_env_open().
  1866  	//
  1867  	// \see mdbx_env_set_maxdbs() \see mdbx_env_get_maxdbs()
  1868  	OptMaxDB = Opt(C.MDBX_opt_max_db)
  1869  
  1870  	// OptMaxReaders \brief Defines the maximum number of threads/reader slots
  1871  	// for all processes interacting with the database.
  1872  	//
  1873  	// \details This defines the number of slots in the lock table that is used to
  1874  	// track readers in the the environment. The default is about 100 for 4K
  1875  	// system page size. Starting a read-only transaction normally ties a lock
  1876  	// table slot to the current thread until the environment closes or the thread
  1877  	// exits. If \ref MDBX_NOTLS is in use, \ref mdbx_txn_begin() instead ties the
  1878  	// slot to the \ref MDBX_txn object until it or the \ref MDBX_env object is
  1879  	// destroyed. This option may only set after \ref mdbx_env_create() and before
  1880  	// \ref mdbx_env_open(), and has an effect only when the database is opened by
  1881  	// the first process interacts with the database.
  1882  	//
  1883  	// \see mdbx_env_set_maxreaders() \see mdbx_env_get_maxreaders()
  1884  	OptMaxReaders = Opt(C.MDBX_opt_max_readers)
  1885  
  1886  	// OptSyncBytes \brief Controls interprocess/shared threshold to force flush the data
  1887  	// buffers to disk, if \ref MDBX_SAFE_NOSYNC is used.
  1888  	//
  1889  	// \see mdbx_env_set_syncbytes() \see mdbx_env_get_syncbytes()
  1890  	OptSyncBytes = Opt(C.MDBX_opt_sync_bytes)
  1891  
  1892  	// OptSyncPeriod \brief Controls interprocess/shared relative period since the last
  1893  	// unsteady commit to force flush the data buffers to disk,
  1894  	// if \ref MDBX_SAFE_NOSYNC is used.
  1895  	// \see mdbx_env_set_syncperiod() \see mdbx_env_get_syncperiod()
  1896  	OptSyncPeriod = Opt(C.MDBX_opt_sync_period)
  1897  
  1898  	// OptRpAugmentLimit \brief Controls the in-process limit to grow a list of reclaimed/recycled
  1899  	// page's numbers for finding a sequence of contiguous pages for large data
  1900  	// items.
  1901  	//
  1902  	// \details A long values requires allocation of contiguous database pages.
  1903  	// To find such sequences, it may be necessary to accumulate very large lists,
  1904  	// especially when placing very long values (more than a megabyte) in a large
  1905  	// databases (several tens of gigabytes), which is much expensive in extreme
  1906  	// cases. This threshold allows you to avoid such costs by allocating new
  1907  	// pages at the end of the database (with its possible growth on disk),
  1908  	// instead of further accumulating/reclaiming Garbage Collection records.
  1909  	//
  1910  	// On the other hand, too small threshold will lead to unreasonable database
  1911  	// growth, or/and to the inability of put long values.
  1912  	//
  1913  	// The `MDBX_opt_rp_augment_limit` controls described limit for the current
  1914  	// process. Default is 262144, it is usually enough for most cases.
  1915  	OptRpAugmentLimit = Opt(C.MDBX_opt_rp_augment_limit)
  1916  
  1917  	// OptLooseLimit \brief Controls the in-process limit to grow a cache of dirty
  1918  	// pages for reuse in the current transaction.
  1919  	//
  1920  	// \details A 'dirty page' refers to a page that has been updated in memory
  1921  	// only, the changes to a dirty page are not yet stored on disk.
  1922  	// To reduce overhead, it is reasonable to release not all such pages
  1923  	// immediately, but to leave some ones in cache for reuse in the current
  1924  	// transaction.
  1925  	//
  1926  	// The `MDBX_opt_loose_limit` allows you to set a limit for such cache inside
  1927  	// the current process. Should be in the range 0..255, default is 64.
  1928  	OptLooseLimit = Opt(C.MDBX_opt_loose_limit)
  1929  
  1930  	// OptDpReserveLimit \brief Controls the in-process limit of a pre-allocated memory items
  1931  	// for dirty pages.
  1932  	//
  1933  	// \details A 'dirty page' refers to a page that has been updated in memory
  1934  	// only, the changes to a dirty page are not yet stored on disk.
  1935  	// Without \ref MDBX_WRITEMAP dirty pages are allocated from memory and
  1936  	// released when a transaction is committed. To reduce overhead, it is
  1937  	// reasonable to release not all ones, but to leave some allocations in
  1938  	// reserve for reuse in the next transaction(s).
  1939  	//
  1940  	// The `MDBX_opt_dp_reserve_limit` allows you to set a limit for such reserve
  1941  	// inside the current process. Default is 1024.
  1942  	OptDpReserveLimit = Opt(C.MDBX_opt_dp_reserve_limit)
  1943  
  1944  	// OptTxnDpLimit \brief Controls the in-process limit of dirty pages
  1945  	// for a write transaction.
  1946  	//
  1947  	// \details A 'dirty page' refers to a page that has been updated in memory
  1948  	// only, the changes to a dirty page are not yet stored on disk.
  1949  	// Without \ref MDBX_WRITEMAP dirty pages are allocated from memory and will
  1950  	// be busy until are written to disk. Therefore for a large transactions is
  1951  	// reasonable to limit dirty pages collecting above an some threshold but
  1952  	// spill to disk instead.
  1953  	//
  1954  	// The `MDBX_opt_txn_dp_limit` controls described threshold for the current
  1955  	// process. Default is 65536, it is usually enough for most cases.
  1956  	OptTxnDpLimit = Opt(C.MDBX_opt_txn_dp_limit)
  1957  
  1958  	// OptTxnDpInitial \brief Controls the in-process initial allocation size for dirty pages
  1959  	// list of a write transaction. Default is 1024.
  1960  	OptTxnDpInitial = Opt(C.MDBX_opt_txn_dp_initial)
  1961  
  1962  	// OptSpillMaxDenomiator \brief Controls the in-process how maximal part of the dirty pages may be
  1963  	// spilled when necessary.
  1964  	//
  1965  	// \details The `MDBX_opt_spill_max_denominator` defines the denominator for
  1966  	// limiting from the top for part of the current dirty pages may be spilled
  1967  	// when the free room for a new dirty pages (i.e. distance to the
  1968  	// `MDBX_opt_txn_dp_limit` threshold) is not enough to perform requested
  1969  	// operation.
  1970  	// Exactly `max_pages_to_spill = dirty_pages - dirty_pages / N`,
  1971  	// where `N` is the value set by `MDBX_opt_spill_max_denominator`.
  1972  	//
  1973  	// Should be in the range 0..255, where zero means no limit, i.e. all dirty
  1974  	// pages could be spilled. Default is 8, i.e. no more than 7/8 of the current
  1975  	// dirty pages may be spilled when reached the condition described above.
  1976  	OptSpillMaxDenomiator = Opt(C.MDBX_opt_spill_max_denominator)
  1977  
  1978  	// OptSpillMinDenomiator \brief Controls the in-process how minimal part of the dirty pages should
  1979  	// be spilled when necessary.
  1980  	//
  1981  	// \details The `MDBX_opt_spill_min_denominator` defines the denominator for
  1982  	// limiting from the bottom for part of the current dirty pages should be
  1983  	// spilled when the free room for a new dirty pages (i.e. distance to the
  1984  	// `MDBX_opt_txn_dp_limit` threshold) is not enough to perform requested
  1985  	// operation.
  1986  	// Exactly `min_pages_to_spill = dirty_pages / N`,
  1987  	// where `N` is the value set by `MDBX_opt_spill_min_denominator`.
  1988  	//
  1989  	// Should be in the range 0..255, where zero means no restriction at the
  1990  	// bottom. Default is 8, i.e. at least the 1/8 of the current dirty pages
  1991  	// should be spilled when reached the condition described above.
  1992  	OptSpillMinDenomiator = Opt(C.MDBX_opt_spill_min_denominator)
  1993  
  1994  	// OptSpillParent4ChildDenominator \brief Controls the in-process how much of the parent transaction dirty
  1995  	// pages will be spilled while start each child transaction.
  1996  	//
  1997  	// \details The `MDBX_opt_spill_parent4child_denominator` defines the
  1998  	// denominator to determine how much of parent transaction dirty pages will be
  1999  	// spilled explicitly while start each child transaction.
  2000  	// Exactly `pages_to_spill = dirty_pages / N`,
  2001  	// where `N` is the value set by `MDBX_opt_spill_parent4child_denominator`.
  2002  	//
  2003  	// For a stack of nested transactions each dirty page could be spilled only
  2004  	// once, and parent's dirty pages couldn't be spilled while child
  2005  	// transaction(s) are running. Therefore a child transaction could reach
  2006  	// \ref MDBX_TXN_FULL when parent(s) transaction has  spilled too less (and
  2007  	// child reach the limit of dirty pages), either when parent(s) has spilled
  2008  	// too more (since child can't spill already spilled pages). So there is no
  2009  	// universal golden ratio.
  2010  	//
  2011  	// Should be in the range 0..255, where zero means no explicit spilling will
  2012  	// be performed during starting nested transactions.
  2013  	// Default is 0, i.e. by default no spilling performed during starting nested
  2014  	// transactions, that correspond historically behaviour.
  2015  	OptSpillParent4ChildDenominator = Opt(C.MDBX_opt_spill_parent4child_denominator)
  2016  
  2017  	// OptMergeThreshold16Dot16Percent \brief Controls the in-process threshold of semi-empty pages merge.
  2018  	// \warning This is experimental option and subject for change or removal.
  2019  	// \details This option controls the in-process threshold of minimum page
  2020  	// fill, as used space of percentage of a page. Neighbour pages emptier than
  2021  	// this value are candidates for merging. The threshold value is specified
  2022  	// in 1/65536 of percent, which is equivalent to the 16-dot-16 fixed point
  2023  	// format. The specified value must be in the range from 12.5% (almost empty)
  2024  	// to 50% (half empty) which corresponds to the range from 8192 and to 32768
  2025  	// in units respectively.
  2026  	OptMergeThreshold16Dot16Percent = Opt(C.MDBX_opt_merge_threshold_16dot16_percent)
  2027  )
  2028  
  2029  type DeleteMode int32
  2030  
  2031  const (
  2032  	// DeleteModeJustDelete \brief Just delete the environment's files and directory if any.
  2033  	// \note On POSIX systems, processes already working with the database will
  2034  	// continue to work without interference until it close the environment.
  2035  	// \note On Windows, the behavior of `MDB_ENV_JUST_DELETE` is different
  2036  	// because the system does not support deleting files that are currently
  2037  	// memory mapped.
  2038  	DeleteModeJustDelete = DeleteMode(C.MDBX_ENV_JUST_DELETE)
  2039  
  2040  	// DeleteModeEnsureUnused \brief Make sure that the environment is not being used by other
  2041  	// processes, or return an error otherwise.
  2042  	DeleteModeEnsureUnused = DeleteMode(C.MDBX_ENV_ENSURE_UNUSED)
  2043  
  2044  	// DeleteModeWaitForUnused \brief Wait until other processes closes the environment before deletion.
  2045  	DeleteModeWaitForUnused = DeleteMode(C.MDBX_ENV_WAIT_FOR_UNUSED)
  2046  )
  2047  
  2048  type DBIState uint32
  2049  
  2050  const (
  2051  	DBIStateDirty = DBIState(C.MDBX_DBI_DIRTY) // DB was written in this txn
  2052  	DBIStateState = DBIState(C.MDBX_DBI_STALE) // Named-DB record is older than txnID
  2053  	DBIStateFresh = DBIState(C.MDBX_DBI_FRESH) // Named-DB handle opened in this txn
  2054  	DBIStateCreat = DBIState(C.MDBX_DBI_CREAT) // Named-DB handle created in this txn
  2055  )
  2056  
  2057  // Delete \brief Delete the environment's files in a proper and multiprocess-safe way.
  2058  // \ingroup c_extra
  2059  //
  2060  // \param [in] pathname  The pathname for the database or the directory in which
  2061  //
  2062  //	the database files reside.
  2063  //
  2064  // \param [in] mode      Special deletion mode for the environment. This
  2065  //
  2066  //	parameter must be set to one of the values described
  2067  //	above in the \ref MDBX_env_delete_mode_t section.
  2068  //
  2069  // \note The \ref MDBX_ENV_JUST_DELETE don't supported on Windows since system
  2070  // unable to delete a memory-mapped files.
  2071  //
  2072  // \returns A non-zero error value on failure and 0 on success,
  2073  //
  2074  //	some possible errors are:
  2075  //
  2076  // \retval MDBX_RESULT_TRUE   No corresponding files or directories were found,
  2077  //
  2078  //	so no deletion was performed.
  2079  func Delete(path string, mode DeleteMode) Error {
  2080  	p := C.CString(path)
  2081  	defer C.free(unsafe.Pointer(p))
  2082  	return Error(C.mdbx_env_delete(p, (C.MDBX_env_delete_mode_t)(mode)))
  2083  }
  2084  
  2085  //////////////////////////////////////////////////////////////////////////////////////////
  2086  // Env
  2087  //////////////////////////////////////////////////////////////////////////////////////////
  2088  
  2089  type Env struct {
  2090  	env    *C.MDBX_env
  2091  	opened int64
  2092  	info   EnvInfo
  2093  	closed int64
  2094  	mu     sync.Mutex
  2095  }
  2096  
  2097  // NewEnv \brief Create an MDBX environment instance.
  2098  // \ingroup c_opening
  2099  //
  2100  // This function allocates memory for a \ref MDBX_env structure. To release
  2101  // the allocated memory and discard the handle, call \ref mdbx_env_close().
  2102  // Before the handle may be used, it must be opened using \ref mdbx_env_open().
  2103  //
  2104  // Various other options may also need to be set before opening the handle,
  2105  // e.g. \ref mdbx_env_set_geometry(), \ref mdbx_env_set_maxreaders(),
  2106  // \ref mdbx_env_set_maxdbs(), depending on usage requirements.
  2107  //
  2108  // \param [out] penv  The address where the new handle will be stored.
  2109  //
  2110  // \returns a non-zero error value on failure and 0 on success.
  2111  func NewEnv() (*Env, Error) {
  2112  	env := &Env{}
  2113  	err := Error(C.mdbx_env_create((**C.MDBX_env)(unsafe.Pointer(&env.env))))
  2114  	if err != ErrSuccess {
  2115  		return nil, err
  2116  	}
  2117  	return env, err
  2118  }
  2119  
  2120  // FD returns the open file descriptor (or Windows file handle) for the given
  2121  // environment.  An error is returned if the environment has not been
  2122  // successfully Opened (where C API just retruns an invalid handle).
  2123  //
  2124  // See mdbx_env_get_fd.
  2125  func (env *Env) FD() (uintptr, error) {
  2126  	// fdInvalid is the value -1 as a uintptr, which is used by MDBX in the
  2127  	// case that env has not been opened yet.  the strange construction is done
  2128  	// to avoid constant value overflow errors at compile time.
  2129  	const fdInvalid = ^uintptr(0)
  2130  
  2131  	var mf C.mdbx_filehandle_t
  2132  	err := Error(C.mdbx_env_get_fd(env.env, &mf))
  2133  	//err := operrno("mdbx_env_get_fd", ret)
  2134  	if err != ErrSuccess {
  2135  		return 0, err
  2136  	}
  2137  	fd := uintptr(mf)
  2138  
  2139  	if fd == fdInvalid {
  2140  		return 0, os.ErrClosed
  2141  	}
  2142  	return fd, nil
  2143  }
  2144  
  2145  // ReaderList dumps the contents of the reader lock table as text.  Readers
  2146  // start on the second line as space-delimited fields described by the first
  2147  // line.
  2148  //
  2149  // See mdbx_reader_list.
  2150  //func (env *Env) ReaderList(fn func(string) error) error {
  2151  //	ctx, done := newMsgFunc(fn)
  2152  //	defer done()
  2153  //	if fn == nil {
  2154  //		ctx = 0
  2155  //	}
  2156  //
  2157  //	ret := C.mdbxgo_reader_list(env._env, C.size_t(ctx))
  2158  //	if ret >= 0 {
  2159  //		return nil
  2160  //	}
  2161  //	if ret < 0 && ctx != 0 {
  2162  //		err := ctx.get().err
  2163  //		if err != nil {
  2164  //			return err
  2165  //		}
  2166  //	}
  2167  //	return operrno("mdbx_reader_list", ret)
  2168  //}
  2169  
  2170  // ReaderCheck clears stale entries from the reader lock table and returns the
  2171  // number of entries cleared.
  2172  //
  2173  // See mdbx_reader_check()
  2174  func (env *Env) ReaderCheck() (int, error) {
  2175  	var dead C.int
  2176  	err := Error(C.mdbx_reader_check(env.env, &dead))
  2177  	if err != ErrSuccess {
  2178  		return int(dead), err
  2179  	}
  2180  	return int(dead), nil
  2181  }
  2182  
  2183  // Path returns the path argument passed to Open.  Path returns a non-nil error
  2184  // if env.Open() was not previously called.
  2185  //
  2186  // See mdbx_env_get_path.
  2187  func (env *Env) Path() (string, error) {
  2188  	var cpath *C.char
  2189  	err := Error(C.mdbx_env_get_path(env.env, &cpath))
  2190  	if err != ErrSuccess {
  2191  		return "", err
  2192  	}
  2193  	if cpath == nil {
  2194  		return "", os.ErrNotExist
  2195  	}
  2196  	return C.GoString(cpath), nil
  2197  }
  2198  
  2199  // MaxKeySize returns the maximum allowed length for a key.
  2200  //
  2201  // See mdbx_env_get_maxkeysize.
  2202  func (env *Env) MaxKeySize() int {
  2203  	if env == nil {
  2204  		return int(C.mdbx_env_get_maxkeysize_ex(nil, 0))
  2205  	}
  2206  	return int(C.mdbx_env_get_maxkeysize_ex(env.env, 0))
  2207  }
  2208  
  2209  // Close the environment and release the memory map.
  2210  // \ingroup c_opening
  2211  //
  2212  // Only a single thread may call this function. All transactions, databases,
  2213  // and cursors must already be closed before calling this function. Attempts
  2214  // to use any such handles after calling this function will cause a `SIGSEGV`.
  2215  // The environment handle will be freed and must not be used again after this
  2216  // call.
  2217  //
  2218  // \param [in] env        An environment handle returned by
  2219  //
  2220  //	\ref mdbx_env_create().
  2221  //
  2222  // \param [in] dont_sync  A dont'sync flag, if non-zero the last checkpoint
  2223  //
  2224  //	will be kept "as is" and may be still "weak" in the
  2225  //	\ref MDBX_SAFE_NOSYNC or \ref MDBX_UTTERLY_NOSYNC
  2226  //	modes. Such "weak" checkpoint will be ignored on
  2227  //	opening next time, and transactions since the last
  2228  //	non-weak checkpoint (meta-page update) will rolledback
  2229  //	for consistency guarantee.
  2230  //
  2231  // \returns A non-zero error value on failure and 0 on success,
  2232  //
  2233  //	some possible errors are:
  2234  //
  2235  // \retval MDBX_BUSY   The write transaction is running by other thread,
  2236  //
  2237  //	in such case \ref MDBX_env instance has NOT be destroyed
  2238  //	not released!
  2239  //	\note If any OTHER error code was returned then
  2240  //	given MDBX_env instance has been destroyed and released.
  2241  //
  2242  // \retval MDBX_EBADSIGN  Environment handle already closed or not valid,
  2243  //
  2244  //	i.e. \ref mdbx_env_close() was already called for the
  2245  //	`env` or was not created by \ref mdbx_env_create().
  2246  //
  2247  // \retval MDBX_PANIC  If \ref mdbx_env_close_ex() was called in the child
  2248  //
  2249  //	process after `fork()`. In this case \ref MDBX_PANIC
  2250  //	is expected, i.e. \ref MDBX_env instance was freed in
  2251  //	proper manner.
  2252  //
  2253  // \retval MDBX_EIO    An error occurred during synchronization.
  2254  func (env *Env) Close(dontSync bool) Error {
  2255  	env.mu.Lock()
  2256  	defer env.mu.Unlock()
  2257  	if env.closed > 0 {
  2258  		return ErrSuccess
  2259  	}
  2260  	err := Error(C.mdbx_env_close_ex(env.env, (C.bool)(dontSync)))
  2261  	if err != ErrSuccess {
  2262  		return err
  2263  	}
  2264  	env.closed = time.Now().UnixNano()
  2265  	return err
  2266  }
  2267  
  2268  // SetFlags Set environment flags.
  2269  // \ingroup c_settings
  2270  //
  2271  // This may be used to set some flags in addition to those from
  2272  // mdbx_env_open(), or to unset these flags.
  2273  // \see mdbx_env_get_flags()
  2274  //
  2275  // \note In contrast to LMDB, the MDBX serialize threads via mutex while
  2276  // changing the flags. Therefore this function will be blocked while a write
  2277  // transaction running by other thread, or \ref MDBX_BUSY will be returned if
  2278  // function called within a write transaction.
  2279  //
  2280  // \param [in] env      An environment handle returned
  2281  //
  2282  //	by \ref mdbx_env_create().
  2283  //
  2284  // \param [in] flags    The \ref env_flags to change, bitwise OR'ed together.
  2285  // \param [in] onoff    A non-zero value sets the flags, zero clears them.
  2286  //
  2287  // \returns A non-zero error value on failure and 0 on success,
  2288  //
  2289  //	some possible errors are:
  2290  //
  2291  // \retval MDBX_EINVAL  An invalid parameter was specified.
  2292  func (env *Env) SetFlags(flags EnvFlags, onoff bool) Error {
  2293  	return Error(C.mdbx_env_set_flags(env.env, (C.MDBX_env_flags_t)(flags), (C.bool)(onoff)))
  2294  }
  2295  
  2296  // GetFlags Get environment flags.
  2297  // \ingroup c_statinfo
  2298  // \see mdbx_env_set_flags()
  2299  //
  2300  // \param [in] env     An environment handle returned by \ref mdbx_env_create().
  2301  // \param [out] flags  The address of an integer to store the flags.
  2302  //
  2303  // \returns A non-zero error value on failure and 0 on success,
  2304  //
  2305  //	some possible errors are:
  2306  //
  2307  // \retval MDBX_EINVAL An invalid parameter was specified.
  2308  func (env *Env) GetFlags() (EnvFlags, Error) {
  2309  	flags := C.unsigned(0)
  2310  	err := Error(C.mdbx_env_get_flags(env.env, &flags))
  2311  	return EnvFlags(flags), err
  2312  }
  2313  
  2314  // Copy an MDBX environment to the specified path, with options.
  2315  // \ingroup c_extra
  2316  //
  2317  // This function may be used to make a backup of an existing environment.
  2318  // No lockfile is created, since it gets recreated at need.
  2319  // \note This call can trigger significant file size growth if run in
  2320  // parallel with write transactions, because it employs a read-only
  2321  // transaction. See long-lived transactions under \ref restrictions section.
  2322  //
  2323  // \param [in] env    An environment handle returned by mdbx_env_create().
  2324  //
  2325  //	It must have already been opened successfully.
  2326  //
  2327  // \param [in] dest   The pathname of a file in which the copy will reside.
  2328  //
  2329  //	This file must not be already exist, but parent directory
  2330  //	must be writable.
  2331  //
  2332  // \param [in] flags  Special options for this operation. This parameter must
  2333  //
  2334  //	                  be set to 0 or by bitwise OR'ing together one or more
  2335  //	                  of the values described here:
  2336  //
  2337  //	- \ref MDBX_CP_COMPACT
  2338  //	    Perform compaction while copying: omit free pages and sequentially
  2339  //	    renumber all pages in output. This option consumes little bit more
  2340  //	    CPU for processing, but may running quickly than the default, on
  2341  //	    account skipping free pages.
  2342  //
  2343  //	- \ref MDBX_CP_FORCE_DYNAMIC_SIZE
  2344  //	    Force to make resizeable copy, i.e. dynamic size instead of fixed.
  2345  //
  2346  // \returns A non-zero error value on failure and 0 on success.
  2347  func (env *Env) Copy(dest string, flags CopyFlags) Error {
  2348  	if env.env == nil {
  2349  		return ErrSuccess
  2350  	}
  2351  	d := C.CString(dest)
  2352  	defer C.free(unsafe.Pointer(d))
  2353  	return Error(C.mdbx_env_copy(env.env, d, (C.MDBX_copy_flags_t)(flags)))
  2354  }
  2355  
  2356  // Open \brief Open an environment instance.
  2357  // \ingroup c_opening
  2358  //
  2359  // Indifferently this function will fails or not, the \ref mdbx_env_close() must
  2360  // be called later to discard the \ref MDBX_env handle and release associated
  2361  // resources.
  2362  //
  2363  // \param [in] env       An environment handle returned
  2364  //
  2365  //	by \ref mdbx_env_create()
  2366  //
  2367  // \param [in] pathname  The pathname for the database or the directory in which
  2368  //
  2369  //	the database files reside. In the case of directory it
  2370  //	must already exist and be writable.
  2371  //
  2372  // \param [in] flags     Special options for this environment. This parameter
  2373  //
  2374  //	must be set to 0 or by bitwise OR'ing together one
  2375  //	or more of the values described above in the
  2376  //	\ref env_flags and \ref sync_modes sections.
  2377  //
  2378  // Flags set by mdbx_env_set_flags() are also used:
  2379  //
  2380  //   - \ref MDBX_NOSUBDIR, \ref MDBX_RDONLY, \ref MDBX_EXCLUSIVE,
  2381  //     \ref MDBX_WRITEMAP, \ref MDBX_NOTLS, \ref MDBX_NORDAHEAD,
  2382  //     \ref MDBX_NOMEMINIT, \ref MDBX_COALESCE, \ref MDBX_LIFORECLAIM.
  2383  //     See \ref env_flags section.
  2384  //
  2385  //   - \ref MDBX_NOMETASYNC, \ref MDBX_SAFE_NOSYNC, \ref MDBX_UTTERLY_NOSYNC.
  2386  //     See \ref sync_modes section.
  2387  //
  2388  // \note `MDB_NOLOCK` flag don't supported by MDBX,
  2389  //
  2390  //	try use \ref MDBX_EXCLUSIVE as a replacement.
  2391  //
  2392  // \note MDBX don't allow to mix processes with different \ref MDBX_SAFE_NOSYNC
  2393  //
  2394  //	flags on the same environment.
  2395  //	In such case \ref MDBX_INCOMPATIBLE will be returned.
  2396  //
  2397  // If the database is already exist and parameters specified early by
  2398  // \ref mdbx_env_set_geometry() are incompatible (i.e. for instance, different
  2399  // page size) then \ref mdbx_env_open() will return \ref MDBX_INCOMPATIBLE
  2400  // error.
  2401  //
  2402  // \param [in] mode   The UNIX permissions to set on created files.
  2403  //
  2404  //	Zero value means to open existing, but do not create.
  2405  //
  2406  // \return A non-zero error value on failure and 0 on success,
  2407  //
  2408  //	some possible errors are:
  2409  //
  2410  // \retval MDBX_VERSION_MISMATCH The version of the MDBX library doesn't match
  2411  //
  2412  //	the version that created the database environment.
  2413  //
  2414  // \retval MDBX_INVALID       The environment file headers are corrupted.
  2415  // \retval MDBX_ENOENT        The directory specified by the path parameter
  2416  //
  2417  //	doesn't exist.
  2418  //
  2419  // \retval MDBX_EACCES        The user didn't have permission to access
  2420  //
  2421  //	the environment files.
  2422  //
  2423  // \retval MDBX_EAGAIN        The environment was locked by another process.
  2424  // \retval MDBX_BUSY          The \ref MDBX_EXCLUSIVE flag was specified and the
  2425  //
  2426  //	environment is in use by another process,
  2427  //	or the current process tries to open environment
  2428  //	more than once.
  2429  //
  2430  // \retval MDBX_INCOMPATIBLE  Environment is already opened by another process,
  2431  //
  2432  //	but with different set of \ref MDBX_SAFE_NOSYNC,
  2433  //	\ref MDBX_UTTERLY_NOSYNC flags.
  2434  //	Or if the database is already exist and parameters
  2435  //	specified early by \ref mdbx_env_set_geometry()
  2436  //	are incompatible (i.e. different pagesize, etc).
  2437  //
  2438  // \retval MDBX_WANNA_RECOVERY The \ref MDBX_RDONLY flag was specified but
  2439  //
  2440  //	read-write access is required to rollback
  2441  //	inconsistent state after a system crash.
  2442  //
  2443  // \retval MDBX_TOO_LARGE      Database is too large for this process,
  2444  //
  2445  //	i.e. 32-bit process tries to open >4Gb database.
  2446  func (env *Env) Open(path string, flags EnvFlags, mode os.FileMode) Error {
  2447  	if env.opened > 0 {
  2448  		return ErrSuccess
  2449  	}
  2450  
  2451  	p := C.CString(path)
  2452  	defer C.free(unsafe.Pointer(p))
  2453  
  2454  	err := Error(C.mdbx_env_open(
  2455  		(*C.MDBX_env)(unsafe.Pointer(env.env)),
  2456  		p,
  2457  		(C.MDBX_env_flags_t)(flags),
  2458  		(C.mdbx_mode_t)(mode),
  2459  	))
  2460  	if err != ErrSuccess {
  2461  		return err
  2462  	}
  2463  
  2464  	env.opened = time.Now().UnixNano()
  2465  	return err
  2466  }
  2467  
  2468  type Geometry struct {
  2469  	env             uintptr
  2470  	SizeLower       uintptr
  2471  	SizeNow         uintptr
  2472  	SizeUpper       uintptr
  2473  	GrowthStep      uintptr
  2474  	ShrinkThreshold uintptr
  2475  	PageSize        uintptr
  2476  	err             Error
  2477  }
  2478  
  2479  // SetGeometry Set all size-related parameters of environment, including page size
  2480  // and the min/max size of the memory map. \ingroup c_settings
  2481  //
  2482  // In contrast to LMDB, the MDBX provide automatic size management of an
  2483  // database according the given parameters, including shrinking and resizing
  2484  // on the fly. From user point of view all of these just working. Nevertheless,
  2485  // it is reasonable to know some details in order to make optimal decisions
  2486  // when choosing parameters.
  2487  //
  2488  // Both \ref mdbx_env_info_ex() and legacy \ref mdbx_env_info() are inapplicable
  2489  // to read-only opened environment.
  2490  //
  2491  // Both \ref mdbx_env_info_ex() and legacy \ref mdbx_env_info() could be called
  2492  // either before or after \ref mdbx_env_open(), either within the write
  2493  // transaction running by current thread or not:
  2494  //
  2495  //   - In case \ref mdbx_env_info_ex() or legacy \ref mdbx_env_info() was called
  2496  //     BEFORE \ref mdbx_env_open(), i.e. for closed environment, then the
  2497  //     specified parameters will be used for new database creation, or will be
  2498  //     applied during opening if database exists and no other process using it.
  2499  //
  2500  //     If the database is already exist, opened with \ref MDBX_EXCLUSIVE or not
  2501  //     used by any other process, and parameters specified by
  2502  //     \ref mdbx_env_set_geometry() are incompatible (i.e. for instance,
  2503  //     different page size) then \ref mdbx_env_open() will return
  2504  //     \ref MDBX_INCOMPATIBLE error.
  2505  //
  2506  //     In another way, if database will opened read-only or will used by other
  2507  //     process during calling \ref mdbx_env_open() that specified parameters will
  2508  //     silently discarded (open the database with \ref MDBX_EXCLUSIVE flag
  2509  //     to avoid this).
  2510  //
  2511  //   - In case \ref mdbx_env_info_ex() or legacy \ref mdbx_env_info() was called
  2512  //     after \ref mdbx_env_open() WITHIN the write transaction running by current
  2513  //     thread, then specified parameters will be applied as a part of write
  2514  //     transaction, i.e. will not be visible to any others processes until the
  2515  //     current write transaction has been committed by the current process.
  2516  //     However, if transaction will be aborted, then the database file will be
  2517  //     reverted to the previous size not immediately, but when a next transaction
  2518  //     will be committed or when the database will be opened next time.
  2519  //
  2520  //   - In case \ref mdbx_env_info_ex() or legacy \ref mdbx_env_info() was called
  2521  //     after \ref mdbx_env_open() but OUTSIDE a write transaction, then MDBX will
  2522  //     execute internal pseudo-transaction to apply new parameters (but only if
  2523  //     anything has been changed), and changes be visible to any others processes
  2524  //     immediately after succesful completion of function.
  2525  //
  2526  // Essentially a concept of "automatic size management" is simple and useful:
  2527  //   - There are the lower and upper bound of the database file size;
  2528  //   - There is the growth step by which the database file will be increased,
  2529  //     in case of lack of space.
  2530  //   - There is the threshold for unused space, beyond which the database file
  2531  //     will be shrunk.
  2532  //   - The size of the memory map is also the maximum size of the database.
  2533  //   - MDBX will automatically manage both the size of the database and the size
  2534  //     of memory map, according to the given parameters.
  2535  //
  2536  // So, there some considerations about choosing these parameters:
  2537  //   - The lower bound allows you to prevent database shrinking below some
  2538  //     rational size to avoid unnecessary resizing costs.
  2539  //   - The upper bound allows you to prevent database growth above some rational
  2540  //     size. Besides, the upper bound defines the linear address space
  2541  //     reservation in each process that opens the database. Therefore changing
  2542  //     the upper bound is costly and may be required reopening environment in
  2543  //     case of \ref MDBX_UNABLE_EXTEND_MAPSIZE errors, and so on. Therefore, this
  2544  //     value should be chosen reasonable as large as possible, to accommodate
  2545  //     future growth of the database.
  2546  //   - The growth step must be greater than zero to allow the database to grow,
  2547  //     but also reasonable not too small, since increasing the size by little
  2548  //     steps will result a large overhead.
  2549  //   - The shrink threshold must be greater than zero to allow the database
  2550  //     to shrink but also reasonable not too small (to avoid extra overhead) and
  2551  //     not less than growth step to avoid up-and-down flouncing.
  2552  //   - The current size (i.e. size_now argument) is an auxiliary parameter for
  2553  //     simulation legacy \ref mdbx_env_set_mapsize() and as workaround Windows
  2554  //     issues (see below).
  2555  //
  2556  // Unfortunately, Windows has is a several issues
  2557  // with resizing of memory-mapped file:
  2558  //   - Windows unable shrinking a memory-mapped file (i.e memory-mapped section)
  2559  //     in any way except unmapping file entirely and then map again. Moreover,
  2560  //     it is impossible in any way if a memory-mapped file is used more than
  2561  //     one process.
  2562  //   - Windows does not provide the usual API to augment a memory-mapped file
  2563  //     (that is, a memory-mapped partition), but only by using "Native API"
  2564  //     in an undocumented way.
  2565  //
  2566  // MDBX bypasses all Windows issues, but at a cost:
  2567  //   - Ability to resize database on the fly requires an additional lock
  2568  //     and release `SlimReadWriteLock during` each read-only transaction.
  2569  //   - During resize all in-process threads should be paused and then resumed.
  2570  //   - Shrinking of database file is performed only when it used by single
  2571  //     process, i.e. when a database closes by the last process or opened
  2572  //     by the first.
  2573  //     = Therefore, the size_now argument may be useful to set database size
  2574  //     by the first process which open a database, and thus avoid expensive
  2575  //     remapping further.
  2576  //
  2577  // For create a new database with particular parameters, including the page
  2578  // size, \ref mdbx_env_set_geometry() should be called after
  2579  // \ref mdbx_env_create() and before mdbx_env_open(). Once the database is
  2580  // created, the page size cannot be changed. If you do not specify all or some
  2581  // of the parameters, the corresponding default values will be used. For
  2582  // instance, the default for database size is 10485760 bytes.
  2583  //
  2584  // If the mapsize is increased by another process, MDBX silently and
  2585  // transparently adopt these changes at next transaction start. However,
  2586  // \ref mdbx_txn_begin() will return \ref MDBX_UNABLE_EXTEND_MAPSIZE if new
  2587  // mapping size could not be applied for current process (for instance if
  2588  // address space is busy).  Therefore, in the case of
  2589  // \ref MDBX_UNABLE_EXTEND_MAPSIZE error you need close and reopen the
  2590  // environment to resolve error.
  2591  //
  2592  // \note Actual values may be different than your have specified because of
  2593  // rounding to specified database page size, the system page size and/or the
  2594  // size of the system virtual memory management unit. You can get actual values
  2595  // by \ref mdbx_env_sync_ex() or see by using the tool `mdbx_chk` with the `-v`
  2596  // option.
  2597  //
  2598  // Legacy \ref mdbx_env_set_mapsize() correspond to calling
  2599  // \ref mdbx_env_set_geometry() with the arguments `size_lower`, `size_now`,
  2600  // `size_upper` equal to the `size` and `-1` (i.e. default) for all other
  2601  // parameters.
  2602  //
  2603  // \param [in] env         An environment handle returned
  2604  //
  2605  //	by \ref mdbx_env_create()
  2606  //
  2607  // \param [in] size_lower  The lower bound of database size in bytes.
  2608  //
  2609  //	Zero value means "minimal acceptable",
  2610  //	and negative means "keep current or use default".
  2611  //
  2612  // \param [in] size_now    The size in bytes to setup the database size for
  2613  //
  2614  //	now. Zero value means "minimal acceptable", and
  2615  //	negative means "keep current or use default". So,
  2616  //	it is recommended always pass -1 in this argument
  2617  //	except some special cases.
  2618  //
  2619  // \param [in] size_upper The upper bound of database size in bytes.
  2620  //
  2621  //	Zero value means "minimal acceptable",
  2622  //	and negative means "keep current or use default".
  2623  //	It is recommended to avoid change upper bound while
  2624  //	database is used by other processes or threaded
  2625  //	(i.e. just pass -1 in this argument except absolutely
  2626  //	necessary). Otherwise you must be ready for
  2627  //	\ref MDBX_UNABLE_EXTEND_MAPSIZE error(s), unexpected
  2628  //	pauses during remapping and/or system errors like
  2629  //	"address busy", and so on. In other words, there
  2630  //	is no way to handle a growth of the upper bound
  2631  //	robustly because there may be a lack of appropriate
  2632  //	system resources (which are extremely volatile in
  2633  //	a multi-process multi-threaded environment).
  2634  //
  2635  // \param [in] growth_step  The growth step in bytes, must be greater than
  2636  //
  2637  //	zero to allow the database to grow. Negative value
  2638  //	means "keep current or use default".
  2639  //
  2640  // \param [in] shrink_threshold  The shrink threshold in bytes, must be greater
  2641  //
  2642  //	than zero to allow the database to shrink and
  2643  //	greater than growth_step to avoid shrinking
  2644  //	right after grow.
  2645  //	Negative value means "keep current
  2646  //	or use default". Default is 2*growth_step.
  2647  //
  2648  // \param [in] pagesize          The database page size for new database
  2649  //
  2650  //	creation or -1 otherwise. Must be power of 2
  2651  //	in the range between \ref MDBX_MIN_PAGESIZE and
  2652  //	\ref MDBX_MAX_PAGESIZE. Zero value means
  2653  //	"minimal acceptable", and negative means
  2654  //	"keep current or use default".
  2655  //
  2656  // \returns A non-zero error value on failure and 0 on success,
  2657  //
  2658  //	some possible errors are:
  2659  //
  2660  // \retval MDBX_EINVAL    An invalid parameter was specified,
  2661  //
  2662  //	or the environment has an active write transaction.
  2663  //
  2664  // \retval MDBX_EPERM     Specific for Windows: Shrinking was disabled before
  2665  //
  2666  //	and now it wanna be enabled, but there are reading
  2667  //	threads that don't use the additional `SRWL` (that
  2668  //	is required to avoid Windows issues).
  2669  //
  2670  // \retval MDBX_EACCESS   The environment opened in read-only.
  2671  // \retval MDBX_MAP_FULL  Specified size smaller than the space already
  2672  //
  2673  //	consumed by the environment.
  2674  //
  2675  // \retval MDBX_TOO_LARGE Specified size is too large, i.e. too many pages for
  2676  //
  2677  //	given size, or a 32-bit process requests too much
  2678  //	bytes for the 32-bit address space.
  2679  func (env *Env) SetGeometry(args Geometry) Error {
  2680  	args.env = uintptr(unsafe.Pointer(env.env))
  2681  	ptr := uintptr(unsafe.Pointer(&args))
  2682  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_env_set_geometry), ptr, 0)
  2683  	return args.err
  2684  }
  2685  
  2686  // GetOption \brief Gets the value of runtime options from an environment.
  2687  // \ingroup c_settings
  2688  //
  2689  // \param [in] env     An environment handle returned by \ref mdbx_env_create().
  2690  // \param [in] option  The option from \ref MDBX_option_t to get value of it.
  2691  // \param [out] pvalue The address where the option's value will be stored.
  2692  //
  2693  // \see MDBX_option_t
  2694  // \see mdbx_env_get_option()
  2695  // \returns A non-zero error value on failure and 0 on success.
  2696  func (env *Env) GetOption(option Opt) (uint64, Error) {
  2697  	value := uint64(0)
  2698  	err := Error(C.mdbx_env_get_option(
  2699  		(*C.MDBX_env)(unsafe.Pointer(env.env)),
  2700  		(C.MDBX_option_t)(option),
  2701  		(*C.uint64_t)(unsafe.Pointer(&value))),
  2702  	)
  2703  	return value, err
  2704  }
  2705  
  2706  // SetOption \brief Sets the value of a runtime options for an environment.
  2707  // \ingroup c_settings
  2708  //
  2709  // \param [in] env     An environment handle returned by \ref mdbx_env_create().
  2710  // \param [in] option  The option from \ref MDBX_option_t to set value of it.
  2711  // \param [in] value   The value of option to be set.
  2712  //
  2713  // \see MDBX_option_t
  2714  // \see mdbx_env_get_option()
  2715  // \returns A non-zero error value on failure and 0 on success.
  2716  func (env *Env) SetOption(option Opt, value uint64) Error {
  2717  	return Error(C.mdbx_env_set_option(
  2718  		(*C.MDBX_env)(unsafe.Pointer(env.env)),
  2719  		(C.MDBX_option_t)(option),
  2720  		C.uint64_t(value)),
  2721  	)
  2722  }
  2723  
  2724  type EnvInfo struct {
  2725  	Geo struct {
  2726  		Lower   uint64 // Lower limit for datafile size
  2727  		Upper   uint64 // Upper limit for datafile size
  2728  		Current uint64 // Current datafile size
  2729  		Shrink  uint64 // Shrink threshold for datafile
  2730  		Grow    uint64 // Growth step for datafile
  2731  	}
  2732  	MapSize               uint64 // Size of the data memory map
  2733  	LastPageNumber        uint64 // Number of the last used page
  2734  	RecentTxnID           uint64 // ID of the last committed transaction
  2735  	LatterReaderTxnID     uint64 // ID of the last reader transaction
  2736  	SelfLatterReaderTxnID uint64 // ID of the last reader transaction of caller process
  2737  
  2738  	Meta0TxnID, MIMeta0Sign uint64
  2739  	Meta1TxnID, MIMeta1Sign uint64
  2740  	Meta2TxnID, MIMeta2Sign uint64
  2741  
  2742  	MaxReaders  uint32 // Total reader slots in the environment
  2743  	NumReaders  uint32 // Max reader slots used in the environment
  2744  	DXBPageSize uint32 // Database pagesize
  2745  	SysPageSize uint32 // System pagesize
  2746  
  2747  	// BootID A mostly unique ID that is regenerated on each boot.
  2748  	// As such it can be used to identify the local machine's current boot. MDBX
  2749  	// uses such when open the database to determine whether rollback required to
  2750  	// the last steady sync point or not. I.e. if current bootid is differ from the
  2751  	// value within a database then the system was rebooted and all changes since
  2752  	// last steady sync must be reverted for data integrity. Zeros mean that no
  2753  	// relevant information is available from the system.
  2754  	BootID struct {
  2755  		Current, Meta0, Meta1, Meta2 struct{ X, Y uint64 }
  2756  	}
  2757  
  2758  	UnSyncVolume                   uint64 // Bytes not explicitly synchronized to disk.
  2759  	AutoSyncThreshold              uint64 // Current auto-sync threshold, see \ref mdbx_env_set_syncbytes().
  2760  	SinceSyncSeconds16Dot16        uint32 // Time since the last steady sync in 1/65536 of second
  2761  	AutoSyncPeriodSeconds16Dot16   uint32 // Current auto-sync period in 1/65536 of second, see \ref mdbx_env_set_syncperiod().
  2762  	SinceReaderCheckSeconds16Dot16 uint32 // Time since the last readers check in 1/65536 of second, see \ref mdbx_reader_check()
  2763  	Mode                           uint32 // Current environment mode. The same as \ref mdbx_env_get_flags() returns.
  2764  
  2765  	// Statistics of page operations.
  2766  	// details Overall statistics of page operations of all (running, completed
  2767  	// and aborted) transactions in the current multi-process session (since the
  2768  	// first process opened the database after everyone had previously closed it).
  2769  	PGOpStat struct {
  2770  		Newly                 uint64 // Quantity of a new pages added
  2771  		Cow                   uint64 // Quantity of pages copied for update
  2772  		Clone                 uint64 // Quantity of parent's dirty pages clones for nested transactions
  2773  		Split                 uint64 // Page splits
  2774  		Merge                 uint64 // Page merges
  2775  		Spill                 uint64 // Quantity of spilled dirty pages
  2776  		UnSpill               uint64 // Quantity of unspilled/reloaded pages
  2777  		Wops                  uint64 // Number of explicit write operations (not a pages) to a disk
  2778  		GCRTimeSeconds16dot16 uint64 // Time spent loading and searching inside GC (aka FreeDB) in 1/65536 of second.
  2779  	}
  2780  }
  2781  
  2782  // Sync Flush the environment data buffers to disk.
  2783  // \ingroup c_extra
  2784  //
  2785  // Unless the environment was opened with no-sync flags (\ref MDBX_NOMETASYNC,
  2786  // \ref MDBX_SAFE_NOSYNC and \ref MDBX_UTTERLY_NOSYNC), then
  2787  // data is always written an flushed to disk when \ref mdbx_txn_commit() is
  2788  // called. Otherwise \ref mdbx_env_sync() may be called to manually write and
  2789  // flush unsynced data to disk.
  2790  //
  2791  // Besides, \ref mdbx_env_sync_ex() with argument `force=false` may be used to
  2792  // provide polling mode for lazy/asynchronous sync in conjunction with
  2793  // \ref mdbx_env_set_syncbytes() and/or \ref mdbx_env_set_syncperiod().
  2794  //
  2795  // \note This call is not valid if the environment was opened with MDBX_RDONLY.
  2796  //
  2797  // \param [in] env      An environment handle returned by \ref mdbx_env_create()
  2798  // \param [in] force    If non-zero, force a flush. Otherwise, If force is
  2799  //
  2800  //	zero, then will run in polling mode,
  2801  //	i.e. it will check the thresholds that were
  2802  //	set \ref mdbx_env_set_syncbytes()
  2803  //	and/or \ref mdbx_env_set_syncperiod() and perform flush
  2804  //	if at least one of the thresholds is reached.
  2805  //
  2806  // \param [in] nonblock Don't wait if write transaction
  2807  //
  2808  //	is running by other thread.
  2809  //
  2810  // \returns A non-zero error value on failure and \ref MDBX_RESULT_TRUE or 0 on
  2811  //
  2812  //	success. The \ref MDBX_RESULT_TRUE means no data pending for flush
  2813  //	to disk, and 0 otherwise. Some possible errors are:
  2814  //
  2815  // \retval MDBX_EACCES   the environment is read-only.
  2816  // \retval MDBX_BUSY     the environment is used by other thread
  2817  //
  2818  //	and `nonblock=true`.
  2819  //
  2820  // \retval MDBX_EINVAL   an invalid parameter was specified.
  2821  // \retval MDBX_EIO      an error occurred during synchronization.
  2822  func (env *Env) Sync(force, nonblock bool) Error {
  2823  	return Error(C.mdbx_env_sync_ex(env.env, (C.bool)(force), (C.bool)(nonblock)))
  2824  }
  2825  
  2826  // CloseDBI Close a database handle. Normally unnecessary.
  2827  // \ingroup c_dbi
  2828  //
  2829  // Closing a database handle is not necessary, but lets \ref mdbx_dbi_open()
  2830  // reuse the handle value. Usually it's better to set a bigger
  2831  // \ref mdbx_env_set_maxdbs(), unless that value would be large.
  2832  //
  2833  // \note Use with care.
  2834  // This call is synchronized via mutex with \ref mdbx_dbi_close(), but NOT with
  2835  // other transactions running by other threads. The "next" version of libmdbx
  2836  // (\ref MithrilDB) will solve this issue.
  2837  //
  2838  // Handles should only be closed if no other threads are going to reference
  2839  // the database handle or one of its cursors any further. Do not close a handle
  2840  // if an existing transaction has modified its database. Doing so can cause
  2841  // misbehavior from database corruption to errors like \ref MDBX_BAD_DBI
  2842  // (since the DB name is gone).
  2843  //
  2844  // \param [in] env  An environment handle returned by \ref mdbx_env_create().
  2845  // \param [in] dbi  A database handle returned by \ref mdbx_dbi_open().
  2846  //
  2847  // \returns A non-zero error value on failure and 0 on success.
  2848  func (env *Env) CloseDBI(dbi DBI) Error {
  2849  	return Error(C.mdbx_dbi_close(env.env, (C.MDBX_dbi)(dbi)))
  2850  }
  2851  
  2852  // GetMaxDBS Controls the maximum number of named databases for the environment.
  2853  //
  2854  // \details By default only unnamed key-value database could used and
  2855  // appropriate value should set by `MDBX_opt_max_db` to using any more named
  2856  // subDB(s). To reduce overhead, use the minimum sufficient value. This option
  2857  // may only set after \ref mdbx_env_create() and before \ref mdbx_env_open().
  2858  //
  2859  // \see mdbx_env_set_maxdbs() \see mdbx_env_get_maxdbs()
  2860  func (env *Env) GetMaxDBS() (uint64, Error) {
  2861  	return env.GetOption(OptMaxDB)
  2862  }
  2863  
  2864  // SetMaxDBS Controls the maximum number of named databases for the environment.
  2865  //
  2866  // \details By default only unnamed key-value database could used and
  2867  // appropriate value should set by `MDBX_opt_max_db` to using any more named
  2868  // subDB(s). To reduce overhead, use the minimum sufficient value. This option
  2869  // may only set after \ref mdbx_env_create() and before \ref mdbx_env_open().
  2870  //
  2871  // \see mdbx_env_set_maxdbs() \see mdbx_env_get_maxdbs()
  2872  func (env *Env) SetMaxDBS(max uint16) Error {
  2873  	return env.SetOption(OptMaxDB, uint64(max))
  2874  }
  2875  
  2876  // GetMaxReaders Defines the maximum number of threads/reader slots
  2877  // for all processes interacting with the database.
  2878  //
  2879  // \details This defines the number of slots in the lock table that is used to
  2880  // track readers in the the environment. The default is about 100 for 4K
  2881  // system page size. Starting a read-only transaction normally ties a lock
  2882  // table slot to the current thread until the environment closes or the thread
  2883  // exits. If \ref MDBX_NOTLS is in use, \ref mdbx_txn_begin() instead ties the
  2884  // slot to the \ref MDBX_txn object until it or the \ref MDBX_env object is
  2885  // destroyed. This option may only set after \ref mdbx_env_create() and before
  2886  // \ref mdbx_env_open(), and has an effect only when the database is opened by
  2887  // the first process interacts with the database.
  2888  //
  2889  // \see mdbx_env_set_maxreaders() \see mdbx_env_get_maxreaders()
  2890  func (env *Env) GetMaxReaders() (uint64, Error) {
  2891  	return env.GetOption(OptMaxReaders)
  2892  }
  2893  
  2894  // SetMaxReaders Defines the maximum number of threads/reader slots
  2895  // for all processes interacting with the database.
  2896  //
  2897  // \details This defines the number of slots in the lock table that is used to
  2898  // track readers in the the environment. The default is about 100 for 4K
  2899  // system page size. Starting a read-only transaction normally ties a lock
  2900  // table slot to the current thread until the environment closes or the thread
  2901  // exits. If \ref MDBX_NOTLS is in use, \ref mdbx_txn_begin() instead ties the
  2902  // slot to the \ref MDBX_txn object until it or the \ref MDBX_env object is
  2903  // destroyed. This option may only set after \ref mdbx_env_create() and before
  2904  // \ref mdbx_env_open(), and has an effect only when the database is opened by
  2905  // the first process interacts with the database.
  2906  //
  2907  // \see mdbx_env_set_maxreaders() \see mdbx_env_get_maxreaders()
  2908  func (env *Env) SetMaxReaders(max uint64) Error {
  2909  	return env.SetOption(OptMaxReaders, max)
  2910  }
  2911  
  2912  // GetSyncBytes Controls interprocess/shared threshold to force flush the data
  2913  // buffers to disk, if \ref MDBX_SAFE_NOSYNC is used.
  2914  //
  2915  // \see mdbx_env_set_syncbytes() \see mdbx_env_get_syncbytes()
  2916  func (env *Env) GetSyncBytes() (uint64, Error) {
  2917  	return env.GetOption(OptSyncBytes)
  2918  }
  2919  
  2920  // SetSyncBytes Controls interprocess/shared threshold to force flush the data
  2921  // buffers to disk, if \ref MDBX_SAFE_NOSYNC is used.
  2922  //
  2923  // \see mdbx_env_set_syncbytes() \see mdbx_env_get_syncbytes()
  2924  func (env *Env) SetSyncBytes(bytes uint64) Error {
  2925  	return env.SetOption(OptSyncBytes, bytes)
  2926  }
  2927  
  2928  // GetSyncPeriod Controls interprocess/shared relative period since the last
  2929  // unsteady commit to force flush the data buffers to disk,
  2930  // if \ref MDBX_SAFE_NOSYNC is used.
  2931  // \see mdbx_env_set_syncperiod() \see mdbx_env_get_syncperiod()
  2932  func (env *Env) GetSyncPeriod() (uint64, Error) {
  2933  	return env.GetOption(OptSyncPeriod)
  2934  }
  2935  
  2936  // SetSyncPeriod Controls interprocess/shared relative period since the last
  2937  // unsteady commit to force flush the data buffers to disk,
  2938  // if \ref MDBX_SAFE_NOSYNC is used.
  2939  // \see mdbx_env_set_syncperiod() \see mdbx_env_get_syncperiod()
  2940  func (env *Env) SetSyncPeriod(period uint64) Error {
  2941  	return env.SetOption(OptSyncPeriod, period)
  2942  }
  2943  
  2944  // GetRPAugmentLimit Controls the in-process limit to grow a list of reclaimed/recycled
  2945  // page's numbers for finding a sequence of contiguous pages for large data
  2946  // items.
  2947  //
  2948  // \details A long values requires allocation of contiguous database pages.
  2949  // To find such sequences, it may be necessary to accumulate very large lists,
  2950  // especially when placing very long values (more than a megabyte) in a large
  2951  // databases (several tens of gigabytes), which is much expensive in extreme
  2952  // cases. This threshold allows you to avoid such costs by allocating new
  2953  // pages at the end of the database (with its possible growth on disk),
  2954  // instead of further accumulating/reclaiming Garbage Collection records.
  2955  //
  2956  // On the other hand, too small threshold will lead to unreasonable database
  2957  // growth, or/and to the inability of put long values.
  2958  //
  2959  // The `MDBX_opt_rp_augment_limit` controls described limit for the current
  2960  // process. Default is 262144, it is usually enough for most cases.
  2961  func (env *Env) GetRPAugmentLimit() (uint64, Error) {
  2962  	return env.GetOption(OptRpAugmentLimit)
  2963  }
  2964  
  2965  // SetRPAugmentLimit Controls the in-process limit to grow a list of reclaimed/recycled
  2966  // page's numbers for finding a sequence of contiguous pages for large data
  2967  // items.
  2968  //
  2969  // \details A long values requires allocation of contiguous database pages.
  2970  // To find such sequences, it may be necessary to accumulate very large lists,
  2971  // especially when placing very long values (more than a megabyte) in a large
  2972  // databases (several tens of gigabytes), which is much expensive in extreme
  2973  // cases. This threshold allows you to avoid such costs by allocating new
  2974  // pages at the end of the database (with its possible growth on disk),
  2975  // instead of further accumulating/reclaiming Garbage Collection records.
  2976  //
  2977  // On the other hand, too small threshold will lead to unreasonable database
  2978  // growth, or/and to the inability of put long values.
  2979  //
  2980  // The `MDBX_opt_rp_augment_limit` controls described limit for the current
  2981  // process. Default is 262144, it is usually enough for most cases.
  2982  func (env *Env) SetRPAugmentLimit(limit uint64) Error {
  2983  	return env.SetOption(OptRpAugmentLimit, limit)
  2984  }
  2985  
  2986  // GetLooseLimit Controls the in-process limit to grow a cache of dirty
  2987  // pages for reuse in the current transaction.
  2988  //
  2989  // \details A 'dirty page' refers to a page that has been updated in memory
  2990  // only, the changes to a dirty page are not yet stored on disk.
  2991  // To reduce overhead, it is reasonable to release not all such pages
  2992  // immediately, but to leave some ones in cache for reuse in the current
  2993  // transaction.
  2994  //
  2995  // The `MDBX_opt_loose_limit` allows you to set a limit for such cache inside
  2996  // the current process. Should be in the range 0..255, default is 64.
  2997  func (env *Env) GetLooseLimit() (uint64, Error) {
  2998  	return env.GetOption(OptLooseLimit)
  2999  }
  3000  
  3001  // SetLooseLimit Controls the in-process limit to grow a cache of dirty
  3002  // pages for reuse in the current transaction.
  3003  //
  3004  // \details A 'dirty page' refers to a page that has been updated in memory
  3005  // only, the changes to a dirty page are not yet stored on disk.
  3006  // To reduce overhead, it is reasonable to release not all such pages
  3007  // immediately, but to leave some ones in cache for reuse in the current
  3008  // transaction.
  3009  //
  3010  // The `MDBX_opt_loose_limit` allows you to set a limit for such cache inside
  3011  // the current process. Should be in the range 0..255, default is 64.
  3012  func (env *Env) SetLooseLimit(limit uint64) Error {
  3013  	return env.SetOption(OptLooseLimit, limit)
  3014  }
  3015  
  3016  // GetDPReserveLimit Controls the in-process limit of a pre-allocated memory items
  3017  // for dirty pages.
  3018  //
  3019  // \details A 'dirty page' refers to a page that has been updated in memory
  3020  // only, the changes to a dirty page are not yet stored on disk.
  3021  // Without \ref MDBX_WRITEMAP dirty pages are allocated from memory and
  3022  // released when a transaction is committed. To reduce overhead, it is
  3023  // reasonable to release not all ones, but to leave some allocations in
  3024  // reserve for reuse in the next transaction(s).
  3025  //
  3026  // The `MDBX_opt_dp_reserve_limit` allows you to set a limit for such reserve
  3027  // inside the current process. Default is 1024.
  3028  func (env *Env) GetDPReserveLimit() (uint64, Error) {
  3029  	return env.GetOption(OptDpReserveLimit)
  3030  }
  3031  
  3032  // SetDPReserveLimit Controls the in-process limit of a pre-allocated memory items
  3033  // for dirty pages.
  3034  //
  3035  // \details A 'dirty page' refers to a page that has been updated in memory
  3036  // only, the changes to a dirty page are not yet stored on disk.
  3037  // Without \ref MDBX_WRITEMAP dirty pages are allocated from memory and
  3038  // released when a transaction is committed. To reduce overhead, it is
  3039  // reasonable to release not all ones, but to leave some allocations in
  3040  // reserve for reuse in the next transaction(s).
  3041  //
  3042  // The `MDBX_opt_dp_reserve_limit` allows you to set a limit for such reserve
  3043  // inside the current process. Default is 1024.
  3044  func (env *Env) SetDPReserveLimit(limit uint64) Error {
  3045  	return env.SetOption(OptDpReserveLimit, limit)
  3046  }
  3047  
  3048  // GetTxDPLimit Controls the in-process limit of dirty pages
  3049  // for a write transaction.
  3050  //
  3051  // \details A 'dirty page' refers to a page that has been updated in memory
  3052  // only, the changes to a dirty page are not yet stored on disk.
  3053  // Without \ref MDBX_WRITEMAP dirty pages are allocated from memory and will
  3054  // be busy until are written to disk. Therefore for a large transactions is
  3055  // reasonable to limit dirty pages collecting above an some threshold but
  3056  // spill to disk instead.
  3057  //
  3058  // The `MDBX_opt_txn_dp_limit` controls described threshold for the current
  3059  // process. Default is 65536, it is usually enough for most cases.
  3060  func (env *Env) GetTxDPLimit() (uint64, Error) {
  3061  	return env.GetOption(OptTxnDpLimit)
  3062  }
  3063  
  3064  // SetTxDPLimit Controls the in-process limit of dirty pages
  3065  // for a write transaction.
  3066  //
  3067  // \details A 'dirty page' refers to a page that has been updated in memory
  3068  // only, the changes to a dirty page are not yet stored on disk.
  3069  // Without \ref MDBX_WRITEMAP dirty pages are allocated from memory and will
  3070  // be busy until are written to disk. Therefore for a large transactions is
  3071  // reasonable to limit dirty pages collecting above an some threshold but
  3072  // spill to disk instead.
  3073  //
  3074  // The `MDBX_opt_txn_dp_limit` controls described threshold for the current
  3075  // process. Default is 65536, it is usually enough for most cases.
  3076  func (env *Env) SetTxDPLimit(limit uint64) Error {
  3077  	return env.SetOption(OptTxnDpLimit, limit)
  3078  }
  3079  
  3080  // GetTxDPInitial Controls the in-process initial allocation size for dirty pages
  3081  // list of a write transaction. Default is 1024.
  3082  func (env *Env) GetTxDPInitial() (uint64, Error) {
  3083  	return env.GetOption(OptTxnDpInitial)
  3084  }
  3085  
  3086  // SetTxDPInitial Controls the in-process initial allocation size for dirty pages
  3087  // list of a write transaction. Default is 1024.
  3088  func (env *Env) SetTxDPInitial(initial uint64) Error {
  3089  	return env.SetOption(OptTxnDpInitial, initial)
  3090  }
  3091  
  3092  // GetSpillMinDenominator Controls the in-process how minimal part of the dirty pages should
  3093  // be spilled when necessary.
  3094  //
  3095  // \details The `MDBX_opt_spill_min_denominator` defines the denominator for
  3096  // limiting from the bottom for part of the current dirty pages should be
  3097  // spilled when the free room for a new dirty pages (i.e. distance to the
  3098  // `MDBX_opt_txn_dp_limit` threshold) is not enough to perform requested
  3099  // operation.
  3100  // Exactly `min_pages_to_spill = dirty_pages / N`,
  3101  // where `N` is the value set by `MDBX_opt_spill_min_denominator`.
  3102  //
  3103  // Should be in the range 0..255, where zero means no restriction at the
  3104  // bottom. Default is 8, i.e. at least the 1/8 of the current dirty pages
  3105  // should be spilled when reached the condition described above.
  3106  func (env *Env) GetSpillMinDenominator() (uint64, Error) {
  3107  	return env.GetOption(OptSpillMinDenomiator)
  3108  }
  3109  
  3110  // SetSpillMinDenominator Controls the in-process how minimal part of the dirty pages should
  3111  // be spilled when necessary.
  3112  //
  3113  // \details The `MDBX_opt_spill_min_denominator` defines the denominator for
  3114  // limiting from the bottom for part of the current dirty pages should be
  3115  // spilled when the free room for a new dirty pages (i.e. distance to the
  3116  // `MDBX_opt_txn_dp_limit` threshold) is not enough to perform requested
  3117  // operation.
  3118  // Exactly `min_pages_to_spill = dirty_pages / N`,
  3119  // where `N` is the value set by `MDBX_opt_spill_min_denominator`.
  3120  //
  3121  // Should be in the range 0..255, where zero means no restriction at the
  3122  // bottom. Default is 8, i.e. at least the 1/8 of the current dirty pages
  3123  // should be spilled when reached the condition described above.
  3124  func (env *Env) SetSpillMinDenominator(min uint64) Error {
  3125  	return env.SetOption(OptSpillMinDenomiator, min)
  3126  }
  3127  
  3128  // GetSpillMaxDenominator Controls the in-process how maximal part of the dirty pages may be
  3129  // spilled when necessary.
  3130  //
  3131  // \details The `MDBX_opt_spill_max_denominator` defines the denominator for
  3132  // limiting from the top for part of the current dirty pages may be spilled
  3133  // when the free room for a new dirty pages (i.e. distance to the
  3134  // `MDBX_opt_txn_dp_limit` threshold) is not enough to perform requested
  3135  // operation.
  3136  // Exactly `max_pages_to_spill = dirty_pages - dirty_pages / N`,
  3137  // where `N` is the value set by `MDBX_opt_spill_max_denominator`.
  3138  //
  3139  // Should be in the range 0..255, where zero means no limit, i.e. all dirty
  3140  // pages could be spilled. Default is 8, i.e. no more than 7/8 of the current
  3141  // dirty pages may be spilled when reached the condition described above.
  3142  func (env *Env) GetSpillMaxDenominator() (uint64, Error) {
  3143  	return env.GetOption(OptSpillMaxDenomiator)
  3144  }
  3145  
  3146  // SetSpillMaxDenominator Controls the in-process how maximal part of the dirty pages may be
  3147  // spilled when necessary.
  3148  //
  3149  // \details The `MDBX_opt_spill_max_denominator` defines the denominator for
  3150  // limiting from the top for part of the current dirty pages may be spilled
  3151  // when the free room for a new dirty pages (i.e. distance to the
  3152  // `MDBX_opt_txn_dp_limit` threshold) is not enough to perform requested
  3153  // operation.
  3154  // Exactly `max_pages_to_spill = dirty_pages - dirty_pages / N`,
  3155  // where `N` is the value set by `MDBX_opt_spill_max_denominator`.
  3156  //
  3157  // Should be in the range 0..255, where zero means no limit, i.e. all dirty
  3158  // pages could be spilled. Default is 8, i.e. no more than 7/8 of the current
  3159  // dirty pages may be spilled when reached the condition described above.
  3160  func (env *Env) SetSpillMaxDenominator(max uint64) Error {
  3161  	return env.SetOption(OptSpillMaxDenomiator, max)
  3162  }
  3163  
  3164  // GetSpillParent4ChildDeominator Controls the in-process how much of the parent transaction dirty
  3165  // pages will be spilled while start each child transaction.
  3166  //
  3167  // \details The `MDBX_opt_spill_parent4child_denominator` defines the
  3168  // denominator to determine how much of parent transaction dirty pages will be
  3169  // spilled explicitly while start each child transaction.
  3170  // Exactly `pages_to_spill = dirty_pages / N`,
  3171  // where `N` is the value set by `MDBX_opt_spill_parent4child_denominator`.
  3172  //
  3173  // For a stack of nested transactions each dirty page could be spilled only
  3174  // once, and parent's dirty pages couldn't be spilled while child
  3175  // transaction(s) are running. Therefore a child transaction could reach
  3176  // \ref MDBX_TXN_FULL when parent(s) transaction has  spilled too less (and
  3177  // child reach the limit of dirty pages), either when parent(s) has spilled
  3178  // too more (since child can't spill already spilled pages). So there is no
  3179  // universal golden ratio.
  3180  //
  3181  // Should be in the range 0..255, where zero means no explicit spilling will
  3182  // be performed during starting nested transactions.
  3183  // Default is 0, i.e. by default no spilling performed during starting nested
  3184  // transactions, that correspond historically behaviour.
  3185  func (env *Env) GetSpillParent4ChildDeominator() (uint64, Error) {
  3186  	return env.GetOption(OptSpillParent4ChildDenominator)
  3187  }
  3188  
  3189  // SetSpillParent4ChildDeominator Controls the in-process how much of the parent transaction dirty
  3190  // pages will be spilled while start each child transaction.
  3191  //
  3192  // \details The `MDBX_opt_spill_parent4child_denominator` defines the
  3193  // denominator to determine how much of parent transaction dirty pages will be
  3194  // spilled explicitly while start each child transaction.
  3195  // Exactly `pages_to_spill = dirty_pages / N`,
  3196  // where `N` is the value set by `MDBX_opt_spill_parent4child_denominator`.
  3197  //
  3198  // For a stack of nested transactions each dirty page could be spilled only
  3199  // once, and parent's dirty pages couldn't be spilled while child
  3200  // transaction(s) are running. Therefore a child transaction could reach
  3201  // \ref MDBX_TXN_FULL when parent(s) transaction has  spilled too less (and
  3202  // child reach the limit of dirty pages), either when parent(s) has spilled
  3203  // too more (since child can't spill already spilled pages). So there is no
  3204  // universal golden ratio.
  3205  //
  3206  // Should be in the range 0..255, where zero means no explicit spilling will
  3207  // be performed during starting nested transactions.
  3208  // Default is 0, i.e. by default no spilling performed during starting nested
  3209  // transactions, that correspond historically behaviour.
  3210  func (env *Env) SetSpillParent4ChildDeominator(value uint64) Error {
  3211  	return env.SetOption(OptSpillParent4ChildDenominator, value)
  3212  }
  3213  
  3214  // GetMergeThreshold16Dot16Percent Controls the in-process threshold of semi-empty pages merge.
  3215  // \warning This is experimental option and subject for change or removal.
  3216  // \details This option controls the in-process threshold of minimum page
  3217  // fill, as used space of percentage of a page. Neighbour pages emptier than
  3218  // this value are candidates for merging. The threshold value is specified
  3219  // in 1/65536 of percent, which is equivalent to the 16-dot-16 fixed point
  3220  // format. The specified value must be in the range from 12.5% (almost empty)
  3221  // to 50% (half empty) which corresponds to the range from 8192 and to 32768
  3222  // in units respectively.
  3223  func (env *Env) GetMergeThreshold16Dot16Percent() (uint64, Error) {
  3224  	return env.GetOption(OptMergeThreshold16Dot16Percent)
  3225  }
  3226  
  3227  // SetMergeThreshold16Dot16Percent Controls the in-process threshold of semi-empty pages merge.
  3228  // \warning This is experimental option and subject for change or removal.
  3229  // \details This option controls the in-process threshold of minimum page
  3230  // fill, as used space of percentage of a page. Neighbour pages emptier than
  3231  // this value are candidates for merging. The threshold value is specified
  3232  // in 1/65536 of percent, which is equivalent to the 16-dot-16 fixed point
  3233  // format. The specified value must be in the range from 12.5% (almost empty)
  3234  // to 50% (half empty) which corresponds to the range from 8192 and to 32768
  3235  // in units respectively.
  3236  func (env *Env) SetMergeThreshold16Dot16Percent(percent uint64) Error {
  3237  	return env.SetOption(OptMergeThreshold16Dot16Percent, percent)
  3238  }
  3239  
  3240  //////////////////////////////////////////////////////////////////////////////////////////
  3241  // DBI
  3242  //////////////////////////////////////////////////////////////////////////////////////////
  3243  
  3244  type DBI uint32
  3245  
  3246  //////////////////////////////////////////////////////////////////////////////////////////
  3247  // Val
  3248  //////////////////////////////////////////////////////////////////////////////////////////
  3249  
  3250  type Val syscall.Iovec
  3251  
  3252  func (v *Val) String() string {
  3253  	b := make([]byte, v.Len)
  3254  	copy(b, *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
  3255  		Data: uintptr(unsafe.Pointer(v.Base)),
  3256  		Len:  int(v.Len),
  3257  		Cap:  int(v.Len),
  3258  	})))
  3259  	return string(b)
  3260  }
  3261  
  3262  func (v *Val) UnsafeString() string {
  3263  	return *(*string)(unsafe.Pointer(&reflect.StringHeader{
  3264  		Data: uintptr(unsafe.Pointer(v.Base)),
  3265  		Len:  int(v.Len),
  3266  	}))
  3267  }
  3268  
  3269  func (v *Val) Bytes() []byte {
  3270  	b := make([]byte, v.Len)
  3271  	copy(b, *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
  3272  		Data: uintptr(unsafe.Pointer(v.Base)),
  3273  		Len:  int(v.Len),
  3274  		Cap:  int(v.Len),
  3275  	})))
  3276  	return b
  3277  }
  3278  
  3279  func (v *Val) UnsafeBytes() []byte {
  3280  	return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
  3281  		Data: uintptr(unsafe.Pointer(v.Base)),
  3282  		Len:  int(v.Len),
  3283  		Cap:  int(v.Len),
  3284  	}))
  3285  }
  3286  
  3287  func (v *Val) Copy(dst []byte) []byte {
  3288  	src := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
  3289  		Data: uintptr(unsafe.Pointer(v.Base)),
  3290  		Len:  int(v.Len),
  3291  		Cap:  int(v.Len),
  3292  	}))
  3293  	if cap(dst) >= int(v.Len) {
  3294  		dst = dst[0:v.Len]
  3295  		copy(dst, src)
  3296  		return dst
  3297  	}
  3298  	dst = make([]byte, v.Len)
  3299  	copy(dst, src)
  3300  	return dst
  3301  }
  3302  
  3303  func U8(v *uint8) Val {
  3304  	return Val{
  3305  		Base: v,
  3306  		Len:  1,
  3307  	}
  3308  }
  3309  
  3310  func I8(v *int8) Val {
  3311  	return Val{
  3312  		Base: (*byte)(unsafe.Pointer(v)),
  3313  		Len:  1,
  3314  	}
  3315  }
  3316  
  3317  func U16(v *uint16) Val {
  3318  	return Val{
  3319  		Base: (*byte)(unsafe.Pointer(v)),
  3320  		Len:  2,
  3321  	}
  3322  }
  3323  
  3324  func I16(v *int16) Val {
  3325  	return Val{
  3326  		Base: (*byte)(unsafe.Pointer(v)),
  3327  		Len:  2,
  3328  	}
  3329  }
  3330  
  3331  func U32(v *uint32) Val {
  3332  	return Val{
  3333  		Base: (*byte)(unsafe.Pointer(v)),
  3334  		Len:  4,
  3335  	}
  3336  }
  3337  
  3338  func I32(v *int32) Val {
  3339  	return Val{
  3340  		Base: (*byte)(unsafe.Pointer(v)),
  3341  		Len:  4,
  3342  	}
  3343  }
  3344  
  3345  func F32(v *float32) Val {
  3346  	return Val{
  3347  		Base: (*byte)(unsafe.Pointer(v)),
  3348  		Len:  4,
  3349  	}
  3350  }
  3351  
  3352  func U64(v *uint64) Val {
  3353  	return Val{
  3354  		Base: (*byte)(unsafe.Pointer(v)),
  3355  		Len:  8,
  3356  	}
  3357  }
  3358  
  3359  func I64(v *int64) Val {
  3360  	return Val{
  3361  		Base: (*byte)(unsafe.Pointer(v)),
  3362  		Len:  8,
  3363  	}
  3364  }
  3365  
  3366  func F64(v *float64) Val {
  3367  	return Val{
  3368  		Base: (*byte)(unsafe.Pointer(v)),
  3369  		Len:  8,
  3370  	}
  3371  }
  3372  
  3373  func Bytes(b *[]byte) Val {
  3374  	return Val{
  3375  		Base: &(*b)[0],
  3376  		Len:  uint64(len(*b)),
  3377  	}
  3378  }
  3379  
  3380  func String(s *string) Val {
  3381  	h := *(*reflect.StringHeader)(unsafe.Pointer(s))
  3382  	return Val{
  3383  		Base: (*byte)(unsafe.Pointer(h.Data)),
  3384  		Len:  uint64(h.Len),
  3385  	}
  3386  }
  3387  
  3388  func StringConst(s string) Val {
  3389  	h := *(*reflect.StringHeader)(unsafe.Pointer(&s))
  3390  	return Val{
  3391  		Base: (*byte)(unsafe.Pointer(h.Data)),
  3392  		Len:  uint64(h.Len),
  3393  	}
  3394  }
  3395  
  3396  func (v *Val) I8() int8 {
  3397  	if v.Len < 1 {
  3398  		return 0
  3399  	}
  3400  	return *(*int8)(unsafe.Pointer(v.Base))
  3401  }
  3402  
  3403  func (v *Val) U8() uint8 {
  3404  	if v.Len < 1 {
  3405  		return 0
  3406  	}
  3407  	return *v.Base
  3408  }
  3409  
  3410  func (v *Val) I16() int16 {
  3411  	if v.Len < 2 {
  3412  		return 0
  3413  	}
  3414  	return *(*int16)(unsafe.Pointer(v.Base))
  3415  }
  3416  
  3417  func (v *Val) U16() uint16 {
  3418  	if v.Len < 2 {
  3419  		return 0
  3420  	}
  3421  	return *(*uint16)(unsafe.Pointer(v.Base))
  3422  }
  3423  
  3424  func (v *Val) I32() int32 {
  3425  	if v.Len < 4 {
  3426  		return 0
  3427  	}
  3428  	return *(*int32)(unsafe.Pointer(v.Base))
  3429  }
  3430  
  3431  func (v *Val) U32() uint32 {
  3432  	if v.Len < 4 {
  3433  		return 0
  3434  	}
  3435  	return *(*uint32)(unsafe.Pointer(v.Base))
  3436  }
  3437  
  3438  func (v *Val) I64() int64 {
  3439  	if v.Len < 8 {
  3440  		return 0
  3441  	}
  3442  	return *(*int64)(unsafe.Pointer(v.Base))
  3443  }
  3444  
  3445  func (v *Val) U64() uint64 {
  3446  	if v.Len < 8 {
  3447  		return 0
  3448  	}
  3449  	return *(*uint64)(unsafe.Pointer(v.Base))
  3450  }
  3451  
  3452  func (v *Val) F32() float32 {
  3453  	if v.Len < 4 {
  3454  		return 0
  3455  	}
  3456  	return *(*float32)(unsafe.Pointer(v.Base))
  3457  }
  3458  
  3459  func (v *Val) F64() float64 {
  3460  	if v.Len < 8 {
  3461  		return 0
  3462  	}
  3463  	return *(*float64)(unsafe.Pointer(v.Base))
  3464  }
  3465  
  3466  //////////////////////////////////////////////////////////////////////////////////////////
  3467  // Tx
  3468  //////////////////////////////////////////////////////////////////////////////////////////
  3469  
  3470  type Tx struct {
  3471  	env       *Env
  3472  	txn       *C.MDBX_txn
  3473  	shared    bool
  3474  	reset     bool
  3475  	aborted   bool
  3476  	committed bool
  3477  }
  3478  
  3479  func NewTransaction(env *Env) *Tx {
  3480  	txn := &Tx{}
  3481  	txn.env = env
  3482  	txn.shared = true
  3483  	return txn
  3484  }
  3485  
  3486  func (tx *Tx) IsReset() bool {
  3487  	return tx.reset
  3488  }
  3489  
  3490  func (tx *Tx) IsAborted() bool {
  3491  	return tx.aborted
  3492  }
  3493  
  3494  func (tx *Tx) IsCommitted() bool {
  3495  	return tx.committed
  3496  }
  3497  
  3498  func (env *Env) Begin(txn *Tx, flags TxFlags) Error {
  3499  	txn.env = env
  3500  	txn.txn = nil
  3501  	txn.reset = false
  3502  	txn.aborted = false
  3503  	txn.committed = false
  3504  	args := struct {
  3505  		env     uintptr
  3506  		parent  uintptr
  3507  		txn     uintptr
  3508  		context uintptr
  3509  		flags   TxFlags
  3510  		result  Error
  3511  	}{
  3512  		env:    uintptr(unsafe.Pointer(env.env)),
  3513  		parent: 0,
  3514  		txn:    uintptr(unsafe.Pointer(&txn.txn)),
  3515  		flags:  flags,
  3516  	}
  3517  	ptr := uintptr(unsafe.Pointer(&args))
  3518  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_txn_begin_ex), ptr, 0)
  3519  	return args.result
  3520  }
  3521  
  3522  // TxInfo Information about the transaction
  3523  type TxInfo struct {
  3524  	// The ID of the transaction. For a READ-ONLY transaction, this corresponds to the snapshot being read.
  3525  	ID uint64
  3526  
  3527  	// For READ-ONLY transaction: the lag from a recent MVCC-snapshot, i.e. the
  3528  	// number of committed transaction since read transaction started.
  3529  	// For WRITE transaction (provided if `scan_rlt=true`): the lag of the oldest
  3530  	// reader from current transaction (i.e. at least 1 if any reader running).
  3531  	ReaderLag uint64
  3532  
  3533  	// Used space by this transaction, i.e. corresponding to the last used database page.
  3534  	SpaceUsed uint64
  3535  
  3536  	// Current size of database file.
  3537  	SpaceLimitSoft uint64
  3538  
  3539  	// Upper bound for size the database file, i.e. the value `size_upper`
  3540  	// argument of the appropriate call of \ref mdbx_env_set_geometry().
  3541  	SpaceLimitHard uint64
  3542  
  3543  	// For READ-ONLY transaction: The total size of the database pages that were
  3544  	// retired by committed write transactions after the reader's MVCC-snapshot,
  3545  	// i.e. the space which would be freed after the Reader releases the
  3546  	// MVCC-snapshot for reuse by completion read transaction.
  3547  	//
  3548  	// For WRITE transaction: The summarized size of the database pages that were
  3549  	// retired for now due Copy-On-Write during this transaction.
  3550  	SpaceRetired uint64
  3551  
  3552  	// For READ-ONLY transaction: the space available for writer(s) and that
  3553  	// must be exhausted for reason to call the Handle-Slow-Readers callback for
  3554  	// this read transaction.
  3555  	//
  3556  	// For WRITE transaction: the space inside transaction
  3557  	// that left to `MDBX_TXN_FULL` error.
  3558  	SpaceLeftover uint64
  3559  
  3560  	// For READ-ONLY transaction (provided if `scan_rlt=true`): The space that
  3561  	// actually become available for reuse when only this transaction will be finished.
  3562  	//
  3563  	// For WRITE transaction: The summarized size of the dirty database
  3564  	// pages that generated during this transaction.
  3565  	SpaceDirty uint64
  3566  }
  3567  
  3568  // Info Return information about the MDBX transaction.
  3569  // \ingroup c_statinfo
  3570  //
  3571  // \param [in] txn        A transaction handle returned by \ref mdbx_txn_begin()
  3572  // \param [out] info      The address of an \ref MDBX_txn_info structure
  3573  //
  3574  //	where the information will be copied.
  3575  //
  3576  // \param [in] scan_rlt   The boolean flag controls the scan of the read lock
  3577  //
  3578  //	table to provide complete information. Such scan
  3579  //	is relatively expensive and you can avoid it
  3580  //	if corresponding fields are not needed.
  3581  //	See description of \ref MDBX_txn_info.
  3582  //
  3583  // \returns A non-zero error value on failure and 0 on success.
  3584  func (tx *Tx) Info(info *TxInfo) Error {
  3585  	args := struct {
  3586  		txn     uintptr
  3587  		info    uintptr
  3588  		scanRlt int32
  3589  		result  Error
  3590  	}{
  3591  		txn:  uintptr(unsafe.Pointer(tx.txn)),
  3592  		info: uintptr(unsafe.Pointer(info)),
  3593  	}
  3594  	ptr := uintptr(unsafe.Pointer(&args))
  3595  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_txn_info), ptr, 0)
  3596  	return args.result
  3597  }
  3598  
  3599  // Flags Return the transaction's flags.
  3600  // \ingroup c_transactions
  3601  //
  3602  // This returns the flags associated with this transaction.
  3603  //
  3604  // \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
  3605  //
  3606  // \returns A transaction flags, valid if input is an valid transaction,
  3607  //
  3608  //	otherwise -1.
  3609  func (tx *Tx) Flags() int32 {
  3610  	args := struct {
  3611  		txn   uintptr
  3612  		flags int32
  3613  	}{
  3614  		txn: uintptr(unsafe.Pointer(tx.txn)),
  3615  	}
  3616  	ptr := uintptr(unsafe.Pointer(&args))
  3617  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_txn_flags), ptr, 0)
  3618  	return args.flags
  3619  }
  3620  
  3621  // ID Return the transaction's ID.
  3622  // \ingroup c_statinfo
  3623  //
  3624  // This returns the identifier associated with this transaction. For a
  3625  // read-only transaction, this corresponds to the snapshot being read;
  3626  // concurrent readers will frequently have the same transaction ID.
  3627  //
  3628  // \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
  3629  //
  3630  // \returns A transaction ID, valid if input is an active transaction,
  3631  //
  3632  //	otherwise 0.
  3633  func (tx *Tx) ID() uint64 {
  3634  	args := struct {
  3635  		txn uintptr
  3636  		id  uint64
  3637  	}{
  3638  		txn: uintptr(unsafe.Pointer(tx.txn)),
  3639  	}
  3640  	ptr := uintptr(unsafe.Pointer(&args))
  3641  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_txn_id), ptr, 0)
  3642  	return args.id
  3643  }
  3644  
  3645  // CommitLatency of commit stages in 1/65536 of seconds units.
  3646  // \warning This structure may be changed in future releases.
  3647  // \see mdbx_txn_commit_ex()
  3648  type CommitLatency struct {
  3649  	// Duration of preparation (commit child transactions, update sub-databases records and cursors destroying).
  3650  	Preparation uint32
  3651  	// Duration of GC/freeDB handling & updation.
  3652  	GC uint32
  3653  	// Duration of internal audit if enabled.
  3654  	Audit uint32
  3655  	// Duration of writing dirty/modified data pages.
  3656  	Write uint32
  3657  	// Duration of syncing written data to the dist/storage.
  3658  	Sync uint32
  3659  	// Duration of transaction ending (releasing resources).
  3660  	Ending uint32
  3661  	// The total duration of a commit.
  3662  	Whole uint32
  3663  }
  3664  
  3665  // CommitEx commit all the operations of a transaction into the database and
  3666  // collect latency information.
  3667  // \see mdbx_txn_commit()
  3668  // \ingroup c_statinfo
  3669  // \warning This function may be changed in future releases.
  3670  func (tx *Tx) CommitEx(latency *CommitLatency) Error {
  3671  	args := struct {
  3672  		txn     uintptr
  3673  		latency uintptr
  3674  		result  Error
  3675  	}{
  3676  		txn:     uintptr(unsafe.Pointer(tx.txn)),
  3677  		latency: uintptr(unsafe.Pointer(latency)),
  3678  	}
  3679  	ptr := uintptr(unsafe.Pointer(&args))
  3680  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_txn_commit_ex), ptr, 0)
  3681  	return args.result
  3682  }
  3683  
  3684  // Commit all the operations of a transaction into the database.
  3685  // \ingroup c_transactions
  3686  //
  3687  // If the current thread is not eligible to manage the transaction then
  3688  // the \ref MDBX_THREAD_MISMATCH error will returned. Otherwise the transaction
  3689  // will be committed and its handle is freed. If the transaction cannot
  3690  // be committed, it will be aborted with the corresponding error returned.
  3691  //
  3692  // Thus, a result other than \ref MDBX_THREAD_MISMATCH means that the
  3693  // transaction is terminated:
  3694  //   - Resources are released;
  3695  //   - Transaction handle is invalid;
  3696  //   - Cursor(s) associated with transaction must not be used, except with
  3697  //     mdbx_cursor_renew() and \ref mdbx_cursor_close().
  3698  //     Such cursor(s) must be closed explicitly by \ref mdbx_cursor_close()
  3699  //     before or after transaction commit, either can be reused with
  3700  //     \ref mdbx_cursor_renew() until it will be explicitly closed by
  3701  //     \ref mdbx_cursor_close().
  3702  //
  3703  // \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
  3704  //
  3705  // \returns A non-zero error value on failure and 0 on success,
  3706  //
  3707  //	some possible errors are:
  3708  //
  3709  // \retval MDBX_RESULT_TRUE      Transaction was aborted since it should
  3710  //
  3711  //	be aborted due to previous errors.
  3712  //
  3713  // \retval MDBX_PANIC            A fatal error occurred earlier
  3714  //
  3715  //	and the environment must be shut down.
  3716  //
  3717  // \retval MDBX_BAD_TXN          Transaction is already finished or never began.
  3718  // \retval MDBX_EBADSIGN         Transaction object has invalid signature,
  3719  //
  3720  //	e.g. transaction was already terminated
  3721  //	or memory was corrupted.
  3722  //
  3723  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  3724  //
  3725  //	by current thread.
  3726  //
  3727  // \retval MDBX_EINVAL           Transaction handle is NULL.
  3728  // \retval MDBX_ENOSPC           No more disk space.
  3729  // \retval MDBX_EIO              A system-level I/O error occurred.
  3730  // \retval MDBX_ENOMEM           Out of memory.
  3731  func (tx *Tx) Commit() Error {
  3732  	tx.committed = true
  3733  	return tx.CommitEx(nil)
  3734  }
  3735  
  3736  // Abort Abandon all the operations of the transaction instead of saving them.
  3737  // \ingroup c_transactions
  3738  //
  3739  // The transaction handle is freed. It and its cursors must not be used again
  3740  // after this call, except with \ref mdbx_cursor_renew() and
  3741  // \ref mdbx_cursor_close().
  3742  //
  3743  // If the current thread is not eligible to manage the transaction then
  3744  // the \ref MDBX_THREAD_MISMATCH error will returned. Otherwise the transaction
  3745  // will be aborted and its handle is freed. Thus, a result other than
  3746  // \ref MDBX_THREAD_MISMATCH means that the transaction is terminated:
  3747  //   - Resources are released;
  3748  //   - Transaction handle is invalid;
  3749  //   - Cursor(s) associated with transaction must not be used, except with
  3750  //     \ref mdbx_cursor_renew() and \ref mdbx_cursor_close().
  3751  //     Such cursor(s) must be closed explicitly by \ref mdbx_cursor_close()
  3752  //     before or after transaction abort, either can be reused with
  3753  //     \ref mdbx_cursor_renew() until it will be explicitly closed by
  3754  //     \ref mdbx_cursor_close().
  3755  //
  3756  // \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
  3757  //
  3758  // \returns A non-zero error value on failure and 0 on success,
  3759  //
  3760  //	some possible errors are:
  3761  //
  3762  // \retval MDBX_PANIC            A fatal error occurred earlier and
  3763  //
  3764  //	the environment must be shut down.
  3765  //
  3766  // \retval MDBX_BAD_TXN          Transaction is already finished or never began.
  3767  // \retval MDBX_EBADSIGN         Transaction object has invalid signature,
  3768  //
  3769  //	e.g. transaction was already terminated
  3770  //	or memory was corrupted.
  3771  //
  3772  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  3773  //
  3774  //	by current thread.
  3775  //
  3776  // \retval MDBX_EINVAL           Transaction handle is NULL.
  3777  func (tx *Tx) Abort() Error {
  3778  	args := struct {
  3779  		txn    uintptr
  3780  		result Error
  3781  	}{
  3782  		txn: uintptr(unsafe.Pointer(tx.txn)),
  3783  	}
  3784  	tx.aborted = true
  3785  	ptr := uintptr(unsafe.Pointer(&args))
  3786  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_txn_abort), ptr, 0)
  3787  	return args.result
  3788  }
  3789  
  3790  // Break Marks transaction as broken.
  3791  // \ingroup c_transactions
  3792  //
  3793  // Function keeps the transaction handle and corresponding locks, but makes
  3794  // impossible to perform any operations within a broken transaction.
  3795  // Broken transaction must then be aborted explicitly later.
  3796  //
  3797  // \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
  3798  //
  3799  // \see mdbx_txn_abort() \see mdbx_txn_reset() \see mdbx_txn_commit()
  3800  // \returns A non-zero error value on failure and 0 on success.
  3801  func (tx *Tx) Break() Error {
  3802  	args := struct {
  3803  		txn    uintptr
  3804  		result Error
  3805  	}{
  3806  		txn: uintptr(unsafe.Pointer(tx.txn)),
  3807  	}
  3808  	ptr := uintptr(unsafe.Pointer(&args))
  3809  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_txn_break), ptr, 0)
  3810  	return args.result
  3811  }
  3812  
  3813  // Reset a read-only transaction.
  3814  // \ingroup c_transactions
  3815  //
  3816  // Abort the read-only transaction like \ref mdbx_txn_abort(), but keep the
  3817  // transaction handle. Therefore \ref mdbx_txn_renew() may reuse the handle.
  3818  // This saves allocation overhead if the process will start a new read-only
  3819  // transaction soon, and also locking overhead if \ref MDBX_NOTLS is in use. The
  3820  // reader table lock is released, but the table slot stays tied to its thread
  3821  // or \ref MDBX_txn. Use \ref mdbx_txn_abort() to discard a reset handle, and to
  3822  // free its lock table slot if \ref MDBX_NOTLS is in use.
  3823  //
  3824  // Cursors opened within the transaction must not be used again after this
  3825  // call, except with \ref mdbx_cursor_renew() and \ref mdbx_cursor_close().
  3826  //
  3827  // Reader locks generally don't interfere with writers, but they keep old
  3828  // versions of database pages allocated. Thus they prevent the old pages from
  3829  // being reused when writers commit new data, and so under heavy load the
  3830  // database size may grow much more rapidly than otherwise.
  3831  //
  3832  // \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
  3833  //
  3834  // \returns A non-zero error value on failure and 0 on success,
  3835  //
  3836  //	some possible errors are:
  3837  //
  3838  // \retval MDBX_PANIC            A fatal error occurred earlier and
  3839  //
  3840  //	the environment must be shut down.
  3841  //
  3842  // \retval MDBX_BAD_TXN          Transaction is already finished or never began.
  3843  // \retval MDBX_EBADSIGN         Transaction object has invalid signature,
  3844  //
  3845  //	e.g. transaction was already terminated
  3846  //	or memory was corrupted.
  3847  //
  3848  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  3849  //
  3850  //	by current thread.
  3851  //
  3852  // \retval MDBX_EINVAL           Transaction handle is NULL.
  3853  func (tx *Tx) Reset() Error {
  3854  	args := struct {
  3855  		txn    uintptr
  3856  		result Error
  3857  	}{
  3858  		txn: uintptr(unsafe.Pointer(tx.txn)),
  3859  	}
  3860  	tx.reset = true
  3861  	ptr := uintptr(unsafe.Pointer(&args))
  3862  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_txn_reset), ptr, 0)
  3863  	return args.result
  3864  }
  3865  
  3866  // Renew a read-only transaction.
  3867  // \ingroup c_transactions
  3868  //
  3869  // This acquires a new reader lock for a transaction handle that had been
  3870  // released by \ref mdbx_txn_reset(). It must be called before a reset
  3871  // transaction may be used again.
  3872  //
  3873  // \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
  3874  //
  3875  // \returns A non-zero error value on failure and 0 on success,
  3876  //
  3877  //	some possible errors are:
  3878  //
  3879  // \retval MDBX_PANIC            A fatal error occurred earlier and
  3880  //
  3881  //	the environment must be shut down.
  3882  //
  3883  // \retval MDBX_BAD_TXN          Transaction is already finished or never began.
  3884  // \retval MDBX_EBADSIGN         Transaction object has invalid signature,
  3885  //
  3886  //	e.g. transaction was already terminated
  3887  //	or memory was corrupted.
  3888  //
  3889  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  3890  //
  3891  //	by current thread.
  3892  //
  3893  // \retval MDBX_EINVAL           Transaction handle is NULL.
  3894  func (tx *Tx) Renew() Error {
  3895  	args := struct {
  3896  		txn    uintptr
  3897  		result Error
  3898  	}{
  3899  		txn: uintptr(unsafe.Pointer(tx.txn)),
  3900  	}
  3901  	tx.reset = false
  3902  	ptr := uintptr(unsafe.Pointer(&args))
  3903  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_txn_renew), ptr, 0)
  3904  	return args.result
  3905  }
  3906  
  3907  type Canary struct {
  3908  	X, Y, Z, V uint64
  3909  }
  3910  
  3911  // PutCanary Set integers markers (aka "canary") associated with the environment.
  3912  // \ingroup c_crud
  3913  // \see mdbx_canary_get()
  3914  //
  3915  // \param [in] txn     A transaction handle returned by \ref mdbx_txn_begin()
  3916  // \param [in] canary  A optional pointer to \ref MDBX_canary structure for `x`,
  3917  //
  3918  //	  `y` and `z` values from.
  3919  //	- If canary is NOT NULL then the `x`, `y` and `z` values will be
  3920  //	  updated from given canary argument, but the 'v' be always set
  3921  //	  to the current transaction number if at least one `x`, `y` or
  3922  //	  `z` values have changed (i.e. if `x`, `y` and `z` have the same
  3923  //	  values as currently present then nothing will be changes or
  3924  //	  updated).
  3925  //	- if canary is NULL then the `v` value will be explicitly update
  3926  //	  to the current transaction number without changes `x`, `y` nor
  3927  //	  `z`.
  3928  //
  3929  // \returns A non-zero error value on failure and 0 on success.
  3930  func (tx *Tx) PutCanary(canary *Canary) Error {
  3931  	args := struct {
  3932  		txn    uintptr
  3933  		canary uintptr
  3934  		result Error
  3935  	}{
  3936  		txn:    uintptr(unsafe.Pointer(tx.txn)),
  3937  		canary: uintptr(unsafe.Pointer(canary)),
  3938  	}
  3939  	ptr := uintptr(unsafe.Pointer(&args))
  3940  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_canary_put), ptr, 0)
  3941  	return args.result
  3942  }
  3943  
  3944  // GetCanary Returns fours integers markers (aka "canary") associated with the
  3945  // environment.
  3946  // \ingroup c_crud
  3947  // \see mdbx_canary_set()
  3948  //
  3949  // \param [in] txn     A transaction handle returned by \ref mdbx_txn_begin().
  3950  // \param [in] canary  The address of an MDBX_canary structure where the
  3951  //
  3952  //	information will be copied.
  3953  //
  3954  // \returns A non-zero error value on failure and 0 on success.
  3955  func (tx *Tx) GetCanary(canary *Canary) Error {
  3956  	args := struct {
  3957  		txn    uintptr
  3958  		canary uintptr
  3959  		result Error
  3960  	}{
  3961  		txn:    uintptr(unsafe.Pointer(tx.txn)),
  3962  		canary: uintptr(unsafe.Pointer(canary)),
  3963  	}
  3964  	ptr := uintptr(unsafe.Pointer(&args))
  3965  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_canary_get), ptr, 0)
  3966  	return args.result
  3967  }
  3968  
  3969  // EnvInfo Return information about the MDBX environment.
  3970  // \ingroup c_statinfo
  3971  //
  3972  // At least one of env or txn argument must be non-null. If txn is passed
  3973  // non-null then stat will be filled accordingly to the given transaction.
  3974  // Otherwise, if txn is null, then stat will be populated by a snapshot from
  3975  // the last committed write transaction, and at next time, other information
  3976  // can be returned.
  3977  //
  3978  // Legacy \ref mdbx_env_info() correspond to calling \ref mdbx_env_info_ex()
  3979  // with the null `txn` argument.
  3980  //
  3981  // \param [in] env     An environment handle returned by \ref mdbx_env_create()
  3982  // \param [in] txn     A transaction handle returned by \ref mdbx_txn_begin()
  3983  // \param [out] info   The address of an \ref MDBX_envinfo structure
  3984  //
  3985  //	where the information will be copied
  3986  //
  3987  // \param [in] bytes   The size of \ref MDBX_envinfo.
  3988  //
  3989  // \returns A non-zero error value on failure and 0 on success.
  3990  func (tx *Tx) EnvInfo(info *EnvInfo) Error {
  3991  	if info == nil {
  3992  		return ErrInvalid
  3993  	}
  3994  	args := struct {
  3995  		env    uintptr
  3996  		txn    uintptr
  3997  		info   uintptr
  3998  		size   uintptr
  3999  		result int32
  4000  	}{
  4001  		env:  uintptr(unsafe.Pointer(tx.env.env)),
  4002  		txn:  uintptr(unsafe.Pointer(tx.txn)),
  4003  		info: uintptr(unsafe.Pointer(info)),
  4004  		size: unsafe.Sizeof(C.MDBX_envinfo{}),
  4005  	}
  4006  	ptr := uintptr(unsafe.Pointer(&args))
  4007  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_env_info_ex), ptr, 0)
  4008  	return Error(args.result)
  4009  }
  4010  
  4011  // OpenDBI Open or Create a database in the environment.
  4012  // \ingroup c_dbi
  4013  //
  4014  // A database handle denotes the name and parameters of a database,
  4015  // independently of whether such a database exists. The database handle may be
  4016  // discarded by calling \ref mdbx_dbi_close(). The old database handle is
  4017  // returned if the database was already open. The handle may only be closed
  4018  // once.
  4019  //
  4020  // \note A notable difference between MDBX and LMDB is that MDBX make handles
  4021  // opened for existing databases immediately available for other transactions,
  4022  // regardless this transaction will be aborted or reset. The REASON for this is
  4023  // to avoiding the requirement for multiple opening a same handles in
  4024  // concurrent read transactions, and tracking of such open but hidden handles
  4025  // until the completion of read transactions which opened them.
  4026  //
  4027  // Nevertheless, the handle for the NEWLY CREATED database will be invisible
  4028  // for other transactions until the this write transaction is successfully
  4029  // committed. If the write transaction is aborted the handle will be closed
  4030  // automatically. After a successful commit the such handle will reside in the
  4031  // shared environment, and may be used by other transactions.
  4032  //
  4033  // In contrast to LMDB, the MDBX allow this function to be called from multiple
  4034  // concurrent transactions or threads in the same process.
  4035  //
  4036  // To use named database (with name != NULL), \ref mdbx_env_set_maxdbs()
  4037  // must be called before opening the environment. Table names are
  4038  // keys in the internal unnamed database, and may be read but not written.
  4039  //
  4040  // \param [in] txn    transaction handle returned by \ref mdbx_txn_begin().
  4041  // \param [in] name   The name of the database to open. If only a single
  4042  //
  4043  //	database is needed in the environment,
  4044  //	this value may be NULL.
  4045  //
  4046  // \param [in] flags  Special options for this database. This parameter must
  4047  //
  4048  //	                  be set to 0 or by bitwise OR'ing together one or more
  4049  //	                  of the values described here:
  4050  //	- \ref MDBX_REVERSEKEY
  4051  //	    Keys are strings to be compared in reverse order, from the end
  4052  //	    of the strings to the beginning. By default, Keys are treated as
  4053  //	    strings and compared from beginning to end.
  4054  //	- \ref MDBX_INTEGERKEY
  4055  //	    Keys are binary integers in native byte order, either uint32_t or
  4056  //	    uint64_t, and will be sorted as such. The keys must all be of the
  4057  //	    same size and must be aligned while passing as arguments.
  4058  //	- \ref MDBX_DUPSORT
  4059  //	    Duplicate keys may be used in the database. Or, from another point of
  4060  //	    view, keys may have multiple data items, stored in sorted order. By
  4061  //	    default keys must be unique and may have only a single data item.
  4062  //	- \ref MDBX_DUPFIXED
  4063  //	    This flag may only be used in combination with \ref MDBX_DUPSORT. This
  4064  //	    option tells the library that the data items for this database are
  4065  //	    all the same size, which allows further optimizations in storage and
  4066  //	    retrieval. When all data items are the same size, the
  4067  //	    \ref MDBX_GET_MULTIPLE, \ref MDBX_NEXT_MULTIPLE and
  4068  //	    \ref MDBX_PREV_MULTIPLE cursor operations may be used to retrieve
  4069  //	    multiple items at once.
  4070  //	- \ref MDBX_INTEGERDUP
  4071  //	    This option specifies that duplicate data items are binary integers,
  4072  //	    similar to \ref MDBX_INTEGERKEY keys. The data values must all be of the
  4073  //	    same size and must be aligned while passing as arguments.
  4074  //	- \ref MDBX_REVERSEDUP
  4075  //	    This option specifies that duplicate data items should be compared as
  4076  //	    strings in reverse order (the comparison is performed in the direction
  4077  //	    from the last byte to the first).
  4078  //	- \ref MDBX_CREATE
  4079  //	    Create the named database if it doesn't exist. This option is not
  4080  //	    allowed in a read-only transaction or a read-only environment.
  4081  //
  4082  // \param [out] dbi     Address where the new \ref MDBX_dbi handle
  4083  //
  4084  //	will be stored.
  4085  //
  4086  // For \ref mdbx_dbi_open_ex() additional arguments allow you to set custom
  4087  // comparison functions for keys and values (for multimaps).
  4088  // \see avoid_custom_comparators
  4089  //
  4090  // \returns A non-zero error value on failure and 0 on success,
  4091  //
  4092  //	some possible errors are:
  4093  //
  4094  // \retval MDBX_NOTFOUND   The specified database doesn't exist in the
  4095  //
  4096  //	environment and \ref MDBX_CREATE was not specified.
  4097  //
  4098  // \retval MDBX_DBS_FULL   Too many databases have been opened.
  4099  //
  4100  //	\see mdbx_env_set_maxdbs()
  4101  //
  4102  // \retval MDBX_INCOMPATIBLE  Database is incompatible with given flags,
  4103  //
  4104  //	i.e. the passed flags is different with which the
  4105  //	database was created, or the database was already
  4106  //	opened with a different comparison function(s).
  4107  //
  4108  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  4109  //
  4110  //	by current thread.
  4111  func (tx *Tx) OpenDBI(name string, flags DBFlags) (DBI, Error) {
  4112  	if len(name) == 0 {
  4113  		var dbi DBI
  4114  		err := Error(C.mdbx_dbi_open(tx.txn, nil, (C.MDBX_db_flags_t)(flags), (*C.MDBX_dbi)(unsafe.Pointer(&dbi))))
  4115  		return dbi, err
  4116  	} else {
  4117  		n := C.CString(name)
  4118  		defer C.free(unsafe.Pointer(n))
  4119  		var dbi DBI
  4120  		err := Error(C.mdbx_dbi_open(tx.txn, n, (C.MDBX_db_flags_t)(flags), (*C.MDBX_dbi)(unsafe.Pointer(&dbi))))
  4121  		return dbi, err
  4122  	}
  4123  }
  4124  
  4125  //// OpenDBIEx OpenDBI with custom comparators.
  4126  //// \ref avoid_custom_comparators "avoid using custom comparators" and use
  4127  //// \ref mdbx_dbi_open() instead.
  4128  ////
  4129  //// \ingroup c_dbi
  4130  ////
  4131  //// \param [in] txn    transaction handle returned by \ref mdbx_txn_begin().
  4132  //// \param [in] name   The name of the database to open. If only a single
  4133  ////                    database is needed in the environment,
  4134  ////                    this value may be NULL.
  4135  //// \param [in] flags  Special options for this database.
  4136  //// \param [in] keycmp  Optional custom key comparison function for a database.
  4137  //// \param [in] datacmp Optional custom data comparison function for a database.
  4138  //// \param [out] dbi    Address where the new MDBX_dbi handle will be stored.
  4139  //// \returns A non-zero error value on failure and 0 on success.
  4140  //func (tx *Tx) OpenDBIEx(name string, flags DBFlags, keyCompare, dataCompare *Cmp) (DBI, Error) {
  4141  //	if len(name) == 0 {
  4142  //		var dbi DBI
  4143  //		err := Error(C.mdbx_dbi_open_ex(tx.txn, nil, (C.MDBX_db_flags_t)(flags), (*C.MDBX_dbi)(unsafe.Pointer(&dbi)),
  4144  //			(*C.MDBX_cmp_func)(unsafe.Pointer(keyCompare)), (*C.MDBX_cmp_func)(unsafe.Pointer(dataCompare))))
  4145  //		return dbi, err
  4146  //	} else {
  4147  //		n := C.CString(name)
  4148  //		defer C.free(unsafe.Pointer(n))
  4149  //		var dbi DBI
  4150  //		err := Error(C.mdbx_dbi_open_ex(tx.txn, n, (C.MDBX_db_flags_t)(flags), (*C.MDBX_dbi)(unsafe.Pointer(&dbi)),
  4151  //			(*C.MDBX_cmp_func)(unsafe.Pointer(keyCompare)), (*C.MDBX_cmp_func)(unsafe.Pointer(dataCompare))))
  4152  //		return dbi, err
  4153  //	}
  4154  //}
  4155  
  4156  // Stats Statistics for a database in the environment
  4157  // \ingroup c_statinfo
  4158  // \see mdbx_env_stat_ex() \see mdbx_dbi_stat()
  4159  type Stats struct {
  4160  	PageSize      uint32 // Size of a database page. This is the same for all databases.
  4161  	Depth         uint32 // Depth (height) of the B-tree
  4162  	BranchPages   uint64 // Number of internal (non-leaf) pages
  4163  	LeafPages     uint64 // Number of leaf pages
  4164  	OverflowPages uint64 // Number of overflow pages
  4165  	Entries       uint64 // Number of data items
  4166  	ModTxnID      uint64 // Transaction ID of committed last modification
  4167  }
  4168  
  4169  // DBIStat Retrieve statistics for a database.
  4170  // \ingroup c_statinfo
  4171  //
  4172  // \param [in] txn     A transaction handle returned by \ref mdbx_txn_begin().
  4173  // \param [in] dbi     A database handle returned by \ref mdbx_dbi_open().
  4174  // \param [out] stat   The address of an \ref MDBX_stat structure where
  4175  //
  4176  //	the statistics will be copied.
  4177  //
  4178  // \param [in] bytes   The size of \ref MDBX_stat.
  4179  //
  4180  // \returns A non-zero error value on failure and 0 on success,
  4181  //
  4182  //	some possible errors are:
  4183  //
  4184  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  4185  //
  4186  //	by current thread.
  4187  //
  4188  // \retval MDBX_EINVAL   An invalid parameter was specified.
  4189  func (tx *Tx) DBIStat(dbi DBI, stat *Stats) Error {
  4190  	args := struct {
  4191  		txn    uintptr
  4192  		stat   uintptr
  4193  		size   uintptr
  4194  		dbi    uint32
  4195  		result Error
  4196  	}{
  4197  		txn:  uintptr(unsafe.Pointer(tx.txn)),
  4198  		stat: uintptr(unsafe.Pointer(stat)),
  4199  		size: unsafe.Sizeof(Stats{}),
  4200  		dbi:  uint32(dbi),
  4201  	}
  4202  	ptr := uintptr(unsafe.Pointer(&args))
  4203  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_dbi_stat), ptr, 0)
  4204  	return args.result
  4205  }
  4206  
  4207  // DBIFlags Retrieve the DB flags and status for a database handle.
  4208  // \ingroup c_statinfo
  4209  //
  4210  // \param [in] txn     A transaction handle returned by \ref mdbx_txn_begin().
  4211  // \param [in] dbi     A database handle returned by \ref mdbx_dbi_open().
  4212  // \param [out] flags  Address where the flags will be returned.
  4213  // \param [out] state  Address where the state will be returned.
  4214  //
  4215  // \returns A non-zero error value on failure and 0 on success.
  4216  func (tx *Tx) DBIFlags(dbi DBI) (DBFlags, DBIState, Error) {
  4217  	var flags DBFlags
  4218  	var state DBIState
  4219  
  4220  	args := struct {
  4221  		txn    uintptr
  4222  		flags  uintptr
  4223  		state  uintptr
  4224  		dbi    uint32
  4225  		result Error
  4226  	}{
  4227  		txn:   uintptr(unsafe.Pointer(tx.txn)),
  4228  		flags: uintptr(unsafe.Pointer(&flags)),
  4229  		state: uintptr(unsafe.Pointer(&state)),
  4230  		dbi:   uint32(dbi),
  4231  	}
  4232  	ptr := uintptr(unsafe.Pointer(&args))
  4233  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_dbi_flags_ex), ptr, 0)
  4234  	return flags, state, args.result
  4235  }
  4236  
  4237  // Drop Empty or delete and close a database.
  4238  // \ingroup c_crud
  4239  //
  4240  // \see mdbx_dbi_close() \see mdbx_dbi_open()
  4241  //
  4242  // \param [in] txn  A transaction handle returned by \ref mdbx_txn_begin().
  4243  // \param [in] dbi  A database handle returned by \ref mdbx_dbi_open().
  4244  // \param [in] del  `false` to empty the DB, `true` to delete it
  4245  //
  4246  //	from the environment and close the DB handle.
  4247  //
  4248  // \returns A non-zero error value on failure and 0 on success.
  4249  func (tx *Tx) Drop(dbi DBI, del bool) Error {
  4250  	args := struct {
  4251  		txn    uintptr
  4252  		del    uintptr
  4253  		dbi    uint32
  4254  		result Error
  4255  	}{
  4256  		txn: uintptr(unsafe.Pointer(tx.txn)),
  4257  		dbi: uint32(dbi),
  4258  	}
  4259  	if del {
  4260  		args.del = 1
  4261  	}
  4262  	ptr := uintptr(unsafe.Pointer(&args))
  4263  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_drop), ptr, 0)
  4264  	return args.result
  4265  }
  4266  
  4267  // Get items from a database.
  4268  // \ingroup c_crud
  4269  //
  4270  // This function retrieves key/data pairs from the database. The address
  4271  // and length of the data associated with the specified key are returned
  4272  // in the structure to which data refers.
  4273  // If the database supports duplicate keys (\ref MDBX_DUPSORT) then the
  4274  // first data item for the key will be returned. Retrieval of other
  4275  // items requires the use of \ref mdbx_cursor_get().
  4276  //
  4277  // \note The memory pointed to by the returned values is owned by the
  4278  // database. The caller need not dispose of the memory, and may not
  4279  // modify it in any way. For values returned in a read-only transaction
  4280  // any modification attempts will cause a `SIGSEGV`.
  4281  //
  4282  // \note Values returned from the database are valid only until a
  4283  // subsequent update operation, or the end of the transaction.
  4284  //
  4285  // \param [in] txn       A transaction handle returned by \ref mdbx_txn_begin().
  4286  // \param [in] dbi       A database handle returned by \ref mdbx_dbi_open().
  4287  // \param [in] key       The key to search for in the database.
  4288  // \param [in,out] data  The data corresponding to the key.
  4289  //
  4290  // \returns A non-zero error value on failure and 0 on success,
  4291  //
  4292  //	some possible errors are:
  4293  //
  4294  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  4295  //
  4296  //	by current thread.
  4297  //
  4298  // \retval MDBX_NOTFOUND  The key was not in the database.
  4299  // \retval MDBX_EINVAL    An invalid parameter was specified.
  4300  func (tx *Tx) Get(dbi DBI, key *Val, data *Val) Error {
  4301  	args := struct {
  4302  		txn    uintptr
  4303  		key    uintptr
  4304  		data   uintptr
  4305  		dbi    uint32
  4306  		result Error
  4307  	}{
  4308  		txn:  uintptr(unsafe.Pointer(tx.txn)),
  4309  		key:  uintptr(unsafe.Pointer(key)),
  4310  		data: uintptr(unsafe.Pointer(data)),
  4311  		dbi:  uint32(dbi),
  4312  	}
  4313  	ptr := uintptr(unsafe.Pointer(&args))
  4314  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_get), ptr, 0)
  4315  	return args.result
  4316  }
  4317  
  4318  // GetEqualOrGreat Get equal or great item from a database.
  4319  // \ingroup c_crud
  4320  //
  4321  // Briefly this function does the same as \ref mdbx_get() with a few
  4322  // differences:
  4323  //  1. Return equal or great (due comparison function) key-value
  4324  //     pair, but not only exactly matching with the key.
  4325  //  2. On success return \ref MDBX_SUCCESS if key found exactly,
  4326  //     and \ref MDBX_RESULT_TRUE otherwise. Moreover, for databases with
  4327  //     \ref MDBX_DUPSORT flag the data argument also will be used to match over
  4328  //     multi-value/duplicates, and \ref MDBX_SUCCESS will be returned only when
  4329  //     BOTH the key and the data match exactly.
  4330  //  3. Updates BOTH the key and the data for pointing to the actual key-value
  4331  //     pair inside the database.
  4332  //
  4333  // \param [in] txn           A transaction handle returned
  4334  //
  4335  //	by \ref mdbx_txn_begin().
  4336  //
  4337  // \param [in] dbi           A database handle returned by \ref mdbx_dbi_open().
  4338  // \param [in,out] key       The key to search for in the database.
  4339  // \param [in,out] data      The data corresponding to the key.
  4340  //
  4341  // \returns A non-zero error value on failure and \ref MDBX_RESULT_FALSE
  4342  //
  4343  //	or \ref MDBX_RESULT_TRUE on success (as described above).
  4344  //	Some possible errors are:
  4345  //
  4346  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  4347  //
  4348  //	by current thread.
  4349  //
  4350  // \retval MDBX_NOTFOUND      The key was not in the database.
  4351  // \retval MDBX_EINVAL        An invalid parameter was specified.
  4352  func (tx *Tx) GetEqualOrGreat(dbi DBI, key *Val, data *Val) Error {
  4353  	args := struct {
  4354  		txn    uintptr
  4355  		key    uintptr
  4356  		data   uintptr
  4357  		dbi    uint32
  4358  		result Error
  4359  	}{
  4360  		txn:  uintptr(unsafe.Pointer(tx.txn)),
  4361  		key:  uintptr(unsafe.Pointer(key)),
  4362  		data: uintptr(unsafe.Pointer(data)),
  4363  		dbi:  uint32(dbi),
  4364  	}
  4365  	ptr := uintptr(unsafe.Pointer(&args))
  4366  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_get_equal_or_great), ptr, 0)
  4367  	return args.result
  4368  }
  4369  
  4370  // GetEx Get items from a database
  4371  // and optionally number of data items for a given key.
  4372  //
  4373  // \ingroup c_crud
  4374  //
  4375  // Briefly this function does the same as \ref mdbx_get() with a few
  4376  // differences:
  4377  //  1. If values_count is NOT NULL, then returns the count
  4378  //     of multi-values/duplicates for a given key.
  4379  //  2. Updates BOTH the key and the data for pointing to the actual key-value
  4380  //     pair inside the database.
  4381  //
  4382  // \param [in] txn           A transaction handle returned
  4383  //
  4384  //	by \ref mdbx_txn_begin().
  4385  //
  4386  // \param [in] dbi           A database handle returned by \ref mdbx_dbi_open().
  4387  // \param [in,out] key       The key to search for in the database.
  4388  // \param [in,out] data      The data corresponding to the key.
  4389  // \param [out] values_count The optional address to return number of values
  4390  //
  4391  //	associated with given key:
  4392  //	 = 0 - in case \ref MDBX_NOTFOUND error;
  4393  //	 = 1 - exactly for databases
  4394  //	       WITHOUT \ref MDBX_DUPSORT;
  4395  //	 >= 1 for databases WITH \ref MDBX_DUPSORT.
  4396  //
  4397  // \returns A non-zero error value on failure and 0 on success,
  4398  //
  4399  //	some possible errors are:
  4400  //
  4401  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  4402  //
  4403  //	by current thread.
  4404  //
  4405  // \retval MDBX_NOTFOUND  The key was not in the database.
  4406  // \retval MDBX_EINVAL    An invalid parameter was specified.
  4407  func (tx *Tx) GetEx(dbi DBI, key *Val, data *Val) (int, Error) {
  4408  	var valuesCount uintptr
  4409  	args := struct {
  4410  		txn         uintptr
  4411  		key         uintptr
  4412  		data        uintptr
  4413  		valuesCount uintptr
  4414  		dbi         uint32
  4415  		result      Error
  4416  	}{
  4417  		txn:         uintptr(unsafe.Pointer(tx.txn)),
  4418  		key:         uintptr(unsafe.Pointer(key)),
  4419  		data:        uintptr(unsafe.Pointer(data)),
  4420  		valuesCount: uintptr(unsafe.Pointer(&valuesCount)),
  4421  		dbi:         uint32(dbi),
  4422  	}
  4423  	ptr := uintptr(unsafe.Pointer(&args))
  4424  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_get_ex), ptr, 0)
  4425  	return int(valuesCount), args.result
  4426  }
  4427  
  4428  // Put Store items into a database.
  4429  // \ingroup c_crud
  4430  //
  4431  // This function stores key/data pairs in the database. The default behavior
  4432  // is to enter the new key/data pair, replacing any previously existing key
  4433  // if duplicates are disallowed, or adding a duplicate data item if
  4434  // duplicates are allowed (see \ref MDBX_DUPSORT).
  4435  //
  4436  // \param [in] txn        A transaction handle returned
  4437  //
  4438  //	by \ref mdbx_txn_begin().
  4439  //
  4440  // \param [in] dbi        A database handle returned by \ref mdbx_dbi_open().
  4441  // \param [in] key        The key to store in the database.
  4442  // \param [in,out] data   The data to store.
  4443  // \param [in] flags      Special options for this operation.
  4444  //
  4445  //	                      This parameter must be set to 0 or by bitwise OR'ing
  4446  //	                      together one or more of the values described here:
  4447  //	 - \ref MDBX_NODUPDATA
  4448  //	    Enter the new key-value pair only if it does not already appear
  4449  //	    in the database. This flag may only be specified if the database
  4450  //	    was opened with \ref MDBX_DUPSORT. The function will return
  4451  //	    \ref MDBX_KEYEXIST if the key/data pair already appears in the database.
  4452  //
  4453  //	- \ref MDBX_NOOVERWRITE
  4454  //	    Enter the new key/data pair only if the key does not already appear
  4455  //	    in the database. The function will return \ref MDBX_KEYEXIST if the key
  4456  //	    already appears in the database, even if the database supports
  4457  //	    duplicates (see \ref  MDBX_DUPSORT). The data parameter will be set
  4458  //	    to point to the existing item.
  4459  //
  4460  //	- \ref MDBX_CURRENT
  4461  //	    Update an single existing entry, but not add new ones. The function will
  4462  //	    return \ref MDBX_NOTFOUND if the given key not exist in the database.
  4463  //	    In case multi-values for the given key, with combination of
  4464  //	    the \ref MDBX_ALLDUPS will replace all multi-values,
  4465  //	    otherwise return the \ref MDBX_EMULTIVAL.
  4466  //
  4467  //	- \ref MDBX_RESERVE
  4468  //	    Reserve space for data of the given size, but don't copy the given
  4469  //	    data. Instead, return a pointer to the reserved space, which the
  4470  //	    caller can fill in later - before the next update operation or the
  4471  //	    transaction ends. This saves an extra memcpy if the data is being
  4472  //	    generated later. MDBX does nothing else with this memory, the caller
  4473  //	    is expected to modify all of the space requested. This flag must not
  4474  //	    be specified if the database was opened with \ref MDBX_DUPSORT.
  4475  //
  4476  //	- \ref MDBX_APPEND
  4477  //	    Append the given key/data pair to the end of the database. This option
  4478  //	    allows fast bulk loading when keys are already known to be in the
  4479  //	    correct order. Loading unsorted keys with this flag will cause
  4480  //	    a \ref MDBX_EKEYMISMATCH error.
  4481  //
  4482  //	- \ref MDBX_APPENDDUP
  4483  //	    As above, but for sorted dup data.
  4484  //
  4485  //	- \ref MDBX_MULTIPLE
  4486  //	    Store multiple contiguous data elements in a single request. This flag
  4487  //	    may only be specified if the database was opened with
  4488  //	    \ref MDBX_DUPFIXED. With combination the \ref MDBX_ALLDUPS
  4489  //	    will replace all multi-values.
  4490  //	    The data argument must be an array of two \ref MDBX_val. The `iov_len`
  4491  //	    of the first \ref MDBX_val must be the size of a single data element.
  4492  //	    The `iov_base` of the first \ref MDBX_val must point to the beginning
  4493  //	    of the array of contiguous data elements which must be properly aligned
  4494  //	    in case of database with \ref MDBX_INTEGERDUP flag.
  4495  //	    The `iov_len` of the second \ref MDBX_val must be the count of the
  4496  //	    number of data elements to store. On return this field will be set to
  4497  //	    the count of the number of elements actually written. The `iov_base` of
  4498  //	    the second \ref MDBX_val is unused.
  4499  //
  4500  // \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
  4501  //
  4502  // \returns A non-zero error value on failure and 0 on success,
  4503  //
  4504  //	some possible errors are:
  4505  //
  4506  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  4507  //
  4508  //	by current thread.
  4509  //
  4510  // \retval MDBX_KEYEXIST  The key/value pair already exists in the database.
  4511  // \retval MDBX_MAP_FULL  The database is full, see \ref mdbx_env_set_mapsize().
  4512  // \retval MDBX_TXN_FULL  The transaction has too many dirty pages.
  4513  // \retval MDBX_EACCES    An attempt was made to write
  4514  //
  4515  //	in a read-only transaction.
  4516  //
  4517  // \retval MDBX_EINVAL    An invalid parameter was specified.
  4518  func (tx *Tx) Put(dbi DBI, key *Val, data *Val, flags PutFlags) Error {
  4519  	args := struct {
  4520  		txn    uintptr
  4521  		key    uintptr
  4522  		data   uintptr
  4523  		dbi    uint32
  4524  		flags  uint32
  4525  		result Error
  4526  	}{
  4527  		txn:   uintptr(unsafe.Pointer(tx.txn)),
  4528  		key:   uintptr(unsafe.Pointer(key)),
  4529  		data:  uintptr(unsafe.Pointer(data)),
  4530  		dbi:   uint32(dbi),
  4531  		flags: uint32(flags),
  4532  	}
  4533  	ptr := uintptr(unsafe.Pointer(&args))
  4534  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_put), ptr, 0)
  4535  	return args.result
  4536  }
  4537  
  4538  // Replace items in a database.
  4539  // \ingroup c_crud
  4540  //
  4541  // This function allows to update or delete an existing value at the same time
  4542  // as the previous value is retrieved. If the argument new_data equal is NULL
  4543  // zero, the removal is performed, otherwise the update/insert.
  4544  //
  4545  // The current value may be in an already changed (aka dirty) page. In this
  4546  // case, the page will be overwritten during the update, and the old value will
  4547  // be lost. Therefore, an additional buffer must be passed via old_data
  4548  // argument initially to copy the old value. If the buffer passed in is too
  4549  // small, the function will return \ref MDBX_RESULT_TRUE by setting iov_len
  4550  // field pointed by old_data argument to the appropriate value, without
  4551  // performing any changes.
  4552  //
  4553  // For databases with non-unique keys (i.e. with \ref MDBX_DUPSORT flag),
  4554  // another use case is also possible, when by old_data argument selects a
  4555  // specific item from multi-value/duplicates with the same key for deletion or
  4556  // update. To select this scenario in flags should simultaneously specify
  4557  // \ref MDBX_CURRENT and \ref MDBX_NOOVERWRITE. This combination is chosen
  4558  // because it makes no sense, and thus allows you to identify the request of
  4559  // such a scenario.
  4560  //
  4561  // \param [in] txn           A transaction handle returned
  4562  //
  4563  //	by \ref mdbx_txn_begin().
  4564  //
  4565  // \param [in] dbi           A database handle returned by \ref mdbx_dbi_open().
  4566  // \param [in] key           The key to store in the database.
  4567  // \param [in] new_data      The data to store, if NULL then deletion will
  4568  //
  4569  //	be performed.
  4570  //
  4571  // \param [in,out] old_data  The buffer for retrieve previous value as describe
  4572  //
  4573  //	above.
  4574  //
  4575  // \param [in] flags         Special options for this operation.
  4576  //
  4577  //	This parameter must be set to 0 or by bitwise
  4578  //	OR'ing together one or more of the values
  4579  //	described in \ref mdbx_put() description above,
  4580  //	and additionally
  4581  //	(\ref MDBX_CURRENT | \ref MDBX_NOOVERWRITE)
  4582  //	combination for selection particular item from
  4583  //	multi-value/duplicates.
  4584  //
  4585  // \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
  4586  //
  4587  // \returns A non-zero error value on failure and 0 on success.
  4588  func (tx *Tx) Replace(dbi DBI, key *Val, data *Val, oldData *Val, flags PutFlags) Error {
  4589  	args := struct {
  4590  		txn     uintptr
  4591  		key     uintptr
  4592  		data    uintptr
  4593  		oldData uintptr
  4594  		dbi     uint32
  4595  		flags   uint32
  4596  		result  Error
  4597  	}{
  4598  		txn:     uintptr(unsafe.Pointer(tx.txn)),
  4599  		key:     uintptr(unsafe.Pointer(key)),
  4600  		data:    uintptr(unsafe.Pointer(data)),
  4601  		oldData: uintptr(unsafe.Pointer(oldData)),
  4602  		dbi:     uint32(dbi),
  4603  		flags:   uint32(flags),
  4604  	}
  4605  	ptr := uintptr(unsafe.Pointer(&args))
  4606  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_replace), ptr, 0)
  4607  	return args.result
  4608  }
  4609  
  4610  // Delete items from a database.
  4611  // \ingroup c_crud
  4612  //
  4613  // This function removes key/data pairs from the database.
  4614  //
  4615  // \note The data parameter is NOT ignored regardless the database does
  4616  // support sorted duplicate data items or not. If the data parameter
  4617  // is non-NULL only the matching data item will be deleted. Otherwise, if data
  4618  // parameter is NULL, any/all value(s) for specified key will be deleted.
  4619  //
  4620  // This function will return \ref MDBX_NOTFOUND if the specified key/data
  4621  // pair is not in the database.
  4622  //
  4623  // \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
  4624  //
  4625  // \param [in] txn   A transaction handle returned by \ref mdbx_txn_begin().
  4626  // \param [in] dbi   A database handle returned by \ref mdbx_dbi_open().
  4627  // \param [in] key   The key to delete from the database.
  4628  // \param [in] data  The data to delete.
  4629  //
  4630  // \returns A non-zero error value on failure and 0 on success,
  4631  //
  4632  //	some possible errors are:
  4633  //
  4634  // \retval MDBX_EACCES   An attempt was made to write
  4635  //
  4636  //	in a read-only transaction.
  4637  //
  4638  // \retval MDBX_EINVAL   An invalid parameter was specified.
  4639  func (tx *Tx) Delete(dbi DBI, key *Val, data *Val) Error {
  4640  	args := struct {
  4641  		txn    uintptr
  4642  		key    uintptr
  4643  		data   uintptr
  4644  		dbi    uint32
  4645  		result Error
  4646  	}{
  4647  		txn:  uintptr(unsafe.Pointer(tx.txn)),
  4648  		key:  uintptr(unsafe.Pointer(key)),
  4649  		data: uintptr(unsafe.Pointer(data)),
  4650  		dbi:  uint32(dbi),
  4651  	}
  4652  	ptr := uintptr(unsafe.Pointer(&args))
  4653  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_del), ptr, 0)
  4654  	return args.result
  4655  }
  4656  
  4657  //////////////////////////////////////////////////////////////////////////////////////////
  4658  // Cursor
  4659  //////////////////////////////////////////////////////////////////////////////////////////
  4660  
  4661  type Cursor C.MDBX_cursor
  4662  
  4663  // NewCursor Create a cursor handle but not bind it to transaction nor DBI handle.
  4664  // \ingroup c_cursors
  4665  //
  4666  // An capable of operation cursor is associated with a specific transaction and
  4667  // database. A cursor cannot be used when its database handle is closed. Nor
  4668  // when its transaction has ended, except with \ref mdbx_cursor_bind() and
  4669  // \ref mdbx_cursor_renew().
  4670  // Also it can be discarded with \ref mdbx_cursor_close().
  4671  //
  4672  // A cursor must be closed explicitly always, before or after its transaction
  4673  // ends. It can be reused with \ref mdbx_cursor_bind()
  4674  // or \ref mdbx_cursor_renew() before finally closing it.
  4675  //
  4676  // \note In contrast to LMDB, the MDBX required that any opened cursors can be
  4677  // reused and must be freed explicitly, regardless ones was opened in a
  4678  // read-only or write transaction. The REASON for this is eliminates ambiguity
  4679  // which helps to avoid errors such as: use-after-free, double-free, i.e.
  4680  // memory corruption and segfaults.
  4681  //
  4682  // \param [in] context A pointer to application context to be associated with
  4683  //
  4684  //	created cursor and could be retrieved by
  4685  //	\ref mdbx_cursor_get_userctx() until cursor closed.
  4686  //
  4687  // \returns Created cursor handle or NULL in case out of memory.
  4688  func NewCursor() *Cursor {
  4689  	args := struct {
  4690  		context uintptr
  4691  		cursor  uintptr
  4692  	}{}
  4693  	ptr := uintptr(unsafe.Pointer(&args))
  4694  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_create), ptr, 0)
  4695  	return (*Cursor)(unsafe.Pointer(args.cursor))
  4696  }
  4697  
  4698  // Bind cursor to specified transaction and DBI handle.
  4699  // \ingroup c_cursors
  4700  //
  4701  // Using of the `mdbx_cursor_bind()` is equivalent to calling
  4702  // \ref mdbx_cursor_renew() but with specifying an arbitrary dbi handle.
  4703  //
  4704  // An capable of operation cursor is associated with a specific transaction and
  4705  // database. The cursor may be associated with a new transaction,
  4706  // and referencing a new or the same database handle as it was created with.
  4707  // This may be done whether the previous transaction is live or dead.
  4708  //
  4709  // \note In contrast to LMDB, the MDBX required that any opened cursors can be
  4710  // reused and must be freed explicitly, regardless ones was opened in a
  4711  // read-only or write transaction. The REASON for this is eliminates ambiguity
  4712  // which helps to avoid errors such as: use-after-free, double-free, i.e.
  4713  // memory corruption and segfaults.
  4714  //
  4715  // \param [in] txn      A transaction handle returned by \ref mdbx_txn_begin().
  4716  // \param [in] dbi      A database handle returned by \ref mdbx_dbi_open().
  4717  // \param [out] cursor  A cursor handle returned by \ref mdbx_cursor_create().
  4718  //
  4719  // \returns A non-zero error value on failure and 0 on success,
  4720  //
  4721  //	some possible errors are:
  4722  //
  4723  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  4724  //
  4725  //	by current thread.
  4726  //
  4727  // \retval MDBX_EINVAL  An invalid parameter was specified.
  4728  func (tx *Tx) Bind(cursor *Cursor, dbi DBI) Error {
  4729  	args := struct {
  4730  		txn    uintptr
  4731  		cursor uintptr
  4732  		dbi    DBI
  4733  		result Error
  4734  	}{
  4735  		txn:    uintptr(unsafe.Pointer(tx.txn)),
  4736  		cursor: uintptr(unsafe.Pointer(cursor)),
  4737  		dbi:    dbi,
  4738  	}
  4739  	ptr := uintptr(unsafe.Pointer(&args))
  4740  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_bind), ptr, 0)
  4741  	return args.result
  4742  }
  4743  
  4744  // OpenCursor Create a cursor handle for the specified transaction and DBI handle.
  4745  // \ingroup c_cursors
  4746  //
  4747  // Using of the `mdbx_cursor_open()` is equivalent to calling
  4748  // \ref mdbx_cursor_create() and then \ref mdbx_cursor_bind() functions.
  4749  //
  4750  // An capable of operation cursor is associated with a specific transaction and
  4751  // database. A cursor cannot be used when its database handle is closed. Nor
  4752  // when its transaction has ended, except with \ref mdbx_cursor_bind() and
  4753  // \ref mdbx_cursor_renew().
  4754  // Also it can be discarded with \ref mdbx_cursor_close().
  4755  //
  4756  // A cursor must be closed explicitly always, before or after its transaction
  4757  // ends. It can be reused with \ref mdbx_cursor_bind()
  4758  // or \ref mdbx_cursor_renew() before finally closing it.
  4759  //
  4760  // \note In contrast to LMDB, the MDBX required that any opened cursors can be
  4761  // reused and must be freed explicitly, regardless ones was opened in a
  4762  // read-only or write transaction. The REASON for this is eliminates ambiguity
  4763  // which helps to avoid errors such as: use-after-free, double-free, i.e.
  4764  // memory corruption and segfaults.
  4765  //
  4766  // \param [in] txn      A transaction handle returned by \ref mdbx_txn_begin().
  4767  // \param [in] dbi      A database handle returned by \ref mdbx_dbi_open().
  4768  // \param [out] cursor  Address where the new \ref MDBX_cursor handle will be
  4769  //
  4770  //	stored.
  4771  //
  4772  // \returns A non-zero error value on failure and 0 on success,
  4773  //
  4774  //	some possible errors are:
  4775  //
  4776  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  4777  //
  4778  //	by current thread.
  4779  //
  4780  // \retval MDBX_EINVAL  An invalid parameter was specified.
  4781  func (tx *Tx) OpenCursor(dbi DBI) (*Cursor, Error) {
  4782  	var cursor *C.MDBX_cursor
  4783  	args := struct {
  4784  		txn    uintptr
  4785  		cursor uintptr
  4786  		dbi    DBI
  4787  		result Error
  4788  	}{
  4789  		txn:    uintptr(unsafe.Pointer(tx.txn)),
  4790  		cursor: uintptr(unsafe.Pointer(&cursor)),
  4791  		dbi:    dbi,
  4792  	}
  4793  	ptr := uintptr(unsafe.Pointer(&args))
  4794  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_open), ptr, 0)
  4795  	return (*Cursor)(unsafe.Pointer(cursor)), args.result
  4796  }
  4797  
  4798  // Close a cursor handle.
  4799  // \ingroup c_cursors
  4800  //
  4801  // The cursor handle will be freed and must not be used again after this call,
  4802  // but its transaction may still be live.
  4803  //
  4804  // \note In contrast to LMDB, the MDBX required that any opened cursors can be
  4805  // reused and must be freed explicitly, regardless ones was opened in a
  4806  // read-only or write transaction. The REASON for this is eliminates ambiguity
  4807  // which helps to avoid errors such as: use-after-free, double-free, i.e.
  4808  // memory corruption and segfaults.
  4809  //
  4810  // \param [in] cursor  A cursor handle returned by \ref mdbx_cursor_open()
  4811  //
  4812  //	or \ref mdbx_cursor_create().
  4813  func (cur *Cursor) Close() Error {
  4814  	ptr := uintptr(unsafe.Pointer(cur))
  4815  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_close), ptr, 0)
  4816  	return ErrSuccess
  4817  }
  4818  
  4819  // Renew a cursor handle.
  4820  // \ingroup c_cursors
  4821  //
  4822  // An capable of operation cursor is associated with a specific transaction and
  4823  // database. The cursor may be associated with a new transaction,
  4824  // and referencing a new or the same database handle as it was created with.
  4825  // This may be done whether the previous transaction is live or dead.
  4826  //
  4827  // Using of the `mdbx_cursor_renew()` is equivalent to calling
  4828  // \ref mdbx_cursor_bind() with the DBI handle that previously
  4829  // the cursor was used with.
  4830  //
  4831  // \note In contrast to LMDB, the MDBX allow any cursor to be re-used by using
  4832  // \ref mdbx_cursor_renew(), to avoid unnecessary malloc/free overhead until it
  4833  // freed by \ref mdbx_cursor_close().
  4834  //
  4835  // \param [in] txn      A transaction handle returned by \ref mdbx_txn_begin().
  4836  // \param [in] cursor   A cursor handle returned by \ref mdbx_cursor_open().
  4837  //
  4838  // \returns A non-zero error value on failure and 0 on success,
  4839  //
  4840  //	some possible errors are:
  4841  //
  4842  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  4843  //
  4844  //	by current thread.
  4845  //
  4846  // \retval MDBX_EINVAL  An invalid parameter was specified.
  4847  func (cur *Cursor) Renew(tx *Tx) Error {
  4848  	args := struct {
  4849  		txn    uintptr
  4850  		cursor uintptr
  4851  		result Error
  4852  	}{
  4853  		txn:    uintptr(unsafe.Pointer(tx.txn)),
  4854  		cursor: uintptr(unsafe.Pointer(cur)),
  4855  	}
  4856  	ptr := uintptr(unsafe.Pointer(&args))
  4857  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_renew), ptr, 0)
  4858  	return args.result
  4859  }
  4860  
  4861  // Tx Return the cursor's transaction handle.
  4862  // \ingroup c_cursors
  4863  //
  4864  // \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open().
  4865  func (cur *Cursor) Tx() *C.MDBX_txn {
  4866  	args := struct {
  4867  		cursor uintptr
  4868  		txn    uintptr
  4869  	}{
  4870  		cursor: uintptr(unsafe.Pointer(cur)),
  4871  	}
  4872  	ptr := uintptr(unsafe.Pointer(&args))
  4873  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_txn), ptr, 0)
  4874  	return (*C.MDBX_txn)(unsafe.Pointer(args.txn))
  4875  }
  4876  
  4877  // DBI Return the cursor's database handle.
  4878  // \ingroup c_cursors
  4879  //
  4880  // \param [in] cursor  A cursor handle returned by \ref mdbx_cursor_open().
  4881  func (cur *Cursor) DBI() DBI {
  4882  	args := struct {
  4883  		cursor uintptr
  4884  		dbi    DBI
  4885  	}{
  4886  		cursor: uintptr(unsafe.Pointer(cur)),
  4887  	}
  4888  	ptr := uintptr(unsafe.Pointer(&args))
  4889  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_dbi), ptr, 0)
  4890  	return args.dbi
  4891  }
  4892  
  4893  // Copy cursor position and state.
  4894  // \ingroup c_cursors
  4895  //
  4896  // \param [in] src       A source cursor handle returned
  4897  // by \ref mdbx_cursor_create() or \ref mdbx_cursor_open().
  4898  //
  4899  // \param [in,out] dest  A destination cursor handle returned
  4900  // by \ref mdbx_cursor_create() or \ref mdbx_cursor_open().
  4901  //
  4902  // \returns A non-zero error value on failure and 0 on success.
  4903  func (cur *Cursor) Copy(dest *Cursor) Error {
  4904  	args := struct {
  4905  		src    uintptr
  4906  		dest   uintptr
  4907  		result Error
  4908  	}{
  4909  		src:  uintptr(unsafe.Pointer(cur)),
  4910  		dest: uintptr(unsafe.Pointer(dest)),
  4911  	}
  4912  	ptr := uintptr(unsafe.Pointer(&args))
  4913  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_copy), ptr, 0)
  4914  	return args.result
  4915  }
  4916  
  4917  // Get Retrieve by cursor.
  4918  // \ingroup c_crud
  4919  //
  4920  // This function retrieves key/data pairs from the database. The address and
  4921  // length of the key are returned in the object to which key refers (except
  4922  // for the case of the \ref MDBX_SET option, in which the key object is
  4923  // unchanged), and the address and length of the data are returned in the object
  4924  // to which data refers.
  4925  // \see mdbx_get()
  4926  //
  4927  // \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
  4928  // \param [in,out] key   The key for a retrieved item.
  4929  // \param [in,out] data  The data of a retrieved item.
  4930  // \param [in] op        A cursor operation \ref MDBX_cursor_op.
  4931  //
  4932  // \returns A non-zero error value on failure and 0 on success,
  4933  //
  4934  //	some possible errors are:
  4935  //
  4936  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  4937  //
  4938  //	by current thread.
  4939  //
  4940  // \retval MDBX_NOTFOUND  No matching key found.
  4941  // \retval MDBX_EINVAL    An invalid parameter was specified.
  4942  func (cur *Cursor) Get(key *Val, data *Val, op CursorOp) Error {
  4943  	args := struct {
  4944  		cursor uintptr
  4945  		key    uintptr
  4946  		data   uintptr
  4947  		op     CursorOp
  4948  		result Error
  4949  	}{
  4950  		cursor: uintptr(unsafe.Pointer(cur)),
  4951  		key:    uintptr(unsafe.Pointer(key)),
  4952  		data:   uintptr(unsafe.Pointer(data)),
  4953  		op:     op,
  4954  	}
  4955  	ptr := uintptr(unsafe.Pointer(&args))
  4956  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_get), ptr, 0)
  4957  	return args.result
  4958  }
  4959  
  4960  // Put Store by cursor.
  4961  // \ingroup c_crud
  4962  //
  4963  // This function stores key/data pairs into the database. The cursor is
  4964  // positioned at the new item, or on failure usually near it.
  4965  //
  4966  // \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
  4967  // \param [in] key       The key operated on.
  4968  // \param [in,out] data  The data operated on.
  4969  // \param [in] flags     Options for this operation. This parameter
  4970  //
  4971  //	                     must be set to 0 or by bitwise OR'ing together
  4972  //	                     one or more of the values described here:
  4973  //	- \ref MDBX_CURRENT
  4974  //	    Replace the item at the current cursor position. The key parameter
  4975  //	    must still be provided, and must match it, otherwise the function
  4976  //	    return \ref MDBX_EKEYMISMATCH. With combination the
  4977  //	    \ref MDBX_ALLDUPS will replace all multi-values.
  4978  //
  4979  //	    \note MDBX allows (unlike LMDB) you to change the size of the data and
  4980  //	    automatically handles reordering for sorted duplicates
  4981  //	    (see \ref MDBX_DUPSORT).
  4982  //
  4983  //	- \ref MDBX_NODUPDATA
  4984  //	    Enter the new key-value pair only if it does not already appear in the
  4985  //	    database. This flag may only be specified if the database was opened
  4986  //	    with \ref MDBX_DUPSORT. The function will return \ref MDBX_KEYEXIST
  4987  //	    if the key/data pair already appears in the database.
  4988  //
  4989  //	- \ref MDBX_NOOVERWRITE
  4990  //	    Enter the new key/data pair only if the key does not already appear
  4991  //	    in the database. The function will return \ref MDBX_KEYEXIST if the key
  4992  //	    already appears in the database, even if the database supports
  4993  //	    duplicates (\ref MDBX_DUPSORT).
  4994  //
  4995  //	- \ref MDBX_RESERVE
  4996  //	    Reserve space for data of the given size, but don't copy the given
  4997  //	    data. Instead, return a pointer to the reserved space, which the
  4998  //	    caller can fill in later - before the next update operation or the
  4999  //	    transaction ends. This saves an extra memcpy if the data is being
  5000  //	    generated later. This flag must not be specified if the database
  5001  //	    was opened with \ref MDBX_DUPSORT.
  5002  //
  5003  //	- \ref MDBX_APPEND
  5004  //	    Append the given key/data pair to the end of the database. No key
  5005  //	    comparisons are performed. This option allows fast bulk loading when
  5006  //	    keys are already known to be in the correct order. Loading unsorted
  5007  //	    keys with this flag will cause a \ref MDBX_KEYEXIST error.
  5008  //
  5009  //	- \ref MDBX_APPENDDUP
  5010  //	    As above, but for sorted dup data.
  5011  //
  5012  //	- \ref MDBX_MULTIPLE
  5013  //	    Store multiple contiguous data elements in a single request. This flag
  5014  //	    may only be specified if the database was opened with
  5015  //	    \ref MDBX_DUPFIXED. With combination the \ref MDBX_ALLDUPS
  5016  //	    will replace all multi-values.
  5017  //	    The data argument must be an array of two \ref MDBX_val. The `iov_len`
  5018  //	    of the first \ref MDBX_val must be the size of a single data element.
  5019  //	    The `iov_base` of the first \ref MDBX_val must point to the beginning
  5020  //	    of the array of contiguous data elements which must be properly aligned
  5021  //	    in case of database with \ref MDBX_INTEGERDUP flag.
  5022  //	    The `iov_len` of the second \ref MDBX_val must be the count of the
  5023  //	    number of data elements to store. On return this field will be set to
  5024  //	    the count of the number of elements actually written. The `iov_base` of
  5025  //	    the second \ref MDBX_val is unused.
  5026  //
  5027  // \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
  5028  //
  5029  // \returns A non-zero error value on failure and 0 on success,
  5030  //
  5031  //	some possible errors are:
  5032  //
  5033  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  5034  //
  5035  //	by current thread.
  5036  //
  5037  // \retval MDBX_EKEYMISMATCH  The given key value is mismatched to the current
  5038  //
  5039  //	cursor position
  5040  //
  5041  // \retval MDBX_MAP_FULL      The database is full,
  5042  //
  5043  //	see \ref mdbx_env_set_mapsize().
  5044  //
  5045  // \retval MDBX_TXN_FULL      The transaction has too many dirty pages.
  5046  // \retval MDBX_EACCES        An attempt was made to write in a read-only
  5047  //
  5048  //	transaction.
  5049  //
  5050  // \retval MDBX_EINVAL        An invalid parameter was specified.
  5051  func (cur *Cursor) Put(key *Val, data *Val, flags PutFlags) Error {
  5052  	args := struct {
  5053  		cursor uintptr
  5054  		key    uintptr
  5055  		data   uintptr
  5056  		flags  PutFlags
  5057  		result Error
  5058  	}{
  5059  		cursor: uintptr(unsafe.Pointer(cur)),
  5060  		key:    uintptr(unsafe.Pointer(key)),
  5061  		data:   uintptr(unsafe.Pointer(data)),
  5062  		flags:  flags,
  5063  	}
  5064  	ptr := uintptr(unsafe.Pointer(&args))
  5065  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_put), ptr, 0)
  5066  	return args.result
  5067  }
  5068  
  5069  // Delete current key/data pair.
  5070  // \ingroup c_crud
  5071  //
  5072  // This function deletes the key/data pair to which the cursor refers. This
  5073  // does not invalidate the cursor, so operations such as \ref MDBX_NEXT can
  5074  // still be used on it. Both \ref MDBX_NEXT and \ref MDBX_GET_CURRENT will
  5075  // return the same record after this operation.
  5076  //
  5077  // \param [in] cursor  A cursor handle returned by mdbx_cursor_open().
  5078  // \param [in] flags   Options for this operation. This parameter must be set
  5079  // to one of the values described here.
  5080  //
  5081  //   - \ref MDBX_CURRENT Delete only single entry at current cursor position.
  5082  //   - \ref MDBX_ALLDUPS
  5083  //     or \ref MDBX_NODUPDATA (supported for compatibility)
  5084  //     Delete all of the data items for the current key. This flag has effect
  5085  //     only for database(s) was created with \ref MDBX_DUPSORT.
  5086  //
  5087  // \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
  5088  //
  5089  // \returns A non-zero error value on failure and 0 on success,
  5090  //
  5091  //	some possible errors are:
  5092  //
  5093  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  5094  //
  5095  //	by current thread.
  5096  //
  5097  // \retval MDBX_MAP_FULL      The database is full,
  5098  //
  5099  //	see \ref mdbx_env_set_mapsize().
  5100  //
  5101  // \retval MDBX_TXN_FULL      The transaction has too many dirty pages.
  5102  // \retval MDBX_EACCES        An attempt was made to write in a read-only
  5103  //
  5104  //	transaction.
  5105  //
  5106  // \retval MDBX_EINVAL        An invalid parameter was specified.
  5107  func (cur *Cursor) Delete(flags PutFlags) Error {
  5108  	args := struct {
  5109  		cursor uintptr
  5110  		flags  PutFlags
  5111  		result Error
  5112  	}{
  5113  		cursor: uintptr(unsafe.Pointer(cur)),
  5114  		flags:  flags,
  5115  	}
  5116  	ptr := uintptr(unsafe.Pointer(&args))
  5117  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_del), ptr, 0)
  5118  	return args.result
  5119  }
  5120  
  5121  // Count Return count of duplicates for current key.
  5122  // \ingroup c_crud
  5123  //
  5124  // This call is valid for all databases, but reasonable only for that support
  5125  // sorted duplicate data items \ref MDBX_DUPSORT.
  5126  //
  5127  // \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
  5128  // \param [out] pcount   Address where the count will be stored.
  5129  //
  5130  // \returns A non-zero error value on failure and 0 on success,
  5131  //
  5132  //	some possible errors are:
  5133  //
  5134  // \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  5135  //
  5136  //	by current thread.
  5137  //
  5138  // \retval MDBX_EINVAL   Cursor is not initialized, or an invalid parameter
  5139  //
  5140  //	was specified.
  5141  func (cur *Cursor) Count() (int, Error) {
  5142  	var count uintptr
  5143  	args := struct {
  5144  		cursor uintptr
  5145  		count  uintptr
  5146  		result Error
  5147  	}{
  5148  		cursor: uintptr(unsafe.Pointer(cur)),
  5149  		count:  uintptr(unsafe.Pointer(&count)),
  5150  	}
  5151  	ptr := uintptr(unsafe.Pointer(&args))
  5152  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_count), ptr, 0)
  5153  	return int(count), args.result
  5154  }
  5155  
  5156  // EOF Determines whether the cursor is pointed to a key-value pair or not,
  5157  // i.e. was not positioned or points to the end of data.
  5158  // \ingroup c_cursors
  5159  //
  5160  // \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
  5161  //
  5162  // \returns A \ref MDBX_RESULT_TRUE or \ref MDBX_RESULT_FALSE value,
  5163  //
  5164  //	otherwise the error code:
  5165  //
  5166  // \retval MDBX_RESULT_TRUE    No more data available or cursor not
  5167  //
  5168  //	positioned
  5169  //
  5170  // \retval MDBX_RESULT_FALSE   A data is available
  5171  // \retval Otherwise the error code
  5172  func (cur *Cursor) EOF() Error {
  5173  	args := struct {
  5174  		cursor uintptr
  5175  		result Error
  5176  	}{
  5177  		cursor: uintptr(unsafe.Pointer(cur)),
  5178  	}
  5179  	ptr := uintptr(unsafe.Pointer(&args))
  5180  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_eof), ptr, 0)
  5181  	return args.result
  5182  }
  5183  
  5184  // OnFirst Determines whether the cursor is pointed to the first key-value pair
  5185  // or not. \ingroup c_cursors
  5186  //
  5187  // \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
  5188  //
  5189  // \returns A MDBX_RESULT_TRUE or MDBX_RESULT_FALSE value,
  5190  //
  5191  //	otherwise the error code:
  5192  //
  5193  // \retval MDBX_RESULT_TRUE   Cursor positioned to the first key-value pair
  5194  // \retval MDBX_RESULT_FALSE  Cursor NOT positioned to the first key-value
  5195  // pair \retval Otherwise the error code
  5196  func (cur *Cursor) OnFirst() Error {
  5197  	args := struct {
  5198  		cursor uintptr
  5199  		result Error
  5200  	}{
  5201  		cursor: uintptr(unsafe.Pointer(cur)),
  5202  	}
  5203  	ptr := uintptr(unsafe.Pointer(&args))
  5204  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_on_first), ptr, 0)
  5205  	return args.result
  5206  }
  5207  
  5208  // OnLast Determines whether the cursor is pointed to the last key-value pair
  5209  // or not. \ingroup c_cursors
  5210  //
  5211  // \param [in] cursor    A cursor handle returned by \ref mdbx_cursor_open().
  5212  //
  5213  // \returns A \ref MDBX_RESULT_TRUE or \ref MDBX_RESULT_FALSE value,
  5214  //
  5215  //	otherwise the error code:
  5216  //
  5217  // \retval MDBX_RESULT_TRUE   Cursor positioned to the last key-value pair
  5218  // \retval MDBX_RESULT_FALSE  Cursor NOT positioned to the last key-value pair
  5219  // \retval Otherwise the error code
  5220  func (cur *Cursor) OnLast() Error {
  5221  	args := struct {
  5222  		cursor uintptr
  5223  		result Error
  5224  	}{
  5225  		cursor: uintptr(unsafe.Pointer(cur)),
  5226  	}
  5227  	ptr := uintptr(unsafe.Pointer(&args))
  5228  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_cursor_on_last), ptr, 0)
  5229  	return args.result
  5230  }
  5231  
  5232  // EstimateDistance
  5233  // \details \note The estimation result varies greatly depending on the filling
  5234  // of specific pages and the overall balance of the b-tree:
  5235  //
  5236  // 1. The number of items is estimated by analyzing the height and fullness of
  5237  // the b-tree. The accuracy of the result directly depends on the balance of
  5238  // the b-tree, which in turn is determined by the history of previous
  5239  // insert/delete operations and the nature of the data (i.e. variability of
  5240  // keys length and so on). Therefore, the accuracy of the estimation can vary
  5241  // greatly in a particular situation.
  5242  //
  5243  // 2. To understand the potential spread of results, you should consider a
  5244  // possible situations basing on the general criteria for splitting and merging
  5245  // b-tree pages:
  5246  //  - the page is split into two when there is no space for added data;
  5247  //  - two pages merge if the result fits in half a page;
  5248  //  - thus, the b-tree can consist of an arbitrary combination of pages filled
  5249  //    both completely and only 1/4. Therefore, in the worst case, the result
  5250  //    can diverge 4 times for each level of the b-tree excepting the first and
  5251  //    the last.
  5252  //
  5253  // 3. In practice, the probability of extreme cases of the above situation is
  5254  // close to zero and in most cases the error does not exceed a few percent. On
  5255  // the other hand, it's just a chance you shouldn't overestimate.///
  5256  
  5257  // EstimateDistance the distance between cursors as a number of elements.
  5258  // \ingroup c_rqest
  5259  //
  5260  // This function performs a rough estimate based only on b-tree pages that are
  5261  // common for the both cursor's stacks. The results of such estimation can be
  5262  // used to build and/or optimize query execution plans.
  5263  //
  5264  // Please see notes on accuracy of the result in the details
  5265  // of \ref c_rqest section.
  5266  //
  5267  // Both cursors must be initialized for the same database and the same
  5268  // transaction.
  5269  //
  5270  // \param [in] first            The first cursor for estimation.
  5271  // \param [in] last             The second cursor for estimation.
  5272  // \param [out] distance_items  The pointer to store estimated distance value,
  5273  //
  5274  //	i.e. `*distance_items = distance(first, last)`.
  5275  //
  5276  // \returns A non-zero error value on failure and 0 on success.
  5277  func EstimateDistance(first, last *Cursor) (int64, Error) {
  5278  	var distance int64
  5279  	args := struct {
  5280  		first    uintptr
  5281  		last     uintptr
  5282  		distance uintptr
  5283  		result   Error
  5284  	}{
  5285  		first:    uintptr(unsafe.Pointer(first)),
  5286  		last:     uintptr(unsafe.Pointer(last)),
  5287  		distance: uintptr(unsafe.Pointer(&distance)),
  5288  	}
  5289  	ptr := uintptr(unsafe.Pointer(&args))
  5290  	unsafecgo.NonBlocking((*byte)(C.do_mdbx_estimate_distance), ptr, 0)
  5291  	return distance, args.result
  5292  }