@pirireis/webglobeplugins 0.15.19-alpha → 0.15.21-alpha

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pirireis/webglobeplugins",
3
- "version": "0.15.19-alpha",
3
+ "version": "0.15.21-alpha",
4
4
  "main": "index.js",
5
5
  "author": "Toprak Nihat Deniz Ozturk",
6
6
  "license": "MIT",
@@ -224,12 +224,19 @@ class PointTracksPlugin {
224
224
  return;
225
225
  this._isFreed = true;
226
226
  this._pickerDisplayer.free();
227
+ this._tracksToPointMap.clear();
227
228
  PointOnGlobeProgramCache.release(this.globe);
228
229
  this.gl.deleteBuffer(this._focusParams.elementBuffer);
229
230
  this._bufferManagersMap.forEach(({ bufferManager, adaptor }) => bufferManager.free());
230
231
  }
231
232
  draw3D() {
232
233
  const { gl, _pointProgram, _pickerDisplayer, _bufferOrchestrator, _vao } = this;
234
+ if (!gl) {
235
+ throw new Error("GL is not loaded, PointTracks Plugin");
236
+ }
237
+ if (this._isFreed) {
238
+ throw new Error("Plugin is unregistered, PointTracks Plugin");
239
+ }
233
240
  this.resize();
234
241
  _pickerDisplayer.bindFBO();
235
242
  _pickerDisplayer.clearTextures();
@@ -270,13 +277,17 @@ class PointTracksPlugin {
270
277
  const trackID = track.trackID;
271
278
  const points = track.points;
272
279
  if (!this._tracksToPointsMap.has(trackID)) {
273
- this._tracksToPointsMap.set(trackID, []); // TODO: alternative to Set?
274
- // this._tracksToPointsMap.set(trackID, new Set()); // TODO: alternative to Set?
280
+ this._tracksToPointsMap.set(trackID, new Set());
275
281
  }
276
- const pointList = this._tracksToPointsMap.get(trackID);
282
+ const pointSet = this._tracksToPointsMap.get(trackID);
277
283
  for (let p = 0; p < points.length; p++) {
278
284
  const pointID = points[p].ID;
279
- pointList.push(pointID);
285
+ if (!pointSet.has(pointID)) {
286
+ pointSet.add(pointID);
287
+ }
288
+ else {
289
+ console.warn(`Point with ID ${pointID} already exists in track ${trackID}. Skipping duplicate.`);
290
+ }
280
291
  }
281
292
  }
282
293
  }
@@ -286,15 +297,22 @@ class PointTracksPlugin {
286
297
  }
287
298
  }
