Hi,
attached is a tricky patch: It skip database rewrites to disk when no changes actually happened. The current issue is that there is no locking/notify mechanism for the database file and, especially if using autosave=true, multiple abook instances imply that "latest closed wins". Reproducer: - term1 run abook - term2 run mutt, add an email (trigger abook --add-email) # here datafile is changed on disk with the new email - close abook in term1 # here datafile is changed on disk, the email is lost There are several ways to avoid/warn when this happens, but all of them first needs that we avoid file rewrites when no change happened, that means isolating write operations. Currently: $ ls -i .abook/addressbook 8535 .abook/addressbook $ abook # press "q" to quit $ ls -i .abook/addressbook 7943 .abook/addressbook This is what the patch attempts to solve by marking the database "need save" after (every) "write" operation on items. That allowed adding a "*" indicator à la emacs to show the "db modified" status. The more sensible here is to ensure that *every* possible action implying modification of the database will really triggers db_need_save = TRUE. If some are missing from the patch the related modifications will *not* be saved to disk. That is to say that this patch has to be *sure*. I need to think more about the behavior when autosave=false but IHMO the check for "is db modified" must be activated for all *saving* vectors, that means that pressing "w" to explicitly save the database to disk will *not* rewrite if there is no modification. I tried many (if not all) of the possible operations offered by the UI and hope to not have missed any. But as shown by the hunk affecting edit.c, database write operations are not strictly restricted to database.c. Further testing welcome. Next I'd see a more robust way to handle concurrent write accesses to datafile. I can think about file-lock and inotify and I'd rather want to avoid any need of datafile "merge". regards -- GPG id: 0xD7F62B21
--- database.c | 22 ++++++++++++++++++++++ edit.c | 2 ++ ui.c | 8 ++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/database.c b/database.c index 7dd4a9a..bea31fd 100644 --- a/database.c +++ b/database.c @@ -62,6 +62,7 @@ abook_field standard_fields[] = { {0} /* ITEM_FIELDS */ }; +bool db_need_save = FALSE; extern int first_list_item; extern int curitem; @@ -294,6 +295,8 @@ next: xfree(line); item_free(&item); + db_need_save = FALSE; + return 0; } @@ -350,6 +353,9 @@ write_database(FILE *out, struct db_enumerator e) int save_database() { + + if(! db_need_save) return 0; + FILE *out; int ret = 0; struct db_enumerator e = init_db_enumerator(ENUM_ALL); @@ -377,6 +383,11 @@ save_database() if((rename(datafile_new, datafile)) == -1) ret = -1; + if(ret == 0) { + db_need_save = FALSE; + refresh_screen(); + } + out: free(datafile_new); free(datafile_old); @@ -486,6 +497,7 @@ add_item2database(list_item item) database[LAST_ITEM] = item_create(); item_copy(database[LAST_ITEM], item); + db_need_save = TRUE; return 0; } @@ -511,6 +523,7 @@ remove_selected_items() } item_free(&database[LAST_ITEM]); items--; + db_need_save = TRUE; } } @@ -546,6 +559,7 @@ void merge_selected_items() } item_free(&database[LAST_ITEM]); items--; + db_need_save = TRUE; } } @@ -577,6 +591,7 @@ void remove_duplicates() } item_free(&database[LAST_ITEM]); items--; + db_need_save = TRUE; } } @@ -656,6 +671,7 @@ sort_by_field(char *name) sort_field = field; qsort((void *)database, items, sizeof(list_item), namecmp); + db_need_save = TRUE; refresh_screen(); } @@ -666,6 +682,7 @@ sort_surname() select_none(); qsort((void *)database, items, sizeof(list_item), surnamecmp); + db_need_save = TRUE; refresh_screen(); } @@ -805,6 +822,9 @@ void item_copy(list_item dest, list_item src) { memmove(dest, src, ITEM_SIZE); + // call by parse_database(), that's why + // parse_database() re-init db_need_save to FALSE + db_need_save = TRUE; } void @@ -873,6 +893,7 @@ item_fput(list_item item, int i, char *val) if(id != -1) { item[id] = val; + db_need_save = TRUE; return 1; } @@ -901,6 +922,7 @@ real_db_field_put(int item, int i, int std, char *val) if(id != -1) { database[item][id] = val; + db_need_save = TRUE; return 1; } diff --git a/edit.c b/edit.c index 9a76c8a..9ad468c 100644 --- a/edit.c +++ b/edit.c @@ -37,6 +37,7 @@ static void locale_date(char *str, size_t str_len, int year, int month, int day) */ extern int views_count; +extern bool db_need_save; WINDOW *editw; @@ -304,6 +305,7 @@ change_field(char *msg, char **field, size_t max_len) *field = ui_readline(msg, old, max_len - 1, 0); if(*field) { + db_need_save = TRUE; xfree(old); if(!**field) xfree(*field); diff --git a/ui.c b/ui.c index e879885..8d8ace0 100644 --- a/ui.c +++ b/ui.c @@ -44,6 +44,8 @@ extern char *datafile; extern bool alternative_datafile; +extern bool db_need_save; + /* * internal variables */ @@ -726,8 +728,10 @@ ui_find(int next) void ui_print_number_of_items() { - char *str = strdup_printf(" " "|%3d/%3d", - selected_items(), db_n_items()); + char *str = strdup_printf(" %c" "|%3d/%3d", + db_need_save ? '*' : ' ', + selected_items(), + db_n_items()); attrset(COLOR_PAIR(CP_HEADER)); mvaddstr(0, COLS-strlen(str), str); -- 1.7.10.4
signature.asc
Description: Digital signature
------------------------------------------------------------------------------ Is your legacy SCM system holding you back? Join Perforce May 7 to find out: • 3 signs your SCM is hindering your productivity • Requirements for releasing software faster • Expert tips and advice for migrating your SCM now http://p.sf.net/sfu/perforce
_______________________________________________ Abook-devel mailing list Abook-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/abook-devel