From f5184f34bfd794884d18057a594e7acb9aeb00e4 Mon Sep 17 00:00:00 2001 From: Miika Pekkarinen Date: Sun, 25 Feb 2007 20:41:51 +0000 Subject: Cleaned up code a bit, fixed possible bug during committing numeric indices and made code more fault tolerant. Added a new numeric tag making it possible to list recently added tracks. Export your DB. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12482 a1c6a512-1295-4272-9138-f99709370657 --- apps/tagcache.c | 193 +++++++++++++++++++++++++++++++++------------------- apps/tagcache.h | 11 +-- apps/tagnavi.config | 1 + apps/tagtree.c | 2 + 4 files changed, 132 insertions(+), 75 deletions(-) diff --git a/apps/tagcache.c b/apps/tagcache.c index 0204771ffa..9e3a4440e0 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -112,13 +112,13 @@ static const int unique_tags[] = { tag_artist, tag_album, tag_genre, /* Numeric tags (we can use these tags with conditional clauses). */ static const int numeric_tags[] = { tag_year, tag_tracknumber, tag_length, - tag_bitrate, tag_playcount, tag_playtime, tag_lastplayed, - tag_virt_autoscore }; + tag_bitrate, tag_playcount, tag_playtime, tag_lastplayed, tag_commitid, + tag_virt_entryage, tag_virt_autoscore }; /* String presentation of the tags defined in tagcache.h. Must be in correct order! */ static const char *tags_str[] = { "artist", "album", "genre", "title", "filename", "composer", "comment", "albumartist", "year", "tracknumber", - "bitrate", "length", "playcount", "playtime", "lastplayed" }; + "bitrate", "length", "playcount", "playtime", "lastplayed", "commitid" }; /* Status information of the tagcache. */ static struct tagcache_stat tc_stat; @@ -158,15 +158,17 @@ struct tagcache_header { struct master_header { struct tagcache_header tch; long serial; /* Increasing counting number */ + long commitid; /* Number of commits so far */ + long dirty; }; /* For the endianess correction */ static const char *tagfile_entry_ec = "ss"; -static const char *index_entry_ec = "llllllllllllllll"; /* (1 + TAG_COUNT) * l */ +static const char *index_entry_ec = "lllllllllllllllll"; /* (1 + TAG_COUNT) * l */ static const char *tagcache_header_ec = "lll"; -static const char *master_header_ec = "llll"; +static const char *master_header_ec = "llllll"; -static long current_serial; +static struct master_header current_tcmh; #ifdef HAVE_TC_RAMCACHE /* Header is created when loading database to ram. */ @@ -658,6 +660,11 @@ static long check_virtual_tags(int tag, const struct index_entry *idx) } break; + /* How many commits before the file has been added to the DB. */ + case tag_virt_entryage: + data = current_tcmh.commitid - idx->tag_seek[tag_commitid] - 1; + break; + default: data = idx->tag_seek[tag]; } @@ -1048,6 +1055,39 @@ static int open_master_fd(struct master_header *hdr, bool write) return fd; } +static bool check_all_headers(void) +{ + struct master_header myhdr; + struct tagcache_header tch; + int tag; + int fd; + + if ( (fd = open_master_fd(&myhdr, false)) < 0) + return false; + + close(fd); + if (myhdr.dirty) + { + logf("tagcache is dirty!"); + return false; + } + + memcpy(¤t_tcmh, &myhdr, sizeof(struct master_header)); + + for (tag = 0; tag < TAG_COUNT; tag++) + { + if (tagcache_is_numeric_tag(tag)) + continue; + + if ( (fd = open_tag_fd(&tch, tag, false)) < 0) + return false; + + close(fd); + } + + return true; +} + bool tagcache_search(struct tagcache_search *tcs, int tag) { struct tagcache_header tag_hdr; @@ -1323,6 +1363,36 @@ bool tagcache_retrieve(struct tagcache_search *tcs, int idxid, return retrieve(tcs, &idx, tag, buf, size); } +static bool update_master_header(void) +{ + struct master_header myhdr; + int fd; + + if (!tc_stat.ready) + return false; + + if ( (fd = open_master_fd(&myhdr, true)) < 0) + return false; + + myhdr.serial = current_tcmh.serial; + myhdr.commitid = current_tcmh.commitid; + + /* Write it back */ + lseek(fd, 0, SEEK_SET); + ecwrite(fd, &myhdr, 1, master_header_ec, tc_stat.econ); + close(fd); + +#ifdef HAVE_TC_RAMCACHE + if (hdr) + { + hdr->h.serial = current_tcmh.serial; + hdr->h.commitid = current_tcmh.commitid; + } +#endif + + return true; +} + #if 0 void tagcache_modify(struct tagcache_search *tcs, int type, const char *text) @@ -1819,7 +1889,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd) while (entries_processed < h->entry_count) { - int count = MIN(h->entry_count, max_entries); + int count = MIN(h->entry_count - entries_processed, max_entries); /* Read in as many entries as possible. */ for (i = 0; i < count; i++) @@ -1859,6 +1929,12 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd) } idx.flag = entrybuf[i].flag; + if (tc_stat.ready && current_tcmh.commitid > 0) + { + idx.tag_seek[tag_commitid] = current_tcmh.commitid; + idx.flag |= FLAG_DIRTYNUM; + } + /* Write back the updated index. */ lseek(masterfd, loc, SEEK_SET); if (ecwrite(masterfd, &idx, 1, index_entry_ec, tc_stat.econ) @@ -1909,6 +1985,8 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) commit_entry_count += tcmh.tch.entry_count; close(masterfd); } + else + remove_files(); /* Just to be sure we are clean. */ /* Open the index file, which contains the tag names. */ fd = open_tag_fd(&tch, index_type, true); @@ -2065,7 +2143,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) if (masterfd < 0) { - logf("Creating new index"); + logf("Creating new DB"); masterfd = open(TAGCACHE_FILE_MASTER, O_WRONLY | O_CREAT | O_TRUNC); if (masterfd < 0) @@ -2080,10 +2158,10 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) tcmh.tch = *h; tcmh.tch.entry_count = 0; tcmh.tch.datasize = 0; + tcmh.dirty = true; ecwrite(masterfd, &tcmh, 1, master_header_ec, tc_stat.econ); init = true; masterfd_pos = lseek(masterfd, 0, SEEK_CUR); - current_serial = 0; } else { @@ -2461,6 +2539,10 @@ static bool commit(void) logf("commit %d entries...", tch.entry_count); + /* Mark DB dirty so it will stay disabled if commit fails. */ + current_tcmh.dirty = true; + update_master_header(); + /* Now create the index files. */ tc_stat.commit_step = 0; tch.datasize = 0; @@ -2489,7 +2571,16 @@ static bool commit(void) } } - build_numeric_indices(&tch, tmpfd); + if (!build_numeric_indices(&tch, tmpfd)) + { + logf("Failure to commit numeric indices"); + close(tmpfd); + remove_files(); + tc_stat.commit_step = 0; + read_lock--; + return false; + } + close(tmpfd); tc_stat.commit_step = 0; @@ -2504,6 +2595,8 @@ static bool commit(void) tcmh.tch.datasize = sizeof(struct master_header) + sizeof(struct index_entry) * tcmh.tch.entry_count + tch.datasize; + tcmh.dirty = false; + tcmh.commitid++; lseek(masterfd, 0, SEEK_SET); ecwrite(masterfd, &tcmh, 1, master_header_ec, tc_stat.econ); @@ -2511,7 +2604,7 @@ static bool commit(void) logf("tagcache committed"); remove(TAGCACHE_FILE_TEMP); - tc_stat.ready = true; + tc_stat.ready = check_all_headers(); if (local_allocation) { @@ -2563,47 +2656,31 @@ static void free_tempbuf(void) tempbuf_size = 0; } -static bool update_current_serial(long serial) -{ - struct master_header myhdr; - int fd; - - if ( (fd = open_master_fd(&myhdr, true)) < 0) - return false; - - myhdr.serial = serial; - current_serial = serial; - -#ifdef HAVE_TC_RAMCACHE - if (hdr) - hdr->h.serial = serial; -#endif - - /* Write it back */ - lseek(fd, 0, SEEK_SET); - ecwrite(fd, &myhdr, 1, master_header_ec, tc_stat.econ); - close(fd); - - return true; -} - long tagcache_increase_serial(void) { + long old; + if (!tc_stat.ready) return -2; while (read_lock) sleep(1); - if (!update_current_serial(current_serial + 1)) + old = current_tcmh.serial++; + if (!update_master_header()) return -1; - return current_serial; + return old; } long tagcache_get_serial(void) { - return current_serial; + return current_tcmh.serial; +} + +long tagcache_get_commitid(void) +{ + return current_tcmh.commitid; } static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data) @@ -2745,7 +2822,8 @@ static int parse_changelog_line(int line_n, const char *buf, void *parameters) char tag_data[TAG_MAXLEN+32]; int idx_id; long masterfd = (long)parameters; - const int import_tags[] = { tag_playcount, tag_playtime, tag_lastplayed }; + const int import_tags[] = { tag_playcount, tag_playtime, tag_lastplayed, + tag_commitid }; int i; (void)line_n; @@ -2796,8 +2874,10 @@ static int parse_changelog_line(int line_n, const char *buf, void *parameters) idx.tag_seek[import_tags[i]] = data; - if (import_tags[i] == tag_lastplayed && data > current_serial) - current_serial = data; + if (import_tags[i] == tag_lastplayed && data > current_tcmh.serial) + current_tcmh.serial = data; + else if (import_tags[i] == tag_commitid && data >= current_tcmh.commitid) + current_tcmh.commitid = data + 1; } return write_index(masterfd, idx_id, &idx) ? 0 : -5; @@ -2846,7 +2926,7 @@ bool tagcache_import_changelog(void) write_lock--; - update_current_serial(current_serial); + update_master_header(); return true; } @@ -3646,33 +3726,6 @@ void tagcache_unload_ramcache(void) } #endif -static bool check_all_headers(void) -{ - struct master_header myhdr; - struct tagcache_header tch; - int tag; - int fd; - - if ( (fd = open_master_fd(&myhdr, false)) < 0) - return false; - - close(fd); - current_serial = myhdr.serial; - - for (tag = 0; tag < TAG_COUNT; tag++) - { - if (tagcache_is_numeric_tag(tag)) - continue; - - if ( (fd = open_tag_fd(&tch, tag, false)) < 0) - return false; - - close(fd); - } - - return true; -} - #ifndef __PCTOOL__ static void tagcache_thread(void) { @@ -3870,8 +3923,8 @@ bool tagcache_is_ramcache(void) void tagcache_init(void) { memset(&tc_stat, 0, sizeof(struct tagcache_stat)); + memset(¤t_tcmh, 0, sizeof(struct master_header)); filenametag_fd = -1; - current_serial = 0; write_lock = read_lock = 0; #ifndef __PCTOOL__ diff --git a/apps/tagcache.h b/apps/tagcache.h index 771629f6f2..ea8b06f4fa 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -23,12 +23,13 @@ #include "id3.h" enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, - tag_filename, tag_composer, tag_comment, tag_albumartist, tag_year, tag_tracknumber, - tag_bitrate, tag_length, tag_playcount, tag_playtime, tag_lastplayed, + tag_filename, tag_composer, tag_comment, tag_albumartist, tag_year, + tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_playtime, + tag_lastplayed, tag_commitid, /* Virtual tags */ - tag_virt_autoscore }; + tag_virt_entryage, tag_virt_autoscore }; -#define TAG_COUNT 15 +#define TAG_COUNT 16 /* Maximum length of a single tag. */ #define TAG_MAXLEN (MAX_PATH*2) @@ -40,7 +41,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, #define IDX_BUF_DEPTH 64 /* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */ -#define TAGCACHE_MAGIC 0x54434807 +#define TAGCACHE_MAGIC 0x54434808 /* How much to allocate extra space for ramcache. */ #define TAGCACHE_RESERVE 32768 diff --git a/apps/tagnavi.config b/apps/tagnavi.config index 9dc24b606c..24428e223a 100644 --- a/apps/tagnavi.config +++ b/apps/tagnavi.config @@ -49,6 +49,7 @@ "Never played tracks" -> artist ? playcount == "0" -> album -> title = "fmt_title" "Best tracks" -> artist ? playcount > "1" & autoscore > "85" -> album -> title = "fmt_best_tracks" "List played tracks" -> title = "fmt_played" ? playcount > "0" +"Last added tracks" -> artist ? entryage == "0" -> album -> title = "fmt_title" "Custom view..." ==> "custom" # And finally set main menu as our root menu diff --git a/apps/tagtree.c b/apps/tagtree.c index 885ff3ecfc..59be2a857f 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -206,6 +206,8 @@ static int get_tag(int *tag) MATCH(tag, buf, "year", tag_year); MATCH(tag, buf, "playcount", tag_playcount); MATCH(tag, buf, "lastplayed", tag_lastplayed); + MATCH(tag, buf, "commitid", tag_commitid); + MATCH(tag, buf, "entryage", tag_virt_entryage); MATCH(tag, buf, "autoscore", tag_virt_autoscore); MATCH(tag, buf, "%sort", var_sorttype); MATCH(tag, buf, "%limit", var_limit); -- cgit