summaryrefslogtreecommitdiff
path: root/apps/tagcache.c
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2006-07-15 17:36:25 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2006-07-15 17:36:25 +0000
commit45dfe2a36f03d1ada7036dedb50fb98d7c5421b2 (patch)
tree866a57b677dce40ef5b772e1514a9ec6a35f60ea /apps/tagcache.c
parente60cb43a982e03b062bd42dbe260abca299fe14d (diff)
downloadrockbox-45dfe2a36f03d1ada7036dedb50fb98d7c5421b2.tar.gz
rockbox-45dfe2a36f03d1ada7036dedb50fb98d7c5421b2.zip
Initial runtimedb support for tagcache. Only for developers,
statistical data will be lost in future until changelogs has been implemented. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10217 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/tagcache.c')
-rw-r--r--apps/tagcache.c264
1 files changed, 180 insertions, 84 deletions
diff --git a/apps/tagcache.c b/apps/tagcache.c
index affdc46a66..a5675850bf 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -58,7 +58,8 @@ static const int sorted_tags[] = { tag_artist, tag_album, tag_genre, tag_compose
58static const int unique_tags[] = { tag_artist, tag_album, tag_genre, tag_composer }; 58static const int unique_tags[] = { tag_artist, tag_album, tag_genre, tag_composer };
59 59
60/* Numeric tags (we can use these tags with conditional clauses). */ 60/* Numeric tags (we can use these tags with conditional clauses). */
61static const int numeric_tags[] = { tag_year, tag_tracknumber, tag_length, tag_bitrate }; 61static const int numeric_tags[] = { tag_year, tag_tracknumber, tag_length, tag_bitrate,
62 tag_playcount, tag_playtime, tag_lastplayed, tag_virt_autoscore };
62 63
63/* Status information of the tagcache. */ 64/* Status information of the tagcache. */
64static struct tagcache_stat stat; 65static struct tagcache_stat stat;
@@ -179,8 +180,8 @@ bool tagcache_is_sorted_tag(int type)
179} 180}
180 181
181#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) 182#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
182static struct index_entry *find_entry_ram(const char *filename, 183static long find_entry_ram(const char *filename,
183 const struct dircache_entry *dc) 184 const struct dircache_entry *dc)
184{ 185{
185 static long last_pos = 0; 186 static long last_pos = 0;
186 int counter = 0; 187 int counter = 0;
@@ -188,7 +189,7 @@ static struct index_entry *find_entry_ram(const char *filename,
188 189
189 /* Check if we tagcache is loaded into ram. */ 190 /* Check if we tagcache is loaded into ram. */
190 if (!stat.ramcache) 191 if (!stat.ramcache)
191 return NULL; 192 return -1;
192 193
193 if (dc == NULL) 194 if (dc == NULL)
194 dc = dircache_get_entry_ptr(filename); 195 dc = dircache_get_entry_ptr(filename);
@@ -196,7 +197,7 @@ static struct index_entry *find_entry_ram(const char *filename,
196 if (dc == NULL) 197 if (dc == NULL)
197 { 198 {
198 logf("tagcache: file not found."); 199 logf("tagcache: file not found.");
199 return NULL; 200 return -1;
200 } 201 }
201 202
202 try_again: 203 try_again:
@@ -211,7 +212,7 @@ static struct index_entry *find_entry_ram(const char *filename,
211 if (hdr->indices[i].tag_seek[tag_filename] == (long)dc) 212 if (hdr->indices[i].tag_seek[tag_filename] == (long)dc)
212 { 213 {
213 last_pos = MAX(0, i - 3); 214 last_pos = MAX(0, i - 3);
214 return &hdr->indices[i]; 215 return i;
215 } 216 }
216 217
217 if (++counter == 100) 218 if (++counter == 100)
@@ -227,28 +228,28 @@ static struct index_entry *find_entry_ram(const char *filename,
227 goto try_again; 228 goto try_again;
228 } 229 }
229 230
230 return NULL; 231 return -1;
231} 232}
232#endif 233#endif
233 234
234static struct index_entry *find_entry_disk(const char *filename, bool retrieve) 235static long find_entry_disk(const char *filename)
235{ 236{
236 static struct index_entry idx;
237 static long last_pos = -1; 237 static long last_pos = -1;
238 long pos_history[POS_HISTORY_COUNT]; 238 long pos_history[POS_HISTORY_COUNT];
239 long pos_history_idx = 0; 239 long pos_history_idx = 0;
240 struct tagcache_header tch;
241 bool found = false; 240 bool found = false;
242 struct tagfile_entry tfe; 241 struct tagfile_entry tfe;
243 int masterfd, fd = filenametag_fd; 242 int fd;
244 char buf[MAX_PATH]; 243 char buf[MAX_PATH];
245 int i; 244 int i;
246 int pos = -1; 245 int pos = -1;
247 246
247 fd = filenametag_fd;
248 if (fd < 0) 248 if (fd < 0)
249 { 249 {
250 last_pos = -1; 250 last_pos = -1;
251 return NULL; 251 if ( (fd = open(TAGCACHE_FILE_MASTER, O_RDONLY)) < 0)
252 return -1;
252 } 253 }
253 254
254 check_again: 255 check_again:
@@ -276,7 +277,7 @@ static struct index_entry *find_entry_disk(const char *filename, bool retrieve)
276 logf("too long tag #1"); 277 logf("too long tag #1");
277 close(fd); 278 close(fd);
278 last_pos = -1; 279 last_pos = -1;
279 return NULL; 280 return -2;
280 } 281 }
281 282
282 if (read(fd, buf, tfe.tag_length) != tfe.tag_length) 283 if (read(fd, buf, tfe.tag_length) != tfe.tag_length)
@@ -284,7 +285,7 @@ static struct index_entry *find_entry_disk(const char *filename, bool retrieve)
284 logf("read error #2"); 285 logf("read error #2");
285 close(fd); 286 close(fd);
286 last_pos = -1; 287 last_pos = -1;
287 return NULL; 288 return -3;
288 } 289 }
289 290
290 if (!strcasecmp(filename, buf)) 291 if (!strcasecmp(filename, buf))
@@ -307,90 +308,106 @@ static struct index_entry *find_entry_disk(const char *filename, bool retrieve)
307 logf("seek again"); 308 logf("seek again");
308 goto check_again; 309 goto check_again;
309 } 310 }
310 //close(fd); 311
311 return NULL; 312 if (fd != filenametag_fd)
313 close(fd);
314 return -4;
312 } 315 }
313 316
314 if (!retrieve) 317 if (fd != filenametag_fd)
315 { 318 close(fd);
316 /* Just return a valid pointer without a valid entry. */ 319
317 return &idx; 320 return tfe.idx_id;
318 } 321}
322
323bool tagcache_find_index(struct tagcache_search *tcs, const char *filename)
324{
325 long idx_id = -1;
319 326
320 /* Found. Now read the index_entry (if requested). */ 327#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
321 masterfd = open(TAGCACHE_FILE_MASTER, O_RDONLY); 328 if (stat.ramcache && dircache_is_enabled())
322 if (masterfd < 0) 329 idx_id = find_entry_ram(filename, NULL);
323 { 330#endif
324 logf("open fail");
325 return NULL;
326 }
327 331
328 if (read(fd, &tch, sizeof(struct tagcache_header)) != 332 if (idx_id < 0)
329 sizeof(struct tagcache_header) || tch.magic != TAGCACHE_MAGIC) 333 idx_id = find_entry_disk(filename);
330 {
331 logf("header error");
332 return NULL;
333 }
334 334
335 for (i = 0; i < tch.entry_count; i++) 335 if (idx_id < 0)
336 { 336 return false;
337 if (read(masterfd, &idx, sizeof(struct index_entry)) !=
338 sizeof(struct index_entry))
339 {
340 logf("read error #3");
341 close(fd);
342 return NULL;
343 }
344
345 if (idx.tag_seek[tag_filename] == pos)
346 break ;
347 }
348 close(masterfd);
349 337
350 /* Not found? */ 338 if (!tagcache_search(tcs, tag_filename))
351 if (i == tch.entry_count) 339 return false;
352 {
353 logf("not found!");
354 return NULL;
355 }
356 340
357 return &idx; 341 tcs->entry_count = 0;
342 tcs->idx_id = idx_id;
343
344 return true;
358} 345}
359 346
360static long tagcache_get_seek(const struct tagcache_search *tcs, 347static bool tagcache_get_index(const struct tagcache_search *tcs,
361 int tag, int idxid) 348 int idxid, struct index_entry *idx)
362{ 349{
363 struct index_entry idx;
364
365#ifdef HAVE_TC_RAMCACHE 350#ifdef HAVE_TC_RAMCACHE
366 if (tcs->ramsearch) 351 if (tcs->ramsearch)
367 { 352 {
368 if (hdr->indices[idxid].flag & FLAG_DELETED) 353 if (hdr->indices[idxid].flag & FLAG_DELETED)
369 return false; 354 return false;
370 355
371 return hdr->indices[idxid].tag_seek[tag]; 356 memcpy(idx, &hdr->indices[idxid], sizeof(struct index_entry));
357 return true;
372 } 358 }
373#endif 359#endif
374 360
375 lseek(tcs->masterfd, idxid * sizeof(struct index_entry) 361 lseek(tcs->masterfd, idxid * sizeof(struct index_entry)
376 + sizeof(struct tagcache_header), SEEK_SET); 362 + sizeof(struct tagcache_header), SEEK_SET);
377 if (read(tcs->masterfd, &idx, sizeof(struct index_entry)) != 363 if (read(tcs->masterfd, idx, sizeof(struct index_entry)) !=
378 sizeof(struct index_entry)) 364 sizeof(struct index_entry))
379 { 365 {
380 logf("read error #3"); 366 logf("read error #3");
381 return -4; 367 return false;
368 }
369
370 return true;
371}
372
373static long check_virtual_tags(int tag, const struct index_entry *idx)
374{
375 long data = 0;
376
377 switch (tag)
378 {
379 case tag_virt_autoscore:
380 if (idx->tag_seek[tag_length] == 0
381 || idx->tag_seek[tag_playcount] == 0)
382 {
383 data = 0;
384 }
385 else
386 {
387 data = 100 * idx->tag_seek[tag_playtime]
388 / idx->tag_seek[tag_length]
389 / idx->tag_seek[tag_playcount];
390 }
391 break;
392
393 default:
394 data = idx->tag_seek[tag];
382 } 395 }
383 396
384 return idx.tag_seek[tag]; 397 return data;
385} 398}
386 399
387long tagcache_get_numeric(const struct tagcache_search *tcs, int tag) 400long tagcache_get_numeric(const struct tagcache_search *tcs, int tag)
388{ 401{
402 struct index_entry idx;
389 403
390 if (!tagcache_is_numeric_tag(tag)) 404 if (!tagcache_is_numeric_tag(tag))
391 return -1; 405 return -1;
392 406
393 return tagcache_get_seek(tcs, tag, tcs->idx_id); 407 if (!tagcache_get_index(tcs, tcs->idx_id, &idx))
408 return -2;
409
410 return check_virtual_tags(tag, &idx);
394} 411}
395 412
396static bool check_against_clause(long numeric, const char *str, 413static bool check_against_clause(long numeric, const char *str,
@@ -459,16 +476,20 @@ static bool build_lookup_list(struct tagcache_search *tcs)
459 /* Go through all conditional clauses. */ 476 /* Go through all conditional clauses. */
460 for (j = 0; j < tcs->clause_count; j++) 477 for (j = 0; j < tcs->clause_count; j++)
461 { 478 {
462 int seek = hdr->indices[i].tag_seek[tcs->clause[j]->tag]; 479 struct index_entry *idx = &hdr->indices[i];
480 int seek;
463 char *str = NULL; 481 char *str = NULL;
464 struct tagfile_entry *entry; 482 struct tagfile_entry *entry;
465 483
484 seek = check_virtual_tags(tcs->clause[j]->tag, idx);
485
466 if (!tagcache_is_numeric_tag(tcs->clause[j]->tag)) 486 if (!tagcache_is_numeric_tag(tcs->clause[j]->tag))
467 { 487 {
468 entry = (struct tagfile_entry *)&hdr->tags[tcs->clause[j]->tag][seek]; 488 entry = (struct tagfile_entry *)&hdr->tags[tcs->clause[j]->tag][seek];
469 str = entry->tag_data; 489 str = entry->tag_data;
470 } 490 }
471 491
492
472 if (!check_against_clause(seek, str, tcs->clause[j])) 493 if (!check_against_clause(seek, str, tcs->clause[j]))
473 break ; 494 break ;
474 } 495 }
@@ -529,9 +550,11 @@ static bool build_lookup_list(struct tagcache_search *tcs)
529 for (i = 0; i < tcs->clause_count; i++) 550 for (i = 0; i < tcs->clause_count; i++)
530 { 551 {
531 struct tagfile_entry tfe; 552 struct tagfile_entry tfe;
532 int seek = entry.tag_seek[tcs->clause[i]->tag]; 553 int seek;
533 char str[256]; 554 char str[256];
534 555
556 seek = check_virtual_tags(tcs->clause[i]->tag, &entry);
557
535 memset(str, 0, sizeof str); 558 memset(str, 0, sizeof str);
536 if (!tagcache_is_numeric_tag(tcs->clause[i]->tag)) 559 if (!tagcache_is_numeric_tag(tcs->clause[i]->tag))
537 { 560 {
@@ -852,9 +875,13 @@ bool tagcache_retrieve(struct tagcache_search *tcs, int idxid,
852 char *buf, long size) 875 char *buf, long size)
853{ 876{
854 struct tagfile_entry tfe; 877 struct tagfile_entry tfe;
878 struct index_entry idx;
855 long seek; 879 long seek;
856 880
857 seek = tagcache_get_seek(tcs, tcs->type, idxid); 881 if (!tagcache_get_index(tcs, idxid, &idx))
882 return false;
883
884 seek = idx.tag_seek[tcs->type];
858 if (seek < 0) 885 if (seek < 0)
859 { 886 {
860 logf("Retrieve failed"); 887 logf("Retrieve failed");
@@ -974,12 +1001,15 @@ static long get_tag_numeric(const struct index_entry *entry, int tag)
974bool tagcache_fill_tags(struct mp3entry *id3, const char *filename) 1001bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
975{ 1002{
976 struct index_entry *entry; 1003 struct index_entry *entry;
1004 int idx_id;
977 1005
978 /* Find the corresponding entry in tagcache. */ 1006 /* Find the corresponding entry in tagcache. */
979 entry = find_entry_ram(filename, NULL); 1007 idx_id = find_entry_ram(filename, NULL);
980 if (entry == NULL || !stat.ramcache) 1008 if (idx_id < 0 || !stat.ramcache)
981 return false; 1009 return false;
982 1010
1011 entry = &hdr->indices[idx_id];
1012
983 id3->title = get_tag(entry, tag_title)->tag_data; 1013 id3->title = get_tag(entry, tag_title)->tag_data;
984 id3->artist = get_tag(entry, tag_artist)->tag_data; 1014 id3->artist = get_tag(entry, tag_artist)->tag_data;
985 id3->album = get_tag(entry, tag_album)->tag_data; 1015 id3->album = get_tag(entry, tag_album)->tag_data;
@@ -1036,13 +1066,13 @@ static void add_tagcache(const char *path)
1036#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) 1066#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
1037 if (stat.ramcache && dircache_is_enabled()) 1067 if (stat.ramcache && dircache_is_enabled())
1038 { 1068 {
1039 if (find_entry_ram(path, dc)) 1069 if (find_entry_ram(path, dc) >= 0)
1040 return ; 1070 return ;
1041 } 1071 }
1042 else 1072 else
1043#endif 1073#endif
1044 { 1074 {
1045 if (find_entry_disk(path, false)) 1075 if (find_entry_disk(path) >= 0)
1046 return ; 1076 return ;
1047 } 1077 }
1048 1078
@@ -2051,35 +2081,101 @@ static void free_tempbuf(void)
2051 tempbuf_size = 0; 2081 tempbuf_size = 0;
2052} 2082}
2053 2083
2054static bool delete_entry(long idx_id) 2084static int open_master_fd(struct tagcache_header *hdr)
2055{ 2085{
2056 int fd; 2086 int fd;
2057 int tag, i;
2058 struct index_entry idx, myidx;
2059 struct tagcache_header hdr;
2060 char buf[MAX_PATH];
2061 int in_use[TAG_COUNT];
2062 2087
2063 fd = open(TAGCACHE_FILE_MASTER, O_RDWR); 2088 fd = open(TAGCACHE_FILE_MASTER, O_RDWR);
2064 if (fd < 0) 2089 if (fd < 0)
2065 { 2090 {
2066 logf("master file open failed for R/W"); 2091 logf("master file open failed for R/W");
2067 return false; 2092 return fd;
2068 } 2093 }
2069 2094
2070 /* Check the header. */ 2095 /* Check the header. */
2071 read(fd, &hdr, sizeof(struct tagcache_header)); 2096 read(fd, hdr, sizeof(struct tagcache_header));
2072 if (hdr.magic != TAGCACHE_MAGIC) 2097 if (hdr->magic != TAGCACHE_MAGIC)
2073 { 2098 {
2074 logf("header error"); 2099 logf("header error");
2100 close(fd);
2101 return -2;
2102 }
2103
2104 return fd;
2105}
2106
2107bool tagcache_modify_numeric_entry(struct tagcache_search *tcs,
2108 int tag, long data)
2109{
2110 struct index_entry idx;
2111 struct tagcache_header myhdr;
2112
2113 if (!tagcache_is_numeric_tag(tag))
2075 return false; 2114 return false;
2115
2116#ifdef HAVE_TC_RAMCACHE
2117 /* Update ram entries first. */
2118 if (tcs->ramsearch)
2119 {
2120 hdr->indices[tcs->idx_id].tag_seek[tag] = data;
2121 hdr->indices[tcs->idx_id].flag |= FLAG_DIRTYNUM;
2076 } 2122 }
2123#endif
2124
2125 /* And now update the db on disk also. */
2126 if (tcs->masterfd < 0)
2127 {
2128 if ( (tcs->masterfd = open_master_fd(&myhdr)) < 0)
2129 return false;
2130 }
2131
2132 lseek(tcs->masterfd, tcs->idx_id * sizeof(struct index_entry)
2133 + sizeof(struct tagcache_header), SEEK_SET);
2134 if (read(tcs->masterfd, &idx, sizeof(struct index_entry))
2135 != sizeof(struct index_entry))
2136 {
2137 logf("read error");
2138 return false;
2139 }
2140
2141 idx.flag |= FLAG_DIRTYNUM;
2142 idx.tag_seek[tag] = data;
2143
2144 lseek(tcs->masterfd, -sizeof(struct index_entry), SEEK_CUR);
2145 if (write(tcs->masterfd, &idx, sizeof(struct index_entry))
2146 != sizeof(struct index_entry))
2147 {
2148 logf("write error");
2149 return false;
2150 }
2151
2152 return true;
2153}
2154
2155static bool delete_entry(long idx_id)
2156{
2157 int fd;
2158 int tag, i;
2159 struct index_entry idx, myidx;
2160 struct tagcache_header myhdr;
2161 char buf[MAX_PATH];
2162 int in_use[TAG_COUNT];
2163
2164#ifdef HAVE_TC_RAMCACHE
2165 /* At first mark the entry removed from ram cache. */
2166 if (hdr)
2167 hdr->indices[idx_id].flag |= FLAG_DELETED;
2168#endif
2169
2170 if ( (fd = open_master_fd(&myhdr) < 0) )
2171 return false;
2077 2172
2078 lseek(fd, idx_id * sizeof(struct index_entry), SEEK_CUR); 2173 lseek(fd, idx_id * sizeof(struct index_entry), SEEK_CUR);
2079 if (read(fd, &myidx, sizeof(struct index_entry)) 2174 if (read(fd, &myidx, sizeof(struct index_entry))
2080 != sizeof(struct index_entry)) 2175 != sizeof(struct index_entry))
2081 { 2176 {
2082 logf("read error"); 2177 logf("read error");
2178 close(fd);
2083 return false; 2179 return false;
2084 } 2180 }
2085 2181
@@ -2089,6 +2185,7 @@ static bool delete_entry(long idx_id)
2089 != sizeof(struct index_entry)) 2185 != sizeof(struct index_entry))
2090 { 2186 {
2091 logf("write error"); 2187 logf("write error");
2188 close(fd);
2092 return false; 2189 return false;
2093 } 2190 }
2094 2191
@@ -2097,7 +2194,7 @@ static bool delete_entry(long idx_id)
2097 in_use[tag] = 0; 2194 in_use[tag] = 0;
2098 2195
2099 lseek(fd, sizeof(struct tagcache_header), SEEK_SET); 2196 lseek(fd, sizeof(struct tagcache_header), SEEK_SET);
2100 for (i = 0; i < hdr.entry_count; i++) 2197 for (i = 0; i < myhdr.entry_count; i++)
2101 { 2198 {
2102 if (read(fd, &idx, sizeof(struct index_entry)) 2199 if (read(fd, &idx, sizeof(struct index_entry))
2103 != sizeof(struct index_entry)) 2200 != sizeof(struct index_entry))
@@ -2376,7 +2473,6 @@ static bool load_tagcache(void)
2376 { 2473 {
2377 logf("Entry no longer valid."); 2474 logf("Entry no longer valid.");
2378 logf("-> %s", buf); 2475 logf("-> %s", buf);
2379 idx->flag |= FLAG_DELETED;
2380 delete_entry(fe->idx_id); 2476 delete_entry(fe->idx_id);
2381 continue ; 2477 continue ;
2382 } 2478 }
@@ -2397,7 +2493,6 @@ static bool load_tagcache(void)
2397 { 2493 {
2398 logf("Entry no longer valid."); 2494 logf("Entry no longer valid.");
2399 logf("-> %s", buf); 2495 logf("-> %s", buf);
2400 idx->flag |= FLAG_DELETED;
2401 delete_entry(fe->idx_id); 2496 delete_entry(fe->idx_id);
2402 continue; 2497 continue;
2403 } 2498 }
@@ -2808,6 +2903,7 @@ void tagcache_init(void)
2808{ 2903{
2809 stat.initialized = false; 2904 stat.initialized = false;
2810 stat.commit_step = 0; 2905 stat.commit_step = 0;
2906 filenametag_fd = -1;
2811 2907
2812 queue_init(&tagcache_queue); 2908 queue_init(&tagcache_queue);
2813 create_thread(tagcache_thread, tagcache_stack, 2909 create_thread(tagcache_thread, tagcache_stack,