Queue song statistical data to the tagcache system and update entirely in background. Fixes ratings disappearing or not saving in the DB at all. Fixes also UI delay when stopping playback and new statistics are committed to DB.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13955 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Miika Pekkarinen 2007-07-21 17:35:19 +00:00
parent 6ed7722db0
commit 9d756e2760
5 changed files with 188 additions and 61 deletions

View File

@ -953,11 +953,14 @@ char *rating_name(int selected_item, void * data, char *buffer)
static bool set_rating_inline(void)
{
struct mp3entry* id3 = audio_current_track();
if(id3) {
if(id3->rating<10)
if (id3 && id3->tagcache_idx)
{
if (id3->rating<10)
id3->rating++;
else
id3->rating=0;
tagcache_update_numeric(id3->tagcache_idx, tag_rating, id3->rating);
}
return false;
}

View File

@ -136,8 +136,26 @@ enum tagcache_queue {
Q_IMPORT_CHANGELOG,
Q_UPDATE,
Q_REBUILD,
/* Internal tagcache command queue. */
CMD_UPDATE_MASTER_HEADER,
CMD_UPDATE_NUMERIC,
};
struct tagcache_command_entry {
long command;
long idx_id;
long tag;
long data;
};
static struct tagcache_command_entry command_queue[TAGCACHE_COMMAND_QUEUE_LENGTH];
static volatile int command_queue_widx = 0;
static volatile int command_queue_ridx = 0;
static struct mutex command_queue_mutex;
/* Timestamp of the last added event, so we can wait a bit before committing the
* whole queue at once. */
static long command_queue_timestamp = 0;
/* Tag database structures. */
@ -2737,33 +2755,6 @@ static void free_tempbuf(void)
tempbuf_size = 0;
}
long tagcache_increase_serial(void)
{
long old;
if (!tc_stat.ready)
return -2;
while (read_lock)
sleep(1);
old = current_tcmh.serial++;
if (!update_master_header())
return -1;
return old;
}
long tagcache_get_serial(void)
{
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)
{
struct index_entry idx;
@ -2783,6 +2774,7 @@ static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data)
return write_index(masterfd, idx_id, &idx);
}
#if 0
bool tagcache_modify_numeric_entry(struct tagcache_search *tcs,
int tag, long data)
{
@ -2796,6 +2788,137 @@ bool tagcache_modify_numeric_entry(struct tagcache_search *tcs,
return modify_numeric_entry(tcs->masterfd, tcs->idx_id, tag, data);
}
#endif
#define COMMAND_QUEUE_IS_EMPTY (command_queue_ridx == command_queue_widx)
static bool command_queue_is_full(void)
{
int next;
next = command_queue_widx + 1;
if (next >= TAGCACHE_COMMAND_QUEUE_LENGTH)
next = 0;
return (next == command_queue_ridx);
}
void run_command_queue(bool force)
{
struct master_header myhdr;
int masterfd;
if (COMMAND_QUEUE_IS_EMPTY)
return;
if (!force && !command_queue_is_full()
&& current_tick - TAGCACHE_COMMAND_QUEUE_COMMIT_DELAY
< command_queue_timestamp)
{
return;
}
mutex_lock(&command_queue_mutex);
if ( (masterfd = open_master_fd(&myhdr, true)) < 0)
return;
while (command_queue_ridx != command_queue_widx)
{
struct tagcache_command_entry *ce = &command_queue[command_queue_ridx];
switch (ce->command)
{
case CMD_UPDATE_MASTER_HEADER:
{
close(masterfd);
update_master_header();
/* Re-open the masterfd. */
if ( (masterfd = open_master_fd(&myhdr, true)) < 0)
return;
break;
}
case CMD_UPDATE_NUMERIC:
{
modify_numeric_entry(masterfd, ce->idx_id, ce->tag, ce->data);
break;
}
}
if (++command_queue_ridx >= TAGCACHE_COMMAND_QUEUE_LENGTH)
command_queue_ridx = 0;
}
close(masterfd);
mutex_unlock(&command_queue_mutex);
}
static void queue_command(int cmd, long idx_id, int tag, long data)
{
while (1)
{
int next;
mutex_lock(&command_queue_mutex);
next = command_queue_widx + 1;
if (next >= TAGCACHE_COMMAND_QUEUE_LENGTH)
next = 0;
/* Make sure queue is not full. */
if (next != command_queue_ridx)
{
struct tagcache_command_entry *ce = &command_queue[command_queue_widx];
ce->command = cmd;
ce->idx_id = idx_id;
ce->tag = tag;
ce->data = data;
command_queue_widx = next;
command_queue_timestamp = current_tick;
mutex_unlock(&command_queue_mutex);
break;
}
/* Queue is full, try again later... */
mutex_unlock(&command_queue_mutex);
sleep(1);
}
}
long tagcache_increase_serial(void)
{
long old;
if (!tc_stat.ready)
return -2;
while (read_lock)
sleep(1);
old = current_tcmh.serial++;
queue_command(CMD_UPDATE_MASTER_HEADER, 0, 0, 0);
return old;
}
void tagcache_update_numeric(int idx_id, int tag, long data)
{
queue_command(CMD_UPDATE_NUMERIC, idx_id, tag, data);
}
long tagcache_get_serial(void)
{
return current_tcmh.serial;
}
long tagcache_get_commitid(void)
{
return current_tcmh.commitid;
}
static bool write_tag(int fd, const char *tagstr, const char *datastr)
{
@ -3860,6 +3983,8 @@ static void tagcache_thread(void)
while (1)
{
run_command_queue(false);
queue_wait_w_tmo(&tagcache_queue, &ev, HZ);
switch (ev.id)
@ -3942,6 +4067,9 @@ bool tagcache_prepare_shutdown(void)
void tagcache_shutdown(void)
{
/* Flush the command queue. */
run_command_queue(true);
#ifdef HAVE_EEPROM_SETTINGS
if (tc_stat.ramcache)
tagcache_dumpsave();
@ -4023,6 +4151,7 @@ void tagcache_init(void)
write_lock = read_lock = 0;
#ifndef __PCTOOL__
mutex_init(&command_queue_mutex);
queue_init(&tagcache_queue, true);
create_thread(tagcache_thread, tagcache_stack,
sizeof(tagcache_stack), tagcache_thread_name

View File

@ -63,6 +63,11 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
/* Always strict align entries for best performance and binary compatability. */
#define TAGCACHE_STRICT_ALIGN 1
/* Max events in the internal tagcache command queue. */
#define TAGCACHE_COMMAND_QUEUE_LENGTH 32
/* Idle time before committing events in the command queue. */
#define TAGCACHE_COMMAND_QUEUE_COMMIT_DELAY HZ*2
#define TAGCACHE_MAX_FILTERS 4
#define TAGCACHE_MAX_CLAUSES 32
@ -170,6 +175,7 @@ long tagcache_increase_serial(void);
long tagcache_get_serial(void);
bool tagcache_import_changelog(void);
bool tagcache_create_changelog(struct tagcache_search *tcs);
void tagcache_update_numeric(int idx_id, int tag, long data);
bool tagcache_modify_numeric_entry(struct tagcache_search *tcs,
int tag, long data);

View File

@ -624,9 +624,14 @@ static void tagtree_buffer_event(struct mp3entry *id3, bool last_track)
}
id3->playcount = tagcache_get_numeric(&tcs, tag_playcount);
if(!id3->rating) id3->rating = tagcache_get_numeric(&tcs, tag_rating);
if (!id3->rating)
id3->rating = tagcache_get_numeric(&tcs, tag_rating);
id3->lastplayed = tagcache_get_numeric(&tcs, tag_lastplayed);
id3->score = tagcache_get_numeric(&tcs, tag_virt_autoscore) / 10;
id3->playtime = tagcache_get_numeric(&tcs, tag_playtime);
/* Store our tagcache index pointer. */
id3->tagcache_idx = tcs.idx_id;
tagcache_search_finish(&tcs);
}
@ -635,7 +640,6 @@ static void tagtree_unbuffer_event(struct mp3entry *id3, bool last_track)
{
(void)last_track;
long playcount;
long rating;
long playtime;
long lastplayed;
@ -646,6 +650,12 @@ static void tagtree_unbuffer_event(struct mp3entry *id3, bool last_track)
return;
}
if (!id3->tagcache_idx)
{
logf("No tagcache index pointer found");
return;
}
/* Don't process unplayed tracks. */
if (id3->elapsed == 0)
{
@ -653,48 +663,25 @@ static void tagtree_unbuffer_event(struct mp3entry *id3, bool last_track)
return;
}
if (!tagcache_find_index(&tcs, id3->path))
{
logf("tc stat: not found: %s", id3->path);
return;
}
playcount = tagcache_get_numeric(&tcs, tag_playcount);
playtime = tagcache_get_numeric(&tcs, tag_playtime);
lastplayed = tagcache_get_numeric(&tcs, tag_lastplayed);
playcount++;
rating = (long) id3->rating;
playcount = id3->playcount + 1;
lastplayed = tagcache_increase_serial();
if (lastplayed < 0)
{
logf("incorrect tc serial:%ld", lastplayed);
tagcache_search_finish(&tcs);
return;
}
/* Ignore the last 15s (crossfade etc.) */
playtime += MIN(id3->length, id3->elapsed + 15 * 1000);
playtime = id3->playtime + MIN(id3->length, id3->elapsed + 15 * 1000);
logf("ube:%s", id3->path);
logf("-> %d/%ld/%ld/%ld", last_track, playcount, rating, playtime);
logf("-> %d/%ld/%ld", last_track, playcount, playtime);
logf("-> %ld/%ld/%ld", id3->elapsed, id3->length, MIN(id3->length, id3->elapsed + 15 * 1000));
/* lastplayed not yet supported. */
if (!tagcache_modify_numeric_entry(&tcs, tag_playcount, playcount)
|| !tagcache_modify_numeric_entry(&tcs, tag_rating, rating)
|| !tagcache_modify_numeric_entry(&tcs, tag_playtime, playtime)
|| !tagcache_modify_numeric_entry(&tcs, tag_lastplayed, lastplayed))
{
logf("tc stat: modify failed!");
tagcache_search_finish(&tcs);
return;
}
tagcache_search_finish(&tcs);
/* Queue the updates to the tagcache system. */
tagcache_update_numeric(id3->tagcache_idx, tag_playcount, playcount);
tagcache_update_numeric(id3->tagcache_idx, tag_playtime, playtime);
tagcache_update_numeric(id3->tagcache_idx, tag_lastplayed, lastplayed);
}
bool tagtree_export(void)

View File

@ -202,10 +202,12 @@ struct mp3entry {
long rundbentryoffset;
/* runtime database fields */
long tagcache_idx;
short rating;
short score;
long playcount;
long lastplayed;
long playtime;
/* replaygain support */