337 lines
12 KiB
Diff
337 lines
12 KiB
Diff
Index: camel/camel-store.c
|
|
===================================================================
|
|
--- camel/camel-store.c (revision 9841)
|
|
+++ camel/camel-store.c (revision 9842)
|
|
@@ -322,6 +322,21 @@
|
|
}
|
|
|
|
if (!folder) {
|
|
+
|
|
+ if (flags & CAMEL_STORE_IS_MIGRATING) {
|
|
+ if ((store->flags & CAMEL_STORE_VTRASH) && strcmp(folder_name, CAMEL_VTRASH_NAME) == 0) {
|
|
+ if (store->folders)
|
|
+ camel_object_bag_abort(store->folders, folder_name);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if ((store->flags & CAMEL_STORE_VJUNK) && strcmp(folder_name, CAMEL_VJUNK_NAME) == 0) {
|
|
+ if (store->folders)
|
|
+ camel_object_bag_abort(store->folders, folder_name);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
if ((store->flags & CAMEL_STORE_VTRASH) && strcmp(folder_name, CAMEL_VTRASH_NAME) == 0) {
|
|
folder = CS_CLASS(store)->get_trash(store, ex);
|
|
} else if ((store->flags & CAMEL_STORE_VJUNK) && strcmp(folder_name, CAMEL_VJUNK_NAME) == 0) {
|
|
Index: camel/camel-store.h
|
|
===================================================================
|
|
--- camel/camel-store.h (revision 9841)
|
|
+++ camel/camel-store.h (revision 9842)
|
|
@@ -115,6 +115,7 @@
|
|
#define CAMEL_STORE_FILTER_INBOX (1 << 2)
|
|
#define CAMEL_STORE_VJUNK (1 << 3)
|
|
#define CAMEL_STORE_PROXY (1 << 4)
|
|
+#define CAMEL_STORE_IS_MIGRATING (1 << 5)
|
|
|
|
struct _CamelDB;
|
|
|
|
Index: camel/providers/local/camel-local-folder.c
|
|
===================================================================
|
|
--- camel/providers/local/camel-local-folder.c (revision 9841)
|
|
+++ camel/providers/local/camel-local-folder.c (revision 9842)
|
|
@@ -289,7 +289,7 @@
|
|
}
|
|
|
|
folder->summary = (CamelFolderSummary *)CLOCALF_CLASS(lf)->create_summary(lf, lf->summary_path, lf->folder_path, lf->index);
|
|
- if (camel_local_summary_load((CamelLocalSummary *)folder->summary, forceindex, NULL) == -1) {
|
|
+ if (!(flags & CAMEL_STORE_IS_MIGRATING) && camel_local_summary_load((CamelLocalSummary *)folder->summary, forceindex, NULL) == -1) {
|
|
/* ? */
|
|
if (camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex) == 0) {
|
|
/* we sync here so that any hard work setting up the folder isn't lost */
|
|
Index: camel/camel-db.c
|
|
===================================================================
|
|
--- camel/camel-db.c (revision 9841)
|
|
+++ camel/camel-db.c (revision 9842)
|
|
@@ -47,6 +47,8 @@
|
|
|
|
static GStaticRecMutex trans_lock = G_STATIC_REC_MUTEX_INIT;
|
|
|
|
+static int write_mir (CamelDB *cdb, const char *folder_name, CamelMIRecord *record, CamelException *ex, gboolean delete_old_record);
|
|
+
|
|
static int
|
|
cdb_sql_exec (sqlite3 *db, const char* stmt, CamelException *ex)
|
|
{
|
|
@@ -812,13 +814,29 @@
|
|
return ret;
|
|
}
|
|
|
|
+
|
|
+int
|
|
+camel_db_write_fresh_message_info_record (CamelDB *cdb, const char *folder_name, CamelMIRecord *record, CamelException *ex)
|
|
+{
|
|
+ return write_mir (cdb, folder_name, record, ex, FALSE);
|
|
+}
|
|
+
|
|
+
|
|
int
|
|
camel_db_write_message_info_record (CamelDB *cdb, const char *folder_name, CamelMIRecord *record, CamelException *ex)
|
|
{
|
|
+ return write_mir (cdb, folder_name, record, ex, TRUE);
|
|
+}
|
|
+
|
|
+static int
|
|
+write_mir (CamelDB *cdb, const char *folder_name, CamelMIRecord *record, CamelException *ex, gboolean delete_old_record)
|
|
+{
|
|
int ret;
|
|
char *del_query;
|
|
char *ins_query;
|
|
|
|
+ /* FIXME: We should migrate from this DELETE followed by INSERT model to an INSERT OR REPLACE model as pointed out by pvanhoof */
|
|
+
|
|
/* NB: UGLIEST Hack. We can't modify the schema now. We are using msg_security (an unsed one to notify of FLAGGED/Dirty infos */
|
|
|
|
ins_query = sqlite3_mprintf ("INSERT INTO %Q VALUES (%Q, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %ld, %ld, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q )",
|
|
@@ -832,7 +850,8 @@
|
|
record->part, record->labels, record->usertags,
|
|
record->cinfo, record->bdata);
|
|
|
|
- del_query = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = %Q", folder_name, record->uid);
|
|
+ if (delete_old_record)
|
|
+ del_query = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = %Q", folder_name, record->uid);
|
|
|
|
#if 0
|
|
char *upd_query;
|
|
@@ -842,12 +861,14 @@
|
|
g_free (upd_query);
|
|
#else
|
|
|
|
- ret = camel_db_add_to_transaction (cdb, del_query, ex);
|
|
+ if (delete_old_record)
|
|
+ ret = camel_db_add_to_transaction (cdb, del_query, ex);
|
|
ret = camel_db_add_to_transaction (cdb, ins_query, ex);
|
|
|
|
#endif
|
|
|
|
- sqlite3_free (del_query);
|
|
+ if (delete_old_record)
|
|
+ sqlite3_free (del_query);
|
|
sqlite3_free (ins_query);
|
|
|
|
return ret;
|
|
@@ -1198,3 +1219,39 @@
|
|
CAMEL_DB_RELEASE_SQLITE_MEMORY;
|
|
return ret;
|
|
}
|
|
+
|
|
+int camel_db_start_in_memory_transactions (CamelDB *cdb, CamelException *ex)
|
|
+{
|
|
+ int ret;
|
|
+ char *cmd = sqlite3_mprintf ("ATTACH DATABASE ':memory:' AS %s", CAMEL_DB_IN_MEMORY_DB);
|
|
+
|
|
+ ret = camel_db_command (cdb, cmd, ex);
|
|
+ sqlite3_free (cmd);
|
|
+
|
|
+ cmd = sqlite3_mprintf ("CREATE TEMPORARY TABLE %Q ( uid TEXT PRIMARY KEY , flags INTEGER , msg_type INTEGER , read INTEGER , deleted INTEGER , replied INTEGER , important INTEGER , junk INTEGER , attachment INTEGER , msg_security INTEGER , size INTEGER , dsent NUMERIC , dreceived NUMERIC , subject TEXT , mail_from TEXT , mail_to TEXT , mail_cc TEXT , mlist TEXT , followup_flag TEXT , followup_completed_on TEXT , followup_due_by TEXT , part TEXT , labels TEXT , usertags TEXT , cinfo TEXT , bdata TEXT )", CAMEL_DB_IN_MEMORY_TABLE);
|
|
+ ret = camel_db_command (cdb, cmd, ex);
|
|
+ if (ret != 0 )
|
|
+ abort ();
|
|
+ sqlite3_free (cmd);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int camel_db_flush_in_memory_transactions (CamelDB *cdb, const char * folder_name, CamelException *ex)
|
|
+{
|
|
+ int ret;
|
|
+ char *cmd = sqlite3_mprintf ("INSERT INTO %Q SELECT * FROM %Q", folder_name, CAMEL_DB_IN_MEMORY_TABLE);
|
|
+
|
|
+ ret = camel_db_command (cdb, cmd, ex);
|
|
+ sqlite3_free (cmd);
|
|
+
|
|
+ cmd = sqlite3_mprintf ("DROP TABLE %Q", CAMEL_DB_IN_MEMORY_TABLE);
|
|
+ ret = camel_db_command (cdb, cmd, ex);
|
|
+ sqlite3_free (cmd);
|
|
+
|
|
+ cmd = sqlite3_mprintf ("DETACH %Q", CAMEL_DB_IN_MEMORY_DB);
|
|
+ ret = camel_db_command (cdb, cmd, ex);
|
|
+ sqlite3_free (cmd);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
Index: camel/camel-db.h
|
|
===================================================================
|
|
--- camel/camel-db.h (revision 9841)
|
|
+++ camel/camel-db.h (revision 9842)
|
|
@@ -4,8 +4,14 @@
|
|
#define __CAMEL_DB_H
|
|
#include <sqlite3.h>
|
|
#include <glib.h>
|
|
+
|
|
#define CAMEL_DB_FILE "folders.db"
|
|
|
|
+/* Hopefully no one will create a folder named EVO_IN_meM_hAnDlE */
|
|
+#define CAMEL_DB_IN_MEMORY_TABLE "EVO_IN_meM_hAnDlE.temp"
|
|
+#define CAMEL_DB_IN_MEMORY_DB "EVO_IN_meM_hAnDlE"
|
|
+#define CAMEL_DB_IN_MEMORY_TABLE_LIMIT 100000
|
|
+
|
|
#include "camel-exception.h"
|
|
|
|
typedef struct _CamelDBPrivate CamelDBPrivate;
|
|
@@ -132,6 +138,7 @@
|
|
int camel_db_prepare_message_info_table (CamelDB *cdb, const char *folder_name, CamelException *ex);
|
|
|
|
int camel_db_write_message_info_record (CamelDB *cdb, const char *folder_name, CamelMIRecord *record, CamelException *ex);
|
|
+int camel_db_write_fresh_message_info_record (CamelDB *cdb, const char *folder_name, CamelMIRecord *record, CamelException *ex);
|
|
int camel_db_read_message_info_records (CamelDB *cdb, const char *folder_name, gpointer p, CamelDBSelectCB read_mir_callback, CamelException *ex);
|
|
int camel_db_read_message_info_record_with_uid (CamelDB *cdb, const char *folder_name, const char *uid, gpointer p, CamelDBSelectCB read_mir_callback, CamelException *ex);
|
|
|
|
@@ -168,5 +175,9 @@
|
|
int camel_db_set_collate (CamelDB *cdb, const char *col, const char *collate, CamelDBCollate func);
|
|
/* Migration APIS */
|
|
int camel_db_migrate_vfolders_to_14(CamelDB *cdb, const char *folder, CamelException *ex);
|
|
+
|
|
+int camel_db_start_in_memory_transactions (CamelDB *cdb, CamelException *ex);
|
|
+int camel_db_flush_in_memory_transactions (CamelDB *cdb, const char * folder_name, CamelException *ex);
|
|
+
|
|
#endif
|
|
|
|
Index: camel/camel-folder-summary.c
|
|
===================================================================
|
|
--- camel/camel-folder-summary.c (revision 9841)
|
|
+++ camel/camel-folder-summary.c (revision 9842)
|
|
@@ -129,7 +129,7 @@
|
|
static int content_info_save(CamelFolderSummary *, FILE *, CamelMessageContentInfo *);
|
|
static void content_info_free(CamelFolderSummary *, CamelMessageContentInfo *);
|
|
|
|
-static int save_message_infos_to_db (CamelFolderSummary *s, CamelException *ex);
|
|
+static int save_message_infos_to_db (CamelFolderSummary *s, gboolean fresh_mir, CamelException *ex);
|
|
static int camel_read_mir_callback (void * ref, int ncol, char ** cols, char ** name);
|
|
|
|
static char *next_uid_string(CamelFolderSummary *s);
|
|
@@ -1237,23 +1237,20 @@
|
|
if (fclose (in) != 0)
|
|
return -1;
|
|
|
|
+ record = (((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_to_db (s, &ex));
|
|
+ if (!record) {
|
|
+ return -1;
|
|
+ }
|
|
|
|
- camel_db_begin_transaction (cdb, &ex);
|
|
+ ret = save_message_infos_to_db (s, TRUE, &ex);
|
|
|
|
- ret = save_message_infos_to_db (s, &ex);
|
|
-
|
|
if (ret != 0) {
|
|
- camel_db_abort_transaction (cdb, &ex);
|
|
return -1;
|
|
}
|
|
- camel_db_end_transaction (cdb, &ex);
|
|
-
|
|
- record = (((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_to_db (s, &ex));
|
|
- if (!record) {
|
|
- return -1;
|
|
- }
|
|
|
|
+ camel_db_begin_transaction (cdb, &ex);
|
|
ret = camel_db_write_folder_info_record (cdb, record, &ex);
|
|
+ camel_db_end_transaction (cdb, &ex);
|
|
|
|
g_free (record->bdata);
|
|
g_free (record);
|
|
@@ -1321,17 +1318,24 @@
|
|
return 0;
|
|
}
|
|
|
|
+typedef struct {
|
|
+ CamelException *ex;
|
|
+ gboolean migration;
|
|
+ int progress;
|
|
+} SaveToDBArgs;
|
|
+
|
|
static void
|
|
save_to_db_cb (gpointer key, gpointer value, gpointer data)
|
|
{
|
|
- CamelException *ex = (CamelException *)data;
|
|
+ SaveToDBArgs *args = (SaveToDBArgs *) data;
|
|
+ CamelException *ex = args->ex;
|
|
CamelMessageInfoBase *mi = (CamelMessageInfoBase *)value;
|
|
CamelFolderSummary *s = (CamelFolderSummary *)mi->summary;
|
|
char *folder_name = s->folder->full_name;
|
|
CamelDB *cdb = s->folder->parent_store->cdb_w;
|
|
CamelMIRecord *mir;
|
|
|
|
- if (!mi->dirty)
|
|
+ if (!args->migration && !mi->dirty)
|
|
return;
|
|
|
|
mir = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_to_db (s, (CamelMessageInfo *)mi);
|
|
@@ -1345,30 +1349,52 @@
|
|
}
|
|
}
|
|
|
|
- if (camel_db_write_message_info_record (cdb, folder_name, mir, ex) != 0) {
|
|
- camel_db_camel_mir_free (mir);
|
|
- return;
|
|
+ if (!args->migration) {
|
|
+ if (camel_db_write_message_info_record (cdb, folder_name, mir, ex) != 0) {
|
|
+ camel_db_camel_mir_free (mir);
|
|
+ return;
|
|
+ }
|
|
+ } else {
|
|
+ if (camel_db_write_fresh_message_info_record (cdb, CAMEL_DB_IN_MEMORY_TABLE, mir, ex) != 0) {
|
|
+ camel_db_camel_mir_free (mir);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (args->progress > CAMEL_DB_IN_MEMORY_TABLE_LIMIT) {
|
|
+ g_print ("BULK INsert limit reached \n");
|
|
+ camel_db_flush_in_memory_transactions (cdb, folder_name, ex);
|
|
+ camel_db_start_in_memory_transactions (cdb, ex);
|
|
+ args->progress = 0;
|
|
+ } else {
|
|
+ args->progress ++;
|
|
+ }
|
|
}
|
|
|
|
/* Reset the flags */
|
|
mi->dirty = FALSE;
|
|
+ mi->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
|
|
|
|
camel_db_camel_mir_free (mir);
|
|
}
|
|
|
|
static int
|
|
-save_message_infos_to_db (CamelFolderSummary *s, CamelException *ex)
|
|
+save_message_infos_to_db (CamelFolderSummary *s, gboolean fresh_mirs, CamelException *ex)
|
|
{
|
|
CamelDB *cdb = s->folder->parent_store->cdb_w;
|
|
char *folder_name;
|
|
+ SaveToDBArgs args;
|
|
|
|
+ args.ex = ex;
|
|
+ args.migration = fresh_mirs;
|
|
+ args.progress = 0;
|
|
+
|
|
folder_name = s->folder->full_name;
|
|
if (camel_db_prepare_message_info_table (cdb, folder_name, ex) != 0) {
|
|
return -1;
|
|
}
|
|
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
|
/* Push MessageInfo-es */
|
|
- g_hash_table_foreach (s->loaded_infos, save_to_db_cb, ex);
|
|
+ g_hash_table_foreach (s->loaded_infos, save_to_db_cb, &args);
|
|
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
|
/* FIXME[disk-summary] make sure we free the message infos that are loaded
|
|
* are freed if not used anymore or should we leave that to the timer? */
|
|
@@ -1398,7 +1424,7 @@
|
|
|
|
camel_db_begin_transaction (cdb, ex);
|
|
|
|
- ret = save_message_infos_to_db (s, ex);
|
|
+ ret = save_message_infos_to_db (s, FALSE, ex);
|
|
if (ret != 0) {
|
|
camel_db_abort_transaction (cdb, ex);
|
|
/* Failed, so lets reset the flag */
|