-
Notifications
You must be signed in to change notification settings - Fork 7
/
tables.h
3670 lines (3325 loc) · 234 KB
/
tables.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Fast Positive Tables (libfpta), aka Позитивные Таблицы.
* Copyright 2016-2020 Leonid Yuriev <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* libfpta = { Fast Positive Tables, aka Позитивные Таблицы }
*
* Ultra fast, compact, embeddable storage engine for (semi)structured data:
* multiprocessing with zero-overhead, full ACID semantics with MVCC,
* variety of indexes, saturation, sequences and much more.
* Please see README.md at https://github.com/erthink/libfpta
*
* The Future will (be) Positive. Всё будет хорошо.
*
* "Позитивные таблицы" предназначены для построения высокоскоростных
* локальных хранилищ структурированных данных, с целевой производительностью
* до 1.000.000 запросов в секунду на каждое ядро процессора.
*/
#pragma once
#ifndef FAST_POSITIVE_TABLES_H
#define FAST_POSITIVE_TABLES_H
#define FPTA_VERSION_MAJOR 0
#define FPTA_VERSION_MINOR 3
#include "fast_positive/config.h"
#include "fast_positive/defs.h"
#if defined(fpta_EXPORTS)
#define FPTA_API __dll_export
#elif LIBFPTA_STATIC
#define FPTA_API
#else
#define FPTA_API __dll_import
#endif /* fpta_EXPORTS */
#include "fast_positive/tuples.h"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4514) /* 'xyz': unreferenced inline function \
has been removed */
#pragma warning(disable : 4710) /* 'xyz': function not inlined */
#pragma warning(disable : 4711) /* function 'xyz' selected for \
automatic inline expansion */
#pragma warning(disable : 4061) /* enumerator 'abc' in switch of enum 'xyz' is \
not explicitly handled by a case label */
#pragma warning(disable : 4201) /* nonstandard extension used : \
nameless struct / union */
#pragma warning(disable : 4127) /* conditional expression is constant */
#pragma warning(push, 1)
#ifndef _STL_WARNING_LEVEL
#define _STL_WARNING_LEVEL 3 /* Avoid warnings inside nasty MSVC STL code */
#endif
#pragma warning(disable : 4548) /* expression before comma has no effect; \
expected expression with side - effect */
#pragma warning(disable : 4530) /* C++ exception handler used, but unwind \
semantics are not enabled. Specify /EHsc */
#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling \
mode specified; termination on exception \
is not guaranteed. Specify /EHsc */
#endif /* _MSC_VER (warnings) */
#include <assert.h> // for assert()
#include <errno.h> // for error codes
#include <limits.h> // for INT_MAX
#include <string.h> // for strlen()
#if defined(HAVE_SYS_STAT_H) && !defined(_WIN32) && !defined(_WIN64)
#include <sys/stat.h> // for mode_t
#elif !defined(__mode_t_defined)
typedef unsigned short mode_t;
#endif
#ifdef _MSC_VER
#pragma warning(pop)
#pragma pack(push, 1)
#endif
//----------------------------------------------------------------------------
/* Опции конфигурации управляющие внутренним поведением libfpta, т.е
* их изменение требует пересборки библиотеки.
*
* Чуть позже эти определения передедут в fpta_config.h */
#ifndef FPTA_ALLOW_DOT4NAMES
/* Опция разрешает использование точки в именах таблиц и колонок. */
#define FPTA_ALLOW_DOT4NAMES 0
#endif /* FPTA_ALLOW_DOT4NAMES */
#ifndef FPTA_PROHIBIT_UPSERT_NAN
/* Опция определяет поведение при вставке NaN значений
* посредством fpta_upsert_column().
*
* Если опция ВЫКЛЮЧЕНА (определена как 0), то будет вставлено переданное
* NaN-значение.
*
* Если же опция ВКЛЮЧЕНА (определена как не 0), то при попытке такой
* вставке или обновлении будет возвращена ошибка FPTA_EVALUE. */
#define FPTA_PROHIBIT_UPSERT_NAN 1
#endif /* FPTA_PROHIBIT_UPSERT_NAN */
#ifndef FPTA_PROHIBIT_UPSERT_DENIL
/* Опция определяет поведение при вставке посредством fpta_upsert_column()
* значений зарезервированных за designated empty.
*
* Если опция ВЫКЛЮЧЕНА (определена как 0), то такая вставка или обновление
* приведет к удалению соответствующей колонки, а не возврату ошибки.
*
* Если же опция ВКЛЮЧЕНА (определена как не 0), то при попытке такой
* вставке или обновлении будет возвращена ошибка FPTA_EVALUE. */
#define FPTA_PROHIBIT_UPSERT_DENIL 1
#endif /* FPTA_PROHIBIT_UPSERT_DENIL */
#ifndef FPTA_CLEAN_DENIL
/* Опция включает внутри fpta_field2value() чистку значений зарезервированных
* за designated empty.
*
* Чистка designated empty не нужна, если fpta_field2value() вызывается для
* данных, которые были штатно помещены и после прочитаны из ftpa-таблицы,
* так как при этом designated empty значения не должны попасть в данные.
*
* Если опция ВЫКЛЮЧЕНА (определена как 0), то чистка не выполняется.
* Соответственно, при подаче на вход fpta_field2value() поля с designated
* empty значением внутри это значение будет преобразовано не в fpta_null,
* а в недопустимое значение соответствующего типа. При этом в отладочных
* версиях библиотеки сработает assert-проверка.
*
* Если же опция ВКЛЮЧЕНА (определена как не 0), то поля с соответствующим
* значениями будут преобразованы в fpta_null. */
#define FPTA_CLEAN_DENIL 0
#endif /* FPTA_CLEAN_DENIL */
#ifndef FPTA_PROHIBIT_NEARBY4UNORDERED
/* Опция определяет поведение при запросах позиционирования к ближайшему
* значению посредством fpta_cursor_locate() для "неупорядоченных" курсоров.
*
* Установка курсора в позицию с ближайшим значением (аналог lower bound)
* возможна, только если заданный при открытии курсора индекс упорядочен.
* В свою очередь, для неупорядоченных индексов допускается открытие только
* курсоров без сортировки. Поэтому для таких курсоров гарантированно
* можно выполнить только точное позиционирование.
*
* Соответственно, опция определяет, будет ли в описанных случаях выполняться
* точное позиционирование (вместо неточного), либо же будет возвращена
* ошибка FPTA_EINVAL. */
#define FPTA_PROHIBIT_NEARBY4UNORDERED 1
#endif /* FPTA_PROHIBIT_NEARBY4UNORDERED */
#ifndef FPTA_PROHIBIT_LOSS_PRECISION
/* При обслуживании индексированных колонок типа float/fptu_fp32
* double значения из fpta_value будут преобразованы во float.
* Опция определяет, считать ли потерю точности ошибкой при этом или нет. */
#define FPTA_PROHIBIT_LOSS_PRECISION 0
#endif /* FPTA_PROHIBIT_LOSS_PRECISION */
#ifndef FPTA_ENABLE_ABORT_ON_PANIC
/* Опция определяет, что делать при фатальных ошибках, например в случае
* ошибки отката/прерывания транзакции.
*
* Как правило, такие ошибки возникают при "росписи" памяти или при серьезных
* нарушениях соглашений API. Лучшим выходом, в таких случаях, обычно является
* скорейшее прерывание выполнения процесса. Согласованность данных при этом
* обеспечивается откатом (не фиксацией) транзакции внутри libmdbx.
*
* Если FPTA_ENABLE_ABORT_ON_PANIC == 0, то при фатальной проблеме
* будет возвращена ошибка FPTA_WANNA_DIE, клиентскому коду следует её
* обработать и максимально быстро завершить выполнение.
*
* Если FPTA_ENABLE_ABORT_ON_PANIC != 0, то при фатальной проблеме будет
* вызвана системная abort().
*
* На платформах с поддержкой __attribute__((weak)) поведение может быть
* дополнительно изменено перекрытием функции fpta_panic(). */
#define FPTA_ENABLE_ABORT_ON_PANIC 1
#endif /* FPTA_ENABLE_ABORT_ON_PANIC */
#ifdef __cplusplus
#include <array> // for std::array
#include <string> // for std::string
extern "C" {
#endif
//----------------------------------------------------------------------------
/* Общие перечисления и структуры */
/* Основные ограничения, константы и их производные. */
enum fpta_bits {
/* Максимальное кол-во таблиц */
fpta_tables_max = 1024,
/* Максимальное кол-во колонок (порядка 1000) */
fpta_max_cols = fptu_max_cols,
/* Максимальный размер строки/записи в байтах */
fpta_max_row_bytes = fptu_max_tuple_bytes,
/* Максимальная длина значения колонки в байтах */
fpta_max_col_bytes = fptu_max_opaque_bytes,
/* Максимальное кол-во элементов в массиве */
fpta_max_array_len = fptu_max_array_len,
/* Максимальная длина ключа и/или индексируемого поля. Ограничение
* актуально только для упорядоченных индексов для строк, бинарных данных
* переменной длины, а также для составных упорядоченных индексов.
*
* ВАЖНО: При превышении заданной величины в индекс попадет только
* помещающаяся часть ключа, с дополнением 64-битным хэшем остатка.
* Поэтому в упорядоченных индексах будет нарушаться порядок сортировки
* для длинных строк, больших бинарных данных и составных колонок с
* подобными длинными значениями внутри.
*
* Для эффективного индексирования значений, у которых наиболее значимая
* часть находится в конце (например доменных имен), предусмотрен
* специальный тип реверсивных индексов. При этом ограничение сохраняется,
* но ключи обрабатываются и сравниваются с конца.
*
* Ограничение можно немного "подвинуть" за счет производительности,
* но нельзя убрать полностью. Также будет рассмотрен вариант перехода
* на 128-битный хэш. */
fpta_max_keylen = 64 * 1 - 8,
/* Размер буфера достаточный для размещения любого ключа во внутреннем
* представлении, в том числе размер буфера необходимого функции
* fpta_get_column2buffer() для формирование fpta_value составной колонки. */
fpta_keybuf_len = fpta_max_keylen + 8 + sizeof(void *) + sizeof(size_t),
/* Минимальная длина имени/идентификатора */
fpta_name_len_min = 1,
/* Максимальная длина имени/идентификатора */
fpta_name_len_max = 64,
/* Далее внутренние технические детали. */
fpta_id_bits = 64,
fpta_column_typeid_bits = fptu_typeid_bits,
fpta_column_typeid_shift = 0,
fpta_column_typeid_mask = (1 << fptu_typeid_bits) - 1,
fpta_column_index_bits = 5,
fpta_column_index_shift = fpta_column_typeid_bits,
fpta_column_index_mask = ((1 << fpta_column_index_bits) - 1)
<< fpta_column_index_shift,
fpta_name_hash_bits =
fpta_id_bits - fpta_column_typeid_bits - fpta_column_index_bits,
fpta_name_hash_shift = fpta_column_index_shift + fpta_column_index_bits,
/* Предельное кол-во вторичных индексов для одной таблице (порядка 1000) */
fpta_max_indexes = (1 << (fpta_id_bits - fpta_name_hash_bits)) -
/* НЗ и для работы юнит-тестов */ 42,
/* Максимальное суммарное кол-во таблиц и всех вторичных индексов,
* включая составные индексы/колонки */
fpta_max_dbi = fpta_tables_max * 4 /* должно быть меньше MDBX_MAX_DBI -
FPTA_SCHEMA_DBI = (INT16_MAX - CORE_DBS) - 1 = 32767 - 2 - 1 = 32764 */
};
/* Экземпляр БД.
*
* Базу следует открыть посредством fpta_db_open(), а по завершении всех
* манипуляций закрыть через fpta_db_close().
* Открытие и закрытие базы относительно дорогие операции. */
typedef struct fpta_db fpta_db;
/* Транзакция.
*
* Чтение и изменение данных всегда происходят в контексте транзакции.
* В fpta есть три вида (уровня) транзакций: только для чтения, для
* чтение-записи, для чтения-записи и изменения схемы БД.
*
* Транзакции инициируются посредством fpta_transaction_begin()
* и завершается через fpta_transaction_end(). */
typedef struct fpta_txn fpta_txn;
/* Курсор для чтения и изменения данных.
*
* Курсор связан с диапазоном записей, которые выбираются в порядке одного
* из индексов и опционально фильтруются (если задан фильтр). Курсор
* позволяет "ходить" по записям, обновлять их и удалять.
*
* Открывается курсор посредством fpta_cursor_open(), а закрывается
* соответственно через fpta_cursor_close(). */
typedef struct fpta_cursor fpta_cursor;
//----------------------------------------------------------------------------
/* Коды ошибок. */
enum fpta_error {
FPTA_SUCCESS = 0,
FPTA_OK = FPTA_SUCCESS,
FPTA_ERRROR_BASE = 4242,
/* Internal unexpected Oops */
FPTA_EOOPS = 4243,
/* Schema is invalid or corrupted (internal error) */
FPTA_SCHEMA_CORRUPTED = 4244,
/* Type mismatch (given value vs column/field or index) */
FPTA_ETYPE = 4245,
/* Data length mismatch (given value vs data type) */
FPTA_DATALEN_MISMATCH = 4246,
/* Key mismatch while updating row via cursor */
FPTA_KEY_MISMATCH = 4247,
/* Required column missing */
FPTA_COLUMN_MISSING = 4248,
/* Index is inconsistent or corrupted (internal error) */
FPTA_INDEX_CORRUPTED = 4249,
/* No (such) index for given column */
FPTA_NO_INDEX = 4250,
/* Schema changed (transaction should be restared) */
FPTA_SCHEMA_CHANGED = 4251,
/* Cursor is not positioned */
FPTA_ECURSOR = 4252,
/* Too many tables, columns or indexes (one of fpta's limits reached) */
FPTA_TOOMANY = 4253,
/* Failure while transaction rollback */
FPTA_WANNA_DIE = 4254,
/* Transaction already cancelled */
FPTA_TXN_CANCELLED = 4255,
/* Adding index which is similar to one of the existing */
FPTA_SIMILAR_INDEX = 4256,
/* Another thread still use handle(s) that should be reopened. */
FPTA_TARDY_DBI = 4257,
/* Adding index which is too clumsy */
FPTA_CLUMSY_INDEX = 4258,
/* Database format mismatch the version of libfpta */
FPTA_FORMAT_MISMATCH = 4259,
/* Applicaton version mismatch the database content */
FPTA_APP_MISMATCH = 4260,
/* Filter has some tautology that cannot be rewritten-out
* due to API compatibility issues. */
FPTA_TAUTOLOGICAL_FILTER = 4261,
FPTA_ERRROR_LAST = FPTA_TAUTOLOGICAL_FILTER,
/* No data or EOF was reached */
FPTA_NODATA = -1,
/* Pseudo error for results by refs, mean `no value` returned */
FPTA_DEADBEEF = INT32_C(0xDeadBeef),
/**************************************** Native (system) error codes ***/
FPTA_ENOFIELD = FPTU_ENOFIELD,
FPTA_ENOSPACE = FPTU_ENOSPACE,
FPTA_EINVAL = FPTU_EINVAL /* Invalid argument */,
#if defined(_WIN32) || defined(_WIN64)
FPTA_ENOMEM = 14 /* ERROR_OUTOFMEMORY */,
FPTA_ENOIMP = 50 /* ERROR_NOT_SUPPORTED */,
FPTA_EVALUE = 13 /* ERROR_INVALID_DATA */,
FPTA_OVERFLOW = 534 /* ERROR_ARITHMETIC_OVERFLOW */,
FPTA_EEXIST = 183 /* ERROR_ALREADY_EXISTS */,
FPTA_ENOENT = 1168 /* ERROR_NOT_FOUND */,
FPTA_EPERM = 1 /* ERROR_INVALID_FUNCTION */,
FPTA_EBUSY = 170 /* ERROR_BUSY */,
FPTA_ENAME = 123 /* ERROR_INVALID_NAME */,
FPTA_EFLAG = 186 /* ERROR_INVALID_FLAG_NUMBER */,
#else
FPTA_ENOMEM = ENOMEM /* Out of Memory (POSIX) */,
FPTA_ENOIMP = ENOSYS /* Function not implemented (POSIX) */,
FPTA_EVALUE =
EDOM /* Mathematics argument out of domain of function (POSIX) */,
FPTA_OVERFLOW =
EOVERFLOW /* Value too large to be stored in data type (POSIX) */,
#ifdef ENOTUNIQ
FPTA_EEXIST = ENOTUNIQ /* Name not unique on network */,
#else
FPTA_EEXIST = EADDRINUSE /* Address already in use (POSIX) */,
#endif
FPTA_ENOENT = ENOENT /* No such file or directory (POSIX) */,
FPTA_EPERM = EPERM /* Operation not permitted (POSIX) */,
FPTA_EBUSY = EBUSY /* Device or resource busy (POSIX) */,
#ifdef EKEYREJECTED
FPTA_ENAME = EKEYREJECTED,
#else
FPTA_ENAME = FPTA_EINVAL,
#endif
#ifdef EBADRQC
FPTA_EFLAG = EBADRQC,
#else
FPTA_EFLAG = FPTA_EINVAL,
#endif
#endif
/************************************************* MDBX's error codes ***/
FPTA_KEYEXIST = -30799 /* key/data pair already exists */,
FPTA_NOTFOUND = -30798 /* key/data pair not found */,
FPTA_DB_REF = -30797 /* wrong page address/number,
* this usually indicates corruption */
,
FPTA_DB_CORRUPTED =
-30796 /* Database is corrupted (page was wrong type and so on) */,
FPTA_DB_PANIC = -30795 /* Environment had fatal error (i.e. update of meta
page failed and so on) */
,
FPTA_DB_MISMATCH = -30794 /* DB version mismatch libmdbx */,
FPTA_DB_INVALID = -30793 /* File is not a valid LMDB file */,
FPTA_DB_FULL = -30792 /* Environment mapsize reached */,
FPTA_DBI_FULL = -30791 /* Too may DBI (maxdbs reached) */,
FPTA_READERS_FULL = -30790 /* Too many readers (maxreaders reached) */,
FPTA_TXN_FULL = -30788 /* Transaction has too many dirty pages,
* i.e transaction too big */
,
FPTA_CURSOR_FULL = -30787 /* Cursor stack too deep (mdbx internal) */,
FPTA_PAGE_FULL = -30786 /* Page has not enough space (mdbx internal) */,
FPTA_DB_UNABLE_EXTEND_MAPSIZE = -30785 /* Database engine was unable
to extend mapping, e.g. since address space is unavailable or busy:
- Database size extended by other process beyond to environment
mapsize and engine was unable to extend mapping while
starting read transaction. Environment should be reopened to
continue.
- Engine was unable to extend mapping during write transaction
or explicit call of mdbx_env_set_geometry(). */
,
FPTA_DB_INCOMPAT = -30784 /* Environment or database is not compatible with
the requested operation or the specified flags. This can mean:
- The operation expects an MDBX_DUPSORT/MDBX_DUPFIXED database.
- Opening a named DB when the unnamed DB has MDBX_DUPSORT/MDBX_INTEGERKEY.
- Accessing a data record as a database, or vice versa.
- The database was dropped and recreated with different flags. */
,
FPTA_BAD_RSLOT =
-30783 /* Invalid reuse of reader locktable slot,
* e.g. read-transaction already run for current thread */
,
FPTA_BAD_TXN = -30782 /* Transaction is not valid for requested operation,
* e.g. had errored and be must aborted, has a child, or
* is invalid */
,
FPTA_BAD_VALSIZE = -30781 /* Invalid size or alignment of key or data for
* target database, either invalid subDB name */
,
FPTA_BAD_DBI = -30780 /* The specified DBI-handle is invalid
* or changed by another thread/transaction */
,
FPTA_DB_PROBLEM = -30779 /* Unexpected internal error,
* transaction should be aborted */
,
FPTA_BUSY = -30778 /* Another write transaction is running or environment is
* already used while opening with MDBX_EXCLUSIVE flag */
,
FPTA_EMULTIVAL =
-30421 /* The specified key has more than one associated value */
,
FPTA_EBADSIGN = -30420 /* Bad signature of a runtime object(s),
* e.g. memory corruption */
,
/* Database should be recovered, but this could NOT be done for now
* since it opened in read-only mode. */
FPTA_EWANNA_RECOVERY = -30419,
/* The given key value is mismatched to the current cursor position */
FPTA_EKEYMISMATCH = -30418,
/* Database is too large for current system,
* e.g. could NOT be mapped into RAM. */
FPTA_ETOO_LARGE = -30417,
/* A thread has attempted to use a not owned object,
* e.g. a transaction that started by another thread. */
FPTA_ETHREAD_MISMATCH = -30416,
/* Overlapping read and write transactions for the current thread */
FPTA_TXN_OVERLAPPING = -30415
};
/* Возвращает краткое описание ошибки по её коду.
*
* Функция идентифицирует "свои" ошибки и при необходимости по-цепочке
* вызывает mdbx_strerror() и системную strerror().
*
* Функция потоко-НЕ-безопасна в случае системной ошибки, так как при
* этом вызывается потоко-НЕ-безопасная системная strerror(). */
FPTA_API const char *fpta_strerror(int errnum);
/* Потоко-безопасный вариант fpta_strerror().
*
* Функция потоко-безопасна в том числе в случае системной ошибки, так
* как при этом вызывается потоко-безопасная системная strerror_r(). */
FPTA_API const char *fpta_strerror_r(int errnum, char *buf, size_t buflen);
/* Внутренняя функция, которая вызывается при фатальных ошибках и может
* быть замещена на платформах с поддержкой __attribute__((weak)).
* При таком замещении:
* - в errnum_initial будет передан первичный код ошибки,
* в результате которой потребовалась отмена транзакции.
* - в errnum_fatal будет передан вторичный код ошибки,
* которая случилась при отмене транзакции и привела к панике.
* - возврат НУЛЯ приведет к вызову системной abort(), ИНАЧЕ выполнение
* будет продолжено с генерацией кода ошибки FPTA_WANNA_DIE. */
FPTA_API int fpta_panic(int errnum_initial, int errnum_fatal);
//----------------------------------------------------------------------------
/* Типы данных для ключей (проиндексированных полей) и значений
* для сравнения в условиях фильтров больше/меньше/равно/не-равно. */
typedef enum fpta_value_type {
fpta_null, /* "Пусто", в том числе для проверки присутствия
* или отсутствия колонки/поля в строке. */
fpta_signed_int, /* Integer со знаком, задается в int64_t */
fpta_unsigned_int, /* Беззнаковый integer, задается в uint64_t */
fpta_datetime, /* Время в форме fptu_time */
fpta_float_point, /* Плавающая точка, задается в double */
fpta_string, /* Строка utf8, задается адресом и длиной,
* без терминирующего нуля!
* (объяснение см внутри fpta_value) */
fpta_binary, /* Бинарные данные, задается адресом и длиной */
fpta_shoved, /* Преобразованный длинный ключ из индекса. */
fpta_begin, /* Псевдо-тип, всегда меньше любого значения.
* Используется при открытии курсора для выборки
* первой записи посредством range_from. */
fpta_end, /* Псевдо-тип, всегда больше любого значения.
* Используется при открытии курсора для выборки
* последней записи посредством range_to. */
fpta_epsilon, /* Псевдо-тип для формирования выборок диапазонов (range query)
минимальной ненулевой ширины, т.е. до следующего или
предыдущего возможного доменного значения типа. */
fpta_invalid /* Псевдо-тип для обозначения разрушенных экземпляров
* или ошибочных результатов */
} fpta_value_type;
/* Структура-контейнер для представления значений.
*
* В том числе для передачи ключей (проиндексированных полей)
* и значений для сравнения в условия больше/меньше/равно/не-равно. */
typedef struct fpta_value {
fpta_value_type type;
unsigned binary_length;
union {
void *binary_data;
int64_t sint;
uint64_t uint;
double fp;
fptu_time datetime;
/* ВАЖНО! К большому сожалению и некоторому неудобству, строка
* здесь НЕ в традиционной для языка "C" форме, а БЕЗ терминирующего
* нуля с явным указанием длины в binary_length.
*
* Причины таковы:
* - fpta_value также используется для возврата значений из индексов;
* - в индексах и ключах строки без терминирующего нуля;
* - поддержка двух форм/типов строк только увеличивает энтропию.
*
* Однако, в реальности терминирующий ноль:
* - будет на конце строк расположенных внутри
* строк таблицы (кортежах);
* - отсутствует в строках от fpta_cursor_key() и fpta_schema_symbol();
* - в остальных случаях - как было подготовлено вашим кодом;
*/
const char *str;
};
#ifdef __cplusplus
/* TODO: constructors from basic types (на самом деле через отдельный
* дочерний класс, так как Clang капризничает и не позволяет возвращать из
* C-linkage функции тип, у которого есть конструкторы C++). */
bool is_number() const {
const int number_mask = (1 << fpta_unsigned_int) | (1 << fpta_signed_int) |
(1 << fpta_float_point);
return (number_mask & (1 << type)) != 0;
}
bool is_negative() const {
assert(is_number());
const int signed_mask = (1 << fpta_signed_int) | (1 << fpta_float_point);
return sint < 0 && (signed_mask & (1 << type));
}
inline fpta_value negative() const;
fpta_value operator-() const { return negative(); }
#endif
} fpta_value;
/* Конструктор value с целочисленным значением. */
static __inline fpta_value fpta_value_sint(int64_t value) {
fpta_value r;
r.type = fpta_signed_int;
r.binary_length = ~0u;
r.sint = value;
return r;
}
/* Конструктор value с беззнаковым целочисленным значением. */
static __inline fpta_value fpta_value_uint(uint64_t value) {
fpta_value r;
r.type = fpta_unsigned_int;
r.binary_length = ~0u;
r.uint = value;
return r;
}
/* Конструктор value для datetime. */
static __inline fpta_value fpta_value_datetime(fptu_time datetime) {
fpta_value r;
r.type = fpta_datetime;
r.binary_length = ~0u;
r.datetime = datetime;
return r;
}
/* Конструктор value с плавающей точкой. */
static __inline fpta_value fpta_value_float(double_t value) {
fpta_value r;
r.type = fpta_float_point;
r.binary_length = ~0u;
r.fp = value;
return r;
}
/* Конструктор value со строковым значением из c-str,
* строка не копируется и не хранится внутри. */
static __inline fpta_value fpta_value_cstr(const char *value) {
size_t length = value ? strlen(value) : 0;
assert(length < INT_MAX);
fpta_value r;
r.type = fpta_string;
r.binary_length = (length < INT_MAX) ? (unsigned)length : INT_MAX;
r.str = value;
return r;
}
/* Конструктор value со строковым значением
* строка не копируется и не хранится внутри. */
static __inline fpta_value fpta_value_string(const char *text, size_t length) {
assert(length == 0 || strnlen(text, length) == length);
assert(length < INT_MAX);
fpta_value r;
r.type = fpta_string;
r.binary_length = (length < INT_MAX) ? (unsigned)length : INT_MAX;
r.str = text;
return r;
}
/* Конструктор value с бинарным/opaque значением,
* даные не копируются и не хранятся внутри. */
static __inline fpta_value fpta_value_binary(const void *data, size_t length) {
assert(length < INT_MAX);
fpta_value r;
r.type = fpta_binary;
r.binary_length = (length < INT_MAX) ? (unsigned)length : INT_MAX;
r.binary_data = (void *)data;
return r;
}
/* Конструктор value с void/null значением. */
static __inline fpta_value fpta_value_null(void) {
fpta_value r;
r.type = fpta_null;
r.binary_length = 0;
r.binary_data = nullptr;
return r;
}
/* Конструктор value с псевдо-значением "начало". */
static __inline fpta_value fpta_value_begin(void) {
fpta_value r;
r.type = fpta_begin;
r.binary_length = ~0u;
r.binary_data = nullptr;
return r;
}
/* Конструктор value с псевдо-значением "конец". */
static __inline fpta_value fpta_value_end(void) {
fpta_value r;
r.type = fpta_end;
r.binary_length = ~0u;
r.binary_data = nullptr;
return r;
}
/* Конструктор value с псевдо-значением "ближайшее отличающееся". */
static __inline fpta_value fpta_value_epsilon(void) {
fpta_value r;
r.type = fpta_epsilon;
r.binary_length = ~0u;
r.binary_data = nullptr;
return r;
}
/* Псевдо-деструктор fpta_value.
* В случае успеха возвращает ноль, иначе код ошибки. */
static __inline int fpta_value_destroy(fpta_value *value) {
if ((unsigned)value->type < (unsigned)fpta_invalid) {
value->type = fpta_invalid;
return FPTA_SUCCESS;
}
return FPTA_EINVAL;
}
/* Значение fpta_value совмещенное с буфером для удобного получения
* составных ключей, используется для вызова fpta_get_column4key(). */
typedef struct fpta_value4key {
fpta_value value;
uint8_t key_buffer[fpta_keybuf_len];
} fpta_value4key;
//----------------------------------------------------------------------------
/* In-place numeric operations with saturation */
typedef enum fpta_inplace {
fpta_saturated_add /* target = min(target + argument, MAX_TYPE_VALUE) */,
fpta_saturated_sub /* target = max(target - argument, MIN_TYPE_VALUE) */,
fpta_saturated_mul /* target = min(target * argument, MAX_TYPE_VALUE) */,
fpta_saturated_div /* target = max(target / argument, MIN_TYPE_VALUE) */,
fpta_min /* target = min(target, argument) */,
fpta_max /* target = max(target, argument) */,
fpta_bes /* Basic Exponential Smoothing, при этом коэффициент сглаживания
* определяется дополнительным (третьим) аргументом.
* https://en.wikipedia.org/wiki/Exponential_smoothing */
,
} fpta_inplace;
//----------------------------------------------------------------------------
/* Designated empty, aka Denoted NILs */
/* Предназначение и использование.
*
* Для части базовых типов выделены значения, которые используются
* для замены "пустоты" внутри fpta, в частности во вторичных индексах
* при физическом отсутствии (NIL) значений соответствующих колонок в строках
* таблиц. Такая замена необходима для сохранения простой и эффективной формы
* индексов, без дополнительных расходов на хранение признаков "пустоты".
*
* Соответственно, для всех типов фиксированной длины возникает проблема
* выбора значений, от использования которых следует отказаться в пользу
* designated empty.
* Одновременно, существует ряд технических сложностей для поддержки NIL
* в индексах с контролем уникальности (чтобы включать такие строки в индекс,
* но не считать их уникальными).
*
* Итоговое соломоново решение (10 заповедей):
* 1) NIL значим для индексов с контролем уникальности,
* т.е. НЕ ДОПУСКАЕТСЯ наличие более одного NIL:
- для первичных индексов NIL является одним из уникальных значений,
и этого нельзя изменить.
- для вторичных индексов NIL является одним из уникальных значений,
либо не индексируется (опция при сборке библиотеки).
* 2) При описании схемы таблиц, каждая колонка помечается
* как nullable или non-nullable.
* 3) Для non-nullable колонок проверяется их наличие (FPTA_COLUMN_MISSING).
* 4) Для индексируемых nullable-колонок НЕ ДОПУСКАЕТСЯ установка
* значений равных designated empty (FPTA_EVALUE),
* а для остальных колонок designated empty НЕ действует.
* 5) При чтении и поиске НЕ ПРОИЗВОДИТСЯ контроль либо "чистка"
* значений равных designated empty.
* 6) Для строк и типов переменной длины допускаются все значения,
* при этом явно различаются NIL и значение нулевой длины.
* 7) Для знаковых целочисленных типов (int32, int64) в качестве designated
* empty используется соответствующие INT_MIN значения.
* 8) Для типов плавающей точки (fp32/float, fp64/double)
* используется NaN-значение (тихое отрицательное бесконечное не-число,
* в бинарном виде «все единицы»).
* 9) Для остальных типов (без знаковых и фиксированных бинарных) designated
* empty зависит от подвида индекса:
* - для obverse-индексов (сравнение от первого байта к последнему):
* designated empty = все нули и 0 для без знаковых целых.
* - для reverse-индексов (сравнение от последнего байта к первому):
* designated empty = все единицы и INT_MAX для без знаковых целых.
* 10) При сортировке (просмотре через курсор) NIL-значения всегда следуют
* в естественном порядке за своим designated empty:
* - NIL меньше не-NIL во всех случаях, КРОМЕ reverse-индексов для
* без знаковых и фиксированных бинарных типов.
* - для без знаковых и фиксированных бинарных и reverse-индексе
* NIL больше не-NIL (так как на самом деле внутри "все единицы").
*
* ВАЖНО: Обратите внимание на наличие функции fpta_confine_number(),
* см описание ниже.
*
* Внутренние механизмы:
* - designated empty нужны только для индексирования NIL-значений,
* остальные ограничения, соглашения и манипуляции являются следствием
* необходимости не допускать или как-то контролировать использование
* значений designated empty.
* - для строк и типов переменной длины, значения в nullable колонках
* дополняются префиксом, с тем чтобы отличать NIL от пустых значений.
* - для плавающей точки учитывается усечение при конвертации из double
* во float, а именно:
* - в качестве designated empty используется бинарное значение
* "все единицы", что соответствует не-сигнальному (тихому)
* отрицательному NaN с максимальной мантиссой.
* - для double/fptu_fp64 дополнительных преобразований не выполняется,
* так как хранимый тип нативно совпадает с double внутри fpta_value;
* - для float/fptu_fp32 необходима конвертация из double изнутри
* fpta_value, при этом float-DENIL (все единицы) будет сформирован
* только если внутри fpta_value было значение double-DENIL.
* Для всех других значений, дающих float-DENIL при конвертации из
* double во float, будет записано ближайшее значение, но отличное от
* float-DENIL ("все единицы" за исключением младшего бита мантиссы).
* - таким образом, при сохранении из fpta_value во float/fptu_fp32
* действуют стандартные правила преобразования, а поведение
* обусловленное designated empty включается только когда в fpta_value
* форме double содержится double-DENIL значение.
*/
#define FPTA_DENIL_SINT32 INT32_MIN
#define FPTA_DENIL_SINT64 INT64_MIN
#define FPTA_DENIL_SINT FPTA_DENIL_SINT64
typedef union {
uint64_t __i;
double __d;
} fpta_fp64_t;
FPTA_API extern const fpta_fp64_t fpta_fp64_denil;
#define FPTA_DENIL_FP64_BIN UINT64_C(0xFFFFffffFFFFffff)
#if !defined(_MSC_VER) /* MSVC provides invalid nanf(), leave it undefined */ \
&& \
!defined(__LCC__) /* https://bugs.mcst.ru/bugzilla/show_bug.cgi?id=5094 */
#define FPTA_DENIL_FP64_MAS "0x000FffffFFFFffff"
#endif /* !MSVC && !LCC */
#if (__GNUC_PREREQ(3, 3) || __has_builtin(nan)) && defined(FPTA_DENIL_FP64_MAS)
#define FPTA_DENIL_FP (-__builtin_nan(FPTA_DENIL_FP64_MAS))
#else
#define FPTA_DENIL_FP (fpta_fp64_denil.__d)
#endif
#define FPTA_DENIL_FIXBIN_OBVERSE UINT8_C(0)
#define FPTA_DENIL_UINT16_OBVERSE UINT16_C(0)
#define FPTA_DENIL_UINT32_OBVERSE UINT32_C(0)
#define FPTA_DENIL_UINT64_OBVERSE UINT64_C(0)
#define FPTA_DENIL_UINT_OBVERSE FPTA_DENIL_UINT64_OBVERSE
#define FPTA_DENIL_FIXBIN_REVERSE UINT8_MAX
#define FPTA_DENIL_UINT16_REVERSE UINT16_MAX
#define FPTA_DENIL_UINT32_REVERSE UINT32_MAX
#define FPTA_DENIL_UINT64_REVERSE UINT64_MAX
#define FPTA_DENIL_UINT_REVERSE FPTA_DENIL_UINT64_REVERSE
#define FPTA_DENIL_DATETIME_BIN FPTU_DENIL_TIME_BIN
#define FPTA_DENIL_DATETIME FPTU_DENIL_TIME
//----------------------------------------------------------------------------
/* Открытие и закрытие БД */
/* Режим сохранности для изменений и БД в целом.
*
* Одновременно выбирает компромисс между производительностью по записи
* и durability. */
typedef enum fpta_durability {
fpta_readonly /* Только чтение, изменения запрещены. */,
fpta_sync /* Полностью синхронная запись на диск.
* Самый надежный и самый медленный режим.
*
* При завершении каждой транзакции формируется сильная точка
* фиксации (выполняется fdatasync).
*
* Производительность по записи определяется скоростью диска,
* ориентировано 500 TPS для SSD. */
,
fpta_lazy /* "Ленивый" режим записи.
* Достаточно быстрый режим, но с риском потери последних
* изменений при аварии.
*
* FIXME: Скорректировать описание после перехода на версию libmdbx
* с "догоняющей" фиксацией.
*
* Периодически формируются сильные точки фиксации. В случае
* системной аварии могут быть потеряны последние транзакции.
*
* Производительность по записи в основном определяется
* скоростью диска, порядка 50K TPS для SSD. */
,
fpta_weak /* Самый быстрый режим, но без гарантий сохранности всей базы
* при аварии.
*
* Сильные точки фиксации не формируются, а существующие стираются
* в процессе сборки мусора.
*
* Ядро ОС, по своему усмотрению, асинхронно записывает измененные
* страницы данных на диск. При этом ядро ОС обещает запись всех
* изменений при сбое приложения, при срабатывании OOM-killer или
* при штатной остановке системы. Но НЕ при сбое в ядре или при
* отключении питания.
*
* Производительность по записи в основном определяется скоростью
* CPU и RAM (более 100K TPS). */
,
} fpta_durability;
/* Дополнительные флаги для оптимизации работы БД.
*
* Все опции можно комбинировать, но совместное использование нескольких
* frendly-опции может как увеличить нагрузку на процессор, так и снизить
* эффективность каждой из них из-за конфликта интересов. */
typedef enum fpta_regime_flags {
fpta_regime_default = 0 /* Режим по-умолчанию */,
fpta_frendly4writeback = 1, /* Для кэша обратной записи. Движок будет
* стремиться повторно использовать страницы в
* LIFO-порядке, что увеличивает эффективность
* работы кэша обратной записи. */
fpta_frendly4hdd = 2 /* Для шпиндельных дисков. Движок будет стремиться
* выделять и повторно использовать
* страницы так, чтобы запись на диск была более
* последовательной. */
,
fpta_frendly4compaction = 4 /* Для освобождения места. Движок будет
* стремиться повторно использовать страницы
* размещенные ближе к началу БД, с тем чтобы
* иметь больше шансов освободить место в конце
* БД и уменьшить размер файла. */
,
fpta_saferam = 8 /* Защита от записи в ОЗУ. Данные будут отображены
* в память в режиме «только для чтения», что
* исключит возможность их непосредственного
* повреждения вследствие некорректно использования
* указателей в коде приложения. */
,
#ifdef FPTA_INTERNALS
/* "Безумный" режим для работы юнит-тестов: Позволяет двойное открытие
БД, неуклюжие индексы и т.п. */
fpta_madness4testing = 2147483648
#endif
} fpta_regime_flags;
FPT_ENUM_FLAG_OPERATORS(fpta_regime_flags)
/* Структура аккумулирующая параметры требуемые для создания новой или
* корректировки геометрии существующей БД. */
typedef struct fpta_db_creation_params {
unsigned params_size /* Размер данной структуры в байтах для контроля
совместимости. */
;
mode_t file_mode /* Маска прав доступа, которая используются в случае создания
новой БД. Значение 0 означает требование открыть
существующую БД, с возвратом ошибки при её отсутствии */
;
intptr_t size_lower,
size_upper /* Минимальный и максимальный размер БД в байтах. Значения
меньше нуля означают "оставить без изменений" при открытии
существующей БД или "по умолчанию" при создании новой БД.
Нулевые значения означают "использовать минимально
возможные" с учётом возможностей движка и содержимого БД. */
;
intptr_t
growth_step /* Шаг приращения размера БД в байтах при нехватке места.
Округляется вверх до размера страницы БД и размера страницы