summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2007-07-21 17:35:19 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2007-07-21 17:35:19 +0000
commit9d756e2760a0926aa416b22e276c4a5b2685e84e (patch)
tree21502b59d472d57f6cdb267eb96177784beec706 /apps
parent6ed7722db0f7e911684f5deb84cc4ae93d15ccac (diff)
downloadrockbox-9d756e2760a0926aa416b22e276c4a5b2685e84e.tar.gz
rockbox-9d756e2760a0926aa416b22e276c4a5b2685e84e.zip
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
Diffstat (limited to 'apps')
-rw-r--r--apps/onplay.c7
-rw-r--r--apps/tagcache.c183
-rw-r--r--apps/tagcache.h6
-rw-r--r--apps/tagtree.c49
4 files changed, 185 insertions, 60 deletions
diff --git a/apps/onplay.c b/apps/onplay.c
index cba03733fd..d7c2504650 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -953,11 +953,14 @@ char *rating_name(int selected_item, void * data, char *buffer)
953static bool set_rating_inline(void) 953static bool set_rating_inline(void)
954{ 954{
955 struct mp3entry* id3 = audio_current_track(); 955 struct mp3entry* id3 = audio_current_track();
956 if(id3) { 956 if (id3 && id3->tagcache_idx)
957 if(id3->rating<10) 957 {
958 if (id3->rating<10)
958 id3->rating++; 959 id3->rating++;
959 else 960 else
960 id3->rating=0; 961 id3->rating=0;
962
963 tagcache_update_numeric(id3->tagcache_idx, tag_rating, id3->rating);
961 } 964 }
962 return false; 965 return false;
963} 966}
diff --git a/apps/tagcache.c b/apps/tagcache.c
index f832f1e543..6d738bc5fb 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -136,8 +136,26 @@ enum tagcache_queue {
136 Q_IMPORT_CHANGELOG, 136 Q_IMPORT_CHANGELOG,
137 Q_UPDATE, 137 Q_UPDATE,
138 Q_REBUILD, 138 Q_REBUILD,
139
140 /* Internal tagcache command queue. */
141 CMD_UPDATE_MASTER_HEADER,
142 CMD_UPDATE_NUMERIC,
143};
144
145struct tagcache_command_entry {
146 long command;
147 long idx_id;
148 long tag;
149 long data;
139}; 150};
140 151
152static struct tagcache_command_entry command_queue[TAGCACHE_COMMAND_QUEUE_LENGTH];
153static volatile int command_queue_widx = 0;
154static volatile int command_queue_ridx = 0;
155static struct mutex command_queue_mutex;
156/* Timestamp of the last added event, so we can wait a bit before committing the
157 * whole queue at once. */
158static long command_queue_timestamp = 0;
141 159
142/* Tag database structures. */ 160/* Tag database structures. */
143 161
@@ -2737,33 +2755,6 @@ static void free_tempbuf(void)
2737 tempbuf_size = 0; 2755 tempbuf_size = 0;
2738} 2756}
2739 2757
2740long tagcache_increase_serial(void)
2741{
2742 long old;
2743
2744 if (!tc_stat.ready)
2745 return -2;
2746
2747 while (read_lock)
2748 sleep(1);
2749
2750 old = current_tcmh.serial++;
2751 if (!update_master_header())
2752 return -1;
2753
2754 return old;
2755}
2756
2757long tagcache_get_serial(void)
2758{
2759 return current_tcmh.serial;
2760}
2761
2762long tagcache_get_commitid(void)
2763{
2764 return current_tcmh.commitid;
2765}
2766
2767static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data) 2758static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data)
2768{ 2759{
2769 struct index_entry idx; 2760 struct index_entry idx;
@@ -2783,6 +2774,7 @@ static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data)
2783 return write_index(masterfd, idx_id, &idx); 2774 return write_index(masterfd, idx_id, &idx);
2784} 2775}
2785 2776
2777#if 0
2786bool tagcache_modify_numeric_entry(struct tagcache_search *tcs, 2778bool tagcache_modify_numeric_entry(struct tagcache_search *tcs,
2787 int tag, long data) 2779 int tag, long data)
2788{ 2780{
@@ -2796,6 +2788,137 @@ bool tagcache_modify_numeric_entry(struct tagcache_search *tcs,
2796 2788
2797 return modify_numeric_entry(tcs->masterfd, tcs->idx_id, tag, data); 2789 return modify_numeric_entry(tcs->masterfd, tcs->idx_id, tag, data);
2798} 2790}
2791#endif
2792
2793#define COMMAND_QUEUE_IS_EMPTY (command_queue_ridx == command_queue_widx)
2794
2795static bool command_queue_is_full(void)
2796{
2797 int next;
2798
2799 next = command_queue_widx + 1;
2800 if (next >= TAGCACHE_COMMAND_QUEUE_LENGTH)
2801 next = 0;
2802
2803 return (next == command_queue_ridx);
2804}
2805
2806void run_command_queue(bool force)
2807{
2808 struct master_header myhdr;
2809 int masterfd;
2810
2811 if (COMMAND_QUEUE_IS_EMPTY)
2812 return;
2813
2814 if (!force && !command_queue_is_full()
2815 && current_tick - TAGCACHE_COMMAND_QUEUE_COMMIT_DELAY
2816 < command_queue_timestamp)
2817 {
2818 return;
2819 }
2820
2821 mutex_lock(&command_queue_mutex);
2822
2823 if ( (masterfd = open_master_fd(&myhdr, true)) < 0)
2824 return;
2825
2826 while (command_queue_ridx != command_queue_widx)
2827 {
2828 struct tagcache_command_entry *ce = &command_queue[command_queue_ridx];
2829
2830 switch (ce->command)
2831 {
2832 case CMD_UPDATE_MASTER_HEADER:
2833 {
2834 close(masterfd);
2835 update_master_header();
2836
2837 /* Re-open the masterfd. */
2838 if ( (masterfd = open_master_fd(&myhdr, true)) < 0)
2839 return;
2840
2841 break;
2842 }
2843 case CMD_UPDATE_NUMERIC:
2844 {
2845 modify_numeric_entry(masterfd, ce->idx_id, ce->tag, ce->data);
2846 break;
2847 }
2848 }
2849
2850 if (++command_queue_ridx >= TAGCACHE_COMMAND_QUEUE_LENGTH)
2851 command_queue_ridx = 0;
2852 }
2853
2854 close(masterfd);
2855
2856 mutex_unlock(&command_queue_mutex);
2857}
2858
2859static void queue_command(int cmd, long idx_id, int tag, long data)
2860{
2861 while (1)
2862 {
2863 int next;
2864
2865 mutex_lock(&command_queue_mutex);
2866 next = command_queue_widx + 1;
2867 if (next >= TAGCACHE_COMMAND_QUEUE_LENGTH)
2868 next = 0;
2869
2870 /* Make sure queue is not full. */
2871 if (next != command_queue_ridx)
2872 {
2873 struct tagcache_command_entry *ce = &command_queue[command_queue_widx];
2874
2875 ce->command = cmd;
2876 ce->idx_id = idx_id;
2877 ce->tag = tag;
2878 ce->data = data;
2879
2880 command_queue_widx = next;
2881 command_queue_timestamp = current_tick;
2882 mutex_unlock(&command_queue_mutex);
2883 break;
2884 }
2885
2886 /* Queue is full, try again later... */
2887 mutex_unlock(&command_queue_mutex);
2888 sleep(1);
2889 }
2890}
2891
2892long tagcache_increase_serial(void)
2893{
2894 long old;
2895
2896 if (!tc_stat.ready)
2897 return -2;
2898
2899 while (read_lock)
2900 sleep(1);
2901
2902 old = current_tcmh.serial++;
2903 queue_command(CMD_UPDATE_MASTER_HEADER, 0, 0, 0);
2904
2905 return old;
2906}
2907
2908void tagcache_update_numeric(int idx_id, int tag, long data)
2909{
2910 queue_command(CMD_UPDATE_NUMERIC, idx_id, tag, data);
2911}
2912
2913long tagcache_get_serial(void)
2914{
2915 return current_tcmh.serial;
2916}
2917
2918long tagcache_get_commitid(void)
2919{
2920 return current_tcmh.commitid;
2921}
2799 2922
2800static bool write_tag(int fd, const char *tagstr, const char *datastr) 2923static bool write_tag(int fd, const char *tagstr, const char *datastr)
2801{ 2924{
@@ -3860,6 +3983,8 @@ static void tagcache_thread(void)
3860 3983
3861 while (1) 3984 while (1)
3862 { 3985 {
3986 run_command_queue(false);
3987
3863 queue_wait_w_tmo(&tagcache_queue, &ev, HZ); 3988 queue_wait_w_tmo(&tagcache_queue, &ev, HZ);
3864 3989
3865 switch (ev.id) 3990 switch (ev.id)
@@ -3942,6 +4067,9 @@ bool tagcache_prepare_shutdown(void)
3942 4067
3943void tagcache_shutdown(void) 4068void tagcache_shutdown(void)
3944{ 4069{
4070 /* Flush the command queue. */
4071 run_command_queue(true);
4072
3945#ifdef HAVE_EEPROM_SETTINGS 4073#ifdef HAVE_EEPROM_SETTINGS
3946 if (tc_stat.ramcache) 4074 if (tc_stat.ramcache)
3947 tagcache_dumpsave(); 4075 tagcache_dumpsave();
@@ -4023,6 +4151,7 @@ void tagcache_init(void)
4023 write_lock = read_lock = 0; 4151 write_lock = read_lock = 0;
4024 4152
4025#ifndef __PCTOOL__ 4153#ifndef __PCTOOL__
4154 mutex_init(&command_queue_mutex);
4026 queue_init(&tagcache_queue, true); 4155 queue_init(&tagcache_queue, true);
4027 create_thread(tagcache_thread, tagcache_stack, 4156 create_thread(tagcache_thread, tagcache_stack,
4028 sizeof(tagcache_stack), tagcache_thread_name 4157 sizeof(tagcache_stack), tagcache_thread_name
diff --git a/apps/tagcache.h b/apps/tagcache.h
index 70677c602b..3d80c6975f 100644
--- a/apps/tagcache.h
+++ b/apps/tagcache.h
@@ -63,6 +63,11 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
63/* Always strict align entries for best performance and binary compatability. */ 63/* Always strict align entries for best performance and binary compatability. */
64#define TAGCACHE_STRICT_ALIGN 1 64#define TAGCACHE_STRICT_ALIGN 1
65 65
66/* Max events in the internal tagcache command queue. */
67#define TAGCACHE_COMMAND_QUEUE_LENGTH 32
68/* Idle time before committing events in the command queue. */
69#define TAGCACHE_COMMAND_QUEUE_COMMIT_DELAY HZ*2
70
66#define TAGCACHE_MAX_FILTERS 4 71#define TAGCACHE_MAX_FILTERS 4
67#define TAGCACHE_MAX_CLAUSES 32 72#define TAGCACHE_MAX_CLAUSES 32
68 73
@@ -170,6 +175,7 @@ long tagcache_increase_serial(void);
170long tagcache_get_serial(void); 175long tagcache_get_serial(void);
171bool tagcache_import_changelog(void); 176bool tagcache_import_changelog(void);
172bool tagcache_create_changelog(struct tagcache_search *tcs); 177bool tagcache_create_changelog(struct tagcache_search *tcs);
178void tagcache_update_numeric(int idx_id, int tag, long data);
173bool tagcache_modify_numeric_entry(struct tagcache_search *tcs, 179bool tagcache_modify_numeric_entry(struct tagcache_search *tcs,
174 int tag, long data); 180 int tag, long data);
175 181
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 03673fc653..271f30ffa8 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -624,9 +624,14 @@ static void tagtree_buffer_event(struct mp3entry *id3, bool last_track)
624 } 624 }
625 625
626 id3->playcount = tagcache_get_numeric(&tcs, tag_playcount); 626 id3->playcount = tagcache_get_numeric(&tcs, tag_playcount);
627 if(!id3->rating) id3->rating = tagcache_get_numeric(&tcs, tag_rating); 627 if (!id3->rating)
628 id3->rating = tagcache_get_numeric(&tcs, tag_rating);
628 id3->lastplayed = tagcache_get_numeric(&tcs, tag_lastplayed); 629 id3->lastplayed = tagcache_get_numeric(&tcs, tag_lastplayed);
629 id3->score = tagcache_get_numeric(&tcs, tag_virt_autoscore) / 10; 630 id3->score = tagcache_get_numeric(&tcs, tag_virt_autoscore) / 10;
631 id3->playtime = tagcache_get_numeric(&tcs, tag_playtime);
632
633 /* Store our tagcache index pointer. */
634 id3->tagcache_idx = tcs.idx_id;
630 635
631 tagcache_search_finish(&tcs); 636 tagcache_search_finish(&tcs);
632} 637}
@@ -635,7 +640,6 @@ static void tagtree_unbuffer_event(struct mp3entry *id3, bool last_track)
635{ 640{
636 (void)last_track; 641 (void)last_track;
637 long playcount; 642 long playcount;
638 long rating;
639 long playtime; 643 long playtime;
640 long lastplayed; 644 long lastplayed;
641 645
@@ -646,55 +650,38 @@ static void tagtree_unbuffer_event(struct mp3entry *id3, bool last_track)
646 return; 650 return;
647 } 651 }
648 652
649 /* Don't process unplayed tracks. */ 653 if (!id3->tagcache_idx)
650 if (id3->elapsed == 0)
651 { 654 {
652 logf("not logging unplayed track"); 655 logf("No tagcache index pointer found");
653 return; 656 return;
654 } 657 }
655 658
656 if (!tagcache_find_index(&tcs, id3->path)) 659 /* Don't process unplayed tracks. */
660 if (id3->elapsed == 0)
657 { 661 {
658 logf("tc stat: not found: %s", id3->path); 662 logf("not logging unplayed track");
659 return; 663 return;
660 } 664 }
661 665
662 playcount = tagcache_get_numeric(&tcs, tag_playcount); 666 playcount = id3->playcount + 1;
663 playtime = tagcache_get_numeric(&tcs, tag_playtime);
664 lastplayed = tagcache_get_numeric(&tcs, tag_lastplayed);
665
666 playcount++;
667
668 rating = (long) id3->rating;
669
670 lastplayed = tagcache_increase_serial(); 667 lastplayed = tagcache_increase_serial();
671 if (lastplayed < 0) 668 if (lastplayed < 0)
672 { 669 {
673 logf("incorrect tc serial:%ld", lastplayed); 670 logf("incorrect tc serial:%ld", lastplayed);
674 tagcache_search_finish(&tcs);
675 return; 671 return;
676 } 672 }
677 673
678 /* Ignore the last 15s (crossfade etc.) */ 674 /* Ignore the last 15s (crossfade etc.) */
679 playtime += MIN(id3->length, id3->elapsed + 15 * 1000); 675 playtime = id3->playtime + MIN(id3->length, id3->elapsed + 15 * 1000);
680 676
681 logf("ube:%s", id3->path); 677 logf("ube:%s", id3->path);
682 logf("-> %d/%ld/%ld/%ld", last_track, playcount, rating, playtime); 678 logf("-> %d/%ld/%ld", last_track, playcount, playtime);
683 logf("-> %ld/%ld/%ld", id3->elapsed, id3->length, MIN(id3->length, id3->elapsed + 15 * 1000)); 679 logf("-> %ld/%ld/%ld", id3->elapsed, id3->length, MIN(id3->length, id3->elapsed + 15 * 1000));
684 680
685 /* lastplayed not yet supported. */ 681 /* Queue the updates to the tagcache system. */
686 682 tagcache_update_numeric(id3->tagcache_idx, tag_playcount, playcount);
687 if (!tagcache_modify_numeric_entry(&tcs, tag_playcount, playcount) 683 tagcache_update_numeric(id3->tagcache_idx, tag_playtime, playtime);
688 || !tagcache_modify_numeric_entry(&tcs, tag_rating, rating) 684 tagcache_update_numeric(id3->tagcache_idx, tag_lastplayed, lastplayed);
689 || !tagcache_modify_numeric_entry(&tcs, tag_playtime, playtime)
690 || !tagcache_modify_numeric_entry(&tcs, tag_lastplayed, lastplayed))
691 {
692 logf("tc stat: modify failed!");
693 tagcache_search_finish(&tcs);
694 return;
695 }
696
697 tagcache_search_finish(&tcs);
698} 685}
699 686
700bool tagtree_export(void) 687bool tagtree_export(void)