288
299
  _deletePointsFromTracksMap(trackID, pointIDs) {
289
- const trackSet = this._tracksToPointsMap.get(trackID);
290
- const pointList = new Set(pointIDs);
291
- const newList = [];
292
- for (const pointID of trackSet) {
293
- if (!pointList.has(pointID)) {
294
- newList.push(pointID);
300
+ const trackIDs = this._tracksToPointsMap.get(trackID);
301
+ if (trackIDs === undefined) {
302
+ console.warn(`Track with ID ${trackID} not found.`);
303
+ return;
304
+ }
305
+ for (const pointID of pointIDs) {
306
+ if (!trackIDs.has(pointID)) {
307
+ console.warn(`Point with ID ${pointID} not found in track ${trackID}.`);
308
+ }
309
+ else {
310
+ trackIDs.delete(pointID);
295
311
  }
296
312
  }
297
- this._tracksToPointsMap.set(trackID, newList);
313
+ if (trackIDs.size === 0) {
314
+ this._tracksToPointsMap.delete(trackID);
315
+ }
298
316
  }
299
317
  _selfSelect() {
300
318
  const { globe } = this;
@@ -324,6 +342,9 @@ class PointTracksPlugin {
324
342
  for (const pointID of pointList) {
325
343
  const key = keyMethod(trackID, pointID);
326
344
  const index = this._bufferOrchestrator.offsetMap.get(key);
345
+ if (index === undefined) {
346
+ throw new Error;
347
+ }
327
348
  indexes.push(index);
328
349
  length++;
329
350
  }
@@ -47,7 +47,7 @@ export class CircleLineChainPlugin {
47
47
  dashedLineOpacityVariativeOn: false,
48
48
  dashedLineRatioVariativeOn: false,
49
49
  bufferType: "DYNAMIC_DRAW",
50
- opacity: 1.0
50
+ opacity: 1.0,
51
51
  }
52
52
  };
53
53
  constructor(id, { drawCircleOn, textWritersMap, textDataPreAdaptor, opacities, lineAdaptor, arcAdaptor, circleAdaptor, arcOnTerrainOptions, circleOnTerrainOptions, lineOptions } = {}) {
@@ -1,5 +1,6 @@
1
1
  import { LineOnGlobeCache } from "../../programs/line-on-globe/naive-accurate-flexible";
2
- import { BufferMapOrchestrator } from "../../util/account/create-buffermap-orchastration";
2
+ import { BufferOrchestrator } from "../../util/account/single-attribute-buffer-management/buffer-orchestrator";
3
+ import { BufferManager } from "../../util/account/single-attribute-buffer-management/buffer-manager";
3
4
  import { sphereCoord } from "../../util/geometry/index";
4
5
  import { constraintFloat } from "../../util/check/typecheck";
5
6
  export class LinePlugin {
@@ -10,20 +11,23 @@ export class LinePlugin {
10
11
  vao = null;
11
12
  _options;
12
13
  _uboHandler = null;
13
- _bufferOrchestrator = null;
14
+ _bufferOrchestrator;
15
+ _bufferManagersMap = new Map();
14
16
  _freed = false;
15
- constructor(id, { flatViewOn = true, globeViewOn = true, variativeColorsOn = false, defaultColor = [1, 1, 1, 1], dashedLineOpacityVariativeOn = false, dashedLineRatioVariativeOn = false, bufferType = "DYNAMIC_DRAW", opacity = 1.0 } = {}) {
17
+ constructor(id, { flatViewOn = true, globeViewOn = true, variativeColorsOn = false, defaultColor = [1, 1, 1, 1], dashedLineOpacityVariativeOn = false, dashedLineRatioVariativeOn = false, bufferType = "DYNAMIC_DRAW", opacity = 1.0, initialCapacity = 10 } = {}) {
16
18
  this.id = id;
17
19
  this._options = {
18
- flatViewOn,
19
- globeViewOn,
20
- variativeColorsOn,
21
- defaultColor,
22
- dashedLineOpacityVariativeOn,
23
- dashedLineRatioVariativeOn,
24
- bufferType,
25
- opacity
20
+ flatViewOn: flatViewOn ?? true,
21
+ globeViewOn: globeViewOn ?? true,
22
+ variativeColorsOn: variativeColorsOn ?? false,
23
+ defaultColor: defaultColor ?? [1, 1, 1, 1],
24
+ dashedLineOpacityVariativeOn: dashedLineOpacityVariativeOn ?? false,
25
+ dashedLineRatioVariativeOn: dashedLineRatioVariativeOn ?? false,
26
+ bufferType: bufferType ?? "DYNAMIC_DRAW",
27
+ opacity: opacity ?? 1.0,
28
+ initialCapacity: initialCapacity ?? 10
26
29
  };
30
+ this._bufferOrchestrator = new BufferOrchestrator({ capacity: initialCapacity ?? 10 });
27
31
  }
28
32
  init(globe, gl) {
29
33
  this.globe = globe;
@@ -31,13 +35,12 @@ export class LinePlugin {
31
35
  this.program = LineOnGlobeCache.get(globe);
32
36
  this._uboHandler = this.program.createUBO();
33
37
  this.setDefaultColor(this._options.defaultColor);
34
- this._bufferOrchestrator = new BufferMapOrchestrator(gl, this._createBufferDetailsMap(), 10 // initial capacity
35
- );
38
+ this._fillManagerMap();
36
39
  this.vao = this.program.createVAO(...this._createSelectBufferNames().map((key) => {
37
40
  if (key === null) {
38
41
  return null;
39
42
  }
40
- const bufferManagerComp = this._bufferOrchestrator?.bufferManagersMap.get(key);
43
+ const bufferManagerComp = this._bufferManagersMap.get(key);
41
44
  if (bufferManagerComp === undefined) {
42
45
  throw new Error(`Buffer key ${key} does not exist in bufferManagersMap`);
43
46
  }
@@ -51,19 +54,19 @@ export class LinePlugin {
51
54
  }
52
55
  // PLUGIN INTERFACE METHODS
53
56
  insertBulk(items) {
54
- const { _bufferOrchestrator, globe } = this;
57
+ const { _bufferOrchestrator, _bufferManagersMap, globe } = this;
55
58
  if (!_bufferOrchestrator || !globe) {
56
59
  throw new Error("Buffer orchestrator or globe is not initialized.");
57
60
  }
58
- _bufferOrchestrator.insertBulk(items);
61
+ _bufferOrchestrator.insertBulk(items, _bufferManagersMap);
59
62
  this.globe?.DrawRender();
60
63
  }
61
64
  deleteBulk(keys) {
62
- const { _bufferOrchestrator, globe } = this;
65
+ const { _bufferOrchestrator, _bufferManagersMap, globe } = this;
63
66
  if (!_bufferOrchestrator || !globe) {
64
67
  throw new Error("Buffer orchestrator or globe is not initialized.");
65
68
  }
66
- _bufferOrchestrator.deleteBulk(keys);
69
+ _bufferOrchestrator.deleteBulk(keys, _bufferManagersMap);
67
70
  this.globe?.DrawRender();
68
71
  }
69
72
  setPluginOpacity(opacity, drawRender = false) {
@@ -108,12 +111,11 @@ export class LinePlugin {
108
111
  if (!_bufferOrchestrator || !_bufferOrchestrator || !_uboHandler) {
109
112
  throw new Error("Buffer orchestrator is not initialized.");
110
113
  }
111
- const { bufferOrchestrator } = _bufferOrchestrator;
112
114
  const { flatViewOn, globeViewOn, opacity } = _options;
113
115
  const drawOptions = {
114
116
  drawRange: {
115
117
  first: 0,
116
- count: bufferOrchestrator.length
118
+ count: _bufferOrchestrator.length
117
119
  }
118
120
  };
119
121
  this.gl.disable(this.gl.DEPTH_TEST); // Disable depth test for lines
@@ -132,67 +134,60 @@ export class LinePlugin {
132
134
  if (this._freed)
133
135
  return;
134
136
  // TODO: FILL
135
- this._bufferOrchestrator?.free();
137
+ this._bufferManagersMap.forEach((manager) => {
138
+ manager.bufferManager.free();
139
+ });
136
140
  this._uboHandler?.free();
137
141
  LineOnGlobeCache.release(this.globe);
138
142
  this._freed = true;
139
143
  }
140
144
  // IMPLICIT INTERFACE METHODS
141
- _createBufferDetailsMap() {
145
+ _fillManagerMap() {
142
146
  const globe = this.globe;
143
147
  const { flatViewOn, globeViewOn, variativeColorsOn, dashedLineOpacityVariativeOn, dashedLineRatioVariativeOn, bufferType = "DYNAMIC_DRAW" } = this._options;
144
- const m = new Map();
148
+ const m = this._bufferManagersMap;
149
+ const initialCapacity = this._options.initialCapacity;
145
150
  if (flatViewOn) {
146
151
  m.set("start_position", {
147
- itemSize: 2,
148
- bufferType: bufferType, // TODO: Ask User?
149
- buffer: null,
152
+ bufferManager: new BufferManager(globe.gl, 2, { bufferType, initialCapacity: this._options.initialCapacity }),
150
153
  adaptor: (item) => {
151
154
  const result = new Float32Array(globe.api_GetMercator2DPoint(item.start[0], item.start[1]));
152
155
  return result;
153
156
  }
154
157
  });
155
158
  m.set("end_position", {
156
- itemSize: 2,
157
- bufferType: bufferType,
158
- buffer: null,
159
+ bufferManager: new BufferManager(globe.gl, 2, { bufferType, initialCapacity: this._options.initialCapacity }),
159
160
  adaptor: (item) => new Float32Array(globe.api_GetMercator2DPoint(item.end[0], item.end[1]))
160
161
  });
161
162
  }
162
163
  if (globeViewOn) {
163
164
  m.set("start_position_3d", {
164
- itemSize: 3,
165
- bufferType: bufferType,
165
+ bufferManager: new BufferManager(globe.gl, 3, { bufferType, initialCapacity: this._options.initialCapacity }),
166
166
  adaptor: (item) => sphereCoord(item.start[0], item.start[1], globe, item.start_altitude || 0)
167
167
  });
168
168
  m.set("end_position_3d", {
169
- itemSize: 3,
170
- bufferType: bufferType,
169
+ bufferManager: new BufferManager(globe.gl, 3, { bufferType, initialCapacity: this._options.initialCapacity }),
171
170
  adaptor: (item) => sphereCoord(item.end[0], item.end[1], globe, item.end_altitude || 0)
172
171
  });
173
172
  }
174
173
  if (variativeColorsOn) {
175
174
  m.set("color", {
176
- itemSize: 4,
177
- bufferType: bufferType,
175
+ bufferManager: new BufferManager(globe.gl, 4, { bufferType, initialCapacity: this._options.initialCapacity }),
178
176
  adaptor: (item) => new Float32Array(item.color !== undefined ? item.color : [-1, -1, -1, -1])
179
177
  });
180
178
  }
181
179
  if (dashedLineOpacityVariativeOn) {
182
180
  m.set("dashed_line_opacity", {
183
- itemSize: 1,
184
- bufferType: bufferType,
181
+ bufferManager: new BufferManager(globe.gl, 1, { bufferType, initialCapacity: this._options.initialCapacity }),
185
182
  adaptor: (item) => new Float32Array(item.dashed_line_opacity !== undefined ? [item.dashed_line_opacity] : [-1])
186
183
  });
187
184
  }
188
185
  if (dashedLineRatioVariativeOn) {
189
186
  m.set("dashed_line_ratio", {
190
- itemSize: 1,
191
- bufferType: bufferType,
187
+ bufferManager: new BufferManager(globe.gl, 1, { bufferType, initialCapacity: this._options.initialCapacity }),
192
188
  adaptor: (item) => new Float32Array(item.dashed_line_ratio !== undefined ? [item.dashed_line_ratio] : [-1])
193
189
  });
194
190
  }
195
- return m;
196
191
  }
197
192
  _createSelectBufferNames() {
198
193
  const { flatViewOn, globeViewOn, variativeColorsOn, dashedLineOpacityVariativeOn, dashedLineRatioVariativeOn } = this._options;
@@ -60,7 +60,7 @@ export class BufferManager {
60
60
  }
61
61
  gl.bindBuffer(gl.ARRAY_BUFFER, null);
62
62
  }
63
- insertConsecutiveBulk(items, offset, adapter, Constructor = Float32Array) {
63
+ insertBlock(items, offset, adapter, Constructor = Float32Array) {
64
64
  const { gl, buffer, itemSize } = this;
65
65
  const cpuBuffer = new Constructor(itemSize * items.length);
66
66
  for (let i = 0; i < items.length; i++) {
@@ -19,6 +19,92 @@ export class BufferOrchestrator {
19
19
  this.tombstoneOffsets = [];
20
20
  this._length = 0;
21
21
  }
22
+ // ...existing code...
23
+ // TODO: CLEAN THIS
24
+ // insertBulk2(items: any[], bufferManagersMap: BufferManagersMap, bufferKeys: string[] | null = null) {
25
+ // this.ensureSpace(items.length, bufferManagersMap);
26
+ // const { offsetMap } = this;
27
+ // // For block insert (truly new, consecutive offsets)
28
+ // const blockItems: any[] = [];
29
+ // let blockStart: number | null = null;
30
+ // let lastBlockOffset: number | null = null;
31
+ // // For single insert (existing or tombstone-assigned)
32
+ // const singleItems: any[] = [];
33
+ // const singleOffsets: number[] = [];
34
+ // for (const item of items) {
35
+ // let offset = offsetMap.get(item.key);
36
+ // if (offset !== undefined) {
37
+ // // Already present, update in place
38
+ // singleItems.push(item);
39
+ // singleOffsets.push(offset);
40
+ // } else {
41
+ // // Assign offset (tombstone or new)
42
+ // if (this.tombstoneOffsets.length > 0) {
43
+ // offset = this.tombstoneOffsets.pop() as number;
44
+ // offsetMap.set(item.key, offset);
45
+ // singleItems.push(item);
46
+ // singleOffsets.push(offset);
47
+ // } else {
48
+ // offset = this._length++;
49
+ // if (offset >= this._capacity) throw new Error("The Size Should Be Increased!!");
50
+ // offsetMap.set(item.key, offset);
51
+ // // Check for consecutive block
52
+ // if (blockStart === null) {
53
+ // blockStart = offset;
54
+ // lastBlockOffset = offset;
55
+ // blockItems.push(item);
56
+ // } else if (lastBlockOffset !== null && offset === lastBlockOffset + 1) {
57
+ // lastBlockOffset = offset;
58
+ // blockItems.push(item);
59
+ // } else {
60
+ // // Not consecutive, flush current block
61
+ // if (blockItems.length > 0) {
62
+ // this._insertBlock(blockItems, blockStart, bufferManagersMap, bufferKeys);
63
+ // blockItems.length = 0;
64
+ // }
65
+ // blockStart = offset;
66
+ // lastBlockOffset = offset;
67
+ // blockItems.push(item);
68
+ // }
69
+ // }
70
+ // }
71
+ // }
72
+ // // Flush any remaining block
73
+ // if (blockItems.length > 0 && blockStart !== null) {
74
+ // this._insertBlock(blockItems, blockStart, bufferManagersMap, bufferKeys);
75
+ // }
76
+ // // Insert singles
77
+ // if (singleItems.length > 0) {
78
+ // if (bufferKeys) {
79
+ // for (const key of bufferKeys) {
80
+ // const bufferManagerComp = bufferManagersMap.get(key);
81
+ // if (!bufferManagerComp) throw new Error("insertBulk bufferKey does not exist");
82
+ // const { bufferManager, adaptor } = bufferManagerComp;
83
+ // bufferManager.insertBulk(singleItems.map(adaptor), singleOffsets);
84
+ // }
85
+ // } else {
86
+ // for (const [key, { bufferManager, adaptor }] of bufferManagersMap) {
87
+ // bufferManager.insertBulk(singleItems.map(adaptor), singleOffsets);
88
+ // }
89
+ // }
90
+ // }
91
+ // }
92
+ // // Helper for block insert
93
+ // private _insertBlock(blockItems: any[], blockStart: number, bufferManagersMap: BufferManagersMap, bufferKeys: string[] | null) {
94
+ // if (bufferKeys) {
95
+ // for (const key of bufferKeys) {
96
+ // const bufferManagerComp = bufferManagersMap.get(key);
97
+ // if (!bufferManagerComp) throw new Error("insertBulk bufferKey does not exist");
98
+ // const { bufferManager, adaptor } = bufferManagerComp;
99
+ // bufferManager.insertBlock(blockItems, blockStart, adaptor, Float32Array);
100
+ // }
101
+ // } else {
102
+ // for (const [key, { bufferManager, adaptor }] of bufferManagersMap) {
103
+ // bufferManager.insertBlock(blockItems, blockStart, adaptor, Float32Array);
104
+ // }
105
+ // }
106
+ // }
107
+ // ...existing code...
22
108
  // want to add stack load to this method
23
109
  // if offsetMap.has(item.key) === false get next offset, add the item to stack
24
110
  // create a single big float32array and fill it with the items
@@ -27,10 +113,18 @@ export class BufferOrchestrator {
27
113
  this.ensureSpace(items.length, bufferManagersMap);
28
114
  const { offsetMap } = this;
29
115
  let offsetStart = null;
30
- const itemForConsecutiveLoad = [];
116
+ const offsets = [];
117
+ const blockLoad = [];
31
118
  for (const item of items) {
32
119
  let o = offsetMap.get(item.key);
120
+ if (o === undefined && this.tombstoneOffsets.length > 0) {
121
+ // If there is a tombstone, use it
122
+ o = this.tombstoneOffsets.pop();
123
+ offsetMap.set(item.key, o);
124
+ }
33
125
  if (o !== undefined) {
126
+ // Already exist or there is a random empty space in earlear part of memory.
127
+ // insert for single slots
34
128
  if (bufferKeys) {
35
129
  for (const key of bufferKeys) {
36
130
  const bufferManagerComp = bufferManagersMap.get(key);
@@ -45,88 +139,42 @@ export class BufferOrchestrator {
45
139
  bufferManager.insertBulk([adaptor(item)], [o]);
46
140
  }
47
141
  }
48
- continue;
49
142
  }
50
- const offset = this.nextOffset();
51
- offsetMap.set(item.key, offset);
52
- itemForConsecutiveLoad.push(item);
53
- if (offsetStart === null) {
54
- offsetStart = offset;
143
+ else {
144
+ // offset comes from increment function
145
+ // this part stacks data to be load a a single big block.
146
+ const offset = this.nextOffset();
147
+ if (offset === undefined) {
148
+ throw new Error("The Size Should Be Increased!!");
149
+ }
150
+ offsets.push(offset);
151
+ offsetMap.set(item.key, offset);
152
+ blockLoad.push(item);
153
+ if (offsetStart === null) {
154
+ offsetStart = offset;
155
+ }
55
156
  }
56
157
  }
57
158
  if (offsetStart === null)
58
159
  return;
160
+ for (let i = 0; i < offsets.length - 1; i++) {
161
+ if (offsets[i] - offsets[i + 1] !== -1) {
162
+ // TODO: DELETE THIS
163
+ throw new Error("consecutive is not consecutive");
164
+ }
165
+ }
59
166
  if (bufferKeys) {
60
167
  for (const key of bufferKeys) {
61
168
  const bufferManagerComp = bufferManagersMap.get(key);
62
169
  if (bufferManagerComp === undefined)
63
170
  throw new Error("insertBulk bufferKey does not exist");
64
171
  const { bufferManager, adaptor } = bufferManagerComp;
65
- bufferManager.insertConsecutiveBulk(itemForConsecutiveLoad, offsetStart, adaptor, Float32Array);
172
+ bufferManager.insertBlock(blockLoad, offsetStart, adaptor, Float32Array);
66
173
  }
67
174
  }
68
175
  else {
69
176
  for (const [key, { bufferManager, adaptor }] of bufferManagersMap) {
70
- bufferManager.insertConsecutiveBulk(itemForConsecutiveLoad, offsetStart, adaptor, Float32Array);
71
- }
72
- }
73
- }
74
- insertBulk2(items, bufferManagersMap, bufferKeys = null) {
75
- this.ensureSpace(items.length, bufferManagersMap);
76
- const { offsetMap } = this;
77
- // Pre-allocate arrays only if needed
78
- const newItemsCount = items.reduce((acc, item) => acc + (offsetMap.has(item.key) ? 0 : 1), 0);
79
- if (newItemsCount === 0)
80
- return;
81
- // Only allocate if there are new items
82
- const newItems = new Array(newItemsCount);
83
- const newOffsets = new Array(newItemsCount);
84
- let idx = 0;
85
- for (const item of items) {
86
- let o = offsetMap.get(item.key);
87
- if (o !== undefined) {
88
- // Update existing
89
- if (bufferKeys) {
90
- for (const key of bufferKeys) {
91
- const bufferManagerComp = bufferManagersMap.get(key);
92
- if (!bufferManagerComp)
93
- throw new Error("insertBulk bufferKey does not exist");
94
- const { bufferManager, adaptor } = bufferManagerComp;
95
- bufferManager.insertBulk([adaptor(item)], [o]);
96
- }
97
- }
98
- else {
99
- for (const [key, { bufferManager, adaptor }] of bufferManagersMap) {
100
- bufferManager.insertBulk([adaptor(item)], [o]);
101
- }
102
- }
103
- }
104
- else {
105
- // New item
106
- const offset = this.nextOffset();
107
- offsetMap.set(item.key, offset);
108
- newItems[idx] = item;
109
- newOffsets[idx] = offset;
110
- idx++;
111
- }
112
- }
113
- if (idx > 0) {
114
- // Only slice the arrays to the actual number of new items
115
- const itemsToInsert = newItems.slice(0, idx);
116
- const offsetsToInsert = newOffsets.slice(0, idx);
117
- if (bufferKeys) {
118
- for (const key of bufferKeys) {
119
- const bufferManagerComp = bufferManagersMap.get(key);
120
- if (!bufferManagerComp)
121
- throw new Error("insertBulk bufferKey does not exist");
122
- const { bufferManager, adaptor } = bufferManagerComp;
123
- bufferManager.insertConsecutiveBulk(itemsToInsert, offsetsToInsert[0], adaptor, Float32Array);
124
- }
125
- }
126
- else {
127
- for (const [key, { bufferManager, adaptor }] of bufferManagersMap) {
128
- bufferManager.insertConsecutiveBulk(itemsToInsert, offsetsToInsert[0], adaptor, Float32Array);
129
- }
177
+ bufferManager.insertBlock(blockLoad, offsetStart, adaptor, Float32Array);
130
178
  }
131
179
  }
132
180
  }
@@ -175,15 +223,18 @@ export class BufferOrchestrator {
175
223
  getOffset(key) {
176
224
  return this.offsetMap.get(key);
177
225
  }
178
- nextOffset() {
226
+ nextTombstone() {
179
227
  if (this.tombstoneOffsets.length > 0) {
180
228
  const offset = this.tombstoneOffsets.pop();
181
229
  return offset;
182
230
  }
231
+ return undefined;
232
+ }
233
+ nextOffset() {
183
234
  if (this._length < this._capacity) {
184
235
  return this._length++;
185
236
  }
186
- return false;
237
+ return undefined;
187
238
  }
188
239
  ensureSpace(itemsLength, bufferManagersMap) {
189
240
  if (itemsLength <= this.emptySpace)
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ // import { BufferOrchestrator as BufferOrchestratorI, BufferManagersMap, BufferManager } from "./types";
3
+ // const EXTRA_SIZE = 10;
4
+ // export class BufferOrchestrator implements BufferOrchestratorI {
5
+ // _capacity: number;
6
+ // offsetMap: Map<string, number>;
7
+ // tombstoneOffsets: number[];
8
+ // _length: number;
9
+ // constructor({ capacity = 10 } = {}) {
10
+ // this._capacity = capacity;
11
+ // this.offsetMap = new Map();
12
+ // this.tombstoneOffsets = [];
13
+ // this._length = 0;
14
+ // }
15
+ // resetWithCapacity(bufferManagersMap: BufferManagersMap, capacity: number | null = null) {
16
+ // this._capacity = capacity !== null ? capacity : this._capacity;
17
+ // for (const [key, { bufferManager }] of bufferManagersMap) {
18
+ // bufferManager.resetWithCapacity(this._capacity);
19
+ // }
20
+ // this.offsetMap.clear();
21
+ // this.tombstoneOffsets = [];
22
+ // this._length = 0;
23
+ // }
24
+ // insertBulk(items: any[], bufferManagersMap: BufferManagersMap, bufferKeys: string[] | null = null) {
25
+ // this.ensureSpace(items.length, bufferManagersMap);
26
+ // const { offsetMap } = this;
27
+ // const offsets = [];
28
+ // for (const item of items) {
29
+ // let o = offsetMap.get(item.key);
30
+ // const offset = o !== undefined ? o : this.nextOffset() as number;
31
+ // if (offset === undefined) {
32
+ // throw new Error("The Size Should Be Increased!!")
33
+ // }
34
+ // offsetMap.set(item.key, offset);
35
+ // offsets.push(offset);
36
+ // }
37
+ // if (bufferKeys) {
38
+ // for (const key of bufferKeys) {
39
+ // const bufferManagerComp = bufferManagersMap.get(key);
40
+ // if (bufferManagerComp === undefined) throw new Error("insertBulk bufferKey does not exist");
41
+ // const { bufferManager, adaptor } = bufferManagerComp;
42
+ // bufferManager.insertBulk(items.map(adaptor), offsets);
43
+ // }
44
+ // } else {
45
+ // for (const [key, { bufferManager, adaptor }] of bufferManagersMap) {
46
+ // bufferManager.insertBulk(items.map(adaptor), offsets);
47
+ // }
48
+ // }
49
+ // }
50
+ // // does not assign offset to the new items.
51
+ // updateBulk(items: any[], bufferManagersMap: BufferManagersMap, bufferKeys: string[] | null = null) {
52
+ // const { offsetMap } = this;
53
+ // const offsets = [];
54
+ // for (const item of items) {
55
+ // const offset = offsetMap.get(item.key);
56
+ // if (offset !== undefined) {
57
+ // offsets.push(offset);
58
+ // } else {
59
+ // throw new Error("updateBulk item Key does not exist");
60
+ // }
61
+ // }
62
+ // if (bufferKeys) {
63
+ // for (const key of bufferKeys) {
64
+ // const bufferManagerComp = bufferManagersMap.get(key);
65
+ // if (bufferManagerComp === undefined) throw new Error("updateBulk bufferKey does not exist");
66
+ // const { bufferManager, adaptor } = bufferManagerComp;
67
+ // bufferManager.insertBulk(items.map(adaptor), offsets);
68
+ // }
69
+ // } else {
70
+ // for (const [key, { bufferManager, adaptor }] of bufferManagersMap) {
71
+ // bufferManager.insertBulk(items.map(adaptor), offsets);
72
+ // }
73
+ // }
74
+ // }
75
+ // deleteBulk(keys: string[], bufferManagersMap: BufferManagersMap) {
76
+ // const offsets = [];
77
+ // for (const key of keys) {
78
+ // const offset = this.getOffset(key);
79
+ // if (offset !== undefined) {
80
+ // offsets.push(offset);
81
+ // this.offsetMap.delete(key);
82
+ // this.tombstoneOffsets.push(offset);
83
+ // }
84
+ // }
85
+ // for (const [key, { bufferManager }] of bufferManagersMap) {
86
+ // bufferManager.deleteBulk(offsets);
87
+ // }
88
+ // }
89
+ // getOffset(key: string) {
90
+ // return this.offsetMap.get(key);
91
+ // }
92
+ // nextOffset(): number | undefined {
93
+ // if (this.tombstoneOffsets.length > 0) {
94
+ // const offset = this.tombstoneOffsets.pop() as number;
95
+ // return offset;
96
+ // }
97
+ // if (this._length < this._capacity) {
98
+ // return this._length++;
99
+ // }
100
+ // return undefined;
101
+ // }
102
+ // ensureSpace(itemsLength: number, bufferManagersMap: BufferManagersMap) {
103
+ // if (itemsLength <= this.emptySpace) return;
104
+ // const newCapacity = this.length + itemsLength;
105
+ // for (const [key, { bufferManager }] of bufferManagersMap) {
106
+ // bufferManager.extendBuffer(this.length, newCapacity);
107
+ // }
108
+ // this._capacity = newCapacity;
109
+ // }
110
+ // defrag(bufferManagers: BufferManagersMap, bufferKeys: string[]) { // TODO defrag and leave some empty space
111
+ // const offsetMap = this.offsetMap;
112
+ // const newCapacity = offsetMap.size + EXTRA_SIZE;
113
+ // if (bufferKeys) {
114
+ // for (const key of bufferKeys) {
115
+ // const offset = offsetMap.get(key);
116
+ // if (offset !== undefined) {
117
+ // for (const [key, { bufferManager }] of bufferManagers) {
118
+ // bufferManager.defrag([offset], this.length, newCapacity);
119
+ // }
120
+ // }
121
+ // }
122
+ // } else {
123
+ // for (const [key, { bufferManager }] of bufferManagers) {
124
+ // bufferManager.defrag(offsetMap.values(), this.length, newCapacity);
125
+ // }
126
+ // }
127
+ // this._defrag();
128
+ // this._length = offsetMap.size;
129
+ // this._capacity = newCapacity;
130
+ // this.tombstoneOffsets = [];
131
+ // }
132
+ // /**
133
+ // * Flushes metadata and sets length to 0 without actualize change on buffers
134
+ // * This method created for cases in which data is loaded on each frame
135
+ // */
136
+ // flush({ capacity = 10 } = {}) {
137
+ // this._length = 0;
138
+ // this._capacity = capacity;
139
+ // this.tombstoneOffsets = []
140
+ // this.offsetMap.clear();
141
+ // }
142
+ // _defrag() {
143
+ // const newOffsetMap = new Map();
144
+ // let newOffset = 0;
145
+ // for (const [key, offset] of this.offsetMap) {
146
+ // newOffsetMap.set(key, newOffset++);
147
+ // }
148
+ // this.offsetMap = newOffsetMap
149
+ // }
150
+ // get length() {
151
+ // return this._length;
152
+ // }
153
+ // get emptySpace() {
154
+ // return this._capacity - this.offsetMap.size;
155
+ // }
156
+ // get capacity() {
157
+ // return this._capacity;
158
+ // }
159
+ // }
@@ -23,7 +23,7 @@ export class ObjectStore {
23
23
  }
24
24
  }
25
25
  }
26
- insertConsecutiveBulk(objects, startOffset) {
26
+ insertBlock(objects, startOffset) {
27
27
  for (let i = 0; i < objects.length; i++) {
28
28
  const object = objects[i];
29
29
  const offset = startOffset + i;
@@ -1,161 +0,0 @@
1
- const EXTRA_SIZE = 10;
2
- export class BufferOrchestrator {
3
- _capacity;
4
- offsetMap;
5
- tombstoneOffsets;
6
- _length;
7
- constructor({ capacity = 10 } = {}) {
8
- this._capacity = capacity;
9
- this.offsetMap = new Map();
10
- this.tombstoneOffsets = [];
11
- this._length = 0;
12
- }
13
- resetWithCapacity(bufferManagersMap, capacity = null) {
14
- this._capacity = capacity !== null ? capacity : this._capacity;
15
- for (const [key, { bufferManager }] of bufferManagersMap) {
16
- bufferManager.resetWithCapacity(this._capacity);
17
- }
18
- this.offsetMap.clear();
19
- this.tombstoneOffsets = [];
20
- this._length = 0;
21
- }
22
- insertBulk(items, bufferManagersMap, bufferKeys = null) {
23
- this.ensureSpace(items.length, bufferManagersMap);
24
- const { offsetMap } = this;
25
- const offsets = [];
26
- for (const item of items) {
27
- let o = offsetMap.get(item.key);
28
- const offset = o !== undefined ? o : this.nextOffset();
29
- offsetMap.set(item.key, offset);
30
- offsets.push(offset);
31
- }
32
- if (bufferKeys) {
33
- for (const key of bufferKeys) {
34
- const bufferManagerComp = bufferManagersMap.get(key);
35
- if (bufferManagerComp === undefined)
36
- throw new Error("insertBulk bufferKey does not exist");
37
- const { bufferManager, adaptor } = bufferManagerComp;
38
- bufferManager.insertBulk(items.map(adaptor), offsets);
39
- }
40
- }
41
- else {
42
- for (const [key, { bufferManager, adaptor }] of bufferManagersMap) {
43
- bufferManager.insertBulk(items.map(adaptor), offsets);
44
- }
45
- }
46
- }
47
- // does not assign offset to the new items.
48
- updateBulk(items, bufferManagersMap, bufferKeys = null) {
49
- const { offsetMap } = this;
50
- const offsets = [];
51
- for (const item of items) {
52
- const offset = offsetMap.get(item.key);
53
- if (offset !== undefined) {
54
- offsets.push(offset);
55
- }
56
- else {
57
- throw new Error("updateBulk item Key does not exist");
58
- }
59
- }
60
- if (bufferKeys) {
61
- for (const key of bufferKeys) {
62
- const bufferManagerComp = bufferManagersMap.get(key);
63
- if (bufferManagerComp === undefined)
64
- throw new Error("updateBulk bufferKey does not exist");
65
- const { bufferManager, adaptor } = bufferManagerComp;
66
- bufferManager.insertBulk(items.map(adaptor), offsets);
67
- }
68
- }
69
- else {
70
- for (const [key, { bufferManager, adaptor }] of bufferManagersMap) {
71
- bufferManager.insertBulk(items.map(adaptor), offsets);
72
- }
73
- }
74
- }
75
- deleteBulk(keys, bufferManagersMap) {
76
- const offsets = [];
77
- for (const key of keys) {
78
- const offset = this.getOffset(key);
79
- if (offset !== undefined) {
80
- offsets.push(offset);
81
- this.offsetMap.delete(key);
82
- this.tombstoneOffsets.push(offset);
83
- }
84
- }
85
- for (const [key, { bufferManager }] of bufferManagersMap) {
86
- bufferManager.deleteBulk(offsets);
87
- }
88
- }
89
- getOffset(key) {
90
- return this.offsetMap.get(key);
91
- }
92
- nextOffset() {
93
- if (this.tombstoneOffsets.length > 0) {
94
- const offset = this.tombstoneOffsets.pop();
95
- return offset;
96
- }
97
- if (this._length < this._capacity) {
98
- return this._length++;
99
- }
100
- return false;
101
- }
102
- ensureSpace(itemsLength, bufferManagersMap) {
103
- if (itemsLength <= this.emptySpace)
104
- return;
105
- const newCapacity = this.length + itemsLength;
106
- for (const [key, { bufferManager }] of bufferManagersMap) {
107
- bufferManager.extendBuffer(this.length, newCapacity);
108
- }
109
- this._capacity = newCapacity;
110
- }
111
- defrag(bufferManagers, bufferKeys) {
112
- const offsetMap = this.offsetMap;
113
- const newCapacity = offsetMap.size + EXTRA_SIZE;
114
- if (bufferKeys) {
115
- for (const key of bufferKeys) {
116
- const offset = offsetMap.get(key);
117
- if (offset !== undefined) {
118
- for (const [key, { bufferManager }] of bufferManagers) {
119
- bufferManager.defrag([offset], this.length, newCapacity);
120
- }
121
- }
122
- }
123
- }
124
- else {
125
- for (const [key, { bufferManager }] of bufferManagers) {
126
- bufferManager.defrag(offsetMap.values(), this.length, newCapacity);
127
- }
128
- }
129
- this._defrag();
130
- this._length = offsetMap.size;
131
- this._capacity = newCapacity;
132
- this.tombstoneOffsets = [];
133
- }
134
- /**
135
- * Flushes metadata and sets length to 0 without actualize change on buffers
136
- * This method created for cases in which data is loaded on each frame
137
- */
138
- flush({ capacity = 10 } = {}) {
139
- this._length = 0;
140
- this._capacity = capacity;
141
- this.tombstoneOffsets = [];
142
- this.offsetMap.clear();
143
- }
144
- _defrag() {
145
- const newOffsetMap = new Map();
146
- let newOffset = 0;
147
- for (const [key, offset] of this.offsetMap) {
148
- newOffsetMap.set(key, newOffset++);
149
- }
150
- this.offsetMap = newOffsetMap;
151
- }
152
- get length() {
153
- return this._length;
154
- }
155
- get emptySpace() {
156
- return this._capacity - this.offsetMap.size;
157
- }
158
- get capacity() {
159
- return this._capacity;
160
- }
161
- }
@@ -1,75 +0,0 @@
1
- import { BufferManager } from "./buffer-manager";
2
- export class ChunkedBufferManager extends BufferManager {
3
- // Chunked insert that batches multiple items into fewer GPU calls
4
- insertBulkChunked(blocks, offsets, chunkSize = 1000) {
5
- const { gl, buffer, itemSize } = this;
6
- gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
7
- const offsetMultiplier = itemSize * 4;
8
- // Process in chunks to reduce GPU call overhead
9
- for (let i = 0; i < blocks.length; i += chunkSize) {
10
- const chunkEnd = Math.min(i + chunkSize, blocks.length);
11
- const chunkBlocks = blocks.slice(i, chunkEnd);
12
- const chunkOffsets = offsets.slice(i, chunkEnd);
13
- // Create a single large buffer for this chunk
14
- const totalItems = chunkBlocks.length;
15
- const chunkBuffer = new Float32Array(totalItems * itemSize);
16
- // Copy all chunk data into one buffer
17
- for (let j = 0; j < chunkBlocks.length; j++) {
18
- chunkBuffer.set(chunkBlocks[j], j * itemSize);
19
- }
20
- // Find contiguous ranges for efficient uploads
21
- const ranges = this.findContiguousRanges(chunkOffsets, offsetMultiplier);
22
- for (const range of ranges) {
23
- const startOffset = range.startOffset;
24
- const dataStart = range.indices[0] * itemSize;
25
- const dataLength = range.indices.length * itemSize;
26
- const rangeData = chunkBuffer.subarray(dataStart, dataStart + dataLength);
27
- gl.bufferSubData(gl.ARRAY_BUFFER, startOffset, rangeData);
28
- }
29
- }
30
- gl.bindBuffer(gl.ARRAY_BUFFER, null);
31
- }
32
- // Optimized delete that batches operations
33
- deleteBulkChunked(offsets, chunkSize = 1000) {
34
- const { gl, buffer, itemSize } = this;
35
- const emptyBlock = new Float32Array(itemSize).fill(NaN);
36
- const offsetMultiplier = itemSize * 4;
37
- gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
38
- // Sort offsets for better cache coherency
39
- const sortedOffsets = [...offsets].sort((a, b) => a - b);
40
- // Process in chunks
41
- for (let i = 0; i < sortedOffsets.length; i += chunkSize) {
42
- const chunkEnd = Math.min(i + chunkSize, sortedOffsets.length);
43
- for (let j = i; j < chunkEnd; j++) {
44
- const offset = sortedOffsets[j];
45
- if (offset !== undefined) {
46
- gl.bufferSubData(gl.ARRAY_BUFFER, offset * offsetMultiplier, emptyBlock);
47
- }
48
- }
49
- }
50
- gl.bindBuffer(gl.ARRAY_BUFFER, null);
51
- }
52
- // Find contiguous memory ranges for batch uploads
53
- findContiguousRanges(offsets, offsetMultiplier) {
54
- const ranges = [];
55
- const sortedIndices = offsets
56
- .map((offset, index) => ({ offset: offset * offsetMultiplier, index }))
57
- .sort((a, b) => a.offset - b.offset);
58
- let currentRange = null;
59
- for (const { offset, index } of sortedIndices) {
60
- if (!currentRange || offset !== currentRange.startOffset + currentRange.indices.length * offsetMultiplier) {
61
- // Start new range
62
- if (currentRange)
63
- ranges.push(currentRange);
64
- currentRange = { startOffset: offset, indices: [index] };
65
- }
66
- else {
67
- // Extend current range
68
- currentRange.indices.push(index);
69
- }
70
- }
71
- if (currentRange)
72
- ranges.push(currentRange);
73
- return ranges;
74
- }
75
- }
@@ -1,195 +0,0 @@
1
- export class ChunkedBufferOrchestrator {
2
- _capacity;
3
- _length;
4
- offsetMap;
5
- tombstoneOffsets;
6
- // Chunking configuration
7
- chunkSize;
8
- maxPendingOperations;
9
- autoFlushInterval;
10
- // Pending operations batching
11
- pendingInserts;
12
- pendingUpdates;
13
- pendingDeletes;
14
- operationCount;
15
- flushTimer;
16
- constructor({ capacity = 10, chunkSize = 1000, maxPendingOperations = 5000, autoFlushInterval = 16 // ~60fps
17
- } = {}) {
18
- this._capacity = capacity;
19
- this._length = 0;
20
- this.offsetMap = new Map();
21
- this.tombstoneOffsets = [];
22
- this.chunkSize = chunkSize;
23
- this.maxPendingOperations = maxPendingOperations;
24
- this.autoFlushInterval = autoFlushInterval;
25
- this.pendingInserts = new Map();
26
- this.pendingUpdates = new Map();
27
- this.pendingDeletes = new Set();
28
- this.operationCount = 0;
29
- this.flushTimer = null;
30
- this.startAutoFlush();
31
- }
32
- resetWithCapacity(bufferManagersMap, capacity = null) {
33
- this.flushPendingOperations(bufferManagersMap);
34
- this._capacity = capacity !== null ? capacity : this._capacity;
35
- for (const [key, { bufferManager }] of bufferManagersMap) {
36
- bufferManager.resetWithCapacity(this._capacity);
37
- }
38
- this.offsetMap.clear();
39
- this.tombstoneOffsets = [];
40
- this._length = 0;
41
- }
42
- // Batch insert operations
43
- insertBulk(items, bufferManagersMap, bufferKeys = null) {
44
- const targetKeys = bufferKeys || Array.from(bufferManagersMap.keys());
45
- // Process items in chunks
46
- for (let i = 0; i < items.length; i += this.chunkSize) {
47
- const chunk = items.slice(i, i + this.chunkSize);
48
- this.queueInsertChunk(chunk, targetKeys);
49
- }
50
- this.operationCount += items.length;
51
- this.checkAutoFlush(bufferManagersMap);
52
- }
53
- // Batch update operations
54
- updateBulk(items, bufferManagersMap, bufferKeys = null) {
55
- const targetKeys = bufferKeys || Array.from(bufferManagersMap.keys());
56
- for (let i = 0; i < items.length; i += this.chunkSize) {
57
- const chunk = items.slice(i, i + this.chunkSize);
58
- this.queueUpdateChunk(chunk, targetKeys);
59
- }
60
- this.operationCount += items.length;
61
- this.checkAutoFlush(bufferManagersMap);
62
- }
63
- // Batch delete operations
64
- deleteBulk(keys, bufferManagersMap) {
65
- for (const key of keys) {
66
- const offset = this.offsetMap.get(key);
67
- if (offset !== undefined) {
68
- this.pendingDeletes.add(offset);
69
- this.offsetMap.delete(key);
70
- this.tombstoneOffsets.push(offset);
71
- }
72
- }
73
- this.operationCount += keys.length;
74
- this.checkAutoFlush(bufferManagersMap);
75
- }
76
- queueInsertChunk(items, bufferKeys) {
77
- this.ensureSpaceForItems(items.length);
78
- const offsets = [];
79
- for (const item of items) {
80
- let offset = this.offsetMap.get(item.key);
81
- if (offset === undefined) {
82
- offset = this.nextOffset();
83
- this.offsetMap.set(item.key, offset);
84
- }
85
- offsets.push(offset);
86
- }
87
- for (const bufferKey of bufferKeys) {
88
- if (!this.pendingInserts.has(bufferKey)) {
89
- this.pendingInserts.set(bufferKey, { items: [], offsets: [] });
90
- }
91
- const pending = this.pendingInserts.get(bufferKey);
92
- pending.items.push(...items);
93
- pending.offsets.push(...offsets);
94
- }
95
- }
96
- queueUpdateChunk(items, bufferKeys) {
97
- const offsets = [];
98
- for (const item of items) {
99
- const offset = this.offsetMap.get(item.key);
100
- if (offset === undefined) {
101
- throw new Error(`Update item key '${item.key}' does not exist`);
102
- }
103
- offsets.push(offset);
104
- }
105
- for (const bufferKey of bufferKeys) {
106
- if (!this.pendingUpdates.has(bufferKey)) {
107
- this.pendingUpdates.set(bufferKey, { items: [], offsets: [] });
108
- }
109
- const pending = this.pendingUpdates.get(bufferKey);
110
- pending.items.push(...items);
111
- pending.offsets.push(...offsets);
112
- }
113
- }
114
- checkAutoFlush(bufferManagersMap) {
115
- if (this.operationCount >= this.maxPendingOperations) {
116
- this.flushPendingOperations(bufferManagersMap);
117
- }
118
- }
119
- // Force flush all pending operations to GPU
120
- flushPendingOperations(bufferManagersMap) {
121
- // Process deletes first
122
- if (this.pendingDeletes.size > 0) {
123
- const deleteOffsets = Array.from(this.pendingDeletes);
124
- for (const [key, { bufferManager }] of bufferManagersMap) {
125
- bufferManager.deleteBulk(deleteOffsets);
126
- }
127
- this.pendingDeletes.clear();
128
- }
129
- // Process inserts
130
- for (const [bufferKey, { items, offsets }] of this.pendingInserts) {
131
- const bufferManagerComp = bufferManagersMap.get(bufferKey);
132
- if (bufferManagerComp) {
133
- const { bufferManager, adaptor } = bufferManagerComp;
134
- const adaptedData = items.map(adaptor);
135
- bufferManager.insertBulkChunked(adaptedData, offsets, this.chunkSize);
136
- }
137
- }
138
- this.pendingInserts.clear();
139
- // Process updates
140
- for (const [bufferKey, { items, offsets }] of this.pendingUpdates) {
141
- const bufferManagerComp = bufferManagersMap.get(bufferKey);
142
- if (bufferManagerComp) {
143
- const { bufferManager, adaptor } = bufferManagerComp;
144
- const adaptedData = items.map(adaptor);
145
- bufferManager.insertBulkChunked(adaptedData, offsets, this.chunkSize);
146
- }
147
- }
148
- this.pendingUpdates.clear();
149
- this.operationCount = 0;
150
- }
151
- ensureSpaceForItems(itemCount) {
152
- if (itemCount <= this.emptySpace)
153
- return;
154
- const newCapacity = Math.max(this._capacity * 2, this._length + itemCount + this.chunkSize);
155
- this._capacity = newCapacity;
156
- }
157
- nextOffset() {
158
- if (this.tombstoneOffsets.length > 0) {
159
- return this.tombstoneOffsets.pop();
160
- }
161
- if (this._length < this._capacity) {
162
- return this._length++;
163
- }
164
- return false;
165
- }
166
- startAutoFlush() {
167
- if (this.autoFlushInterval > 0) {
168
- this.flushTimer = setInterval(() => {
169
- if (this.operationCount > 0) {
170
- // Note: You'll need to pass bufferManagersMap here
171
- // This requires restructuring to maintain reference
172
- console.log(`Auto-flush triggered with ${this.operationCount} pending operations`);
173
- }
174
- }, this.autoFlushInterval);
175
- }
176
- }
177
- stopAutoFlush() {
178
- if (this.flushTimer) {
179
- clearInterval(this.flushTimer);
180
- this.flushTimer = null;
181
- }
182
- }
183
- // Getters
184
- get length() { return this._length; }
185
- get emptySpace() { return this._capacity - this.offsetMap.size; }
186
- get capacity() { return this._capacity; }
187
- get pendingOperationCount() { return this.operationCount; }
188
- // Manual control
189
- forceMajorFlush(bufferManagersMap) {
190
- this.flushPendingOperations(bufferManagersMap);
191
- }
192
- getOffset(key) {
193
- return this.offsetMap.get(key);
194
- }
195
- }