Commit 8b6cf027 authored by Yuanle Song's avatar Yuanle Song

v0.101.0 redesign use of main and user database.

the old design have flaws and limitations. see :id001: and :id002: in
operational file.

new design:

open :memory: db readwrite, this will be the m_db handler.

try attach main db at known path (readonly if possible) to "maindb".
if failed, try next known path,
if all failed, initDB() should return false and gave up.

try attach user db at known path to "userdb" schema, if failed,
create :memory: db and initialize it as user db. attach it as "userdb"
schema.

update all query against main db to query from maindb.* table.
update all SQL against user db to run again userdb.* table.

benefits:
- access to user db is concurrent safe. multiple libpyzy app won't overwrite
  user's user db file and lose data.
- there is no need to saveUserDB() using timer in the bg.
- there is no need to copy data from user db to :memory:, if user db is
  large, this can lower memory usage.
parent 95b8f0b6
This diff is collapsed.
......@@ -27,6 +27,7 @@
#include "String.h"
#include "Types.h"
#include "Util.h"
#include "sqlite3_util.h"
typedef struct sqlite3 sqlite3;
......@@ -61,10 +62,19 @@ class Database {
public:
~Database ();
protected:
Database (const std::string & user_data_dir);
Database (const std::string &user_data_dir);
public:
static void init (const std::string & data_dir);
static bool init (const std::string &data_dir);
static Database & instance (void)
{
if (m_instance == NULL) {
g_error ("Error: Please call InputContext::init () !");
g_assert_not_reached ();
}
return *m_instance;
}
static void finalize (void);
SQLStmtPtr query (const PinyinArray & pinyin,
size_t pinyin_begin,
......@@ -74,40 +84,23 @@ public:
void commit (const PhraseArray & phrases);
void remove (const Phrase & phrase);
void conditionsDouble (void);
void conditionsTriple (void);
static void finalize (void);
static Database & instance (void)
{
if (m_instance == NULL) {
g_error ("Error: Please call InputContext::init () !");
}
return *m_instance;
}
private:
bool initDB (void);
static bool initUserDB (sqlite3* userdb, const char* schema);
String getMainDBFile (void);
String getUserDBFile (void);
gboolean createUserDBFile (void);
bool setPragmaOnMainDB (void);
bool open (void);
bool initUserDB (sqlite3* userdb);
bool copyDB (sqlite3* dest, const char* dest_dbname,
sqlite3* src, const char* src_dbname);
bool loadUserDB (void);
bool saveUserDB (void);
void prefetch (void);
void phraseSql (const Phrase & p, String & sql);
void phraseWhereSql (const Phrase & p, String & sql);
bool executeSQL (const char* sql, sqlite3* db = NULL);
static gboolean cb_saveUserDB (gpointer user_data);
void modified (void);
private:
sqlite3 *m_db; /* sqlite3 database */
String m_sql; /* sql stmt */
unsigned int m_timeout_id;
GTimer *m_timer;
sqlite3 *m_db; /* db handler to access maindb and userdb */
String m_user_data_dir;
String m_main_db_file; /* main db file name with full path */
String m_user_db_file; /* user db file name with full path */
private:
......
......@@ -152,8 +152,8 @@ PhraseEditor::updateTheFirstCandidate (void)
ret = query.fill (m_candidate_0_phrases, 1);
if (ret != 1) {
g_warning ("expect query.fill() result be 1, found %d", ret);
break;
}
g_assert (ret == 1);
begin += m_candidate_0_phrases.back ().len;
}
}
......
# -*- mode: conf -*-
project('pyzy', 'cpp',
project('pyzy', ['cpp', 'c'],
version: '1.0.1-6',
license: 'GPL',
default_options: [
......@@ -21,7 +21,10 @@ add_project_arguments(
language: 'cpp')
if get_option('buildtype').startswith('release')
add_project_arguments('-DG_DISABLE_ASSERT', language: 'cpp')
add_project_arguments(
'-DG_DISABLE_ASSERT',
'-DG_DISABLE_CHECKS',
language: 'cpp')
endif
glib = dependency('glib-2.0')
......@@ -44,11 +47,12 @@ lib_src = [
'SpecialPhrase.cc',
'SpecialPhraseTable.cc',
'Variant.cc',
'sqlite3_util.c',
]
shared_library('pyzy-1.0',
lib_src,
soversion: '0',
version: '0.100.1',
version: '0.101.0',
dependencies: shared_dep,
install: true)
......
#include "sqlite3_util.h"
/**
* execute sql on sqlite3 db using sqlite3_exec().
*
* Returns: TRUE on success, FALSE otherwise. if FALSE, errmsg will be printed
* with g_warning().
*/
gboolean
sqlite3_exec_simple (sqlite3 *db, const char *sql)
{
if (! db) {
g_warning ("trying to execute sql %s on NULL db handler", sql);
g_assert_not_reached ();
return FALSE;
}
char *errmsg = NULL;
if (sqlite3_exec (db, sql, NULL, NULL, &errmsg) != SQLITE_OK) {
g_warning ("execute sql failed: sql=%s error=%s", sql, errmsg);
sqlite3_free (errmsg);
return FALSE;
}
g_assert_null (errmsg);
return TRUE;
}
/**
* copy all data from src db to dest db.
*
* it's a wrapper for sqlite3_backup_init(), sqlite3_backup_step(),
* sqlite3_backup_finish().
*
* TODO probably should add glib based error handling instead of print via
* g_warning and return gboolean for real world use.
*
* @dest: dest db handler
* @dest_dbname: dest db name
* @src: src db handler
* @src_dbname: src db name
*/
gboolean
sqlite3_copy_db (sqlite3 *dest, const char* dest_dbname,
sqlite3 *src, const char* src_dbname)
{
gboolean copy_done = FALSE;
sqlite3_backup *backup = sqlite3_backup_init (
dest, dest_dbname, src, src_dbname);
if (backup) {
int r = sqlite3_backup_step (backup, -1);
if (r == SQLITE_DONE) {
copy_done = TRUE;
} else {
g_warning ("sqlite3_backup_step() failed: %d (%s)",
r, sqlite3_errmsg (dest));
}
r = sqlite3_backup_finish (backup);
if (r != SQLITE_OK) {
g_warning ("sqlite3_backup_finish() failed: %d (%s)",
r, sqlite3_errmsg (dest));
}
} else {
g_warning ("sqlite3_backup_init() failed: %d (%s)",
sqlite3_errcode (dest), sqlite3_errmsg (dest));
}
return copy_done;
}
#ifndef _SQLITE3_UTIL_H_
#define _SQLITE3_UTIL_H_
#include <sqlite3.h>
#include <glib.h>
#ifdef __cplusplus
extern "C"
{
#endif
gboolean sqlite3_exec_simple (sqlite3 *db, const char *sql);
/**
* copy src_dbname to dest_dbname using sqlite3_backup_step().
*
* dest and src should be opened sqlite3 db handler.
* dest_dbname and src_dbname are db (schema) names.
*
* Returns: TRUE on success, FALSE otherwise.
*/
gboolean sqlite3_copy_db (sqlite3 *dest, const char* dest_dbname,
sqlite3 *src, const char* src_dbname);
#ifdef __cplusplus
}
#endif
#endif /* _SQLITE3_UTIL_H_ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment