jeudi 24 mars 2016

C++ SQLite Serialized Mode Questions

I have been through Quite a few pages, and have an ok Idea of whats happening it think, but I have a few Questions just to be sure....

my program uses the -DTHREADSAFE=1 compile options, forks on receiving a database request (Select, Delete, Insert, Update) from a user or my network, then the child process handles the various database tasks, and relaying of messages should that be required and so on,

at the moment my database is not setup for concurrency which I wont lie is a major design flaw, but that's beside the point at the moment, let's say I have a function that prints all the entries in my table LEDGER as follows...

void PersonalDataBase::printAllEntries()
{
//get all entries
const char query [] = "select * from LEDGER";
sqlite3_stmt *stmt;
int error

try
{
    if ((error = sqlite3_prepare(publicDB, query, -1, &stmt, 0 )) == SQLITE_OK)
    {
        int ctotal = sqlite3_column_count(stmt);
        int res = 0;

        while ( 1 )         
        {
                res = sqlite3_step(stmt);

                if ( res == SQLITE_ROW ) 
                {
                    Entry *temp = loadBlockRow(stmt);

                    string from, to;
                    from = getNameForHash(temp -> from);
                    to = getNameForHash(temp -> to);

                    temp -> setFromOrTo(from, 0);
                    temp -> setFromOrTo(to, 1);

                    temp -> printEntry();
                    printlnEnd();
                    delete temp;
                }
                else if ( res == SQLITE_DONE || res==SQLITE_ERROR)    
                {
                    if (res == SQLITE_ERROR) { throw res; }
                    sqlite3_finalize(stmt);
                    break;
                }    
        }
    }
    //problems
    else
    {
        throw error;
    }
}
catch (int err)
{
    sqlite3_finalize(stmt);
    setupOutput();
    cout << "Database Error: " << sqlite3_errmsg(publicDB) << ", Error Code: " << (int) error << endl;
    cout << "Did Not Find Values Try Again After Fixing Problems Above." << endl;   
    printlnEnd();
}
println("Done!");
}

  • my setupOutput(), printlnEnd(), println(), all help with my use of 'non-blocking' keyboard i/o, they work as I want lets not worry about them here, and think of them as just a call to cout

ok so now at this point I figure there are 4 options...

  1. A while around my try/catch, then in catch check if err = 5, if so I need to setup a sqlite3_busy_handler and have it wait for whatever is blocking the current operation (once it returns SQLITE_OK and have cleaned up all my old variables I reiterate through the while/try again), now as only one of these can be setup at a time, let's say for instance Child1 is doing a large write and child2 and child3 are trying to say read and update concurrently on top of the first child's write, so if a SQLITE_BUSY is returned by this function I print out an error, then restart my while loop (restarting the function), of course after I have finalized my old statement, and cleared up any local objects that may have been created, if this a correct line of thinking?

  2. Should I setup a recursive mutex, say screw it to SQLites own locking mechanism, set it up to be shared across processes then only allow one operation on a database at a time? for using my app on a small scale this doesn't seem to bad of an option, however I'm reading a lot of warnings on using a recursive mutex and am wondering if this is is the best option, as many posts say handle mutual exclusion yourself. however then I cannot have concurrent reads, which is a bit of a pain

  3. Use option 1 but instead of using the SQLite busy handler, just call usleep on a random number, clean up data, and restart while?

  4. before/after any function involving my database use sqlite3_exec() with "BEGIN IMMEDIATE"/"COMMIT" respectively, Locking the database for the duration of the code in between those 2 statements. So that nothing enclosed within can(or at least should) return SQLITE_BUSY, then if my "BEGIN IMMEDIATE" returns BUSY (it should be the only one so long as everything is set up correctly), I use the sqlite3_busy_handler which honestly, if only one process can use it at a time seems annoying... or a random number with usleep(), (presumably at this number is rather large 1mil = 1 second the chance of overlap between 1-20 processes is pretty slim) so each process will constantly try to re lock the database at random intervals for their own purposes

  5. Is there a better way? or which one of these is best?

Aucun commentaire:

Enregistrer un commentaire