mobilexag / cordova-sqlite-evplus-ext-free

Other
0 stars 2 forks source link

transition to cordova-sqlite-evmax-eu-build-free #38

Open brodycj opened 1 year ago

brodycj commented 1 year ago

As discussed by email, we want to transition away from this private fork towards a new evmax pluign version: https://github.com/brodybits/cordova-sqlite-evmax-eu-build-free

Here are the most important changes:

Here are the changes between this plugin version and cordova-sqlite-evmax-eu-build-free:

with the following changes in the Android NDK library:

TODO:

brodycj commented 1 year ago

I have just updated https://github.com/brodybits/cordova-sqlite-evmax-eu-build-free with SQLite 3.43.0 & math functions enabled, with 0.0.1-pre02 tag

kryops commented 1 year ago

Hi @brodybits ,

iOS is looking good, however on Android I noticed random freezes that occur after a few seconds or minutes of clicking through the app.

I tried a bit of debugging with medium success; here's my findings:

image

"pool-10-thread-2@23553" prio=5 tid=0x12d nid=NA waiting
  java.lang.Thread.State: WAITING
      at sun.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2067)
      at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
      at io.sqlc.SQLitePlugin$DBRunner.run(SQLitePlugin.java:541)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
      at java.lang.Thread.run(Thread.java:920)

Is there anything more that we can do on our end to locate the root cause?

Thanks for looking into it!

brodycj commented 1 year ago

My understanding is that you observe this form of instability with the new evmax plugin version but NOT with this existing mobileX fork.

It would help me if you could test the stability with another plugin fork, which has no EU character support: https://github.com/storesafe/cordova-plugin-sqlite-evplus-ext-common-free

I am now wondering if there could be an issue my evmax workaround solution for 200 MB input data and something and your mobileX application.

kryops commented 1 year ago

That's correct, in the existing mobileX fork we did not observe this issue.

I just tested with https://github.com/storesafe/cordova-plugin-sqlite-evplus-ext-common-free#0.9.1-rc01, and I could reproduce the issue there as well.

brodycj commented 1 year ago

That indicates to me that there is an issue somewhere between your application and the evplus enhancements in cordova-plugin-sqlite-evplus-ext-common-free. At this point I am suspecting an issue in the plugin, NOT in your application code. (Note that this plugin version never got the enhancements from cordova-plugin-sqlite-evplus-ext-common-free despite its "evplus" plugin name.)

It may help if you can give me an idea what kind of data it is getting stuck on. Here is my email address in case you don't have it on hand: chris.brody+brodybits@gmail.com

kryops commented 1 year ago

I tried to dig a little deeper: It seems that this affects queries with quite large result sets.

I observed two separate error cases in SQLitePluginTransaction.prototype.run_batch_flatjson: 1) The result does not end with a "endrows" item, so the loop runs infinitely and causes an out of memory because it keeps adding empty rows to the rows array

image

(I set a conditional breakpoint for ri > 10000)

image

2) The mycb callback is called twice for the same query, but the result array only seems to be a slice of what we expect, and it does not start with "okrows". Thus the whole result set is skipped and the callback in the user code is never called:

image

I did not have much luck yet debugging further down in SQLitePluginTransaction.prototype.run_batch_flat_with_dbid_part2.

I also tried to build a minimal Cordova app with a reproduction, but had no luck either. Maybe we will end up sending you our actual app via e-mail so you can use it for debugging 😅

brodycj commented 1 year ago

@kryops thanks for all of your efforts!

It seems to me like the result data has quite a number of columns with null, integer, and short string values. I will guess there may be some longer string values in the result columns as well.

I would like to do some testing on my own with a large number of columns with varying column data types & sizes and see how my evplus & evmax plugin versions hold up.

I would like to discuss some other options by private email with @DanielSWolf as well.

brodycj commented 1 year ago

@kryops it may be helpful if you can give me a rough idea of how many columns may be in the result data and now many of the columns may have string length greater than 10 characters or so.

