storesafe / cordova-sqlite-storage

A Cordova/PhoneGap plugin to open and use sqlite databases on Android, iOS and Windows with HTML5/Web SQL API
Other
2.15k stars 715 forks source link

Is possible to abort all pending transactions before deleting DB? #367

Open sriram275 opened 9 years ago

sriram275 commented 9 years ago

Hi.., I am doing more than 2000 records inserting or updating..so it will run in background. If I want to delete the db by clicking on stop and delete from user while transactions are in background. Is possible to abort all pending transactions and then delete the DB. I have seen some piece of code from SQLiteplugin.js

deleteDb: function(first, success, error) {
      var args, dblocation;
      args = {};
      if (first.constructor === String) {
        args.path = first;
        args.dblocation = dblocations[0];
      } else {
        if (!(first && first['name'])) {
          throw new Error("Please specify db name");
        }
        args.path = first.name;
        dblocation = !!first.location ? dblocations[first.location] : null;
        args.dblocation = dblocation || dblocations[0];
      }
      delete SQLitePlugin.prototype.openDBs[args.path];
      return cordova.exec(success, error, "SQLitePlugin", "delete", [args]);
    }
  };

In this method before we calling delete SQLitePlugin.prototype.openDBs[args.path]; can we abort all pending transactions.?

And more over we have already abort pending transactions method also.

SQLitePlugin.prototype.abortAllPendingTransactions = function() {
    var tx, txLock, _i, _len, _ref;
    txLock = txLocks[this.dbname];
    if (!!txLock && txLock.queue.length > 0) {
      _ref = txLock.queue;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        tx = _ref[_i];
        tx.abortFromQ(newSQLError('Invalid database handle'));
      }
      txLock.queue = [];
      txLock.inProgress = false;
    }
  };

So I am using this method to abort all pending transactions of the DB( by passing DB name instead of this.dbname) which I am trying to Delete.

It is working fine but some cases its throwing some exception and stuck the application.

Let me know your thoughts and if you have any other option to abort pending transactions before deleting that DB.

brodycj commented 9 years ago

Yes but it would be a bit of a challenge to get this right. Basically, we would remove all transactions from the queue except for the transaction that is currently in progress, keep a record that the user is attempting to delete the database, and wait for the transaction to finish.

I have already raised #210 to abort all pending transactions when closing a database.

sriram275 commented 9 years ago

In DB close also we are checking about in progress transactions..so if any pending transactions are there then it's throwing exception..

SQLitePlugin.prototype.close = function(success, error) {
    if (this.dbname in this.openDBs) {
      if (txLocks[this.dbname] && txLocks[this.dbname].inProgress) {
        console.log('cannot close: transaction is in progress');
        error(newSQLError('database cannot be closed while a transaction is in progress'));
        return;
      }
      console.log('CLOSE database: ' + this.dbname);
      delete this.openDBs[this.dbname];
      if (txLocks[this.dbname]) {
        console.log('closing db with transaction queue length: ' + txLocks[this.dbname].queue.length);
      } else {
        console.log('closing db with no transaction lock state');
      }
      cordova.exec(success, error, "SQLitePlugin", "close", [
        {
          path: this.dbname
        }
      ]);
    } else {
      console.log('cannot close: database is not open');
      if (error) {
        nextTick(function() {
          return error();
        });
      }
    }
  };

So if any pending transactions are there then it won't close the DB.

Let me know if the following steps will helpful means..

abortAllPendingTransactions ( for abort pending transactions ) close ( to close DB ) deleteDb ( to delete the DB )

brodycj commented 9 years ago

In general that sounds like a good approach. The one issue is that if there is a transaction already in progress, it will probably finish up can call its success callback if successful.

sriram275 commented 8 years ago

Hi.., The above approach is working fine but in some cases it's failing..

one of the situation is:

var tempDb = 'tempInv24537.db';
 if (tempDb != '') {
            window.sqlitePlugin.abortPendingtempTransaction(tempDb); //created new method from your existing method and passing db name
            setTimeout(function () { $cordovaSQLite.deleteDB(tempDb); }, 100);
        }

in the above example I am trying to abort all pending transactions and then deleting db...but if the pending transactions are more and it is in process of trying to abort all pending ones meanwhile deleteDB is called and db is deleted. In this case app is getting hanged and user not able to do any function on the app. (I am running app through xcode so once its gets hanged then in xcode it is going to a pointer to the line in SQLitePlugin.m at 373 i.e previousRowsAffected )

So my question: is possible to have abortpendingtransaction method with promise..? so once after aborting all transactions then only we will call deleteDB method and then it will care of delete DB.

Why I am asking all these because we are dealing with temparary dbs which are for just in case..which will work on one a particular page and user is leaving from that page I want to delete that DB..I don't want store all DBs. So while user is in that page there should be one temporary DB.

If you have any other approach other than this let me know..

brodycj commented 8 years ago

Would an in-memory database solve your issue?

sriram275 commented 8 years ago

I don't know much about in-memory database..but by checking this In-Memory Databases I came to know that

will this plugin( either cordova sqlite storage or cordova sqlite evfree) support with in-memory database? can we do the same transactions(insert,update and delete) like what we are doing with .db?

brodycj commented 8 years ago

Unfortunately I do not expect the in-memory databases to work correctly with this plugin since each implementation will try prepending the implementation-specific database storage path before the sqlite3_open() call. I cannot promise when I will be able to fix this due to my existing backlog of both paid and free software work.

The recommended workaround is to keep a limited set of temporary database tables that you can clear by using DROP or DELETE FROM when a new page is loaded.