summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2007-12-16 21:10:26 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2007-12-16 21:10:26 +0000
commitf6039466fb275f55be16113bbbf46872f90862c8 (patch)
tree5ab33d8b5b933266f5dcdcffe8e7711e25e5b6a8 /apps
parent646d39ec4e51c2736737a5689f37256e31db2620 (diff)
downloadrockbox-f6039466fb275f55be16113bbbf46872f90862c8.tar.gz
rockbox-f6039466fb275f55be16113bbbf46872f90862c8.zip
Added file modify time field to the DB. Now metadata changes should be detected with database autoupdate enabled. Runtime statistics are not yet preserved. Preserving statistics over moving of files and altering metadata is going to be implemented next. IMPORTANT: Export database before upgrading.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15946 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/tagcache.c195
-rw-r--r--apps/tagcache.h19
2 files changed, 147 insertions, 67 deletions
diff --git a/apps/tagcache.c b/apps/tagcache.c
index bf2df7cc0b..1f4521168e 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -85,7 +85,6 @@
85#define do_timed_yield() do { } while(0) 85#define do_timed_yield() do { } while(0)
86#endif 86#endif
87 87
88
89#ifndef __PCTOOL__ 88#ifndef __PCTOOL__
90/* Tag Cache thread. */ 89/* Tag Cache thread. */
91static struct event_queue tagcache_queue; 90static struct event_queue tagcache_queue;
@@ -115,16 +114,18 @@ static const int unique_tags[] = { tag_artist, tag_album, tag_genre,
115 tag_composer, tag_comment, tag_albumartist, tag_grouping }; 114 tag_composer, tag_comment, tag_albumartist, tag_grouping };
116 115
117/* Numeric tags (we can use these tags with conditional clauses). */ 116/* Numeric tags (we can use these tags with conditional clauses). */
118static const int numeric_tags[] = { tag_year, tag_discnumber, tag_tracknumber, tag_length, 117static const int numeric_tags[] = { tag_year, tag_discnumber,
119 tag_bitrate, tag_playcount, tag_rating, tag_playtime, tag_lastplayed, tag_commitid, 118 tag_tracknumber, tag_length, tag_bitrate, tag_playcount, tag_rating,
119 tag_playtime, tag_lastplayed, tag_commitid, tag_mtime,
120 tag_virt_length_min, tag_virt_length_sec, 120 tag_virt_length_min, tag_virt_length_sec,
121 tag_virt_playtime_min, tag_virt_playtime_sec, 121 tag_virt_playtime_min, tag_virt_playtime_sec,
122 tag_virt_entryage, tag_virt_autoscore }; 122 tag_virt_entryage, tag_virt_autoscore };
123 123
124/* String presentation of the tags defined in tagcache.h. Must be in correct order! */ 124/* String presentation of the tags defined in tagcache.h. Must be in correct order! */
125static const char *tags_str[] = { "artist", "album", "genre", "title", 125static const char *tags_str[] = { "artist", "album", "genre", "title",
126 "filename", "composer", "comment", "albumartist", "grouping", "year", "discnumber", "tracknumber", 126 "filename", "composer", "comment", "albumartist", "grouping", "year",
127 "bitrate", "length", "playcount", "rating", "playtime", "lastplayed", "commitid" }; 127 "discnumber", "tracknumber", "bitrate", "length", "playcount", "rating",
128 "playtime", "lastplayed", "commitid", "mtime" };
128 129
129/* Status information of the tagcache. */ 130/* Status information of the tagcache. */
130static struct tagcache_stat tc_stat; 131static struct tagcache_stat tc_stat;
@@ -188,7 +189,7 @@ struct master_header {
188 189
189/* For the endianess correction */ 190/* For the endianess correction */
190static const char *tagfile_entry_ec = "ss"; 191static const char *tagfile_entry_ec = "ss";
191static const char *index_entry_ec = "llllllllllllllllllll"; /* (1 + TAG_COUNT) * l */ 192static const char *index_entry_ec = "lllllllllllllllllllll"; /* (1 + TAG_COUNT) * l */
192static const char *tagcache_header_ec = "lll"; 193static const char *tagcache_header_ec = "lll";
193static const char *master_header_ec = "llllll"; 194static const char *master_header_ec = "llllll";
194 195
@@ -252,6 +253,8 @@ static int processed_dir_count;
252static volatile int write_lock; 253static volatile int write_lock;
253static volatile int read_lock; 254static volatile int read_lock;
254 255
256static bool delete_entry(long idx_id);
257
255const char* tagcache_tag_to_str(int tag) 258const char* tagcache_tag_to_str(int tag)
256{ 259{
257 return tags_str[tag]; 260 return tags_str[tag];
@@ -328,6 +331,46 @@ static int open_tag_fd(struct tagcache_header *hdr, int tag, bool write)
328 return fd; 331 return fd;
329} 332}
330 333
334static int open_master_fd(struct master_header *hdr, bool write)
335{
336 int fd;
337 int rc;
338
339 fd = open(TAGCACHE_FILE_MASTER, write ? O_RDWR : O_RDONLY);
340 if (fd < 0)
341 {
342 logf("master file open failed for R/W");
343 tc_stat.ready = false;
344 return fd;
345 }
346
347 tc_stat.econ = false;
348
349 /* Check the header. */
350 rc = read(fd, hdr, sizeof(struct master_header));
351 if (hdr->tch.magic == TAGCACHE_MAGIC && rc == sizeof(struct master_header))
352 {
353 /* Success. */
354 return fd;
355 }
356
357 /* Trying to read again, this time with endianess correction enabled. */
358 lseek(fd, 0, SEEK_SET);
359
360 rc = ecread(fd, hdr, 1, master_header_ec, true);
361 if (hdr->tch.magic != TAGCACHE_MAGIC || rc != sizeof(struct master_header))
362 {
363 logf("header error");
364 tc_stat.ready = false;
365 close(fd);
366 return -2;
367 }
368
369 tc_stat.econ = true;
370
371 return fd;
372}
373
331#ifndef __PCTOOL__ 374#ifndef __PCTOOL__
332static bool do_timed_yield(void) 375static bool do_timed_yield(void)
333{ 376{
@@ -521,6 +564,8 @@ bool tagcache_find_index(struct tagcache_search *tcs, const char *filename)
521static bool get_index(int masterfd, int idxid, 564static bool get_index(int masterfd, int idxid,
522 struct index_entry *idx, bool use_ram) 565 struct index_entry *idx, bool use_ram)
523{ 566{
567 bool localfd = false;
568
524 if (idxid < 0) 569 if (idxid < 0)
525 { 570 {
526 logf("Incorrect idxid: %d", idxid); 571 logf("Incorrect idxid: %d", idxid);
@@ -540,15 +585,31 @@ static bool get_index(int masterfd, int idxid,
540 (void)use_ram; 585 (void)use_ram;
541#endif 586#endif
542 587
588 if (masterfd < 0)
589 {
590 struct master_header tcmh;
591
592 localfd = true;
593 masterfd = open_master_fd(&tcmh, false);
594 if (masterfd < 0)
595 return false;
596 }
597
543 lseek(masterfd, idxid * sizeof(struct index_entry) 598 lseek(masterfd, idxid * sizeof(struct index_entry)
544 + sizeof(struct master_header), SEEK_SET); 599 + sizeof(struct master_header), SEEK_SET);
545 if (ecread(masterfd, idx, 1, index_entry_ec, tc_stat.econ) 600 if (ecread(masterfd, idx, 1, index_entry_ec, tc_stat.econ)
546 != sizeof(struct index_entry)) 601 != sizeof(struct index_entry))
547 { 602 {
548 logf("read error #3"); 603 logf("read error #3");
604 if (localfd)
605 close(masterfd);
606
549 return false; 607 return false;
550 } 608 }
551 609
610 if (localfd)
611 close(masterfd);
612
552 if (idx->flag & FLAG_DELETED) 613 if (idx->flag & FLAG_DELETED)
553 return false; 614 return false;
554 615
@@ -1080,46 +1141,6 @@ static void remove_files(void)
1080} 1141}
1081 1142
1082 1143
1083static int open_master_fd(struct master_header *hdr, bool write)
1084{
1085 int fd;
1086 int rc;
1087
1088 fd = open(TAGCACHE_FILE_MASTER, write ? O_RDWR : O_RDONLY);
1089 if (fd < 0)
1090 {
1091 logf("master file open failed for R/W");
1092 tc_stat.ready = false;
1093 return fd;
1094 }
1095
1096 tc_stat.econ = false;
1097
1098 /* Check the header. */
1099 rc = read(fd, hdr, sizeof(struct master_header));
1100 if (hdr->tch.magic == TAGCACHE_MAGIC && rc == sizeof(struct master_header))
1101 {
1102 /* Success. */
1103 return fd;
1104 }
1105
1106 /* Trying to read again, this time with endianess correction enabled. */
1107 lseek(fd, 0, SEEK_SET);
1108
1109 rc = ecread(fd, hdr, 1, master_header_ec, true);
1110 if (hdr->tch.magic != TAGCACHE_MAGIC || rc != sizeof(struct master_header))
1111 {
1112 logf("header error");
1113 tc_stat.ready = false;
1114 close(fd);
1115 return -2;
1116 }
1117
1118 tc_stat.econ = true;
1119
1120 return fd;
1121}
1122
1123static bool check_all_headers(void) 1144static bool check_all_headers(void)
1124{ 1145{
1125 struct master_header myhdr; 1146 struct master_header myhdr;
@@ -1602,16 +1623,17 @@ static int check_if_empty(char **tag)
1602 entry.tag_length[tag] = check_if_empty(data); \ 1623 entry.tag_length[tag] = check_if_empty(data); \
1603 offset += entry.tag_length[tag] 1624 offset += entry.tag_length[tag]
1604 1625
1626static void add_tagcache(char *path, unsigned long mtime
1605#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) 1627#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
1606static void add_tagcache(char *path, const struct dirent *dc) 1628 ,const struct dirent *dc
1607#else
1608static void add_tagcache(char *path)
1609#endif 1629#endif
1630 )
1610{ 1631{
1611 struct mp3entry id3; 1632 struct mp3entry id3;
1612 struct temp_file_entry entry; 1633 struct temp_file_entry entry;
1613 bool ret; 1634 bool ret;
1614 int fd; 1635 int fd;
1636 int idx_id = -1;
1615 char tracknumfix[3]; 1637 char tracknumfix[3];
1616 int offset = 0; 1638 int offset = 0;
1617 int path_length = strlen(path); 1639 int path_length = strlen(path);
@@ -1637,16 +1659,40 @@ static void add_tagcache(char *path)
1637#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) 1659#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
1638 if (tc_stat.ramcache && dircache_is_enabled()) 1660 if (tc_stat.ramcache && dircache_is_enabled())
1639 { 1661 {
1640 if (find_entry_ram(path, dc) >= 0) 1662 idx_id = find_entry_ram(path, dc);
1641 return ;
1642 } 1663 }
1643 else 1664 else
1644#endif 1665#endif
1645 { 1666 {
1646 if (filenametag_fd >= 0) 1667 if (filenametag_fd >= 0)
1647 { 1668 {
1648 if (find_entry_disk(path) >= 0) 1669 idx_id = find_entry_disk(path);
1649 return ; 1670 }
1671 }
1672
1673 /* Check if file has been modified. */
1674 if (idx_id >= 0)
1675 {
1676 struct index_entry idx;
1677
1678 if (!get_index(-1, idx_id, &idx, true))
1679 {
1680 logf("failed to retrieve index entry");
1681 return ;
1682 }
1683
1684 if ((unsigned long)idx.tag_seek[tag_mtime] == mtime)
1685 {
1686 /* No changes to file. */
1687 return ;
1688 }
1689
1690 /* Metadata might have been changed. Delete the entry. */
1691 logf("Re-adding: %s", path);
1692 if (!delete_entry(idx_id))
1693 {
1694 logf("delete_entry failed: %d", idx_id);
1695 return ;
1650 } 1696 }
1651 } 1697 }
1652 1698
@@ -1706,6 +1752,7 @@ static void add_tagcache(char *path)
1706 entry.tag_offset[tag_tracknumber] = id3.tracknum; 1752 entry.tag_offset[tag_tracknumber] = id3.tracknum;
1707 entry.tag_offset[tag_length] = id3.length; 1753 entry.tag_offset[tag_length] = id3.length;
1708 entry.tag_offset[tag_bitrate] = id3.bitrate; 1754 entry.tag_offset[tag_bitrate] = id3.bitrate;
1755 entry.tag_offset[tag_mtime] = mtime;
1709 1756
1710 /* String tags. */ 1757 /* String tags. */
1711 has_albumartist = id3.albumartist != NULL 1758 has_albumartist = id3.albumartist != NULL
@@ -3241,7 +3288,8 @@ bool tagcache_create_changelog(struct tagcache_search *tcs)
3241 3288
3242static bool delete_entry(long idx_id) 3289static bool delete_entry(long idx_id)
3243{ 3290{
3244 int fd; 3291 int fd = -1;
3292 /*int dbdel_fd = -1;*/
3245 int tag, i; 3293 int tag, i;
3246 struct index_entry idx, myidx; 3294 struct index_entry idx, myidx;
3247 struct master_header myhdr; 3295 struct master_header myhdr;
@@ -3259,13 +3307,23 @@ static bool delete_entry(long idx_id)
3259 if ( (fd = open_master_fd(&myhdr, true) ) < 0) 3307 if ( (fd = open_master_fd(&myhdr, true) ) < 0)
3260 return false; 3308 return false;
3261 3309
3310 /*
3311 TODO: Implement soon.
3312 dbdel_fd = open(TAGCACHE_FILE_DELETED, O_RDWR | O_APPEND | O_CREAT);
3313 if (dbdel_fd < 0)
3314 {
3315 logf("delete_entry(): DBDEL open failed");
3316 goto cleanup;
3317 }
3318 close(dbdel_fd);
3319 dbdel_fd = -1;
3320 */
3262 lseek(fd, idx_id * sizeof(struct index_entry), SEEK_CUR); 3321 lseek(fd, idx_id * sizeof(struct index_entry), SEEK_CUR);
3263 if (ecread(fd, &myidx, 1, index_entry_ec, tc_stat.econ) 3322 if (ecread(fd, &myidx, 1, index_entry_ec, tc_stat.econ)
3264 != sizeof(struct index_entry)) 3323 != sizeof(struct index_entry))
3265 { 3324 {
3266 logf("delete_entry(): read error"); 3325 logf("delete_entry(): read error");
3267 close(fd); 3326 goto cleanup;
3268 return false;
3269 } 3327 }
3270 3328
3271 myidx.flag |= FLAG_DELETED; 3329 myidx.flag |= FLAG_DELETED;
@@ -3274,8 +3332,7 @@ static bool delete_entry(long idx_id)
3274 != sizeof(struct index_entry)) 3332 != sizeof(struct index_entry))
3275 { 3333 {
3276 logf("delete_entry(): write_error"); 3334 logf("delete_entry(): write_error");
3277 close(fd); 3335 goto cleanup;
3278 return false;
3279 } 3336 }
3280 3337
3281 /* Now check which tags are no longer in use (if any) */ 3338 /* Now check which tags are no longer in use (if any) */
@@ -3298,8 +3355,7 @@ static bool delete_entry(long idx_id)
3298 != sizeof(struct index_entry)) 3355 != sizeof(struct index_entry))
3299 { 3356 {
3300 logf("delete_entry(): read error #2"); 3357 logf("delete_entry(): read error #2");
3301 close(fd); 3358 goto cleanup;
3302 return false;
3303 } 3359 }
3304 idxp = &idx; 3360 idxp = &idx;
3305 } 3361 }
@@ -3318,6 +3374,7 @@ static bool delete_entry(long idx_id)
3318 } 3374 }
3319 3375
3320 close(fd); 3376 close(fd);
3377 fd = -1;
3321 3378
3322 /* Now delete all tags no longer in use. */ 3379 /* Now delete all tags no longer in use. */
3323 for (tag = 0; tag < TAG_COUNT; tag++) 3380 for (tag = 0; tag < TAG_COUNT; tag++)
@@ -3347,7 +3404,7 @@ static bool delete_entry(long idx_id)
3347 if (fd < 0) 3404 if (fd < 0)
3348 { 3405 {
3349 logf("open failed"); 3406 logf("open failed");
3350 return false; 3407 goto cleanup;
3351 } 3408 }
3352 3409
3353 /* Skip the header block */ 3410 /* Skip the header block */
@@ -3368,6 +3425,14 @@ static bool delete_entry(long idx_id)
3368 } 3425 }
3369 3426
3370 return true; 3427 return true;
3428
3429 cleanup:
3430 if (fd >= 0)
3431 close(fd);
3432/* if (dbdel_fd >= 0)
3433 close(dbdel_fd);
3434 */
3435 return false;
3371} 3436}
3372 3437
3373#ifndef __PCTOOL__ 3438#ifndef __PCTOOL__
@@ -3846,11 +3911,13 @@ static bool check_dir(const char *dirname)
3846 else 3911 else
3847 { 3912 {
3848 tc_stat.curentry = curpath; 3913 tc_stat.curentry = curpath;
3914
3915 /* Add a new entry to the temporary db file. */
3916 add_tagcache(curpath, (entry->wrtdate << 16) | entry->wrttime
3849#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) 3917#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
3850 add_tagcache(curpath, dir->internal_entry); 3918 , dir->internal_entry
3851#else
3852 add_tagcache(curpath);
3853#endif 3919#endif
3920 );
3854 3921
3855 /* Wait until current path for debug screen is read and unset. */ 3922 /* Wait until current path for debug screen is read and unset. */
3856 while (tc_stat.syncscreen && tc_stat.curentry != NULL) 3923 while (tc_stat.syncscreen && tc_stat.curentry != NULL)
diff --git a/apps/tagcache.h b/apps/tagcache.h
index 39f0c61f7e..879cf66fbd 100644
--- a/apps/tagcache.h
+++ b/apps/tagcache.h
@@ -25,13 +25,13 @@
25enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, 25enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
26 tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year, 26 tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year,
27 tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating, 27 tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating,
28 tag_playtime, tag_lastplayed, tag_commitid, 28 tag_playtime, tag_lastplayed, tag_commitid, tag_mtime,
29 /* Virtual tags */ 29 /* Virtual tags */
30 tag_virt_length_min, tag_virt_length_sec, 30 tag_virt_length_min, tag_virt_length_sec,
31 tag_virt_playtime_min, tag_virt_playtime_sec, 31 tag_virt_playtime_min, tag_virt_playtime_sec,
32 tag_virt_entryage, tag_virt_autoscore }; 32 tag_virt_entryage, tag_virt_autoscore };
33 33
34#define TAG_COUNT 19 34#define TAG_COUNT 20
35 35
36/* Maximum length of a single tag. */ 36/* Maximum length of a single tag. */
37#define TAG_MAXLEN (MAX_PATH*2) 37#define TAG_MAXLEN (MAX_PATH*2)
@@ -43,7 +43,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
43#define IDX_BUF_DEPTH 64 43#define IDX_BUF_DEPTH 64
44 44
45/* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */ 45/* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */
46#define TAGCACHE_MAGIC 0x5443480b 46#define TAGCACHE_MAGIC 0x5443480c
47 47
48/* How much to allocate extra space for ramcache. */ 48/* How much to allocate extra space for ramcache. */
49#define TAGCACHE_RESERVE 32768 49#define TAGCACHE_RESERVE 32768
@@ -72,10 +72,23 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
72#define TAGCACHE_MAX_CLAUSES 32 72#define TAGCACHE_MAX_CLAUSES 32
73 73
74/* Tag database files. */ 74/* Tag database files. */
75
76/* Temporary database containing new tags to be committed to the main db. */
75#define TAGCACHE_FILE_TEMP ROCKBOX_DIR "/database_tmp.tcd" 77#define TAGCACHE_FILE_TEMP ROCKBOX_DIR "/database_tmp.tcd"
78
79/* Database containing deleted entries with runtime statistics. */
80#define TAGCACHE_FILE_DELETED ROCKBOX_DIR "/database_del.tcd"
81
82/* The main database master index and numeric data. */
76#define TAGCACHE_FILE_MASTER ROCKBOX_DIR "/database_idx.tcd" 83#define TAGCACHE_FILE_MASTER ROCKBOX_DIR "/database_idx.tcd"
84
85/* The main database string data. */
77#define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/database_%d.tcd" 86#define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/database_%d.tcd"
87
88/* ASCII dumpfile of the DB contents. */
78#define TAGCACHE_FILE_CHANGELOG ROCKBOX_DIR "/database_changelog.txt" 89#define TAGCACHE_FILE_CHANGELOG ROCKBOX_DIR "/database_changelog.txt"
90
91/* Serialized DB. */
79#define TAGCACHE_STATEFILE ROCKBOX_DIR "/database_state.tcd" 92#define TAGCACHE_STATEFILE ROCKBOX_DIR "/database_state.tcd"
80 93
81/* Flags */ 94/* Flags */