I will work on a test case to see how my evplus & evmax plugin versions work with such a large number of result columns. I will also follow up with @DanielSWolf by email, maybe later today.

kryops commented 1 year ago

@brodybits here are example rows from the two queries that seem to be the ones affected most:

committed: true
description: null
id: "12353"
installationDisplayId: null
installationId: null
installationShortText: null
locationDisplayId: "10224"
locationId: "14"
locationShortText: "Klinikum der Universität München"
notificationDisplayId: null
notificationId: null
notificationShortText: null
position: 1
workingState: "NOT_DONE"
assignmentId: "1251"
assignmentType: "SM01"
assignmentWorkflowStatus: "SEEN"
installationDisplayId: "10018863"
installationId: "5515"
installationMaterialNo: null
installationType: "M"
locationDisplayId: "10223"
locationId: "7"
notificationDate: "2017-04-28T12:21:53.000Z"
notificationId: "625"
notificationPriority: "2"
notificationStatus: "MAUF MIAR"
notificationType: "S2"
objectListItemDisplayId: "10018863"
objectListItemId: "12355"
orderActivityType: "001"
orderId: "774"
orderType: "SM02"
brodycj commented 1 year ago

Also rough estimate of how many result rows from each of the queries?

Thanks!

kryops commented 1 year ago

in this particular case it was 154 rows for both queries

brodycj commented 1 year ago

Thanks. By design the result is split up and sent in parts, looks like something is not working right. I may need a few weeks to try these out.

brodycj commented 1 year ago

I found a possible reproduction case,

UPDATED: This reproduces an issue with error handling in case of not enough SQLite statement parameters which ends up with no response back to the JavaScript side - will discuss further in comments coming up below

