diff --git a/apps/tagcache.c b/apps/tagcache.c index 191c245597..195de2f467 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -631,6 +631,30 @@ static bool check_against_clause(long numeric, const char *str, return false; } +static bool add_uniqbuf(struct tagcache_search *tcs, long id) +{ + int i; + + /* If uniq buffer is not defined we must return true for search to work. */ + if (tcs->unique_list == NULL) + return true; + + for (i = 0; i < tcs->unique_list_count; i++) + { + /* Return false if entry is found. */ + if (tcs->unique_list[i] == id) + return false; + } + + if (tcs->unique_list_count < tcs->unique_list_capacity) + { + tcs->unique_list[i] = id; + tcs->unique_list_count++; + } + + return true; +} + static bool build_lookup_list(struct tagcache_search *tcs) { struct index_entry entry; @@ -699,22 +723,16 @@ static bool build_lookup_list(struct tagcache_search *tcs) if (j < tcs->clause_count) continue ; - /* Add to the seek list if not already there. */ - for (j = 0; j < tcs->seek_list_count; j++) - { - if (tcs->seek_list[j] == hdr->indices[i].tag_seek[tcs->type]) - break ; - } - + /* Add to the seek list if not already in uniq buffer. */ + if (!add_uniqbuf(tcs, hdr->indices[i].tag_seek[tcs->type])) + continue; + /* Lets add it. */ - if (j == tcs->seek_list_count) - { - tcs->seek_list[tcs->seek_list_count] = - hdr->indices[i].tag_seek[tcs->type]; - tcs->seek_flags[tcs->seek_list_count] = - hdr->indices[i].flag; - tcs->seek_list_count++; - } + tcs->seek_list[tcs->seek_list_count] = + hdr->indices[i].tag_seek[tcs->type]; + tcs->seek_flags[tcs->seek_list_count] = + hdr->indices[i].flag; + tcs->seek_list_count++; } tcs->seek_pos = i; @@ -783,22 +801,14 @@ static bool build_lookup_list(struct tagcache_search *tcs) if (i < tcs->clause_count) continue ; - /* Add to the seek list if not already there. */ - for (i = 0; i < tcs->seek_list_count; i++) - { - if (tcs->seek_list[i] == entry.tag_seek[tcs->type]) - break ; - } - + /* Add to the seek list if not already in uniq buffer. */ + if (!add_uniqbuf(tcs, entry.tag_seek[tcs->type])) + continue; + /* Lets add it. */ - if (i == tcs->seek_list_count) - { - tcs->seek_list[tcs->seek_list_count] = - entry.tag_seek[tcs->type]; - tcs->seek_flags[tcs->seek_list_count] = entry.flag; - tcs->seek_list_count++; - } - + tcs->seek_list[tcs->seek_list_count] = entry.tag_seek[tcs->type]; + tcs->seek_flags[tcs->seek_list_count] = entry.flag; + tcs->seek_list_count++; } return tcs->seek_list_count > 0; @@ -913,6 +923,14 @@ bool tagcache_search(struct tagcache_search *tcs, int tag) return true; } +void tagcache_search_set_uniqbuf(struct tagcache_search *tcs, + void *buffer, long length) +{ + tcs->unique_list = (unsigned long *)buffer; + tcs->unique_list_capacity = length / sizeof(*tcs->unique_list); + tcs->unique_list_count = 0; +} + bool tagcache_search_add_filter(struct tagcache_search *tcs, int tag, int seek) { @@ -932,12 +950,23 @@ bool tagcache_search_add_filter(struct tagcache_search *tcs, bool tagcache_search_add_clause(struct tagcache_search *tcs, struct tagcache_search_clause *clause) { + int i; + if (tcs->clause_count >= TAGCACHE_MAX_CLAUSES) { logf("Too many clauses"); return false; } + /* Check if there is already a similar filter in present (filters are + * much faster than clauses). + */ + for (i = 0; i < tcs->filter_count; i++) + { + if (tcs->filter_tag[i] == clause->tag) + return true; + } + if (!tagcache_is_numeric_tag(clause->tag) && tcs->idxfd[clause->tag] < 0) { char buf[MAX_PATH]; diff --git a/apps/tagcache.h b/apps/tagcache.h index e43414cba5..d9e1c93cab 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -51,13 +51,13 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, #define TAGFILE_ENTRY_AVG_LENGTH 16 /* How many entries to fetch to the seek table at once while searching. */ -#define SEEK_LIST_SIZE 50 +#define SEEK_LIST_SIZE 32 /* Always strict align entries for best performance and binary compatability. */ #define TAGCACHE_STRICT_ALIGN 1 -#define TAGCACHE_MAX_FILTERS 3 -#define TAGCACHE_MAX_CLAUSES 10 +#define TAGCACHE_MAX_FILTERS 4 +#define TAGCACHE_MAX_CLAUSES 16 /* Tag database files. */ #define TAGCACHE_FILE_TEMP ROCKBOX_DIR "/tagcache_tmp.tcd" @@ -116,6 +116,9 @@ struct tagcache_search { int entry_count; bool valid; bool initialized; + long *unique_list; + int unique_list_capacity; + int unique_list_count; /* Exported variables. */ bool ramsearch; @@ -133,6 +136,8 @@ bool tagcache_is_unique_tag(int type); bool tagcache_is_sorted_tag(int type); bool tagcache_find_index(struct tagcache_search *tcs, const char *filename); bool tagcache_search(struct tagcache_search *tcs, int tag); +void tagcache_search_set_uniqbuf(struct tagcache_search *tcs, + void *buffer, long length); bool tagcache_search_add_filter(struct tagcache_search *tcs, int tag, int seek); bool tagcache_search_add_clause(struct tagcache_search *tcs, diff --git a/apps/tagtree.c b/apps/tagtree.c index eaee9b9fd1..70c8a3e6e7 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -48,6 +48,11 @@ static int tagtree_play_folder(struct tree_context* c); static char searchstring[32]; + +/* Capacity 10 000 entries (for example 10k different artists) */ +#define UNIQBUF_SIZE (64*1024) +static long *uniqbuf; + #define MAX_TAGS 5 /* @@ -500,6 +505,7 @@ void tagtree_init(void) } close(fd); + uniqbuf = buffer_alloc(UNIQBUF_SIZE); audio_set_track_buffer_event(tagtree_buffer_event); audio_set_track_unbuffer_event(tagtree_unbuffer_event); } @@ -566,16 +572,21 @@ int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs, if (!tagcache_search(tcs, tag)) return -1; - for (i = 0; i < extra; i++) - { - tagcache_search_add_filter(tcs, csi->tagorder[i], csi->result_seek[i]); - sort = true; - } + /* Prevent duplicate entries in the search list. */ + tagcache_search_set_uniqbuf(tcs, uniqbuf, UNIQBUF_SIZE); - for (i = 0; i < csi->clause_count[extra]; i++) - { - tagcache_search_add_clause(tcs, &csi->clause[extra][i]); + if (extra || csi->clause_count[0]) sort = true; + + for (i = 0; i < extra; i++) + tagcache_search_add_filter(tcs, csi->tagorder[i], csi->result_seek[i]); + + for (i = 0; i <= extra; i++) + { + int j; + + for (j = 0; j < csi->clause_count[i]; j++) + tagcache_search_add_clause(tcs, &csi->clause[i][j]); } current_offset = offset;