dataply 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +712 -67
- package/dist/types/core/DataplyAPI.d.ts +22 -8
- package/dist/types/core/LogManager.d.ts +6 -0
- package/dist/types/core/Page.d.ts +43 -0
- package/dist/types/core/PageFileSystem.d.ts +17 -1
- package/dist/types/core/VirtualFileSystem.d.ts +14 -1
- package/dist/types/core/transaction/GlobalTransaction.d.ts +25 -0
- package/dist/types/core/transaction/Transaction.d.ts +5 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +4 -3
- package/readme.md +51 -2
- package/dist/types/core/RowIndexStategy.d.ts +0 -19
- package/dist/types/core/Shard.d.ts +0 -75
- package/dist/types/core/ShareAPI.d.ts +0 -121
package/dist/cjs/index.js
CHANGED
|
@@ -36,6 +36,7 @@ __export(src_exports, {
|
|
|
36
36
|
CacheEntanglementSync: () => CacheEntanglementSync2,
|
|
37
37
|
Dataply: () => Dataply,
|
|
38
38
|
DataplyAPI: () => DataplyAPI,
|
|
39
|
+
GlobalTransaction: () => GlobalTransaction,
|
|
39
40
|
InMemoryStoreStrategyAsync: () => InMemoryStoreStrategyAsync,
|
|
40
41
|
InMemoryStoreStrategySync: () => InMemoryStoreStrategySync,
|
|
41
42
|
InvertedWeakMap: () => InvertedWeakMap,
|
|
@@ -2906,6 +2907,320 @@ var InvertedWeakMap = class {
|
|
|
2906
2907
|
// src/core/DataplyAPI.ts
|
|
2907
2908
|
var import_node_fs3 = __toESM(require("node:fs"));
|
|
2908
2909
|
|
|
2910
|
+
// node_modules/hookall/dist/esm/index.mjs
|
|
2911
|
+
var HookallStore = class extends WeakMap {
|
|
2912
|
+
ensure(obj, key) {
|
|
2913
|
+
if (!this.has(obj)) {
|
|
2914
|
+
const scope2 = {};
|
|
2915
|
+
this.set(obj, scope2);
|
|
2916
|
+
}
|
|
2917
|
+
const scope = this.get(obj);
|
|
2918
|
+
if (!Object.prototype.hasOwnProperty.call(scope, key)) {
|
|
2919
|
+
scope[key] = /* @__PURE__ */ new Map();
|
|
2920
|
+
}
|
|
2921
|
+
return scope[key];
|
|
2922
|
+
}
|
|
2923
|
+
};
|
|
2924
|
+
var Hookall = class _Hookall {
|
|
2925
|
+
static Global = {};
|
|
2926
|
+
static _Store = new HookallStore();
|
|
2927
|
+
beforeHooks;
|
|
2928
|
+
afterHooks;
|
|
2929
|
+
/**
|
|
2930
|
+
* Create hook system. you can pass a target object or undefined.
|
|
2931
|
+
* If you pass a object, the hook system will be work for object locally. You're going to want this kind of usage in general.
|
|
2932
|
+
* If not specified, will be work for global. This is useful when you want to share your work with multiple files.
|
|
2933
|
+
* @param target The object to work with locally. If not specified, will be work for global.
|
|
2934
|
+
*/
|
|
2935
|
+
constructor(target) {
|
|
2936
|
+
this.beforeHooks = _Hookall._Store.ensure(target, "before");
|
|
2937
|
+
this.afterHooks = _Hookall._Store.ensure(target, "after");
|
|
2938
|
+
}
|
|
2939
|
+
_ensureCommand(hooks, command) {
|
|
2940
|
+
if (!hooks.has(command)) {
|
|
2941
|
+
hooks.set(command, []);
|
|
2942
|
+
}
|
|
2943
|
+
return hooks.get(command);
|
|
2944
|
+
}
|
|
2945
|
+
_createWrapper(command, callback, repeat) {
|
|
2946
|
+
return {
|
|
2947
|
+
callback,
|
|
2948
|
+
command,
|
|
2949
|
+
repeat
|
|
2950
|
+
};
|
|
2951
|
+
}
|
|
2952
|
+
_on(hooks, command, callback, repeat) {
|
|
2953
|
+
const wrappers = this._ensureCommand(hooks, command);
|
|
2954
|
+
const wrapper = this._createWrapper(command, callback, repeat);
|
|
2955
|
+
wrappers.unshift(wrapper);
|
|
2956
|
+
}
|
|
2957
|
+
/**
|
|
2958
|
+
* You register a preprocessing function, which is called before the callback function of the `trigger` method.
|
|
2959
|
+
* The value returned by this function is passed as a parameter to the `trigger` method's callback function.
|
|
2960
|
+
* If you register multiple preprocessing functions, they are executed in order, with each function receiving the value returned by the previous one as a parameter.
|
|
2961
|
+
* @param command Command to work.
|
|
2962
|
+
* @param callback Preprocessing function to register.
|
|
2963
|
+
*/
|
|
2964
|
+
onBefore(command, callback) {
|
|
2965
|
+
this._on(this.beforeHooks, command, callback, -1);
|
|
2966
|
+
return this;
|
|
2967
|
+
}
|
|
2968
|
+
/**
|
|
2969
|
+
* Similar to the `onBefore` method, but it only runs once.
|
|
2970
|
+
* For more details, please refer to the `onBefore` method.
|
|
2971
|
+
* @param command Command to work.
|
|
2972
|
+
* @param callback Preprocessing function to register.
|
|
2973
|
+
*/
|
|
2974
|
+
onceBefore(command, callback) {
|
|
2975
|
+
this._on(this.beforeHooks, command, callback, 1);
|
|
2976
|
+
return this;
|
|
2977
|
+
}
|
|
2978
|
+
/**
|
|
2979
|
+
* You register a post-processing function which is called after the callback function of the `trigger` method finishes.
|
|
2980
|
+
* This function receives the value returned by the `trigger` method's callback function as a parameter.
|
|
2981
|
+
* If you register multiple post-processing functions, they are executed in order, with each function receiving the value returned by the previous one as a parameter.
|
|
2982
|
+
* @param command Command to work.
|
|
2983
|
+
* @param callback Post-preprocessing function to register.
|
|
2984
|
+
*/
|
|
2985
|
+
onAfter(command, callback) {
|
|
2986
|
+
this._on(this.afterHooks, command, callback, -1);
|
|
2987
|
+
return this;
|
|
2988
|
+
}
|
|
2989
|
+
/**
|
|
2990
|
+
* Similar to the `onAfter` method, but it only runs once.
|
|
2991
|
+
* For more details, please refer to the `onAfter` method.
|
|
2992
|
+
* @param command Command to work.
|
|
2993
|
+
* @param callback Post-preprocessing function to register.
|
|
2994
|
+
*/
|
|
2995
|
+
onceAfter(command, callback) {
|
|
2996
|
+
this._on(this.afterHooks, command, callback, 1);
|
|
2997
|
+
return this;
|
|
2998
|
+
}
|
|
2999
|
+
_off(hooks, command, callback) {
|
|
3000
|
+
const wrappers = this._ensureCommand(hooks, command);
|
|
3001
|
+
if (callback) {
|
|
3002
|
+
const i = wrappers.findIndex((wrapper) => wrapper.callback === callback);
|
|
3003
|
+
if (i !== -1) {
|
|
3004
|
+
wrappers.splice(i, 1);
|
|
3005
|
+
}
|
|
3006
|
+
} else {
|
|
3007
|
+
wrappers.length = 0;
|
|
3008
|
+
}
|
|
3009
|
+
return this;
|
|
3010
|
+
}
|
|
3011
|
+
/**
|
|
3012
|
+
* You remove the preprocessing functions registered with `onBefore` or `onceBefore` methods.
|
|
3013
|
+
* If you don't specify a callback parameter, it removes all preprocessing functions registered for that command.
|
|
3014
|
+
* @param command Commands with preprocessing functions to be deleted.
|
|
3015
|
+
* @param callback Preprocessing function to be deleted.
|
|
3016
|
+
*/
|
|
3017
|
+
offBefore(command, callback) {
|
|
3018
|
+
this._off(this.beforeHooks, command, callback);
|
|
3019
|
+
return this;
|
|
3020
|
+
}
|
|
3021
|
+
/**
|
|
3022
|
+
* You remove the post-preprocessing functions registered with `onAfter` or `onceAfter` methods.
|
|
3023
|
+
* If you don't specify a callback parameter, it removes all post-preprocessing functions registered for that command.
|
|
3024
|
+
* @param command Commands with post-preprocessing functions to be deleted.
|
|
3025
|
+
* @param callback post-Preprocessing function to be deleted.
|
|
3026
|
+
*/
|
|
3027
|
+
offAfter(command, callback) {
|
|
3028
|
+
this._off(this.afterHooks, command, callback);
|
|
3029
|
+
return this;
|
|
3030
|
+
}
|
|
3031
|
+
async _hookWith(hooks, command, value, ...params) {
|
|
3032
|
+
let wrappers = this._ensureCommand(hooks, command);
|
|
3033
|
+
let i = wrappers.length;
|
|
3034
|
+
while (i--) {
|
|
3035
|
+
const wrapper = wrappers[i];
|
|
3036
|
+
value = await wrapper.callback(value, ...params);
|
|
3037
|
+
wrapper.repeat -= 1;
|
|
3038
|
+
if (wrapper.repeat === 0) {
|
|
3039
|
+
this._off(hooks, command, wrapper.callback);
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
3042
|
+
return value;
|
|
3043
|
+
}
|
|
3044
|
+
/**
|
|
3045
|
+
* You execute the callback function provided as a parameter. This callback function receives the 'initialValue' parameter.
|
|
3046
|
+
*
|
|
3047
|
+
* If preprocessing functions are registered, they run first, and the value returned by the preprocessing functions becomes the 'initialValue' parameter.
|
|
3048
|
+
* After the callback function finishes, post-processing functions are called.
|
|
3049
|
+
* These post-processing functions receive the value returned by the callback function as a parameter and run sequentially.
|
|
3050
|
+
*
|
|
3051
|
+
* The final value returned becomes the result of the `trigger` method.
|
|
3052
|
+
* @param command Command to work.
|
|
3053
|
+
* @param initialValue Initial value to be passed to the callback function.
|
|
3054
|
+
* @param callback The callback function to be executed.
|
|
3055
|
+
*/
|
|
3056
|
+
async trigger(command, initialValue, callback, ...params) {
|
|
3057
|
+
let value;
|
|
3058
|
+
value = await this._hookWith(this.beforeHooks, command, initialValue, ...params);
|
|
3059
|
+
value = await callback(value, ...params);
|
|
3060
|
+
value = await this._hookWith(this.afterHooks, command, value, ...params);
|
|
3061
|
+
return value;
|
|
3062
|
+
}
|
|
3063
|
+
};
|
|
3064
|
+
function useHookall(target = Hookall.Global) {
|
|
3065
|
+
return new Hookall(target);
|
|
3066
|
+
}
|
|
3067
|
+
var HookallStore2 = class extends WeakMap {
|
|
3068
|
+
ensure(obj, key) {
|
|
3069
|
+
if (!this.has(obj)) {
|
|
3070
|
+
const scope2 = {};
|
|
3071
|
+
this.set(obj, scope2);
|
|
3072
|
+
}
|
|
3073
|
+
const scope = this.get(obj);
|
|
3074
|
+
if (!Object.prototype.hasOwnProperty.call(scope, key)) {
|
|
3075
|
+
scope[key] = /* @__PURE__ */ new Map();
|
|
3076
|
+
}
|
|
3077
|
+
return scope[key];
|
|
3078
|
+
}
|
|
3079
|
+
};
|
|
3080
|
+
var HookallSync = class _HookallSync {
|
|
3081
|
+
static Global = {};
|
|
3082
|
+
static _Store = new HookallStore2();
|
|
3083
|
+
beforeHooks;
|
|
3084
|
+
afterHooks;
|
|
3085
|
+
/**
|
|
3086
|
+
* Create hook system. you can pass a target object or undefined.
|
|
3087
|
+
* If you pass a object, the hook system will be work for object locally. You're going to want this kind of usage in general.
|
|
3088
|
+
* If not specified, will be work for global. This is useful when you want to share your work with multiple files.
|
|
3089
|
+
* @param target The object to work with locally. If not specified, will be work for global.
|
|
3090
|
+
*/
|
|
3091
|
+
constructor(target) {
|
|
3092
|
+
this.beforeHooks = _HookallSync._Store.ensure(target, "before");
|
|
3093
|
+
this.afterHooks = _HookallSync._Store.ensure(target, "after");
|
|
3094
|
+
}
|
|
3095
|
+
_ensureCommand(hooks, command) {
|
|
3096
|
+
if (!hooks.has(command)) {
|
|
3097
|
+
hooks.set(command, []);
|
|
3098
|
+
}
|
|
3099
|
+
return hooks.get(command);
|
|
3100
|
+
}
|
|
3101
|
+
_createWrapper(command, callback, repeat) {
|
|
3102
|
+
return {
|
|
3103
|
+
callback,
|
|
3104
|
+
command,
|
|
3105
|
+
repeat
|
|
3106
|
+
};
|
|
3107
|
+
}
|
|
3108
|
+
_on(hooks, command, callback, repeat) {
|
|
3109
|
+
const wrappers = this._ensureCommand(hooks, command);
|
|
3110
|
+
const wrapper = this._createWrapper(command, callback, repeat);
|
|
3111
|
+
wrappers.unshift(wrapper);
|
|
3112
|
+
}
|
|
3113
|
+
/**
|
|
3114
|
+
* You register a preprocessing function, which is called before the callback function of the `trigger` method.
|
|
3115
|
+
* The value returned by this function is passed as a parameter to the `trigger` method's callback function.
|
|
3116
|
+
* If you register multiple preprocessing functions, they are executed in order, with each function receiving the value returned by the previous one as a parameter.
|
|
3117
|
+
* @param command Command to work.
|
|
3118
|
+
* @param callback Preprocessing function to register.
|
|
3119
|
+
*/
|
|
3120
|
+
onBefore(command, callback) {
|
|
3121
|
+
this._on(this.beforeHooks, command, callback, -1);
|
|
3122
|
+
return this;
|
|
3123
|
+
}
|
|
3124
|
+
/**
|
|
3125
|
+
* Similar to the `onBefore` method, but it only runs once.
|
|
3126
|
+
* For more details, please refer to the `onBefore` method.
|
|
3127
|
+
* @param command Command to work.
|
|
3128
|
+
* @param callback Preprocessing function to register.
|
|
3129
|
+
*/
|
|
3130
|
+
onceBefore(command, callback) {
|
|
3131
|
+
this._on(this.beforeHooks, command, callback, 1);
|
|
3132
|
+
return this;
|
|
3133
|
+
}
|
|
3134
|
+
/**
|
|
3135
|
+
* You register a post-processing function which is called after the callback function of the `trigger` method finishes.
|
|
3136
|
+
* This function receives the value returned by the `trigger` method's callback function as a parameter.
|
|
3137
|
+
* If you register multiple post-processing functions, they are executed in order, with each function receiving the value returned by the previous one as a parameter.
|
|
3138
|
+
* @param command Command to work.
|
|
3139
|
+
* @param callback Post-preprocessing function to register.
|
|
3140
|
+
*/
|
|
3141
|
+
onAfter(command, callback) {
|
|
3142
|
+
this._on(this.afterHooks, command, callback, -1);
|
|
3143
|
+
return this;
|
|
3144
|
+
}
|
|
3145
|
+
/**
|
|
3146
|
+
* Similar to the `onAfter` method, but it only runs once.
|
|
3147
|
+
* For more details, please refer to the `onAfter` method.
|
|
3148
|
+
* @param command Command to work.
|
|
3149
|
+
* @param callback Post-preprocessing function to register.
|
|
3150
|
+
*/
|
|
3151
|
+
onceAfter(command, callback) {
|
|
3152
|
+
this._on(this.afterHooks, command, callback, 1);
|
|
3153
|
+
return this;
|
|
3154
|
+
}
|
|
3155
|
+
_off(hooks, command, callback) {
|
|
3156
|
+
const wrappers = this._ensureCommand(hooks, command);
|
|
3157
|
+
if (callback) {
|
|
3158
|
+
const i = wrappers.findIndex((wrapper) => wrapper.callback === callback);
|
|
3159
|
+
if (i !== -1) {
|
|
3160
|
+
wrappers.splice(i, 1);
|
|
3161
|
+
}
|
|
3162
|
+
} else {
|
|
3163
|
+
wrappers.length = 0;
|
|
3164
|
+
}
|
|
3165
|
+
return this;
|
|
3166
|
+
}
|
|
3167
|
+
/**
|
|
3168
|
+
* You remove the preprocessing functions registered with `onBefore` or `onceBefore` methods.
|
|
3169
|
+
* If you don't specify a callback parameter, it removes all preprocessing functions registered for that command.
|
|
3170
|
+
* @param command Commands with preprocessing functions to be deleted.
|
|
3171
|
+
* @param callback Preprocessing function to be deleted.
|
|
3172
|
+
*/
|
|
3173
|
+
offBefore(command, callback) {
|
|
3174
|
+
this._off(this.beforeHooks, command, callback);
|
|
3175
|
+
return this;
|
|
3176
|
+
}
|
|
3177
|
+
/**
|
|
3178
|
+
* You remove the post-preprocessing functions registered with `onAfter` or `onceAfter` methods.
|
|
3179
|
+
* If you don't specify a callback parameter, it removes all post-preprocessing functions registered for that command.
|
|
3180
|
+
* @param command Commands with post-preprocessing functions to be deleted.
|
|
3181
|
+
* @param callback post-Preprocessing function to be deleted.
|
|
3182
|
+
*/
|
|
3183
|
+
offAfter(command, callback) {
|
|
3184
|
+
this._off(this.afterHooks, command, callback);
|
|
3185
|
+
return this;
|
|
3186
|
+
}
|
|
3187
|
+
_hookWith(hooks, command, value, ...params) {
|
|
3188
|
+
let wrappers = this._ensureCommand(hooks, command);
|
|
3189
|
+
let i = wrappers.length;
|
|
3190
|
+
while (i--) {
|
|
3191
|
+
const wrapper = wrappers[i];
|
|
3192
|
+
value = wrapper.callback(value, ...params);
|
|
3193
|
+
wrapper.repeat -= 1;
|
|
3194
|
+
if (wrapper.repeat === 0) {
|
|
3195
|
+
this._off(hooks, command, wrapper.callback);
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
return value;
|
|
3199
|
+
}
|
|
3200
|
+
/**
|
|
3201
|
+
* You execute the callback function provided as a parameter. This callback function receives the 'initialValue' parameter.
|
|
3202
|
+
*
|
|
3203
|
+
* If preprocessing functions are registered, they run first, and the value returned by the preprocessing functions becomes the 'initialValue' parameter.
|
|
3204
|
+
* After the callback function finishes, post-processing functions are called.
|
|
3205
|
+
* These post-processing functions receive the value returned by the callback function as a parameter and run sequentially.
|
|
3206
|
+
*
|
|
3207
|
+
* The final value returned becomes the result of the `trigger` method.
|
|
3208
|
+
* @param command Command to work.
|
|
3209
|
+
* @param initialValue Initial value to be passed to the callback function.
|
|
3210
|
+
* @param callback The callback function to be executed.
|
|
3211
|
+
*/
|
|
3212
|
+
trigger(command, initialValue, callback, ...params) {
|
|
3213
|
+
let value;
|
|
3214
|
+
value = this._hookWith(this.beforeHooks, command, initialValue, ...params);
|
|
3215
|
+
value = callback(value, ...params);
|
|
3216
|
+
value = this._hookWith(this.afterHooks, command, value, ...params);
|
|
3217
|
+
return value;
|
|
3218
|
+
}
|
|
3219
|
+
};
|
|
3220
|
+
function useHookallSync(target = HookallSync.Global) {
|
|
3221
|
+
return new HookallSync(target);
|
|
3222
|
+
}
|
|
3223
|
+
|
|
2909
3224
|
// src/utils/numberToBytes.ts
|
|
2910
3225
|
function numberToBytes(value, buffer, offset = 0, length = buffer.length) {
|
|
2911
3226
|
if (length === 4) {
|
|
@@ -3776,11 +4091,16 @@ var MetadataPageManager = class _MetadataPageManager extends PageManager {
|
|
|
3776
4091
|
OFFSET_ROOT_INDEX_ORDER: 126,
|
|
3777
4092
|
OFFSET_LAST_INSERT_PAGE_ID: 130,
|
|
3778
4093
|
OFFSET_LAST_ROW_PK: 134,
|
|
4094
|
+
OFFSET_BITMAP_PAGE_ID: 140,
|
|
4095
|
+
OFFSET_FREE_PAGE_ID: 144,
|
|
3779
4096
|
SIZE_PAGE_COUNT: 4,
|
|
3780
4097
|
SIZE_PAGE_SIZE: 4,
|
|
3781
4098
|
SIZE_ROOT_INDEX_PAGE_ID: 4,
|
|
3782
4099
|
SIZE_ROOT_INDEX_ORDER: 4,
|
|
3783
|
-
SIZE_LAST_INSERT_PAGE_ID: 4
|
|
4100
|
+
SIZE_LAST_INSERT_PAGE_ID: 4,
|
|
4101
|
+
SIZE_ROW_PK: 6,
|
|
4102
|
+
SIZE_BITMAP_PAGE_ID: 4,
|
|
4103
|
+
SIZE_FREE_PAGE_ID: 4
|
|
3784
4104
|
};
|
|
3785
4105
|
/**
|
|
3786
4106
|
* Checks if the page type is `MetadataPage`.
|
|
@@ -3882,7 +4202,7 @@ var MetadataPageManager = class _MetadataPageManager extends PageManager {
|
|
|
3882
4202
|
return bytesToNumber(
|
|
3883
4203
|
page,
|
|
3884
4204
|
_MetadataPageManager.CONSTANT.OFFSET_LAST_ROW_PK,
|
|
3885
|
-
|
|
4205
|
+
_MetadataPageManager.CONSTANT.SIZE_ROW_PK
|
|
3886
4206
|
);
|
|
3887
4207
|
}
|
|
3888
4208
|
/**
|
|
@@ -3894,8 +4214,33 @@ var MetadataPageManager = class _MetadataPageManager extends PageManager {
|
|
|
3894
4214
|
return bytesToNumber(
|
|
3895
4215
|
page,
|
|
3896
4216
|
_MetadataPageManager.CONSTANT.OFFSET_ROW_COUNT,
|
|
3897
|
-
|
|
4217
|
+
_MetadataPageManager.CONSTANT.SIZE_ROW_PK
|
|
4218
|
+
);
|
|
4219
|
+
}
|
|
4220
|
+
/**
|
|
4221
|
+
* Returns the ID of the bitmap page.
|
|
4222
|
+
* @param page Page data
|
|
4223
|
+
* @returns Bitmap page ID
|
|
4224
|
+
*/
|
|
4225
|
+
getBitmapPageId(page) {
|
|
4226
|
+
return bytesToNumber(
|
|
4227
|
+
page,
|
|
4228
|
+
_MetadataPageManager.CONSTANT.OFFSET_BITMAP_PAGE_ID,
|
|
4229
|
+
_MetadataPageManager.CONSTANT.SIZE_BITMAP_PAGE_ID
|
|
4230
|
+
);
|
|
4231
|
+
}
|
|
4232
|
+
/**
|
|
4233
|
+
* Returns the ID of the free page.
|
|
4234
|
+
* @param page Page data
|
|
4235
|
+
* @returns Free page ID
|
|
4236
|
+
*/
|
|
4237
|
+
getFreePageId(page) {
|
|
4238
|
+
const id = bytesToNumber(
|
|
4239
|
+
page,
|
|
4240
|
+
_MetadataPageManager.CONSTANT.OFFSET_FREE_PAGE_ID,
|
|
4241
|
+
_MetadataPageManager.CONSTANT.SIZE_FREE_PAGE_ID
|
|
3898
4242
|
);
|
|
4243
|
+
return id === 4294967295 ? -1 : id;
|
|
3899
4244
|
}
|
|
3900
4245
|
/**
|
|
3901
4246
|
* Sets the number of pages stored in the database.
|
|
@@ -3997,6 +4342,32 @@ var MetadataPageManager = class _MetadataPageManager extends PageManager {
|
|
|
3997
4342
|
Row.CONSTANT.SIZE_PK
|
|
3998
4343
|
);
|
|
3999
4344
|
}
|
|
4345
|
+
/**
|
|
4346
|
+
* Sets the ID of the bitmap page.
|
|
4347
|
+
* @param page Page data
|
|
4348
|
+
* @param bitmapPageId Bitmap page ID
|
|
4349
|
+
*/
|
|
4350
|
+
setBitmapPageId(page, bitmapPageId) {
|
|
4351
|
+
numberToBytes(
|
|
4352
|
+
bitmapPageId,
|
|
4353
|
+
page,
|
|
4354
|
+
_MetadataPageManager.CONSTANT.OFFSET_BITMAP_PAGE_ID,
|
|
4355
|
+
_MetadataPageManager.CONSTANT.SIZE_BITMAP_PAGE_ID
|
|
4356
|
+
);
|
|
4357
|
+
}
|
|
4358
|
+
/**
|
|
4359
|
+
* Sets the ID of the free page.
|
|
4360
|
+
* @param page Page data
|
|
4361
|
+
* @param pageId Free page ID
|
|
4362
|
+
*/
|
|
4363
|
+
setFreePageId(page, pageId) {
|
|
4364
|
+
numberToBytes(
|
|
4365
|
+
pageId,
|
|
4366
|
+
page,
|
|
4367
|
+
_MetadataPageManager.CONSTANT.OFFSET_FREE_PAGE_ID,
|
|
4368
|
+
_MetadataPageManager.CONSTANT.SIZE_FREE_PAGE_ID
|
|
4369
|
+
);
|
|
4370
|
+
}
|
|
4000
4371
|
};
|
|
4001
4372
|
var BitmapPageManager = class _BitmapPageManager extends PageManager {
|
|
4002
4373
|
get pageType() {
|
|
@@ -4027,6 +4398,31 @@ var BitmapPageManager = class _BitmapPageManager extends PageManager {
|
|
|
4027
4398
|
isEmptyPage(page, index) {
|
|
4028
4399
|
return bytesToNumber(page, index, 1) === 0;
|
|
4029
4400
|
}
|
|
4401
|
+
/**
|
|
4402
|
+
* Gets a bit from the bitmap page.
|
|
4403
|
+
* @param page Page data
|
|
4404
|
+
* @param index Bit index
|
|
4405
|
+
* @returns boolean indicating if the bit is set
|
|
4406
|
+
*/
|
|
4407
|
+
getBit(page, index) {
|
|
4408
|
+
const bitOffset = Math.floor(index / 8);
|
|
4409
|
+
const offset = _BitmapPageManager.CONSTANT.SIZE_PAGE_HEADER + bitOffset;
|
|
4410
|
+
const value = bytesToNumber(page, offset, 1);
|
|
4411
|
+
return getBit(value, index % 8);
|
|
4412
|
+
}
|
|
4413
|
+
/**
|
|
4414
|
+
* Sets a bit in the bitmap page.
|
|
4415
|
+
* @param page Page data
|
|
4416
|
+
* @param index Bit index
|
|
4417
|
+
* @param flag boolean indicating if the bit is set
|
|
4418
|
+
*/
|
|
4419
|
+
setBit(page, index, flag) {
|
|
4420
|
+
const bitOffset = Math.floor(index / 8);
|
|
4421
|
+
const offset = _BitmapPageManager.CONSTANT.SIZE_PAGE_HEADER + bitOffset;
|
|
4422
|
+
const value = bytesToNumber(page, offset, 1);
|
|
4423
|
+
const newValue = setBit(value, index % 8, flag);
|
|
4424
|
+
numberToBytes(newValue, page, offset, 1);
|
|
4425
|
+
}
|
|
4030
4426
|
};
|
|
4031
4427
|
var OverflowPageManager = class _OverflowPageManager extends PageManager {
|
|
4032
4428
|
get pageType() {
|
|
@@ -4242,9 +4638,33 @@ var LogManager = class {
|
|
|
4242
4638
|
});
|
|
4243
4639
|
});
|
|
4244
4640
|
}
|
|
4641
|
+
/**
|
|
4642
|
+
* Writes a commit marker to the log file.
|
|
4643
|
+
* This indicates that the preceding logs are part of a committed transaction.
|
|
4644
|
+
*/
|
|
4645
|
+
async writeCommitMarker() {
|
|
4646
|
+
if (this.fd === null) {
|
|
4647
|
+
this.open();
|
|
4648
|
+
}
|
|
4649
|
+
this.view.setUint32(0, 4294967295, true);
|
|
4650
|
+
this.buffer.fill(0, 4);
|
|
4651
|
+
await new Promise((resolve, reject) => {
|
|
4652
|
+
import_node_fs.default.write(this.fd, this.buffer, 0, this.entrySize, null, (err) => {
|
|
4653
|
+
if (err) return reject(err);
|
|
4654
|
+
resolve();
|
|
4655
|
+
});
|
|
4656
|
+
});
|
|
4657
|
+
await new Promise((resolve, reject) => {
|
|
4658
|
+
import_node_fs.default.fsync(this.fd, (err) => {
|
|
4659
|
+
if (err) return reject(err);
|
|
4660
|
+
resolve();
|
|
4661
|
+
});
|
|
4662
|
+
});
|
|
4663
|
+
}
|
|
4245
4664
|
/**
|
|
4246
4665
|
* Reads the log file to recover the page map.
|
|
4247
4666
|
* Runs synchronously as it is called by the VFS constructor.
|
|
4667
|
+
* Only returns pages from committed transactions (ended with a commit marker).
|
|
4248
4668
|
* @returns Recovered page map
|
|
4249
4669
|
*/
|
|
4250
4670
|
readAllSync() {
|
|
@@ -4254,11 +4674,19 @@ var LogManager = class {
|
|
|
4254
4674
|
const restoredPages = /* @__PURE__ */ new Map();
|
|
4255
4675
|
const currentFileSize = import_node_fs.default.fstatSync(this.fd).size;
|
|
4256
4676
|
let offset = 0;
|
|
4677
|
+
let pendingPages = /* @__PURE__ */ new Map();
|
|
4257
4678
|
while (offset + this.entrySize <= currentFileSize) {
|
|
4258
4679
|
import_node_fs.default.readSync(this.fd, this.buffer, 0, this.entrySize, offset);
|
|
4259
4680
|
const pageId = this.view.getUint32(0, true);
|
|
4260
|
-
|
|
4261
|
-
|
|
4681
|
+
if (pageId === 4294967295) {
|
|
4682
|
+
for (const [pId, pData] of pendingPages) {
|
|
4683
|
+
restoredPages.set(pId, pData);
|
|
4684
|
+
}
|
|
4685
|
+
pendingPages.clear();
|
|
4686
|
+
} else {
|
|
4687
|
+
const pageData = this.buffer.slice(4, 4 + this.pageSize);
|
|
4688
|
+
pendingPages.set(pageId, pageData);
|
|
4689
|
+
}
|
|
4262
4690
|
offset += this.entrySize;
|
|
4263
4691
|
}
|
|
4264
4692
|
return restoredPages;
|
|
@@ -4360,13 +4788,13 @@ var VirtualFileSystem = class {
|
|
|
4360
4788
|
}
|
|
4361
4789
|
}
|
|
4362
4790
|
/**
|
|
4363
|
-
*
|
|
4791
|
+
* Prepares the transaction for commit (Phase 1).
|
|
4792
|
+
* Writes dirty pages to WAL but does not update the main database file.
|
|
4364
4793
|
* @param tx Transaction
|
|
4365
4794
|
*/
|
|
4366
|
-
async
|
|
4795
|
+
async prepareCommit(tx) {
|
|
4367
4796
|
const dirtyPages = tx.__getDirtyPages();
|
|
4368
4797
|
if (dirtyPages.size === 0) {
|
|
4369
|
-
this.cleanupTransaction(tx);
|
|
4370
4798
|
return;
|
|
4371
4799
|
}
|
|
4372
4800
|
const dirtyPageMap = /* @__PURE__ */ new Map();
|
|
@@ -4379,6 +4807,21 @@ var VirtualFileSystem = class {
|
|
|
4379
4807
|
if (this.logManager && dirtyPageMap.size > 0) {
|
|
4380
4808
|
await this.logManager.append(dirtyPageMap);
|
|
4381
4809
|
}
|
|
4810
|
+
}
|
|
4811
|
+
/**
|
|
4812
|
+
* Finalizes the transaction commit (Phase 2).
|
|
4813
|
+
* Writes commit marker to WAL and updates the main database file (Checkpoint).
|
|
4814
|
+
* @param tx Transaction
|
|
4815
|
+
*/
|
|
4816
|
+
async finalizeCommit(tx) {
|
|
4817
|
+
const dirtyPages = tx.__getDirtyPages();
|
|
4818
|
+
if (dirtyPages.size === 0) {
|
|
4819
|
+
this.cleanupTransaction(tx);
|
|
4820
|
+
return;
|
|
4821
|
+
}
|
|
4822
|
+
if (this.logManager) {
|
|
4823
|
+
await this.logManager.writeCommitMarker();
|
|
4824
|
+
}
|
|
4382
4825
|
const sortedPages = Array.from(dirtyPages).sort((a, b) => a - b);
|
|
4383
4826
|
const promises = [];
|
|
4384
4827
|
for (const pageId of sortedPages) {
|
|
@@ -4401,6 +4844,15 @@ var VirtualFileSystem = class {
|
|
|
4401
4844
|
}
|
|
4402
4845
|
this.cleanupTransaction(tx);
|
|
4403
4846
|
}
|
|
4847
|
+
/**
|
|
4848
|
+
* Commits the transaction (Single Phase).
|
|
4849
|
+
* Wrapper for prepare + finalize for backward compatibility.
|
|
4850
|
+
* @param tx Transaction
|
|
4851
|
+
*/
|
|
4852
|
+
async commit(tx) {
|
|
4853
|
+
await this.prepareCommit(tx);
|
|
4854
|
+
await this.finalizeCommit(tx);
|
|
4855
|
+
}
|
|
4404
4856
|
/**
|
|
4405
4857
|
* Rolls back the transaction.
|
|
4406
4858
|
* @param tx Transaction
|
|
@@ -4448,8 +4900,8 @@ var VirtualFileSystem = class {
|
|
|
4448
4900
|
* @param position Start position in file
|
|
4449
4901
|
*/
|
|
4450
4902
|
_writeAsync(handle, buffer, offset, length, position) {
|
|
4451
|
-
if (position + length >
|
|
4452
|
-
return Promise.reject(new Error(`[Safety Limit] File write exceeds
|
|
4903
|
+
if (position + length > 512 * 1024 * 1024) {
|
|
4904
|
+
return Promise.reject(new Error(`[Safety Limit] File write exceeds 512MB limit at position ${position}`));
|
|
4453
4905
|
}
|
|
4454
4906
|
return new Promise((resolve, reject) => {
|
|
4455
4907
|
import_node_fs2.default.write(handle, buffer, offset, length, position, (err, bytesWritten) => {
|
|
@@ -4627,6 +5079,43 @@ var PageFileSystem = class {
|
|
|
4627
5079
|
pageFactory = new PageManagerFactory();
|
|
4628
5080
|
vfs;
|
|
4629
5081
|
pageManagerFactory;
|
|
5082
|
+
/**
|
|
5083
|
+
* Updates the bitmap status for a specific page.
|
|
5084
|
+
* @param pageId The ID of the page to update
|
|
5085
|
+
* @param isFree True to mark as free, false to mark as used
|
|
5086
|
+
* @param tx Transaction
|
|
5087
|
+
*/
|
|
5088
|
+
async updateBitmap(pageId, isFree, tx) {
|
|
5089
|
+
const metadata = await this.getMetadata(tx);
|
|
5090
|
+
const metadataManager = this.pageFactory.getManager(metadata);
|
|
5091
|
+
const bitmapPageId = metadataManager.getBitmapPageId(metadata);
|
|
5092
|
+
const headerSize = PageManager.CONSTANT.SIZE_PAGE_HEADER;
|
|
5093
|
+
const capacityPerBitmapPage = (this.pageSize - headerSize) * 8;
|
|
5094
|
+
let currentBitmapPageId = bitmapPageId;
|
|
5095
|
+
let targetBitIndex = pageId;
|
|
5096
|
+
while (targetBitIndex >= capacityPerBitmapPage) {
|
|
5097
|
+
const currentBitmapPage = await this.get(currentBitmapPageId, tx);
|
|
5098
|
+
const manager = this.pageFactory.getManager(currentBitmapPage);
|
|
5099
|
+
targetBitIndex -= capacityPerBitmapPage;
|
|
5100
|
+
const nextPageId = manager.getNextPageId(currentBitmapPage);
|
|
5101
|
+
if (nextPageId === -1) {
|
|
5102
|
+
if (!isFree) {
|
|
5103
|
+
throw new Error("Bitmap page not found for reused page");
|
|
5104
|
+
}
|
|
5105
|
+
const newBitmapPageId = await this.appendNewPage(PageManager.CONSTANT.PAGE_TYPE_BITMAP, tx);
|
|
5106
|
+
manager.setNextPageId(currentBitmapPage, newBitmapPageId);
|
|
5107
|
+
await this.setPage(currentBitmapPageId, currentBitmapPage, tx);
|
|
5108
|
+
currentBitmapPageId = newBitmapPageId;
|
|
5109
|
+
} else {
|
|
5110
|
+
currentBitmapPageId = nextPageId;
|
|
5111
|
+
}
|
|
5112
|
+
}
|
|
5113
|
+
await tx.__acquireWriteLock(currentBitmapPageId);
|
|
5114
|
+
const targetBitmapPage = await this.get(currentBitmapPageId, tx);
|
|
5115
|
+
const bitmapManager = this.pageFactory.getManager(targetBitmapPage);
|
|
5116
|
+
bitmapManager.setBit(targetBitmapPage, targetBitIndex, isFree);
|
|
5117
|
+
await this.setPage(currentBitmapPageId, targetBitmapPage, tx);
|
|
5118
|
+
}
|
|
4630
5119
|
/**
|
|
4631
5120
|
* VFS 인스턴스를 반환합니다.
|
|
4632
5121
|
* Transaction 생성 시 사용됩니다.
|
|
@@ -4735,12 +5224,28 @@ var PageFileSystem = class {
|
|
|
4735
5224
|
}
|
|
4736
5225
|
/**
|
|
4737
5226
|
* Appends and inserts a new page.
|
|
4738
|
-
*
|
|
5227
|
+
* If a free page is available in the free list, it reuses it.
|
|
5228
|
+
* Otherwise, it appends a new page to the end of the file.
|
|
5229
|
+
* @returns Created or reused page ID
|
|
4739
5230
|
*/
|
|
4740
5231
|
async appendNewPage(pageType = PageManager.CONSTANT.PAGE_TYPE_EMPTY, tx) {
|
|
4741
5232
|
await tx.__acquireWriteLock(0);
|
|
4742
5233
|
const metadata = await this.getMetadata(tx);
|
|
4743
5234
|
const metadataManager = this.pageFactory.getManager(metadata);
|
|
5235
|
+
const freePageId = metadataManager.getFreePageId(metadata);
|
|
5236
|
+
if (freePageId !== -1) {
|
|
5237
|
+
const reusedPageId = freePageId;
|
|
5238
|
+
const reusedPage = await this.get(reusedPageId, tx);
|
|
5239
|
+
const reusedPageManager = this.pageFactory.getManager(reusedPage);
|
|
5240
|
+
const nextFreePageId = reusedPageManager.getNextPageId(reusedPage);
|
|
5241
|
+
metadataManager.setFreePageId(metadata, nextFreePageId);
|
|
5242
|
+
await this.setPage(0, metadata, tx);
|
|
5243
|
+
await this.updateBitmap(reusedPageId, false, tx);
|
|
5244
|
+
const manager2 = this.pageFactory.getManagerFromType(pageType);
|
|
5245
|
+
const newPage2 = manager2.create(this.pageSize, reusedPageId);
|
|
5246
|
+
await this.setPage(reusedPageId, newPage2, tx);
|
|
5247
|
+
return reusedPageId;
|
|
5248
|
+
}
|
|
4744
5249
|
const pageCount = metadataManager.getPageCount(metadata);
|
|
4745
5250
|
const newPageIndex = pageCount;
|
|
4746
5251
|
const newTotalCount = pageCount + 1;
|
|
@@ -4805,6 +5310,26 @@ var PageFileSystem = class {
|
|
|
4805
5310
|
}
|
|
4806
5311
|
}
|
|
4807
5312
|
}
|
|
5313
|
+
/**
|
|
5314
|
+
* Frees the page and marks it as available in the bitmap.
|
|
5315
|
+
* It also adds the page to the linked list of free pages in metadata.
|
|
5316
|
+
* @param pageId Page ID
|
|
5317
|
+
* @param tx Transaction
|
|
5318
|
+
*/
|
|
5319
|
+
async setFreePage(pageId, tx) {
|
|
5320
|
+
await tx.__acquireWriteLock(0);
|
|
5321
|
+
await tx.__acquireWriteLock(pageId);
|
|
5322
|
+
const metadata = await this.getMetadata(tx);
|
|
5323
|
+
const metadataManager = this.pageFactory.getManager(metadata);
|
|
5324
|
+
const currentHeadFreePageId = metadataManager.getFreePageId(metadata);
|
|
5325
|
+
const emptyPageManager = this.pageFactory.getManagerFromType(PageManager.CONSTANT.PAGE_TYPE_EMPTY);
|
|
5326
|
+
const emptyPage = emptyPageManager.create(this.pageSize, pageId);
|
|
5327
|
+
emptyPageManager.setNextPageId(emptyPage, currentHeadFreePageId);
|
|
5328
|
+
await this.setPage(pageId, emptyPage, tx);
|
|
5329
|
+
await this.updateBitmap(pageId, true, tx);
|
|
5330
|
+
metadataManager.setFreePageId(metadata, pageId);
|
|
5331
|
+
await this.setPage(0, metadata, tx);
|
|
5332
|
+
}
|
|
4808
5333
|
/**
|
|
4809
5334
|
* Closes the page file system.
|
|
4810
5335
|
*/
|
|
@@ -4944,8 +5469,7 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
|
|
|
4944
5469
|
while (true) {
|
|
4945
5470
|
const page = await this.pfs.get(pageId, tx);
|
|
4946
5471
|
const nextPageId = manager.getNextPageId(page);
|
|
4947
|
-
|
|
4948
|
-
manager.setRemainingCapacity(page, this.pfs.pageSize - PageManager.CONSTANT.SIZE_PAGE_HEADER);
|
|
5472
|
+
await this.pfs.setFreePage(pageId, tx);
|
|
4949
5473
|
if (nextPageId === -1) {
|
|
4950
5474
|
break;
|
|
4951
5475
|
}
|
|
@@ -5337,13 +5861,41 @@ var RowTableEngine = class {
|
|
|
5337
5861
|
if (this.rowManager.getDeletedFlag(row)) {
|
|
5338
5862
|
return;
|
|
5339
5863
|
}
|
|
5864
|
+
if (this.rowManager.getOverflowFlag(row)) {
|
|
5865
|
+
let overflowPageId = bytesToNumber(this.rowManager.getBody(row));
|
|
5866
|
+
while (overflowPageId !== -1) {
|
|
5867
|
+
const overflowPage = await this.pfs.get(overflowPageId, tx);
|
|
5868
|
+
const manager = this.factory.getManager(overflowPage);
|
|
5869
|
+
const nextPageId = manager.getNextPageId(overflowPage);
|
|
5870
|
+
await this.pfs.setFreePage(overflowPageId, tx);
|
|
5871
|
+
overflowPageId = nextPageId;
|
|
5872
|
+
}
|
|
5873
|
+
}
|
|
5340
5874
|
this.rowManager.setDeletedFlag(row, true);
|
|
5341
5875
|
await this.pfs.setPage(pageId, page, tx);
|
|
5342
5876
|
if (decrementRowCount) {
|
|
5343
|
-
const
|
|
5344
|
-
const currentRowCount = this.metadataPageManager.getRowCount(
|
|
5345
|
-
this.metadataPageManager.setRowCount(
|
|
5346
|
-
await this.pfs.setMetadata(
|
|
5877
|
+
const metadataPage2 = await this.pfs.getMetadata(tx);
|
|
5878
|
+
const currentRowCount = this.metadataPageManager.getRowCount(metadataPage2);
|
|
5879
|
+
this.metadataPageManager.setRowCount(metadataPage2, currentRowCount - 1);
|
|
5880
|
+
await this.pfs.setMetadata(metadataPage2, tx);
|
|
5881
|
+
}
|
|
5882
|
+
const insertedRowCount = this.dataPageManager.getInsertedRowCount(page);
|
|
5883
|
+
let allDeleted = true;
|
|
5884
|
+
const metadataPage = await this.pfs.getMetadata(tx);
|
|
5885
|
+
const lastInsertPageId = this.metadataPageManager.getLastInsertPageId(metadataPage);
|
|
5886
|
+
if (pageId === lastInsertPageId) {
|
|
5887
|
+
allDeleted = false;
|
|
5888
|
+
} else {
|
|
5889
|
+
for (let i = 0; i < insertedRowCount; i++) {
|
|
5890
|
+
const slotRow = this.dataPageManager.getRow(page, i);
|
|
5891
|
+
if (!this.rowManager.getDeletedFlag(slotRow)) {
|
|
5892
|
+
allDeleted = false;
|
|
5893
|
+
break;
|
|
5894
|
+
}
|
|
5895
|
+
}
|
|
5896
|
+
}
|
|
5897
|
+
if (allDeleted) {
|
|
5898
|
+
await this.pfs.setFreePage(pageId, tx);
|
|
5347
5899
|
}
|
|
5348
5900
|
}
|
|
5349
5901
|
/**
|
|
@@ -5547,11 +6099,19 @@ var Transaction = class {
|
|
|
5547
6099
|
this.heldLocks.add(lockId);
|
|
5548
6100
|
this.pageLocks.set(pageId, lockId);
|
|
5549
6101
|
}
|
|
6102
|
+
/**
|
|
6103
|
+
* Prepares the transaction for commit (Phase 1 of 2PC).
|
|
6104
|
+
* Writes dirty pages to WAL but does not update the database file yet.
|
|
6105
|
+
*/
|
|
6106
|
+
async prepare() {
|
|
6107
|
+
await this.vfs.prepareCommit(this);
|
|
6108
|
+
}
|
|
5550
6109
|
/**
|
|
5551
6110
|
* Commits the transaction.
|
|
5552
6111
|
*/
|
|
5553
6112
|
async commit() {
|
|
5554
|
-
await this.vfs.
|
|
6113
|
+
await this.vfs.prepareCommit(this);
|
|
6114
|
+
await this.vfs.finalizeCommit(this);
|
|
5555
6115
|
await TxContext.run(this, async () => {
|
|
5556
6116
|
for (const hook of this.commitHooks) {
|
|
5557
6117
|
await hook();
|
|
@@ -5595,11 +6155,20 @@ var Transaction = class {
|
|
|
5595
6155
|
|
|
5596
6156
|
// src/core/DataplyAPI.ts
|
|
5597
6157
|
var DataplyAPI = class {
|
|
5598
|
-
constructor(file,
|
|
6158
|
+
constructor(file, options) {
|
|
5599
6159
|
this.file = file;
|
|
5600
|
-
this.
|
|
5601
|
-
|
|
5602
|
-
|
|
6160
|
+
this.hook = {
|
|
6161
|
+
sync: useHookallSync(this),
|
|
6162
|
+
async: useHookall(this)
|
|
6163
|
+
};
|
|
6164
|
+
this.options = this.verboseOptions(options);
|
|
6165
|
+
this.fileHandle = this.createOrOpen(file, this.options);
|
|
6166
|
+
this.pfs = new PageFileSystem(
|
|
6167
|
+
this.fileHandle,
|
|
6168
|
+
this.options.pageSize,
|
|
6169
|
+
this.options.pageCacheCapacity,
|
|
6170
|
+
this.options.wal
|
|
6171
|
+
);
|
|
5603
6172
|
this.textCodec = new TextCodec();
|
|
5604
6173
|
this.lockManager = new LockManager();
|
|
5605
6174
|
this.rowTableEngine = new RowTableEngine(this.pfs, this.options);
|
|
@@ -5607,10 +6176,12 @@ var DataplyAPI = class {
|
|
|
5607
6176
|
this.txIdCounter = 0;
|
|
5608
6177
|
}
|
|
5609
6178
|
options;
|
|
6179
|
+
fileHandle;
|
|
5610
6180
|
pfs;
|
|
5611
6181
|
rowTableEngine;
|
|
5612
6182
|
lockManager;
|
|
5613
6183
|
textCodec;
|
|
6184
|
+
hook;
|
|
5614
6185
|
initialized;
|
|
5615
6186
|
txIdCounter;
|
|
5616
6187
|
/**
|
|
@@ -5619,7 +6190,7 @@ var DataplyAPI = class {
|
|
|
5619
6190
|
* @param fileHandle File handle
|
|
5620
6191
|
* @returns Whether the page file is a valid Dataply file
|
|
5621
6192
|
*/
|
|
5622
|
-
|
|
6193
|
+
verifyFormat(fileHandle) {
|
|
5623
6194
|
const size = MetadataPageManager.CONSTANT.OFFSET_MAGIC_STRING + MetadataPageManager.CONSTANT.MAGIC_STRING.length;
|
|
5624
6195
|
const metadataPage = new Uint8Array(size);
|
|
5625
6196
|
import_node_fs3.default.readSync(fileHandle, metadataPage, 0, size, 0);
|
|
@@ -5633,7 +6204,7 @@ var DataplyAPI = class {
|
|
|
5633
6204
|
* @param options Options
|
|
5634
6205
|
* @returns Options filled without omissions
|
|
5635
6206
|
*/
|
|
5636
|
-
|
|
6207
|
+
verboseOptions(options) {
|
|
5637
6208
|
return Object.assign({
|
|
5638
6209
|
pageSize: 8192,
|
|
5639
6210
|
pageCacheCapacity: 1e4,
|
|
@@ -5644,53 +6215,71 @@ var DataplyAPI = class {
|
|
|
5644
6215
|
* Initializes the database file.
|
|
5645
6216
|
* The first page is initialized as the metadata page.
|
|
5646
6217
|
* The second page is initialized as the first data page.
|
|
6218
|
+
* @param file Database file path
|
|
5647
6219
|
* @param fileHandle File handle
|
|
5648
6220
|
*/
|
|
5649
|
-
|
|
5650
|
-
const
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
1
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
6221
|
+
initializeFile(file, fileHandle, options) {
|
|
6222
|
+
const fileData = this.hook.sync.trigger("create", new Uint8Array(), (prepareFileData) => {
|
|
6223
|
+
const metadataPageManager = new MetadataPageManager();
|
|
6224
|
+
const bitmapPageManager = new BitmapPageManager();
|
|
6225
|
+
const dataPageManager = new DataPageManager();
|
|
6226
|
+
const metadataPage = new Uint8Array(options.pageSize);
|
|
6227
|
+
const dataPage = new Uint8Array(options.pageSize);
|
|
6228
|
+
metadataPageManager.initial(
|
|
6229
|
+
metadataPage,
|
|
6230
|
+
MetadataPageManager.CONSTANT.PAGE_TYPE_METADATA,
|
|
6231
|
+
0,
|
|
6232
|
+
0,
|
|
6233
|
+
options.pageSize - MetadataPageManager.CONSTANT.SIZE_PAGE_HEADER
|
|
6234
|
+
);
|
|
6235
|
+
metadataPageManager.setMagicString(metadataPage);
|
|
6236
|
+
metadataPageManager.setPageSize(metadataPage, options.pageSize);
|
|
6237
|
+
metadataPageManager.setRootIndexPageId(metadataPage, -1);
|
|
6238
|
+
metadataPageManager.setBitmapPageId(metadataPage, 1);
|
|
6239
|
+
metadataPageManager.setLastInsertPageId(metadataPage, 2);
|
|
6240
|
+
metadataPageManager.setPageCount(metadataPage, 3);
|
|
6241
|
+
metadataPageManager.setFreePageId(metadataPage, -1);
|
|
6242
|
+
const bitmapPage = new Uint8Array(options.pageSize);
|
|
6243
|
+
bitmapPageManager.initial(
|
|
6244
|
+
bitmapPage,
|
|
6245
|
+
BitmapPageManager.CONSTANT.PAGE_TYPE_BITMAP,
|
|
6246
|
+
1,
|
|
6247
|
+
-1,
|
|
6248
|
+
options.pageSize - BitmapPageManager.CONSTANT.SIZE_PAGE_HEADER
|
|
6249
|
+
);
|
|
6250
|
+
dataPageManager.initial(
|
|
6251
|
+
dataPage,
|
|
6252
|
+
DataPageManager.CONSTANT.PAGE_TYPE_DATA,
|
|
6253
|
+
2,
|
|
6254
|
+
-1,
|
|
6255
|
+
options.pageSize - DataPageManager.CONSTANT.SIZE_PAGE_HEADER
|
|
6256
|
+
);
|
|
6257
|
+
return new Uint8Array([
|
|
6258
|
+
...prepareFileData,
|
|
6259
|
+
...metadataPage,
|
|
6260
|
+
...bitmapPage,
|
|
6261
|
+
...dataPage
|
|
6262
|
+
]);
|
|
6263
|
+
}, file, fileHandle, options);
|
|
6264
|
+
import_node_fs3.default.appendFileSync(fileHandle, fileData);
|
|
5675
6265
|
}
|
|
5676
6266
|
/**
|
|
5677
6267
|
* Opens the database file. If the file does not exist, it initializes it.
|
|
5678
6268
|
* @param file Database file path
|
|
5679
6269
|
* @param options Options
|
|
5680
|
-
* @returns
|
|
6270
|
+
* @returns File handle
|
|
5681
6271
|
*/
|
|
5682
|
-
|
|
5683
|
-
const verboseOption = this.VerboseOptions(options);
|
|
6272
|
+
createOrOpen(file, options) {
|
|
5684
6273
|
let fileHandle;
|
|
5685
|
-
if (
|
|
6274
|
+
if (options.pageCacheCapacity < 100) {
|
|
5686
6275
|
throw new Error("Page cache capacity must be at least 100");
|
|
5687
6276
|
}
|
|
5688
6277
|
if (!import_node_fs3.default.existsSync(file)) {
|
|
5689
|
-
if (
|
|
6278
|
+
if (options.pageSize < 4096) {
|
|
5690
6279
|
throw new Error("Page size must be at least 4096 bytes");
|
|
5691
6280
|
}
|
|
5692
6281
|
fileHandle = import_node_fs3.default.openSync(file, "w+");
|
|
5693
|
-
this.
|
|
6282
|
+
this.initializeFile(file, fileHandle, options);
|
|
5694
6283
|
} else {
|
|
5695
6284
|
fileHandle = import_node_fs3.default.openSync(file, "r+");
|
|
5696
6285
|
const buffer = new Uint8Array(
|
|
@@ -5701,14 +6290,14 @@ var DataplyAPI = class {
|
|
|
5701
6290
|
if (metadataManager.isMetadataPage(buffer)) {
|
|
5702
6291
|
const storedPageSize = metadataManager.getPageSize(buffer);
|
|
5703
6292
|
if (storedPageSize > 0) {
|
|
5704
|
-
|
|
6293
|
+
options.pageSize = storedPageSize;
|
|
5705
6294
|
}
|
|
5706
6295
|
}
|
|
5707
6296
|
}
|
|
5708
|
-
if (!this.
|
|
6297
|
+
if (!this.verifyFormat(fileHandle)) {
|
|
5709
6298
|
throw new Error("Invalid dataply file");
|
|
5710
6299
|
}
|
|
5711
|
-
return
|
|
6300
|
+
return fileHandle;
|
|
5712
6301
|
}
|
|
5713
6302
|
/**
|
|
5714
6303
|
* Initializes the dataply instance.
|
|
@@ -5719,8 +6308,12 @@ var DataplyAPI = class {
|
|
|
5719
6308
|
if (this.initialized) {
|
|
5720
6309
|
return;
|
|
5721
6310
|
}
|
|
5722
|
-
await this.runWithDefault(() =>
|
|
5723
|
-
|
|
6311
|
+
await this.runWithDefault(() => {
|
|
6312
|
+
return this.hook.async.trigger("init", void 0, async () => {
|
|
6313
|
+
await this.rowTableEngine.init();
|
|
6314
|
+
this.initialized = true;
|
|
6315
|
+
});
|
|
6316
|
+
});
|
|
5724
6317
|
}
|
|
5725
6318
|
/**
|
|
5726
6319
|
* Creates a transaction.
|
|
@@ -5779,10 +6372,11 @@ var DataplyAPI = class {
|
|
|
5779
6372
|
throw new Error("Dataply instance is not initialized");
|
|
5780
6373
|
}
|
|
5781
6374
|
return this.runWithDefault((tx2) => {
|
|
6375
|
+
incrementRowCount = incrementRowCount ?? true;
|
|
5782
6376
|
if (typeof data === "string") {
|
|
5783
6377
|
data = this.textCodec.encode(data);
|
|
5784
6378
|
}
|
|
5785
|
-
return this.rowTableEngine.insert(data, incrementRowCount
|
|
6379
|
+
return this.rowTableEngine.insert(data, incrementRowCount, tx2);
|
|
5786
6380
|
}, tx);
|
|
5787
6381
|
}
|
|
5788
6382
|
/**
|
|
@@ -5798,10 +6392,11 @@ var DataplyAPI = class {
|
|
|
5798
6392
|
throw new Error("Dataply instance is not initialized");
|
|
5799
6393
|
}
|
|
5800
6394
|
return this.runWithDefault(async (tx2) => {
|
|
6395
|
+
incrementRowCount = incrementRowCount ?? true;
|
|
5801
6396
|
const pks = [];
|
|
5802
6397
|
for (const data of dataList) {
|
|
5803
6398
|
const encoded = typeof data === "string" ? this.textCodec.encode(data) : data;
|
|
5804
|
-
const pk = await this.rowTableEngine.insert(encoded, incrementRowCount
|
|
6399
|
+
const pk = await this.rowTableEngine.insert(encoded, incrementRowCount, tx2);
|
|
5805
6400
|
pks.push(pk);
|
|
5806
6401
|
}
|
|
5807
6402
|
return pks;
|
|
@@ -5835,7 +6430,8 @@ var DataplyAPI = class {
|
|
|
5835
6430
|
throw new Error("Dataply instance is not initialized");
|
|
5836
6431
|
}
|
|
5837
6432
|
return this.runWithDefault(async (tx2) => {
|
|
5838
|
-
|
|
6433
|
+
decrementRowCount = decrementRowCount ?? true;
|
|
6434
|
+
await this.rowTableEngine.delete(pk, decrementRowCount, tx2);
|
|
5839
6435
|
}, tx);
|
|
5840
6436
|
}
|
|
5841
6437
|
async select(pk, asRaw = false, tx) {
|
|
@@ -5856,8 +6452,10 @@ var DataplyAPI = class {
|
|
|
5856
6452
|
if (!this.initialized) {
|
|
5857
6453
|
throw new Error("Dataply instance is not initialized");
|
|
5858
6454
|
}
|
|
5859
|
-
|
|
5860
|
-
|
|
6455
|
+
return this.hook.async.trigger("close", void 0, async () => {
|
|
6456
|
+
await this.pfs.close();
|
|
6457
|
+
import_node_fs3.default.closeSync(this.fileHandle);
|
|
6458
|
+
});
|
|
5861
6459
|
}
|
|
5862
6460
|
};
|
|
5863
6461
|
|
|
@@ -5865,7 +6463,7 @@ var DataplyAPI = class {
|
|
|
5865
6463
|
var Dataply = class {
|
|
5866
6464
|
api;
|
|
5867
6465
|
constructor(file, options) {
|
|
5868
|
-
this.api = DataplyAPI
|
|
6466
|
+
this.api = new DataplyAPI(file, options ?? {});
|
|
5869
6467
|
}
|
|
5870
6468
|
/**
|
|
5871
6469
|
* Gets the options used to open the dataply.
|
|
@@ -5944,6 +6542,52 @@ var Dataply = class {
|
|
|
5944
6542
|
return this.api.close();
|
|
5945
6543
|
}
|
|
5946
6544
|
};
|
|
6545
|
+
|
|
6546
|
+
// src/core/transaction/GlobalTransaction.ts
|
|
6547
|
+
var GlobalTransaction = class {
|
|
6548
|
+
transactions = [];
|
|
6549
|
+
isCommitted = false;
|
|
6550
|
+
isRolledBack = false;
|
|
6551
|
+
/**
|
|
6552
|
+
* Adds a transaction to the global transaction.
|
|
6553
|
+
* @param tx Transaction to add
|
|
6554
|
+
*/
|
|
6555
|
+
add(tx) {
|
|
6556
|
+
this.transactions.push(tx);
|
|
6557
|
+
}
|
|
6558
|
+
/**
|
|
6559
|
+
* Commits all transactions atomically.
|
|
6560
|
+
* Phase 1: Prepare (Write WAL)
|
|
6561
|
+
* Phase 2: Commit (Write Commit Marker & Checkpoint)
|
|
6562
|
+
*/
|
|
6563
|
+
async commit() {
|
|
6564
|
+
if (this.isCommitted || this.isRolledBack) {
|
|
6565
|
+
throw new Error("Transaction is already finished");
|
|
6566
|
+
}
|
|
6567
|
+
try {
|
|
6568
|
+
await Promise.all(this.transactions.map((tx) => tx.prepare()));
|
|
6569
|
+
} catch (e) {
|
|
6570
|
+
await this.rollback();
|
|
6571
|
+
throw new Error(`Global commit failed during prepare phase: ${e}`);
|
|
6572
|
+
}
|
|
6573
|
+
try {
|
|
6574
|
+
await Promise.all(this.transactions.map((tx) => tx.commit()));
|
|
6575
|
+
this.isCommitted = true;
|
|
6576
|
+
} catch (e) {
|
|
6577
|
+
throw new Error(`Global commit failed during finalize phase: ${e}`);
|
|
6578
|
+
}
|
|
6579
|
+
}
|
|
6580
|
+
/**
|
|
6581
|
+
* Rolls back all transactions.
|
|
6582
|
+
*/
|
|
6583
|
+
async rollback() {
|
|
6584
|
+
if (this.isCommitted || this.isRolledBack) {
|
|
6585
|
+
return;
|
|
6586
|
+
}
|
|
6587
|
+
await Promise.all(this.transactions.map((tx) => tx.rollback()));
|
|
6588
|
+
this.isRolledBack = true;
|
|
6589
|
+
}
|
|
6590
|
+
};
|
|
5947
6591
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5948
6592
|
0 && (module.exports = {
|
|
5949
6593
|
BPTreeAsync,
|
|
@@ -5952,6 +6596,7 @@ var Dataply = class {
|
|
|
5952
6596
|
CacheEntanglementSync,
|
|
5953
6597
|
Dataply,
|
|
5954
6598
|
DataplyAPI,
|
|
6599
|
+
GlobalTransaction,
|
|
5955
6600
|
InMemoryStoreStrategyAsync,
|
|
5956
6601
|
InMemoryStoreStrategySync,
|
|
5957
6602
|
InvertedWeakMap,
|