(based on a reproduction I made for https://github.com/storesafe/cordova-sqlite-storage-help/issues/70 from the past):

        it(suiteName + 'INSERT JSON TEXT string many rows with hundred properties each with extra columns & SELECT the data 6x', function(done) {
          var db = openDatabase('INSERT-JSON-TEXT-string-many-rows-with-hundred-properties-extra-columns-and-select-data-6x.db')

          var test_rows = 700
          var test_props = 100

          db.transaction(function(tx) {
            tx.executeSql('DROP TABLE IF EXISTS test_table');
            tx.executeSql('CREATE TABLE IF NOT EXISTS test_table (data, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15)', [], function(ignored1, ignored2) {

              for (var id=0; id<test_rows; ++id) {
                var obj = {}

                obj.id = id;

                for (var i=0; i<test_props; ++i) {
                  obj['prop'+i] = 'value-'+(1000+i)
                }

                var insert_data = JSON.stringify(obj)

                tx.executeSql('INSERT INTO test_table VALUES (?,?,?,?,?,?,?,?)', [insert_data, null, 8881, null, 8882, null, 8883, 8884])
              }

              tx.executeSql('INSERT INTO test_table VALUES (?)', ['{extra:true}'], function(tx_ignored, rs1) {
                expect(rs1).toBeDefined();
                expect(rs1.rowsAffected).toBe(1);

                tx.executeSql('SELECT * FROM test_table')
                tx.executeSql('SELECT * FROM test_table')
                tx.executeSql('SELECT * FROM test_table')
                tx.executeSql('SELECT * FROM test_table')
                tx.executeSql('SELECT * FROM test_table')
                tx.executeSql('SELECT data FROM test_table', [], function(tx_ignored, rs2) {
                  expect(rs2).toBeDefined();
                  expect(rs2.rows).toBeDefined();
                  // expect(rs2.rows.length).toBe(???);

                  var row = rs2.rows.item(0);
                  expect(row.data).toBeDefined() // [TBD (...)]

                  done();

                });
              });
            });
          }, function(error) {
            // NOT EXPECTED:
            expect(false).toBe(true);
            expect(error.message).toBe('---');
            // Close (plugin only) & finish:
            (isWebSql) ? done() : db.close(done, done);
          });
        }, MYTIMEOUT);

The new evmax plugin version freezes with this case; both cordova-sqlite-evcore-extbuild-free and the existing mobileX evplus fork end up with an internal batch error.

I would absolutely hope to support this case. I may need some time to investigate further and find a solution. Thanks.

brodycj commented 1 year ago

The previous reproduction I made was incorrect due to not enough INSERT parameters, and it led to the frozen execution in the new evmax plugin version. I would like to resolve that, but I am not (yet) convinced that my previous reproduction covers the issue with your application.

I have made another test case that can successfully insert many records that I think should reflect the kind of data that your application inserts into the database, then tried selecting multiple times within the same transaction. In this case I am able to SELECT & ignore the data 3 times, uncomment the 4th time and it crashes on my emulator. (I have also added a commented-out line that reproduces the issue I found with not enough INSERT parameters.)

        it(suiteName + 'INSERT JSON TEXT string many rows with hundred properties each with extra columns & SELECT the data 6x', function(done) {
          var db = openDatabase('INSERT-JSON-TEXT-string-many-rows-with-hundred-properties-extra-columns-and-select-data-6x.db')

          var test_rows = 7000
          var test_props = 100

          db.transaction(function(tx) {
            tx.executeSql('DROP TABLE IF EXISTS test_table');
            tx.executeSql('CREATE TABLE IF NOT EXISTS test_table (data, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15)', [], function(ignored1, ignored2) {

              for (var id=0; id<test_rows; ++id) {
                var obj = {}

                obj.id = id;

                for (var i=0; i<test_props; ++i) {
                  obj['prop'+i] = 'value-'+(1000+i)
                }

                var insert_data = JSON.stringify(obj)

                // INCORRECT INSERT - MISSING 2 ARGUMENTS - NO RESPONSE TO JAVASCRIPT SIDE:
                // tx.executeSql('INSERT INTO test_table VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)', [insert_data, 'abcdefghijklmnopqrst', null, 7771, 'abcdef', null, 71, 'abcdefghijklmnopqrst', null, 7771, 'abcdef', null, 71])
                // CORRECT INSERT:
                tx.executeSql('INSERT INTO test_table VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [insert_data, 'abcdefghijklmnopqrst', null, 7771, 'abcdef', null, 71, 'abcdefghijklmnopqrst', null, 7771, 'abcdef', null, 71, 'abcdef', null])
              }

              tx.executeSql('INSERT INTO test_table VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', ['{extra:true}', null, 8881, null, 8882, null, 8883, 8884, 1, 1, 1, 1, 1, 1, 1], function(tx_ignored, rs1) {
                expect(rs1).toBeDefined();
                expect(rs1.rowsAffected).toBe(1);

                // SELECT & IGNORE:
                tx.executeSql('SELECT * FROM test_table')

                // SELECT & IGNORE - AGAIN & AGAIN:
                tx.executeSql('SELECT * FROM test_table')
                tx.executeSql('SELECT * FROM test_table')

                // UNCOMMENT FOR ONE MORE TIME CRASHES IN MY EMULATOR:
                // tx.executeSql('SELECT * FROM test_table')

                // SELECT & EXAMINE (just a little):
                tx.executeSql('SELECT data FROM test_table', [], function(tx_ignored, rs2) {
                  expect(rs2).toBeDefined();
                  expect(rs2.rows).toBeDefined();
                  // expect(rs2.rows.length).toBe(???);

                  var row = rs2.rows.item(0);
                  expect(row.data).toBeDefined() // [TBD (...)]

                  done();

                });
              });
            });
          }, function(error) {
            // NOT EXPECTED:
            expect(false).toBe(true);
            expect(error.message).toBe('---');
            // Close (plugin only) & finish:
            (isWebSql) ? done() : db.close(done, done);
          });
        }, MYTIMEOUT);

I would really love to get all of these cases working, still need to investigate further before promising any timelines.