appy-one / acebase

A fast, low memory, transactional, index & query enabled NoSQL database engine and server for node.js and browser with realtime data change notifications
MIT License
489 stars 27 forks source link

Live query and indexing #225

Open TELECI-PROJECT opened 1 year ago

TELECI-PROJECT commented 1 year ago

Hi! I’m facing the following issue. It seems it is related to live queries and index updates. I did some testing, my setup was working well when indexing by keys that are not included as parameters in live queries.

As I indexed my data by key/keys included in a live query my node script started

This is my system setup: acebase-server@1.16.2 acebase-client@1.20.1 acebase@1.28.3

This is what works well: I have data objects stored in ‘items’ folder, each one has unique ID. Item/uniqueid/{category: category1, location: location1, status: 1} Item/uniqueid/{category: category2, location: location1, status: 3} Item/uniqueid/{..} Etc.

Then I have two indexes set up: Index(‘item’, ‘category’); Index(‘item’, ‘location);

Also, I have a running a live query listening to changes on ‘status’ property (on my app client).

I’m adding new items, then updating them (status is updated) and later some items are removed. Data removal is done periodically (every 10min). All updates are done sequentially.

This is what not working well: I have the same setup as above:

The difference is: now I have added an index: Index(‘item’, ‘status); I still have a running live query listening to changes on ‘status’ property as before (on my app client). This works well until the data removal script has started to remove items.

Now I see the following error and node script restarts: /loc1/xxx/xxxx/nodejs/node_modules/acebase-client/dist/cjs/request/index.js:89 reject(new error_1.AceBaseRequestError(request, null, err.code || err.name, err.message)); ^

AceBaseRequestError: connect ECONNRESET XXXXXXXXXXXXXXXXXXX:1234 at ClientRequest. (/loc1/xxx/xxxx/nodejs/node_modules/acebase-client/dist/cjs/request/index.js:89:20) at ClientRequest.emit (node:events:390:28) at TLSSocket.socketErrorListener (node:_http_client:447:9) at TLSSocket.emit (node:events:390:28) at emitErrorNT (node:internal/streams/destroy:157:8) at emitErrorCloseNT (node:internal/streams/destroy:122:3) at processTicksAndRejections (node:internal/process/task_queues:83:21) { request: { method: 'PUT', protocol: 'https:', host: 'xxxxxxxxx', port: '1234', path: '/data/acebase_test/items/1197171', headers: { 'AceBase-Context': '{"skipProcess":true,"acebase_mutation":{"client_id":"xxxxxxxxx","id":"xxxxxxxxxxxxx","op":"set","path":"items/1197171","flow":"server"}}', 'Content-Type': 'application/json', 'Content-Length': 12, Authorization: 'Bearer xxxxxxxxxx==' }, body: undefined }, response: null, code: 'ECONNRESET' }

I don’t see any errors when my data removal script is disabled. It seems deletion process interferes with the index. The index (on status key) gets corrupted and I have to recreate it. I have tried deleting data items using delete query as well.

appy-one commented 1 year ago

Thanks for reporting, I'll dive into it asap!

TELECI-PROJECT commented 1 year ago

Thanks, I did some more testing. I was able to catch another error.

The setup is the same as above: 1) I have an index on 'status' running, 2) Live query is running as before, 3) Then I update (status value changes) /items/itemd/{ status: other status value }

This corrupts 'status' index and I see this error message:

Lock "./acebase_xxxxxxx3v_2.acebase/items-status.idx" timed out! lock.release() was not called in a timely fashion [acebase_xxxxxxx3v_2] failed to set "items/1278796": Error: Could not achieve lock because the current lock ("./acebase_xxxxxxx3v_2.acebase/items-status.idx") was not released in time (and lock is flagged critical) at /loc1/yyy/ccccc3/nodejs/node_modules/acebase/dist/cjs/thread-safe.js:52:33 at Array.forEach () at Timeout.timeoutHandler [as _onTimeout] (/home/yyy/ccccc3/nodejs/node_modules/acebase/dist/cjs/thread-safe.js:50:29) at listOnTimeout (node:internal/timers:571:11) at process.processTimers (node:internal/timers:512:7) /loc1/yyy/ccccc3/nodejs/node_modules/acebase-client/dist/cjs/request/index.js:84 return reject(new error_1.AceBaseRequestError(request, response, code, message));

appy-one commented 1 year ago

@TELECI-PROJECT I managed to reproduce the issue, looking into it now

appy-one commented 1 year ago

I spent the entire day on this issue, I am pretty sure #226 fixes it! The fix has been published with v1.28.6, let me know if it works!

TELECI-PROJECT commented 1 year ago

Hi, thanks, I don't see any errors anymore.

What I noticed is there is an issue with the live query events emission.

When index on 'status' is enabled, live query is not emitting 'change' events. It seems 'remove' events are working fine. (I don't use 'add' event).

Everything works fine when there is no index on 'status'.

appy-one commented 1 year ago

Are you sure this is not the right behavior? If you have a query with a filter on status == 1, and the status changes to 2, this will cause a remove event on your query because it does not meet the filter requirement. If you change any other field that is in the result set of your query (and still meets any filter requirements) that should emit change events.

The fact that you mention in works differently without the index in place does require further investigation on my end though! It would be helpful if you can submit minimal code that reproduces it and demonstrates this faulty behavior, that would save me a lot of time trying to reproduce it. You can use my test code created for this issue as boilerplate code if that helps: https://github.com/appy-one/acebase/blob/master/src/test/issue-225.spec.ts

TELECI-PROJECT commented 1 year ago

Ok, I will think of the code reproduction soon.

It seems I was wrong about remove event.

I have two live queries, one is listening to status == 1, the other is listening to status == 2. (events on CHANGE and on REMOVE).

Test 1: Index 'status' is enabled: my live query is firing no events.

Test 2: No 'status' index enabled: my live query is firing events (CHANGE and REMOVE)

TELECI-PROJECT commented 1 year ago

Hi, please find information about my tests below:

This is the test code was using: https://github.com/TELECI-PROJECT/acebase-testing/blob/main/testing-live-query-and-indexing (this is based on your test code https://github.com/appy-one/acebase/blob/master/src/test/issue-225.spec.ts)

I was running it on Nodejs v18.14.0. This is my setup: acebase@1.29.0 acebase-server@1.18.0 acebase-client@1.21.0

The database folder was removed for every test.

Testing results:

TEST 1 I was running the code with all tree indexes: await db.indexes.create('items', 'location'); await db.indexes.create('items', 'category'); await db.indexes.create('items', 'status');

There were no events fired by Acebase live query Test result: 0 added, 0 changed, 0 removed

TEST 2 I was running the code with one index: await db.indexes.create('items', 'location'); //await db.indexes.create('items', 'category'); //await db.indexes.create('items', 'status');

Acebase live query was firing events as expected Test result: 1000 added, 144 changed, 1000 removed

Conclusion: Acebase live query is firing events as expected if none of query filter parameters is indexed. In this case they are params ‘category’ and ‘status’. The live query won’t fire events if any of filter parameters is indexed.

The following two test scenario won’t work either (meaning the live query won’t emit any events): await db.indexes.create('items', 'location'); await db.indexes.create('items', 'category'); //await db.indexes.create('items', 'status');

OR await db.indexes.create('items', 'location'); //await db.indexes.create('items', 'category'); await db.indexes.create('items', 'status');