2010-03-12 24 views
5

Estoy desarrollando una aplicación en Visual C++ que usa una base de datos SQLite3 para almacenar datos. Por lo general, se sienta en la bandeja la mayor parte del tiempo.Bloqueo de archivos SQLite y DropBox

También me gustaría permitir que ponga mi aplicación en una carpeta DropBox para compartirla en varias PC. Funcionó realmente bien hasta que DropBox se actualizó recientemente. Y ahora dice que "no se puede sincronizar el archivo en uso". El archivo SQLite está abierto en mi aplicación, pero el bloqueo se comparte. Hay algunas declaraciones preparadas, pero todas se restablecen inmediatamente después de usar step.

¿Hay alguna forma de habilitar la sincronización de un archivo de base de datos SQLite abierto? ¡Gracias!

Aquí es el simple envoltorio que lo uso sólo para las pruebas (sin control de errores), en caso de que esto ayuda:

class Statement 
{ 
private: 
    Statement(sqlite3* db, const std::wstring& sql) : db(db) 
    { 
    sqlite3_prepare16_v2(db, sql.c_str(), sql.length() * sizeof(wchar_t), &stmt, NULL); 
    } 

public: 
    ~Statement() { sqlite3_finalize(stmt); } 

public: 
    void reset() { sqlite3_reset(stmt); } 
    int step() { return sqlite3_step(stmt); } 
    int getInt(int i) const { return sqlite3_column_int(stmt, i); } 

    std::wstring getText(int i) const 
    { 
    const wchar_t* v = (const wchar_t*)sqlite3_column_text16(stmt, i); 
    int sz = sqlite3_column_bytes16(stmt, i)/sizeof(wchar_t); 
    return std::wstring(v, v + sz); 
    } 

private: 
    friend class Database; 

    sqlite3* db; 
    sqlite3_stmt* stmt; 
}; 


class Database 
{ 
public: 
    Database(const std::wstring& filename = L"")) : db(NULL) 
    { 
    sqlite3_open16(filename.c_str(), &db); 
    } 

    ~Database() { sqlite3_close(db); } 

    void exec(const std::wstring& sql) 
    { 
    auto_ptr<Statement> st(prepare(sql)); 
    st->step(); 
    } 

    auto_ptr<Statement> prepare(const std::wstring& sql) const 
    { 
    return auto_ptr<Statement>(new Statement(db, sql)); 
    } 

private: 
    sqlite3* db; 
}; 

UPD: trató comentando todas las llamadas a LockFile y LockFileEx en sqlite3.c - Mismo resultado.

UPD2: Trató de llamar a sqlite3_close cuando está inactivo (como prueba de concepto) - ¡el mismo resultado! Filemon dice que el archivo aún no está cerrado, solo desbloqueado.

UPD3: modo de confirmación automática está activada. Los números de COMIENZOS y COMPROMISOS coinciden (Transacción de clase y RAII se encargan de eso). SQliteManager puede conectarse a la base de datos mientras mi aplicación se está ejecutando y hacer modificaciones a la misma.

+1

¿Está revisando el resultado de sqlite3_close()? Tal vez no esté funcionando porque no ha finalizado todas sus declaraciones preparadas. –

+0

¡Esto fue todo! No funcionaba debido a una copia de seguridad de fondo en ejecución. Error tonto .. Gracias! Ponlo como una respuesta y lo aceptaré. –

Respuesta

4

Comprobando el resultado de sqlite3_close(). Tal vez no esté funcionando porque no ha finalizado todas sus declaraciones preparadas.

2

¿Qué sistema de archivos está utilizando?

¿Está seguro de que AutoCommit está activado y/o está confirmando sus declaraciones? Recuerdo haber tenido un problema al no comprometerme y la cerradura se mantendría encendida.

+0

NTFS. Buena idea sobre el compromiso, gracias, verifico si este podría ser el caso. –

+0

El modo de confirmación automática está activado. Los números de COMIENZOS y COMPROMISOS coinciden (Transacción de clase y RAII se encargan de eso). Parece que esta no es la razón. SQliteManager puede conectarse a la base de datos mientras mi aplicación se está ejecutando y hacer modificaciones a la misma. –

2

Alex Pechnikov tiene un programa de replicación de bases de datos SQLite de varios maestros sqlite3-rdiff. Probablemente sea excesivo para lo que intenta lograr, pero puede ser más fácil que la replicación de archivos.

SQLite también tiene un Online Backup API; hay un ejemplo en esa página: Ejemplo 2: Copia de seguridad en línea de una base de datos en ejecución.

+0

No puedo pensar en una forma de cómo puedo usar eso automáticamente. sqlite3-rdiff requiere Tcl, y usar la API de respaldo significa hacer una copia del DB completo después de cada cambio. –

+0

¿No es DropBox haciendo una copia (o un rdiff) del DB después de cada cambio? Si es así, una copia local no tiene demasiados gastos generales. De lo contrario, solo haga la copia local tan pronto como DropBox lo necesite. –

Cuestiones relacionadas