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
This commit is contained in:
Miika Pekkarinen 2007-02-25 20:41:51 +00:00
parent fcf8145fee
commit f5184f34bf
4 changed files with 132 additions and 75 deletions

View file

@ -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(&current_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(&current_tcmh, 0, sizeof(struct master_header));
filenametag_fd = -1;
current_serial = 0;
write_lock = read_lock = 0;
#ifndef __PCTOOL__

View file

@ -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

View file

@ -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

View file

@ -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);