summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2006-07-10 16:22:03 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2006-07-10 16:22:03 +0000
commit9cd5c3e1195d872cbac2e8744bac5430490f6636 (patch)
tree8e70af5786bf38379333c38f63bea6e379f01b07 /apps
parentdae39989db4809d02cb4f6743c5f152a78ea0f8b (diff)
downloadrockbox-9cd5c3e1195d872cbac2e8744bac5430490f6636.tar.gz
rockbox-9cd5c3e1195d872cbac2e8744bac5430490f6636.zip
Tagcache update: Support removal of entries and no longer the need for
dircache to load tagcache in ram (however, dircache with tagcache is still strongly recommended). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10192 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/lang/english.lang46
-rw-r--r--apps/settings.c6
-rw-r--r--apps/settings_menu.c46
-rw-r--r--apps/tagcache.c460
-rw-r--r--apps/tagcache.h11
-rw-r--r--apps/tagtree.c1
6 files changed, 452 insertions, 118 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index ad9c82dfcf..7859b3ddae 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -1676,7 +1676,7 @@
1676</phrase> 1676</phrase>
1677<phrase> 1677<phrase>
1678 id: LANG_TAGCACHE 1678 id: LANG_TAGCACHE
1679 desc: in tag cache settings 1679 desc: in settings menu
1680 user: 1680 user:
1681 <source> 1681 <source>
1682 *: "Tag Cache" 1682 *: "Tag Cache"
@@ -1690,16 +1690,16 @@
1690</phrase> 1690</phrase>
1691<phrase> 1691<phrase>
1692 id: LANG_TAGCACHE_DISK 1692 id: LANG_TAGCACHE_DISK
1693 desc: in tag cache settings 1693 desc:
1694 user: 1694 user:
1695 <source> 1695 <source>
1696 *: "Keep on Disk" 1696 *: ""
1697 </source> 1697 </source>
1698 <dest> 1698 <dest>
1699 *: "Keep on Disk" 1699 *: ""
1700 </dest> 1700 </dest>
1701 <voice> 1701 <voice>
1702 *: "Keep on Disk" 1702 *: ""
1703 </voice> 1703 </voice>
1704</phrase> 1704</phrase>
1705<phrase> 1705<phrase>
@@ -1717,17 +1717,17 @@
1717 </voice> 1717 </voice>
1718</phrase> 1718</phrase>
1719<phrase> 1719<phrase>
1720 id: LANG_TAGCACHE_FORCE_UPDATE 1720 id: LANG_TAGCACHE_INITIALIZE
1721 desc: in tag cache settings 1721 desc: in tag cache settings
1722 user: 1722 user:
1723 <source> 1723 <source>
1724 *: "Force Tag Cache Update" 1724 *: "Initialize now"
1725 </source> 1725 </source>
1726 <dest> 1726 <dest>
1727 *: "Force Tag Cache Update" 1727 *: "Initialize now"
1728 </dest> 1728 </dest>
1729 <voice> 1729 <voice>
1730 *: "Force Tag Cache Update" 1730 *: "Initialize now"
1731 </voice> 1731 </voice>
1732</phrase> 1732</phrase>
1733<phrase> 1733<phrase>
@@ -8529,3 +8529,31 @@
8529 *: "Remote Scrolling Options" 8529 *: "Remote Scrolling Options"
8530 </voice> 8530 </voice>
8531</phrase> 8531</phrase>
8532<phrase>
8533 id: LANG_TAGCACHE_UPDATE
8534 desc: in tag cache settings
8535 user:
8536 <source>
8537 *: "Update now"
8538 </source>
8539 <dest>
8540 *: "Update now"
8541 </dest>
8542 <voice>
8543 *: "Update now"
8544 </voice>
8545</phrase>
8546<phrase>
8547 id: LANG_TAGCACHE_AUTOUPDATE
8548 desc: in tag cache settings
8549 user:
8550 <source>
8551 *: "Auto update"
8552 </source>
8553 <dest>
8554 *: "Auto update"
8555 </dest>
8556 <voice>
8557 *: "Auto update"
8558 </voice>
8559</phrase>
diff --git a/apps/settings.c b/apps/settings.c
index 6d7f250436..fb2b369cd7 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -94,7 +94,7 @@ const char rec_base_directory[] = REC_BASE_DIR;
94#include "dsp.h" 94#include "dsp.h"
95#endif 95#endif
96 96
97#define CONFIG_BLOCK_VERSION 44 97#define CONFIG_BLOCK_VERSION 45
98#define CONFIG_BLOCK_SIZE 512 98#define CONFIG_BLOCK_SIZE 512
99#define RTC_BLOCK_SIZE 44 99#define RTC_BLOCK_SIZE 44
100 100
@@ -554,8 +554,11 @@ static const struct bit_entry hd_bits[] =
554#ifdef HAVE_DIRCACHE 554#ifdef HAVE_DIRCACHE
555 {1, S_O(dircache), false, "dircache", off_on }, 555 {1, S_O(dircache), false, "dircache", off_on },
556 {22, S_O(dircache_size), 0, NULL, NULL }, 556 {22, S_O(dircache_size), 0, NULL, NULL },
557#endif
558#ifdef HAVE_TC_RAMCACHE
557 {1, S_O(tagcache_ram), 0, "tagcache_ram", off_on }, 559 {1, S_O(tagcache_ram), 0, "tagcache_ram", off_on },
558#endif 560#endif
561 {1, S_O(tagcache_autoupdate), 0, "tagcache_autoupdate", off_on },
559 562
560 {4, S_O(default_codepage), 0, "default codepage", 563 {4, S_O(default_codepage), 0, "default codepage",
561 "iso8859-1,iso8859-7,iso8859-8,cp1251,iso8859-11,cp1256,iso8859-9,iso8859-2,sjis,gb2312,ksx1001,big5,utf-8,cp1256" }, 564 "iso8859-1,iso8859-7,iso8859-8,cp1251,iso8859-11,cp1256,iso8859-9,iso8859-2,sjis,gb2312,ksx1001,big5,utf-8,cp1256" },
@@ -563,6 +566,7 @@ static const struct bit_entry hd_bits[] =
563 {1, S_O(warnon_erase_dynplaylist), false, 566 {1, S_O(warnon_erase_dynplaylist), false,
564 "warn when erasing dynamic playlist", off_on }, 567 "warn when erasing dynamic playlist", off_on },
565 568
569
566 /* If values are just added to the end, no need to bump the version. */ 570 /* If values are just added to the end, no need to bump the version. */
567 /* new stuff to be added at the end */ 571 /* new stuff to be added at the end */
568 572
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 821ad53dec..5d24431fe5 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -1520,18 +1520,51 @@ static bool dircache(void)
1520 1520
1521 return result; 1521 return result;
1522} 1522}
1523#endif /* HAVE_DIRCACHE */
1523 1524
1525#ifdef HAVE_TC_RAMCACHE
1524static bool tagcache_ram(void) 1526static bool tagcache_ram(void)
1525{ 1527{
1526 bool result = set_bool_options(str(LANG_TAGCACHE), 1528 bool result = set_bool_options(str(LANG_TAGCACHE_RAM),
1527 &global_settings.tagcache_ram, 1529 &global_settings.tagcache_ram,
1528 STR(LANG_TAGCACHE_RAM), 1530 STR(LANG_SET_BOOL_YES),
1529 STR(LANG_TAGCACHE_DISK), 1531 STR(LANG_SET_BOOL_NO),
1530 NULL); 1532 NULL);
1531 1533
1532 return result; 1534 return result;
1533} 1535}
1534#endif /* HAVE_DIRCACHE */ 1536#endif
1537
1538static bool tagcache_autoupdate(void)
1539{
1540 bool rc = set_bool_options(str(LANG_TAGCACHE_AUTOUPDATE),
1541 &global_settings.tagcache_autoupdate,
1542 STR(LANG_ON),
1543 STR(LANG_OFF),
1544 NULL);
1545 return rc;
1546}
1547
1548static bool tagcache_settings_menu(void)
1549{
1550 int m;
1551 bool result;
1552
1553 static const struct menu_item items[] = {
1554#ifdef HAVE_TC_RAMCACHE
1555 { ID2P(LANG_TAGCACHE_RAM), tagcache_ram },
1556#endif
1557 { ID2P(LANG_TAGCACHE_AUTOUPDATE), tagcache_autoupdate },
1558 { ID2P(LANG_TAGCACHE_INITIALIZE), tagcache_rebuild },
1559 { ID2P(LANG_TAGCACHE_UPDATE), tagcache_update },
1560 };
1561
1562 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
1563 NULL, NULL, NULL);
1564 result = menu_run(m);
1565 menu_exit(m);
1566 return result;
1567}
1535 1568
1536static bool playback_settings_menu(void) 1569static bool playback_settings_menu(void)
1537{ 1570{
@@ -1641,10 +1674,7 @@ static bool fileview_settings_menu(void)
1641 { ID2P(LANG_FILTER), dir_filter }, 1674 { ID2P(LANG_FILTER), dir_filter },
1642 { ID2P(LANG_FOLLOW), browse_current }, 1675 { ID2P(LANG_FOLLOW), browse_current },
1643 { ID2P(LANG_SHOW_ICONS), show_icons }, 1676 { ID2P(LANG_SHOW_ICONS), show_icons },
1644#ifdef HAVE_DIRCACHE 1677 { ID2P(LANG_TAGCACHE), tagcache_settings_menu},
1645 { ID2P(LANG_TAGCACHE), tagcache_ram },
1646#endif
1647 { ID2P(LANG_TAGCACHE_FORCE_UPDATE), tagcache_force_update },
1648 }; 1678 };
1649 1679
1650 m=menu_init( items, sizeof(items) / sizeof(*items), NULL, 1680 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
diff --git a/apps/tagcache.c b/apps/tagcache.c
index b3bce45b9a..d2ef9845bb 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -67,7 +67,8 @@ static struct tagcache_stat stat;
67enum tagcache_queue { 67enum tagcache_queue {
68 Q_STOP_SCAN = 0, 68 Q_STOP_SCAN = 0,
69 Q_START_SCAN, 69 Q_START_SCAN,
70 Q_FORCE_UPDATE, 70 Q_UPDATE,
71 Q_REBUILD,
71}; 72};
72 73
73 74
@@ -177,7 +178,7 @@ bool tagcache_is_sorted_tag(int type)
177 return false; 178 return false;
178} 179}
179 180
180#ifdef HAVE_TC_RAMCACHE 181#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
181static struct index_entry *find_entry_ram(const char *filename, 182static struct index_entry *find_entry_ram(const char *filename,
182 const struct dircache_entry *dc) 183 const struct dircache_entry *dc)
183{ 184{
@@ -272,7 +273,7 @@ static struct index_entry *find_entry_disk(const char *filename, bool retrieve)
272 273
273 if (tfe.tag_length >= (long)sizeof(buf)) 274 if (tfe.tag_length >= (long)sizeof(buf))
274 { 275 {
275 logf("too long tag"); 276 logf("too long tag #1");
276 close(fd); 277 close(fd);
277 last_pos = -1; 278 last_pos = -1;
278 return NULL; 279 return NULL;
@@ -487,6 +488,8 @@ static bool build_lookup_list(struct tagcache_search *tcs)
487 { 488 {
488 tcs->seek_list[tcs->seek_list_count] = 489 tcs->seek_list[tcs->seek_list_count] =
489 hdr->indices[i].tag_seek[tcs->type]; 490 hdr->indices[i].tag_seek[tcs->type];
491 tcs->seek_flags[tcs->seek_list_count] =
492 hdr->indices[i].flag;
490 tcs->seek_list_count++; 493 tcs->seek_list_count++;
491 } 494 }
492 } 495 }
@@ -503,6 +506,10 @@ static bool build_lookup_list(struct tagcache_search *tcs)
503 while (read(tcs->masterfd, &entry, sizeof(struct index_entry)) == 506 while (read(tcs->masterfd, &entry, sizeof(struct index_entry)) ==
504 sizeof(struct index_entry)) 507 sizeof(struct index_entry))
505 { 508 {
509 /* Check if entry has been deleted. */
510 if (entry.flag & FLAG_DELETED)
511 continue;
512
506 if (tcs->seek_list_count == SEEK_LIST_SIZE) 513 if (tcs->seek_list_count == SEEK_LIST_SIZE)
507 break ; 514 break ;
508 515
@@ -538,6 +545,10 @@ static bool build_lookup_list(struct tagcache_search *tcs)
538 } 545 }
539 546
540 read(fd, str, tfe.tag_length); 547 read(fd, str, tfe.tag_length);
548
549 /* Check if entry has been deleted. */
550 if (str[0] == '\0')
551 break;
541 } 552 }
542 553
543 if (!check_against_clause(seek, str, tcs->clause[i])) 554 if (!check_against_clause(seek, str, tcs->clause[i]))
@@ -559,6 +570,7 @@ static bool build_lookup_list(struct tagcache_search *tcs)
559 { 570 {
560 tcs->seek_list[tcs->seek_list_count] = 571 tcs->seek_list[tcs->seek_list_count] =
561 entry.tag_seek[tcs->type]; 572 entry.tag_seek[tcs->type];
573 tcs->seek_flags[tcs->seek_list_count] = entry.flag;
562 tcs->seek_list_count++; 574 tcs->seek_list_count++;
563 } 575 }
564 576
@@ -582,7 +594,6 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
582 return false; 594 return false;
583 595
584 tcs->position = sizeof(struct tagcache_header); 596 tcs->position = sizeof(struct tagcache_header);
585 tcs->fd = -1;
586 tcs->type = tag; 597 tcs->type = tag;
587 tcs->seek_pos = 0; 598 tcs->seek_pos = 0;
588 tcs->seek_list_count = 0; 599 tcs->seek_list_count = 0;
@@ -608,17 +619,15 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
608 return true; 619 return true;
609 620
610 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tcs->type); 621 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tcs->type);
611 tcs->fd = open(buf, O_RDONLY); 622 tcs->idxfd[tcs->type] = open(buf, O_RDONLY);
612 if (tcs->fd < 0) 623 if (tcs->idxfd[tcs->type] < 0)
613 { 624 {
614 logf("failed to open index"); 625 logf("failed to open index");
615 return false; 626 return false;
616 } 627 }
617 628
618 tcs->idxfd[tcs->type] = tcs->fd;
619
620 /* Check the header. */ 629 /* Check the header. */
621 if (read(tcs->fd, &h, sizeof(struct tagcache_header)) != 630 if (read(tcs->idxfd[tcs->type], &h, sizeof(struct tagcache_header)) !=
622 sizeof(struct tagcache_header) || h.magic != TAGCACHE_MAGIC) 631 sizeof(struct tagcache_header) || h.magic != TAGCACHE_MAGIC)
623 { 632 {
624 logf("incorrect header"); 633 logf("incorrect header");
@@ -685,7 +694,30 @@ bool tagcache_search_add_clause(struct tagcache_search *tcs,
685 return true; 694 return true;
686} 695}
687 696
688bool tagcache_get_next(struct tagcache_search *tcs) 697static bool open_files(struct tagcache_search *tcs)
698{
699 if (tcs->idxfd[tcs->type] < 0)
700 {
701 char fn[MAX_PATH];
702
703 snprintf(fn, sizeof fn, TAGCACHE_FILE_INDEX, tcs->type);
704 tcs->idxfd[tcs->type] = open(fn, O_RDONLY);
705 }
706
707 if (tcs->idxfd[tcs->type] < 0)
708 {
709 logf("File not open!");
710 return false;
711 }
712
713 return true;
714}
715
716#define TAG_FILENAME_RAM(tcs) ((tcs->type == tag_filename) \
717 ? (tcs->seek_flags[tcs->seek_list_count] \
718 & FLAG_DIRCACHE) : 1)
719
720static bool get_next(struct tagcache_search *tcs)
689{ 721{
690 static char buf[MAX_PATH]; 722 static char buf[MAX_PATH];
691 struct tagfile_entry entry; 723 struct tagfile_entry entry;
@@ -693,7 +725,7 @@ bool tagcache_get_next(struct tagcache_search *tcs)
693 if (!tcs->valid) 725 if (!tcs->valid)
694 return false; 726 return false;
695 727
696 if (tcs->fd < 0 && !tagcache_is_numeric_tag(tcs->type) 728 if (tcs->idxfd[tcs->type] < 0 && !tagcache_is_numeric_tag(tcs->type)
697#ifdef HAVE_TC_RAMCACHE 729#ifdef HAVE_TC_RAMCACHE
698 && !tcs->ramsearch 730 && !tcs->ramsearch
699#endif 731#endif
@@ -718,15 +750,20 @@ bool tagcache_get_next(struct tagcache_search *tcs)
718 tcs->seek_list_count--; 750 tcs->seek_list_count--;
719 751
720 /* Seek stream to the correct position and continue to direct fetch. */ 752 /* Seek stream to the correct position and continue to direct fetch. */
721 if (!tcs->ramsearch) 753 if (!tcs->ramsearch || !TAG_FILENAME_RAM(tcs))
722 lseek(tcs->fd, tcs->seek_list[tcs->seek_list_count], SEEK_SET); 754 {
755 if (!open_files(tcs))
756 return false;
757
758 lseek(tcs->idxfd[tcs->type], tcs->seek_list[tcs->seek_list_count], SEEK_SET);
759 }
723 else 760 else
724 tcs->position = tcs->seek_list[tcs->seek_list_count]; 761 tcs->position = tcs->seek_list[tcs->seek_list_count];
725 } 762 }
726 763
727 /* Direct fetch. */ 764 /* Direct fetch. */
728#ifdef HAVE_TC_RAMCACHE 765#ifdef HAVE_TC_RAMCACHE
729 if (tcs->ramsearch) 766 if (tcs->ramsearch && TAG_FILENAME_RAM(tcs))
730 { 767 {
731 struct tagfile_entry *ep; 768 struct tagfile_entry *ep;
732 769
@@ -738,20 +775,22 @@ bool tagcache_get_next(struct tagcache_search *tcs)
738 tcs->entry_count--; 775 tcs->entry_count--;
739 tcs->result_seek = tcs->position; 776 tcs->result_seek = tcs->position;
740 777
778# ifdef HAVE_DIRCACHE
741 if (tcs->type == tag_filename) 779 if (tcs->type == tag_filename)
742 { 780 {
743 dircache_copy_path((struct dircache_entry *)tcs->position, 781 dircache_copy_path((struct dircache_entry *)tcs->position,
744 buf, sizeof buf); 782 buf, sizeof buf);
745 tcs->result = buf; 783 tcs->result = buf;
746 tcs->result_len = strlen(buf) + 1; 784 tcs->result_len = strlen(buf) + 1;
747 785
748 return true; 786 return true;
749 } 787 }
788# endif
750 789
751 ep = (struct tagfile_entry *)&hdr->tags[tcs->type][tcs->position]; 790 ep = (struct tagfile_entry *)&hdr->tags[tcs->type][tcs->position];
752 tcs->position += sizeof(struct tagfile_entry) + ep->tag_length; 791 tcs->position += sizeof(struct tagfile_entry) + ep->tag_length;
753 tcs->result = ep->tag_data; 792 tcs->result = ep->tag_data;
754 tcs->result_len = ep->tag_length; 793 tcs->result_len = strlen(tcs->result) + 1;
755 tcs->idx_id = ep->idx_id; 794 tcs->idx_id = ep->idx_id;
756 795
757 if (!tagcache_is_unique_tag(tcs->type)) 796 if (!tagcache_is_unique_tag(tcs->type))
@@ -762,8 +801,11 @@ bool tagcache_get_next(struct tagcache_search *tcs)
762 else 801 else
763#endif 802#endif
764 { 803 {
765 tcs->result_seek = lseek(tcs->fd, 0, SEEK_CUR); 804 if (!open_files(tcs))
766 if (read(tcs->fd, &entry, sizeof(struct tagfile_entry)) != 805 return false;
806
807 tcs->result_seek = lseek(tcs->idxfd[tcs->type], 0, SEEK_CUR);
808 if (read(tcs->idxfd[tcs->type], &entry, sizeof(struct tagfile_entry)) !=
767 sizeof(struct tagfile_entry)) 809 sizeof(struct tagfile_entry))
768 { 810 {
769 /* End of data. */ 811 /* End of data. */
@@ -775,11 +817,11 @@ bool tagcache_get_next(struct tagcache_search *tcs)
775 if (entry.tag_length > (long)sizeof(buf)) 817 if (entry.tag_length > (long)sizeof(buf))
776 { 818 {
777 tcs->valid = false; 819 tcs->valid = false;
778 logf("too long tag"); 820 logf("too long tag #2");
779 return false; 821 return false;
780 } 822 }
781 823
782 if (read(tcs->fd, buf, entry.tag_length) != entry.tag_length) 824 if (read(tcs->idxfd[tcs->type], buf, entry.tag_length) != entry.tag_length)
783 { 825 {
784 tcs->valid = false; 826 tcs->valid = false;
785 logf("read error"); 827 logf("read error");
@@ -787,7 +829,7 @@ bool tagcache_get_next(struct tagcache_search *tcs)
787 } 829 }
788 830
789 tcs->result = buf; 831 tcs->result = buf;
790 tcs->result_len = entry.tag_length; 832 tcs->result_len = strlen(tcs->result) + 1;
791 tcs->idx_id = entry.idx_id; 833 tcs->idx_id = entry.idx_id;
792 if (!tagcache_is_unique_tag(tcs->type)) 834 if (!tagcache_is_unique_tag(tcs->type))
793 tcs->result_seek = tcs->idx_id; 835 tcs->result_seek = tcs->idx_id;
@@ -795,6 +837,17 @@ bool tagcache_get_next(struct tagcache_search *tcs)
795 return true; 837 return true;
796} 838}
797 839
840bool tagcache_get_next(struct tagcache_search *tcs)
841{
842 while (get_next(tcs))
843 {
844 if (tcs->result_len > 1)
845 return true;
846 }
847
848 return false;
849}
850
798bool tagcache_retrieve(struct tagcache_search *tcs, int idxid, 851bool tagcache_retrieve(struct tagcache_search *tcs, int idxid,
799 char *buf, long size) 852 char *buf, long size)
800{ 853{
@@ -809,38 +862,29 @@ bool tagcache_retrieve(struct tagcache_search *tcs, int idxid,
809 } 862 }
810 863
811#ifdef HAVE_TC_RAMCACHE 864#ifdef HAVE_TC_RAMCACHE
812 if (tcs->ramsearch) 865 if (tcs->ramsearch && TAG_FILENAME_RAM(tcs))
813 { 866 {
867 struct tagfile_entry *ep;
868
869# ifdef HAVE_DIRCACHE
814 if (tcs->type == tag_filename) 870 if (tcs->type == tag_filename)
815 { 871 {
816 dircache_copy_path((struct dircache_entry *)seek, 872 dircache_copy_path((struct dircache_entry *)seek,
817 buf, size); 873 buf, size);
818 } 874 return true;
819 else
820 {
821 struct tagfile_entry *ep;
822
823 ep = (struct tagfile_entry *)&hdr->tags[tcs->type][seek];
824 strncpy(buf, ep->tag_data, size-1);
825 } 875 }
876# endif
877
878
879 ep = (struct tagfile_entry *)&hdr->tags[tcs->type][seek];
880 strncpy(buf, ep->tag_data, size-1);
826 881
827 return true; 882 return true;
828 } 883 }
829#endif 884#endif
830
831 if (tcs->idxfd[tcs->type] < 0)
832 {
833 char fn[MAX_PATH];
834
835 snprintf(fn, sizeof fn, TAGCACHE_FILE_INDEX, tcs->type);
836 tcs->idxfd[tcs->type] = open(fn, O_RDONLY);
837 }
838 885
839 if (tcs->idxfd[tcs->type] < 0) 886 if (!open_files(tcs))
840 {
841 logf("File not open!");
842 return false; 887 return false;
843 }
844 888
845 lseek(tcs->idxfd[tcs->type], seek, SEEK_SET); 889 lseek(tcs->idxfd[tcs->type], seek, SEEK_SET);
846 if (read(tcs->idxfd[tcs->type], &tfe, sizeof(struct tagfile_entry)) != 890 if (read(tcs->idxfd[tcs->type], &tfe, sizeof(struct tagfile_entry)) !=
@@ -870,18 +914,6 @@ bool tagcache_retrieve(struct tagcache_search *tcs, int idxid,
870 914
871#if 0 915#if 0
872 916
873static bool tagcache_delete(const char *filename)
874{
875 struct index_entry *entry;
876
877 entry = find_entry_disk(filename, true);
878 if (entry == NULL)
879 {
880 logf("not found: %s", filename);
881 return false;
882 }
883}
884
885void tagcache_modify(struct tagcache_search *tcs, int type, const char *text) 917void tagcache_modify(struct tagcache_search *tcs, int type, const char *text)
886{ 918{
887 struct tagentry *entry; 919 struct tagentry *entry;
@@ -898,7 +930,7 @@ void tagcache_modify(struct tagcache_search *tcs, int type, const char *text)
898 tcs->seek_list[tcs->seek_list_count]; 930 tcs->seek_list[tcs->seek_list_count];
899 } 931 }
900 932
901 entry = find_entry_ram( 933 entry = find_entry_ram();
902 934
903} 935}
904#endif 936#endif
@@ -907,13 +939,6 @@ void tagcache_search_finish(struct tagcache_search *tcs)
907{ 939{
908 int i; 940 int i;
909 941
910 if (tcs->fd >= 0)
911 {
912 close(tcs->fd);
913 tcs->fd = -1;
914 tcs->idxfd[tcs->type] = -1;
915 }
916
917 if (tcs->masterfd >= 0) 942 if (tcs->masterfd >= 0)
918 { 943 {
919 close(tcs->masterfd); 944 close(tcs->masterfd);
@@ -933,7 +958,7 @@ void tagcache_search_finish(struct tagcache_search *tcs)
933 tcs->valid = false; 958 tcs->valid = false;
934} 959}
935 960
936#ifdef HAVE_TC_RAMCACHE 961#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
937static struct tagfile_entry *get_tag(const struct index_entry *entry, int tag) 962static struct tagfile_entry *get_tag(const struct index_entry *entry, int tag)
938{ 963{
939 return (struct tagfile_entry *)&hdr->tags[tag][entry->tag_seek[tag]]; 964 return (struct tagfile_entry *)&hdr->tags[tag][entry->tag_seek[tag]];
@@ -943,7 +968,7 @@ static long get_tag_numeric(const struct index_entry *entry, int tag)
943{ 968{
944 return entry->tag_seek[tag]; 969 return entry->tag_seek[tag];
945} 970}
946 971
947bool tagcache_fill_tags(struct mp3entry *id3, const char *filename) 972bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
948{ 973{
949 struct index_entry *entry; 974 struct index_entry *entry;
@@ -984,7 +1009,7 @@ inline void check_if_empty(char **tag)
984 1009
985#define CRC_BUF_LEN 8 1010#define CRC_BUF_LEN 8
986 1011
987#ifdef HAVE_TC_RAMCACHE 1012#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
988static void add_tagcache(const char *path, const struct dircache_entry *dc) 1013static void add_tagcache(const char *path, const struct dircache_entry *dc)
989#else 1014#else
990static void add_tagcache(const char *path) 1015static void add_tagcache(const char *path)
@@ -1006,8 +1031,8 @@ static void add_tagcache(const char *path)
1006 return ; 1031 return ;
1007 1032
1008 /* Check if the file is already cached. */ 1033 /* Check if the file is already cached. */
1009#ifdef HAVE_TC_RAMCACHE 1034#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
1010 if (stat.ramcache) 1035 if (stat.ramcache && dircache_is_enabled())
1011 { 1036 {
1012 if (find_entry_ram(path, dc)) 1037 if (find_entry_ram(path, dc))
1013 return ; 1038 return ;
@@ -1477,7 +1502,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
1477 1502
1478 if (entry.tag_length >= (int)sizeof(buf)) 1503 if (entry.tag_length >= (int)sizeof(buf))
1479 { 1504 {
1480 logf("too long tag"); 1505 logf("too long tag #3");
1481 close(fd); 1506 close(fd);
1482 return -2; 1507 return -2;
1483 } 1508 }
@@ -1489,6 +1514,10 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
1489 return -2; 1514 return -2;
1490 } 1515 }
1491 1516
1517 /* Skip deleted entries. */
1518 if (buf[0] == '\0')
1519 continue;
1520
1492 /** 1521 /**
1493 * Save the tag and tag id in the memory buffer. Tag id 1522 * Save the tag and tag id in the memory buffer. Tag id
1494 * is saved so we can later reindex the master lookup 1523 * is saved so we can later reindex the master lookup
@@ -1673,6 +1702,18 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
1673 1702
1674 for (j = 0; j < idxbuf_pos; j++) 1703 for (j = 0; j < idxbuf_pos; j++)
1675 { 1704 {
1705 if (idxbuf[j].flag & FLAG_DELETED)
1706 {
1707 int k;
1708
1709 idxbuf_pos--;
1710 for (k = j; k < idxbuf_pos; k++)
1711 idxbuf[k] = idxbuf[k+1];
1712
1713 j--;
1714 continue;
1715 }
1716
1676 idxbuf[j].tag_seek[index_type] = tempbuf_find_location( 1717 idxbuf[j].tag_seek[index_type] = tempbuf_find_location(
1677 idxbuf[j].tag_seek[index_type]/TAGFILE_ENTRY_CHUNK_LENGTH 1718 idxbuf[j].tag_seek[index_type]/TAGFILE_ENTRY_CHUNK_LENGTH
1678 + TAGFILE_MAX_ENTRIES); 1719 + TAGFILE_MAX_ENTRIES);
@@ -2008,6 +2049,117 @@ static void free_tempbuf(void)
2008 tempbuf_size = 0; 2049 tempbuf_size = 0;
2009} 2050}
2010 2051
2052static bool delete_entry(long idx_id)
2053{
2054 int fd;
2055 int tag, i;
2056 struct index_entry idx, myidx;
2057 struct tagcache_header hdr;
2058 char buf[MAX_PATH];
2059 int in_use[TAG_COUNT];
2060
2061 fd = open(TAGCACHE_FILE_MASTER, O_RDWR);
2062 if (fd < 0)
2063 {
2064 logf("master file open failed for R/W");
2065 return false;
2066 }
2067
2068 /* Check the header. */
2069 read(fd, &hdr, sizeof(struct tagcache_header));
2070 if (hdr.magic != TAGCACHE_MAGIC)
2071 {
2072 logf("header error");
2073 return false;
2074 }
2075
2076 lseek(fd, idx_id * sizeof(struct index_entry), SEEK_CUR);
2077 if (read(fd, &myidx, sizeof(struct index_entry))
2078 != sizeof(struct index_entry))
2079 {
2080 logf("read error");
2081 return false;
2082 }
2083
2084 myidx.flag |= FLAG_DELETED;
2085 lseek(fd, -sizeof(struct index_entry), SEEK_CUR);
2086 if (write(fd, &myidx, sizeof(struct index_entry))
2087 != sizeof(struct index_entry))
2088 {
2089 logf("write error");
2090 return false;
2091 }
2092
2093 /* Now check which tags are no longer in use (if any) */
2094 for (tag = 0; tag < TAG_COUNT; tag++)
2095 in_use[tag] = 0;
2096
2097 lseek(fd, sizeof(struct tagcache_header), SEEK_SET);
2098 for (i = 0; i < hdr.entry_count; i++)
2099 {
2100 if (read(fd, &idx, sizeof(struct index_entry))
2101 != sizeof(struct index_entry))
2102 {
2103 logf("read error");
2104 close(fd);
2105 return false;
2106 }
2107
2108 if (idx.flag & FLAG_DELETED)
2109 continue;
2110
2111 for (tag = 0; tag < TAG_COUNT; tag++)
2112 {
2113 if (tagcache_is_numeric_tag(tag))
2114 continue;
2115
2116 if (idx.tag_seek[tag] == myidx.tag_seek[tag])
2117 in_use[tag]++;
2118 }
2119 }
2120
2121 close(fd);
2122
2123 /* Now delete all tags no longer in use. */
2124 for (tag = 0; tag < TAG_COUNT; tag++)
2125 {
2126 if (tagcache_is_numeric_tag(tag))
2127 continue;
2128
2129 if (in_use[tag])
2130 {
2131 logf("in use: %d/%d", tag, in_use[tag]);
2132 continue;
2133 }
2134
2135 /* Open the index file, which contains the tag names. */
2136 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tag);
2137 fd = open(buf, O_RDWR);
2138
2139 if (fd < 0)
2140 {
2141 logf("open failed");
2142 return false;
2143 }
2144
2145 /* Skip the header block */
2146 lseek(fd, myidx.tag_seek[tag] + sizeof(struct tagfile_entry), SEEK_SET);
2147
2148 read(fd, buf, 10);
2149 buf[10]='\0';
2150 logf("TAG:%s", buf);
2151 lseek(fd, -10, SEEK_CUR);
2152
2153 /* Write first data byte in tag as \0 */
2154 write(fd, "", 1);
2155
2156 /* Now tag data has been removed */
2157 close(fd);
2158 }
2159
2160 return true;
2161}
2162
2011#ifdef HAVE_TC_RAMCACHE 2163#ifdef HAVE_TC_RAMCACHE
2012static bool allocate_tagcache(void) 2164static bool allocate_tagcache(void)
2013{ 2165{
@@ -2063,12 +2215,13 @@ static bool load_tagcache(void)
2063 char *p; 2215 char *p;
2064 int i; 2216 int i;
2065 2217
2066 /* We really need the dircache for this. */
2067 if (!dircache_is_enabled())
2068 return false;
2069
2070 logf("loading tagcache to ram..."); 2218 logf("loading tagcache to ram...");
2071 2219
2220# ifdef HAVE_DIRCACHE
2221 while (dircache_is_initializing())
2222 sleep(1);
2223# endif
2224
2072 fd = open(TAGCACHE_FILE_MASTER, O_RDONLY); 2225 fd = open(TAGCACHE_FILE_MASTER, O_RDONLY);
2073 if (fd < 0) 2226 if (fd < 0)
2074 { 2227 {
@@ -2151,8 +2304,11 @@ static bool load_tagcache(void)
2151 hdr->entry_count[i] < tch->entry_count; 2304 hdr->entry_count[i] < tch->entry_count;
2152 hdr->entry_count[i]++) 2305 hdr->entry_count[i]++)
2153 { 2306 {
2307 long pos;
2308
2154 yield(); 2309 yield();
2155 fe = (struct tagfile_entry *)p; 2310 fe = (struct tagfile_entry *)p;
2311 pos = lseek(fd, 0, SEEK_CUR);
2156 rc = read(fd, fe, sizeof(struct tagfile_entry)); 2312 rc = read(fd, fe, sizeof(struct tagfile_entry));
2157 if (rc != sizeof(struct tagfile_entry)) 2313 if (rc != sizeof(struct tagfile_entry))
2158 { 2314 {
@@ -2165,10 +2321,23 @@ static bool load_tagcache(void)
2165 /* We have a special handling for the filename tags. */ 2321 /* We have a special handling for the filename tags. */
2166 if (i == tag_filename) 2322 if (i == tag_filename)
2167 { 2323 {
2324# ifdef HAVE_DIRCACHE
2168 const struct dircache_entry *dc; 2325 const struct dircache_entry *dc;
2326# endif
2169 2327
2328 // FIXME: This is wrong!
2329 // idx = &hdr->indices[hdr->entry_count[i]];
2330 idx = &hdr->indices[fe->idx_id];
2331
2332 /* Check if the entry has already been removed */
2333 if (idx->flag & FLAG_DELETED)
2334 continue;
2335
2170 if (fe->tag_length >= (long)sizeof(buf)-1) 2336 if (fe->tag_length >= (long)sizeof(buf)-1)
2171 { 2337 {
2338 read(fd, buf, 10);
2339 buf[10] = '\0';
2340 logf("TAG:%s", buf);
2172 logf("too long filename"); 2341 logf("too long filename");
2173 close(fd); 2342 close(fd);
2174 return false; 2343 return false;
@@ -2182,22 +2351,47 @@ static bool load_tagcache(void)
2182 return false; 2351 return false;
2183 } 2352 }
2184 2353
2185 dc = dircache_get_entry_ptr(buf); 2354# ifdef HAVE_DIRCACHE
2186 if (dc == NULL) 2355 if (dircache_is_enabled())
2187 { 2356 {
2188 logf("Entry no longer valid."); 2357 dc = dircache_get_entry_ptr(buf);
2189 logf("-> %s", buf); 2358 if (dc == NULL)
2190 /* FIXME: Properly delete the entry. */ 2359 {
2191 hdr->indices[hdr->entry_count[i]].flag |= FLAG_DELETED; 2360 logf("Entry no longer valid.");
2192 continue ; 2361 logf("-> %s", buf);
2362 idx->flag |= FLAG_DELETED;
2363 delete_entry(fe->idx_id);
2364 continue ;
2365 }
2366
2367 idx->flag |= FLAG_DIRCACHE;
2368 idx->tag_seek[tag_filename] = (long)dc;
2369 }
2370 else
2371# endif
2372 {
2373 /* Check if entry has been removed. */
2374 if (global_settings.tagcache_autoupdate)
2375 {
2376 int testfd;
2377
2378 testfd = open(buf, O_RDONLY);
2379 if (testfd < 0)
2380 {
2381 logf("Entry no longer valid.");
2382 logf("-> %s", buf);
2383 idx->flag |= FLAG_DELETED;
2384 delete_entry((long)idx - (long)hdr->indices);
2385 continue;
2386 }
2387 }
2388
2389 idx->tag_seek[i] = pos;
2193 } 2390 }
2194
2195 hdr->indices[hdr->entry_count[i]].tag_seek[tag_filename]
2196 = (long)dc;
2197 2391
2198 continue ; 2392 continue ;
2199 } 2393 }
2200 2394
2201 bytesleft -= sizeof(struct tagfile_entry) + fe->tag_length; 2395 bytesleft -= sizeof(struct tagfile_entry) + fe->tag_length;
2202 if (bytesleft < 0) 2396 if (bytesleft < 0)
2203 { 2397 {
@@ -2231,7 +2425,59 @@ static bool load_tagcache(void)
2231 2425
2232 return true; 2426 return true;
2233} 2427}
2234#endif 2428#endif /* HAVE_TC_RAMCACHE */
2429
2430static bool check_deleted_files(void)
2431{
2432 int fd, testfd;
2433 char buf[MAX_PATH];
2434 struct tagfile_entry tfe;
2435
2436 logf("reverse scan...");
2437 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tag_filename);
2438 fd = open(buf, O_RDONLY);
2439
2440 if (fd < 0)
2441 {
2442 logf("%s open fail", buf);
2443 return false;
2444 }
2445
2446 lseek(fd, sizeof(struct tagcache_header), SEEK_SET);
2447 while (read(fd, &tfe, sizeof(struct tagfile_entry))
2448 == sizeof(struct tagfile_entry) && queue_empty(&tagcache_queue))
2449 {
2450 if (tfe.tag_length >= (long)sizeof(buf)-1)
2451 {
2452 logf("too long tag");
2453 close(fd);
2454 return false;
2455 }
2456
2457 if (read(fd, buf, tfe.tag_length) != tfe.tag_length)
2458 {
2459 logf("read error");
2460 close(fd);
2461 return false;
2462 }
2463
2464 /* Now check if the file exists. */
2465 testfd = open(buf, O_RDONLY);
2466 if (testfd < 0)
2467 {
2468 logf("Entry no longer valid.");
2469 logf("-> %s", buf);
2470 delete_entry(tfe.idx_id);
2471 }
2472 close(testfd);
2473 }
2474
2475 close(fd);
2476
2477 logf("done");
2478
2479 return true;
2480}
2235 2481
2236static bool check_dir(const char *dirname) 2482static bool check_dir(const char *dirname)
2237{ 2483{
@@ -2273,7 +2519,7 @@ static bool check_dir(const char *dirname)
2273 if (entry->attribute & ATTR_DIRECTORY) 2519 if (entry->attribute & ATTR_DIRECTORY)
2274 check_dir(curpath); 2520 check_dir(curpath);
2275 else 2521 else
2276#ifdef HAVE_TC_RAMCACHE 2522#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
2277 add_tagcache(curpath, dir->internal_entry); 2523 add_tagcache(curpath, dir->internal_entry);
2278#else 2524#else
2279 add_tagcache(curpath); 2525 add_tagcache(curpath);
@@ -2423,25 +2669,41 @@ static void tagcache_thread(void)
2423 check_done = false; 2669 check_done = false;
2424 break ; 2670 break ;
2425 2671
2426 case Q_FORCE_UPDATE: 2672 case Q_REBUILD:
2427 //remove_files(); 2673 remove_files();
2674 build_tagcache();
2675 break;
2676
2677 case Q_UPDATE:
2428 build_tagcache(); 2678 build_tagcache();
2679 check_deleted_files();
2429 break ; 2680 break ;
2430 2681
2431#ifdef HAVE_TC_RAMCACHE
2432 case SYS_TIMEOUT: 2682 case SYS_TIMEOUT:
2433 if (check_done || !dircache_is_enabled()) 2683 if (check_done)
2434 break ; 2684 break ;
2435 2685
2686#ifdef HAVE_TC_RAMCACHE
2436 if (!stat.ramcache && global_settings.tagcache_ram) 2687 if (!stat.ramcache && global_settings.tagcache_ram)
2688 {
2437 load_ramcache(); 2689 load_ramcache();
2438 2690 if (stat.ramcache)
2439 if (stat.ramcache) 2691 build_tagcache();
2692 }
2693 else
2694#endif
2695 if (global_settings.tagcache_autoupdate)
2696 {
2440 build_tagcache(); 2697 build_tagcache();
2698 /* Don't do auto removal without dircache (very slow). */
2699#ifdef HAVE_DIRCACHE
2700 if (dircache_is_enabled())
2701 check_deleted_files();
2702#endif
2703 }
2441 2704
2442 check_done = true; 2705 check_done = true;
2443 break ; 2706 break ;
2444#endif
2445 2707
2446 case Q_STOP_SCAN: 2708 case Q_STOP_SCAN:
2447 break ; 2709 break ;
@@ -2470,6 +2732,8 @@ static int get_progress(void)
2470 total_count = dircache_get_entry_count(); 2732 total_count = dircache_get_entry_count();
2471 } 2733 }
2472 else 2734 else
2735#endif
2736#ifdef HAVE_TC_RAMCACHE
2473 { 2737 {
2474 if (hdr && stat.ramcache) 2738 if (hdr && stat.ramcache)
2475 total_count = hdr->h.entry_count; 2739 total_count = hdr->h.entry_count;
@@ -2495,9 +2759,17 @@ void tagcache_start_scan(void)
2495 queue_post(&tagcache_queue, Q_START_SCAN, 0); 2759 queue_post(&tagcache_queue, Q_START_SCAN, 0);
2496} 2760}
2497 2761
2498bool tagcache_force_update(void) 2762bool tagcache_update(void)
2763{
2764 queue_post(&tagcache_queue, Q_UPDATE, 0);
2765 gui_syncsplash(HZ*2, true, str(LANG_TAGCACHE_FORCE_UPDATE_SPLASH));
2766
2767 return false;
2768}
2769
2770bool tagcache_rebuild(void)
2499{ 2771{
2500 queue_post(&tagcache_queue, Q_FORCE_UPDATE, 0); 2772 queue_post(&tagcache_queue, Q_REBUILD, 0);
2501 gui_syncsplash(HZ*2, true, str(LANG_TAGCACHE_FORCE_UPDATE_SPLASH)); 2773 gui_syncsplash(HZ*2, true, str(LANG_TAGCACHE_FORCE_UPDATE_SPLASH));
2502 2774
2503 return false; 2775 return false;
diff --git a/apps/tagcache.h b/apps/tagcache.h
index c94c77f277..a82f6e1634 100644
--- a/apps/tagcache.h
+++ b/apps/tagcache.h
@@ -27,10 +27,6 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
27 27
28#define TAG_COUNT 10 28#define TAG_COUNT 10
29 29
30#ifdef HAVE_DIRCACHE
31#define HAVE_TC_RAMCACHE 1
32#endif
33
34/* Allow a little drift to the filename ordering (should not be too high/low). */ 30/* Allow a little drift to the filename ordering (should not be too high/low). */
35#define POS_HISTORY_COUNT 4 31#define POS_HISTORY_COUNT 4
36 32
@@ -70,7 +66,8 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
70#define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/tagcache_%d.tcd" 66#define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/tagcache_%d.tcd"
71 67
72/* Flags */ 68/* Flags */
73#define FLAG_DELETED 0x0001 69#define FLAG_DELETED 0x0001 /* Entry has been removed from db */
70#define FLAG_DIRCACHE 0x0002 /* Filename is a dircache pointer */
74 71
75enum clause { clause_none, clause_is, clause_gt, clause_gteq, clause_lt, 72enum clause { clause_none, clause_is, clause_gt, clause_gteq, clause_lt,
76 clause_lteq, clause_contains, clause_begins_with, clause_ends_with }; 73 clause_lteq, clause_contains, clause_begins_with, clause_ends_with };
@@ -102,6 +99,7 @@ struct tagcache_search {
102 int fd, masterfd; 99 int fd, masterfd;
103 int idxfd[TAG_COUNT]; 100 int idxfd[TAG_COUNT];
104 long seek_list[SEEK_LIST_SIZE]; 101 long seek_list[SEEK_LIST_SIZE];
102 long seek_flags[SEEK_LIST_SIZE];
105 long filter_tag[TAGCACHE_MAX_FILTERS]; 103 long filter_tag[TAGCACHE_MAX_FILTERS];
106 long filter_seek[TAGCACHE_MAX_FILTERS]; 104 long filter_seek[TAGCACHE_MAX_FILTERS];
107 int filter_count; 105 int filter_count;
@@ -147,6 +145,7 @@ void tagcache_init(void);
147bool tagcache_is_initialized(void); 145bool tagcache_is_initialized(void);
148void tagcache_start_scan(void); 146void tagcache_start_scan(void);
149void tagcache_stop_scan(void); 147void tagcache_stop_scan(void);
150bool tagcache_force_update(void); 148bool tagcache_update(void);
149bool tagcache_rebuild(void);
151 150
152#endif 151#endif
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 0401ca8cee..ded2426d41 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -575,6 +575,7 @@ int tagtree_load(struct tree_context* c)
575 { 575 {
576 case root: 576 case root:
577 count = load_root(c); 577 count = load_root(c);
578 c->dirlevel = 0;
578 break; 579 break;
579 580
580 case allsubentries: 581 case allsubentries: