1
0
Fork 0
forked from len0rd/rockbox

A bunch of stability fixes into tagcache engine and database browser. Mainly data retrieval problems, races, data corruption of sorted index files at the end with junk data, access to unitialized memory and so on. Should fix FS#8710 and may fix FS#8414.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21402 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Miika Pekkarinen 2009-06-20 16:17:54 +00:00
parent d79d239382
commit 8e2bdcaab6
3 changed files with 192 additions and 123 deletions

View file

@ -410,7 +410,7 @@ static long find_entry_ram(const char *filename,
} }
#endif #endif
static long find_entry_disk(const char *filename) static long find_entry_disk(const char *filename, bool localfd)
{ {
struct tagcache_header tch; struct tagcache_header tch;
static long last_pos = -1; static long last_pos = -1;
@ -427,7 +427,7 @@ static long find_entry_disk(const char *filename)
return -2; return -2;
fd = filenametag_fd; fd = filenametag_fd;
if (fd < 0) if (fd < 0 || localfd)
{ {
last_pos = -1; last_pos = -1;
if ( (fd = open_tag_fd(&tch, tag_filename, false)) < 0) if ( (fd = open_tag_fd(&tch, tag_filename, false)) < 0)
@ -458,6 +458,8 @@ static long find_entry_disk(const char *filename)
{ {
logf("too long tag #1"); logf("too long tag #1");
close(fd); close(fd);
if (!localfd)
filenametag_fd = -1;
last_pos = -1; last_pos = -1;
return -2; return -2;
} }
@ -466,6 +468,8 @@ static long find_entry_disk(const char *filename)
{ {
logf("read error #2"); logf("read error #2");
close(fd); close(fd);
if (!localfd)
filenametag_fd = -1;
last_pos = -1; last_pos = -1;
return -3; return -3;
} }
@ -491,12 +495,12 @@ static long find_entry_disk(const char *filename)
goto check_again; goto check_again;
} }
if (fd != filenametag_fd) if (fd != filenametag_fd || localfd)
close(fd); close(fd);
return -4; return -4;
} }
if (fd != filenametag_fd) if (fd != filenametag_fd || localfd)
close(fd); close(fd);
return tfe.idx_id; return tfe.idx_id;
@ -512,7 +516,7 @@ static int find_index(const char *filename)
#endif #endif
if (idx_id < 0) if (idx_id < 0)
idx_id = find_entry_disk(filename); idx_id = find_entry_disk(filename, true);
return idx_id; return idx_id;
} }
@ -554,9 +558,15 @@ static bool get_index(int masterfd, int idxid,
if (hdr->indices[idxid].flag & FLAG_DELETED) if (hdr->indices[idxid].flag & FLAG_DELETED)
return false; return false;
# ifdef HAVE_DIRCACHE
if (!(hdr->indices[idxid].flag & FLAG_DIRCACHE)
|| is_dircache_intact())
#endif
{
memcpy(idx, &hdr->indices[idxid], sizeof(struct index_entry)); memcpy(idx, &hdr->indices[idxid], sizeof(struct index_entry));
return true; return true;
} }
}
#else #else
(void)use_ram; (void)use_ram;
#endif #endif
@ -1006,17 +1016,20 @@ static bool add_uniqbuf(struct tagcache_search *tcs, unsigned long id)
static bool build_lookup_list(struct tagcache_search *tcs) static bool build_lookup_list(struct tagcache_search *tcs)
{ {
struct index_entry entry; struct index_entry entry;
int i; int i, j;
tcs->seek_list_count = 0; tcs->seek_list_count = 0;
#ifdef HAVE_TC_RAMCACHE #ifdef HAVE_TC_RAMCACHE
if (tcs->ramsearch) if (tcs->ramsearch
# ifdef HAVE_DIRCACHE
&& (tcs->type != tag_filename || is_dircache_intact())
# endif
)
{ {
int j;
for (i = tcs->seek_pos; i < hdr->h.tch.entry_count; i++) for (i = tcs->seek_pos; i < hdr->h.tch.entry_count; i++)
{ {
struct tagcache_seeklist_entry *seeklist;
struct index_entry *idx = &hdr->indices[i]; struct index_entry *idx = &hdr->indices[i];
if (tcs->seek_list_count == SEEK_LIST_SIZE) if (tcs->seek_list_count == SEEK_LIST_SIZE)
break ; break ;
@ -1046,8 +1059,10 @@ static bool build_lookup_list(struct tagcache_search *tcs)
continue; continue;
/* Lets add it. */ /* Lets add it. */
tcs->seek_list[tcs->seek_list_count] = idx->tag_seek[tcs->type]; seeklist = &tcs->seeklist[tcs->seek_list_count];
tcs->seek_flags[tcs->seek_list_count] = idx->flag; seeklist->seek = idx->tag_seek[tcs->type];
seeklist->flag = idx->flag;
seeklist->idx_id = i;
tcs->seek_list_count++; tcs->seek_list_count++;
} }
@ -1057,15 +1072,24 @@ static bool build_lookup_list(struct tagcache_search *tcs)
} }
#endif #endif
if (tcs->masterfd < 0)
{
struct master_header tcmh;
tcs->masterfd = open_master_fd(&tcmh, false);
}
lseek(tcs->masterfd, tcs->seek_pos * sizeof(struct index_entry) + lseek(tcs->masterfd, tcs->seek_pos * sizeof(struct index_entry) +
sizeof(struct master_header), SEEK_SET); sizeof(struct master_header), SEEK_SET);
while (ecread(tcs->masterfd, &entry, 1, index_entry_ec, tc_stat.econ) while (ecread(tcs->masterfd, &entry, 1, index_entry_ec, tc_stat.econ)
== sizeof(struct index_entry)) == sizeof(struct index_entry))
{ {
struct tagcache_seeklist_entry *seeklist;
if (tcs->seek_list_count == SEEK_LIST_SIZE) if (tcs->seek_list_count == SEEK_LIST_SIZE)
break ; break ;
i = tcs->seek_pos;
tcs->seek_pos++; tcs->seek_pos++;
/* Check if entry has been deleted. */ /* Check if entry has been deleted. */
@ -1073,13 +1097,13 @@ static bool build_lookup_list(struct tagcache_search *tcs)
continue; continue;
/* Go through all filters.. */ /* Go through all filters.. */
for (i = 0; i < tcs->filter_count; i++) for (j = 0; j < tcs->filter_count; j++)
{ {
if (entry.tag_seek[tcs->filter_tag[i]] != tcs->filter_seek[i]) if (entry.tag_seek[tcs->filter_tag[j]] != tcs->filter_seek[j])
break ; break ;
} }
if (i < tcs->filter_count) if (j < tcs->filter_count)
continue ; continue ;
/* Check for conditions. */ /* Check for conditions. */
@ -1091,8 +1115,10 @@ static bool build_lookup_list(struct tagcache_search *tcs)
continue; continue;
/* Lets add it. */ /* Lets add it. */
tcs->seek_list[tcs->seek_list_count] = entry.tag_seek[tcs->type]; seeklist = &tcs->seeklist[tcs->seek_list_count];
tcs->seek_flags[tcs->seek_list_count] = entry.flag; seeklist->seek = entry.tag_seek[tcs->type];
seeklist->flag = entry.flag;
seeklist->idx_id = i;
tcs->seek_list_count++; tcs->seek_list_count++;
yield(); yield();
@ -1155,15 +1181,17 @@ static bool check_all_headers(void)
return true; return true;
} }
bool tagcache_is_busy(void)
{
return read_lock || write_lock;
}
bool tagcache_search(struct tagcache_search *tcs, int tag) bool tagcache_search(struct tagcache_search *tcs, int tag)
{ {
struct tagcache_header tag_hdr; struct tagcache_header tag_hdr;
struct master_header master_hdr; struct master_header master_hdr;
int i; int i;
if (tcs->initialized)
tagcache_search_finish(tcs);
while (read_lock) while (read_lock)
sleep(1); sleep(1);
@ -1174,6 +1202,7 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
tcs->position = sizeof(struct tagcache_header); tcs->position = sizeof(struct tagcache_header);
tcs->type = tag; tcs->type = tag;
tcs->seek_pos = 0; tcs->seek_pos = 0;
tcs->list_position = 0;
tcs->seek_list_count = 0; tcs->seek_list_count = 0;
tcs->filter_count = 0; tcs->filter_count = 0;
tcs->masterfd = -1; tcs->masterfd = -1;
@ -1192,19 +1221,24 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
else else
#endif #endif
{ {
/* Always open as R/W so we can pass tcs to functions that modify data also
* without failing. */
tcs->masterfd = open_master_fd(&master_hdr, true);
if (tcs->masterfd < 0)
return false;
if (!TAGCACHE_IS_NUMERIC(tcs->type)) if (!TAGCACHE_IS_NUMERIC(tcs->type))
{ {
tcs->idxfd[tcs->type] = open_tag_fd(&tag_hdr, tcs->type, false); tcs->idxfd[tcs->type] = open_tag_fd(&tag_hdr, tcs->type, false);
if (tcs->idxfd[tcs->type] < 0) if (tcs->idxfd[tcs->type] < 0)
return false; return false;
tcs->entry_count = tag_hdr.entry_count;
}
else
{
tcs->entry_count = master_hdr.tch.entry_count;
} }
/* Always open as R/W so we can pass tcs to functions that modify data also
* without failing. */
tcs->masterfd = open_master_fd(&master_hdr, true);
if (tcs->masterfd < 0)
return false;
} }
tcs->valid = true; tcs->valid = true;
@ -1272,14 +1306,6 @@ bool tagcache_search_add_clause(struct tagcache_search *tcs,
return true; return true;
} }
/* TODO: Remove this mess. */
#ifdef HAVE_DIRCACHE
#define TAG_FILENAME_RAM(tcs) ((tcs->type == tag_filename) \
? ((flag & FLAG_DIRCACHE) && is_dircache_intact()) : 1)
#else
#define TAG_FILENAME_RAM(tcs) (tcs->type != tag_filename)
#endif
static bool get_next(struct tagcache_search *tcs) static bool get_next(struct tagcache_search *tcs)
{ {
static char buf[TAG_MAXLEN+32]; static char buf[TAG_MAXLEN+32];
@ -1298,11 +1324,20 @@ static bool get_next(struct tagcache_search *tcs)
/* Relative fetch. */ /* Relative fetch. */
if (tcs->filter_count > 0 || tcs->clause_count > 0 if (tcs->filter_count > 0 || tcs->clause_count > 0
|| TAGCACHE_IS_NUMERIC(tcs->type)) || TAGCACHE_IS_NUMERIC(tcs->type)
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
/* We need to retrieve flag status for dircache. */
|| (tcs->ramsearch && tcs->type == tag_filename)
#endif
)
{ {
struct tagcache_seeklist_entry *seeklist;
/* Check for end of list. */ /* Check for end of list. */
if (tcs->seek_list_count == 0) if (tcs->list_position == tcs->seek_list_count)
{ {
tcs->list_position = 0;
/* Try to fetch more. */ /* Try to fetch more. */
if (!build_lookup_list(tcs)) if (!build_lookup_list(tcs))
{ {
@ -1311,15 +1346,28 @@ static bool get_next(struct tagcache_search *tcs)
} }
} }
tcs->seek_list_count--; seeklist = &tcs->seeklist[tcs->list_position];
flag = tcs->seek_flags[tcs->seek_list_count]; flag = seeklist->flag;
tcs->position = tcs->seek_list[tcs->seek_list_count]; tcs->position = seeklist->seek;
tcs->idx_id = seeklist->idx_id;
tcs->list_position++;
} }
else
{
if (tcs->entry_count == 0)
{
tcs->valid = false;
return false;
}
tcs->entry_count--;
}
tcs->result_seek = tcs->position;
if (TAGCACHE_IS_NUMERIC(tcs->type)) if (TAGCACHE_IS_NUMERIC(tcs->type))
{ {
snprintf(buf, sizeof(buf), "%d", tcs->position); snprintf(buf, sizeof(buf), "%d", tcs->position);
tcs->result_seek = tcs->position;
tcs->result = buf; tcs->result = buf;
tcs->result_len = strlen(buf) + 1; tcs->result_len = strlen(buf) + 1;
return true; return true;
@ -1327,55 +1375,54 @@ static bool get_next(struct tagcache_search *tcs)
/* Direct fetch. */ /* Direct fetch. */
#ifdef HAVE_TC_RAMCACHE #ifdef HAVE_TC_RAMCACHE
if (tcs->ramsearch && TAG_FILENAME_RAM(tcs)) if (tcs->ramsearch)
{ {
struct tagfile_entry *ep;
if (tcs->entry_count == 0) #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
{ if (tcs->type == tag_filename && (flag & FLAG_DIRCACHE)
tcs->valid = false; && is_dircache_intact())
return false;
}
tcs->entry_count--;
tcs->result_seek = tcs->position;
# ifdef HAVE_DIRCACHE
if (tcs->type == tag_filename)
{ {
dircache_copy_path((struct dirent *)tcs->position, dircache_copy_path((struct dirent *)tcs->position,
buf, sizeof buf); buf, sizeof buf);
tcs->result = buf; tcs->result = buf;
tcs->result_len = strlen(buf) + 1; tcs->result_len = strlen(buf) + 1;
tcs->idx_id = FLAG_GET_ATTR(flag);
tcs->ramresult = false; tcs->ramresult = false;
return true; return true;
} }
else
#endif #endif
if (tcs->type != tag_filename)
{
struct tagfile_entry *ep;
ep = (struct tagfile_entry *)&hdr->tags[tcs->type][tcs->position]; ep = (struct tagfile_entry *)&hdr->tags[tcs->type][tcs->position];
tcs->position += sizeof(struct tagfile_entry) + ep->tag_length;
tcs->result = ep->tag_data; tcs->result = ep->tag_data;
tcs->result_len = strlen(tcs->result) + 1; tcs->result_len = strlen(tcs->result) + 1;
tcs->idx_id = ep->idx_id; tcs->idx_id = ep->idx_id;
tcs->ramresult = true; tcs->ramresult = true;
/* Increase position for the next run. This may get overwritten. */
tcs->position += sizeof(struct tagfile_entry) + ep->tag_length;
return true; return true;
} }
}
#endif #endif
if (!open_files(tcs, tcs->type)) if (!open_files(tcs, tcs->type))
{
tcs->valid = false;
return false; return false;
}
/* Seek stream to the correct position and continue to direct fetch. */ /* Seek stream to the correct position and continue to direct fetch. */
lseek(tcs->idxfd[tcs->type], tcs->position, SEEK_SET); lseek(tcs->idxfd[tcs->type], tcs->position, SEEK_SET);
tcs->result_seek = tcs->position;
if (ecread(tcs->idxfd[tcs->type], &entry, 1, if (ecread(tcs->idxfd[tcs->type], &entry, 1,
tagfile_entry_ec, tc_stat.econ) != sizeof(struct tagfile_entry)) tagfile_entry_ec, tc_stat.econ) != sizeof(struct tagfile_entry))
{ {
/* End of data. */ logf("read error #5");
tcs->valid = false; tcs->valid = false;
return false; return false;
} }
@ -1384,6 +1431,7 @@ static bool get_next(struct tagcache_search *tcs)
{ {
tcs->valid = false; tcs->valid = false;
logf("too long tag #2"); logf("too long tag #2");
logf("P:%X/%X", tcs->position, entry.tag_length);
return false; return false;
} }
@ -1536,12 +1584,12 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
struct index_entry *entry; struct index_entry *entry;
int idx_id; int idx_id;
if (!tc_stat.ready) if (!tc_stat.ready || !tc_stat.ramcache)
return false; return false;
/* Find the corresponding entry in tagcache. */ /* Find the corresponding entry in tagcache. */
idx_id = find_entry_ram(filename, NULL); idx_id = find_entry_ram(filename, NULL);
if (idx_id < 0 || !tc_stat.ramcache) if (idx_id < 0)
return false; return false;
entry = &hdr->indices[idx_id]; entry = &hdr->indices[idx_id];
@ -1644,14 +1692,11 @@ static void add_tagcache(char *path, unsigned long mtime
{ {
idx_id = find_entry_ram(path, dc); idx_id = find_entry_ram(path, dc);
} }
else
#endif #endif
{
if (filenametag_fd >= 0) /* Be sure the entry doesn't exist. */
{ if (filenametag_fd >= 0 && idx_id < 0)
idx_id = find_entry_disk(path); idx_id = find_entry_disk(path, false);
}
}
/* Check if file has been modified. */ /* Check if file has been modified. */
if (idx_id >= 0) if (idx_id >= 0)
@ -2548,6 +2593,13 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
/* Sort the buffer data and write it to the index file. */ /* Sort the buffer data and write it to the index file. */
lseek(fd, sizeof(struct tagcache_header), SEEK_SET); lseek(fd, sizeof(struct tagcache_header), SEEK_SET);
/**
* We need to truncate the index file now. There can be junk left
* at the end of file (however, we _should_ always follow the
* entry_count and don't crash with that).
*/
ftruncate(fd, lseek(fd, 0, SEEK_CUR));
i = tempbuf_sort(fd); i = tempbuf_sort(fd);
if (i < 0) if (i < 0)
goto error_exit; goto error_exit;
@ -3328,7 +3380,10 @@ bool tagcache_import_changelog(void)
close(masterfd); close(masterfd);
if (filenametag_fd >= 0) if (filenametag_fd >= 0)
{
close(filenametag_fd); close(filenametag_fd);
filenametag_fd = -1;
}
write_lock--; write_lock--;
@ -3919,7 +3974,6 @@ static bool load_tagcache(void)
} }
idx->flag |= FLAG_DIRCACHE; idx->flag |= FLAG_DIRCACHE;
FLAG_SET_ATTR(idx->flag, fe->idx_id);
idx->tag_seek[tag_filename] = (long)dc; idx->tag_seek[tag_filename] = (long)dc;
} }
else else

View file

@ -112,8 +112,6 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
#define FLAG_DIRTYNUM 0x0004 /* Numeric data has been modified */ #define FLAG_DIRTYNUM 0x0004 /* Numeric data has been modified */
#define FLAG_TRKNUMGEN 0x0008 /* Track number has been generated */ #define FLAG_TRKNUMGEN 0x0008 /* Track number has been generated */
#define FLAG_RESURRECTED 0x0010 /* Statistics data has been resurrected */ #define FLAG_RESURRECTED 0x0010 /* Statistics data has been resurrected */
#define FLAG_GET_ATTR(flag) ((flag >> 16) & 0x0000ffff)
#define FLAG_SET_ATTR(flag,attr) flag = (flag & 0x0000ffff) | (attr << 16)
enum clause { clause_none, clause_is, clause_is_not, clause_gt, clause_gteq, enum clause { clause_none, clause_is, clause_is_not, clause_gt, clause_gteq,
clause_lt, clause_lteq, clause_contains, clause_not_contains, clause_lt, clause_lteq, clause_contains, clause_not_contains,
@ -156,20 +154,26 @@ struct tagcache_search_clause
char *str; char *str;
}; };
struct tagcache_seeklist_entry {
int32_t seek;
int32_t flag;
int32_t idx_id;
};
struct tagcache_search { struct tagcache_search {
/* For internal use only. */ /* For internal use only. */
int fd, masterfd; int fd, masterfd;
int idxfd[TAG_COUNT]; int idxfd[TAG_COUNT];
long seek_list[SEEK_LIST_SIZE]; struct tagcache_seeklist_entry seeklist[SEEK_LIST_SIZE];
long seek_flags[SEEK_LIST_SIZE]; int seek_list_count;
long filter_tag[TAGCACHE_MAX_FILTERS]; int32_t filter_tag[TAGCACHE_MAX_FILTERS];
long filter_seek[TAGCACHE_MAX_FILTERS]; int32_t filter_seek[TAGCACHE_MAX_FILTERS];
int filter_count; int filter_count;
struct tagcache_search_clause *clause[TAGCACHE_MAX_CLAUSES]; struct tagcache_search_clause *clause[TAGCACHE_MAX_CLAUSES];
int clause_count; int clause_count;
int seek_list_count; int list_position;
int seek_pos; int seek_pos;
long position; int32_t position;
int entry_count; int entry_count;
bool valid; bool valid;
bool initialized; bool initialized;
@ -178,13 +182,13 @@ struct tagcache_search {
int unique_list_count; int unique_list_count;
/* Exported variables. */ /* Exported variables. */
bool ramsearch; bool ramsearch; /* Is ram copy of the tagcache being used. */
bool ramresult; bool ramresult; /* False if result is not static, and must be copied. */
int type; int type;
char *result; char *result; /* The result data for all tags. */
int result_len; int result_len; /* Length of the result including \0 */
long result_seek; int32_t result_seek; /* Current position in the tag data. */
int idx_id; int32_t idx_id; /* Entry number in the master index. */
}; };
void tagcache_build(const char *path); void tagcache_build(const char *path);
@ -201,6 +205,7 @@ bool tagcache_is_numeric_tag(int type);
bool tagcache_find_index(struct tagcache_search *tcs, const char *filename); bool tagcache_find_index(struct tagcache_search *tcs, const char *filename);
bool tagcache_check_clauses(struct tagcache_search *tcs, bool tagcache_check_clauses(struct tagcache_search *tcs,
struct tagcache_search_clause **clause, int count); struct tagcache_search_clause **clause, int count);
bool tagcache_is_busy(void);
bool tagcache_search(struct tagcache_search *tcs, int tag); bool tagcache_search(struct tagcache_search *tcs, int tag);
void tagcache_search_set_uniqbuf(struct tagcache_search *tcs, void tagcache_search_set_uniqbuf(struct tagcache_search *tcs,
void *buffer, long length); void *buffer, long length);

View file

@ -23,6 +23,9 @@
* Basic structure on this file was copied from dbtree.c and modified to * Basic structure on this file was copied from dbtree.c and modified to
* support the tag cache interface. * support the tag cache interface.
*/ */
/* #define LOGF_ENABLE */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -96,7 +99,6 @@ static long *uniqbuf;
#define MAX_TAGS 5 #define MAX_TAGS 5
#define MAX_MENU_ID_SIZE 32 #define MAX_MENU_ID_SIZE 32
static struct tagcache_search tcs, tcs2;
static bool sort_inverse; static bool sort_inverse;
/* /*
@ -642,6 +644,8 @@ static int compare(const void *p1, const void *p2)
static void tagtree_buffer_event(struct mp3entry *id3) static void tagtree_buffer_event(struct mp3entry *id3)
{ {
struct tagcache_search tcs;
/* Do not gather data unless proper setting has been enabled. */ /* Do not gather data unless proper setting has been enabled. */
if (!global_settings.runtimedb) if (!global_settings.runtimedb)
return; return;
@ -719,6 +723,8 @@ static void tagtree_track_finish_event(struct mp3entry *id3)
bool tagtree_export(void) bool tagtree_export(void)
{ {
struct tagcache_search tcs;
splash(0, str(LANG_CREATING)); splash(0, str(LANG_CREATING));
if (!tagcache_create_changelog(&tcs)) if (!tagcache_create_changelog(&tcs))
{ {
@ -1040,9 +1046,9 @@ static int format_str(struct tagcache_search *tcs, struct display_format *fmt,
return 0; return 0;
} }
static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs, static int retrieve_entries(struct tree_context *c, int offset, bool init)
int offset, bool init)
{ {
struct tagcache_search tcs;
struct tagentry *dptr = (struct tagentry *)c->dircache; struct tagentry *dptr = (struct tagentry *)c->dircache;
struct display_format *fmt; struct display_format *fmt;
int i; int i;
@ -1055,15 +1061,16 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
int sort_limit; int sort_limit;
int strip; int strip;
if (init if (init && (tagcache_is_busy()
#ifdef HAVE_TC_RAMCACHE #ifdef HAVE_TC_RAMCACHE
&& !tagcache_is_ramcache() || !tagcache_is_ramcache()
#endif #endif
) ) )
{ {
/* Show search progress straight away if the disk needs to spin up, /* Show search progress straight away if the disk needs to spin up,
otherwise show it after the normal 1/2 second delay */ otherwise show it after the normal 1/2 second delay */
show_search_progress( show_search_progress(
!tagcache_is_busy() &&
#ifdef HAVE_DISK_STORAGE #ifdef HAVE_DISK_STORAGE
storage_disk_is_active() storage_disk_is_active()
#else #else
@ -1080,11 +1087,11 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
else else
tag = csi->tagorder[level]; tag = csi->tagorder[level];
if (!tagcache_search(tcs, tag)) if (!tagcache_search(&tcs, tag))
return -1; return -1;
/* Prevent duplicate entries in the search list. */ /* Prevent duplicate entries in the search list. */
tagcache_search_set_uniqbuf(tcs, uniqbuf, UNIQBUF_SIZE); tagcache_search_set_uniqbuf(&tcs, uniqbuf, UNIQBUF_SIZE);
if (level || csi->clause_count[0] || TAGCACHE_IS_NUMERIC(tag)) if (level || csi->clause_count[0] || TAGCACHE_IS_NUMERIC(tag))
sort = true; sort = true;
@ -1100,11 +1107,11 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
cc.type = clause_is; cc.type = clause_is;
cc.numeric = true; cc.numeric = true;
cc.numeric_data = csi->result_seek[i]; cc.numeric_data = csi->result_seek[i];
tagcache_search_add_clause(tcs, &cc); tagcache_search_add_clause(&tcs, &cc);
} }
else else
{ {
tagcache_search_add_filter(tcs, csi->tagorder[i], tagcache_search_add_filter(&tcs, csi->tagorder[i],
csi->result_seek[i]); csi->result_seek[i]);
} }
} }
@ -1114,7 +1121,7 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
int j; int j;
for (j = 0; j < csi->clause_count[i]; j++) for (j = 0; j < csi->clause_count[i]; j++)
tagcache_search_add_clause(tcs, csi->clause[i][j]); tagcache_search_add_clause(&tcs, csi->clause[i][j]);
} }
current_offset = offset; current_offset = offset;
@ -1164,7 +1171,7 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
total_count += special_entry_count; total_count += special_entry_count;
while (tagcache_get_next(tcs)) while (tagcache_get_next(&tcs))
{ {
if (total_count++ < offset) if (total_count++ < offset)
continue; continue;
@ -1173,10 +1180,10 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
if (tag == tag_title || tag == tag_filename) if (tag == tag_title || tag == tag_filename)
{ {
dptr->newtable = PLAYTRACK; dptr->newtable = PLAYTRACK;
dptr->extraseek = tcs->idx_id; dptr->extraseek = tcs.idx_id;
} }
else else
dptr->extraseek = tcs->result_seek; dptr->extraseek = tcs.result_seek;
fmt = NULL; fmt = NULL;
/* Check the format */ /* Check the format */
@ -1185,7 +1192,7 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
if (formats[i]->group_id != csi->format_id[level]) if (formats[i]->group_id != csi->format_id[level])
continue; continue;
if (tagcache_check_clauses(tcs, formats[i]->clause, if (tagcache_check_clauses(&tcs, formats[i]->clause,
formats[i]->clause_count)) formats[i]->clause_count))
{ {
fmt = formats[i]; fmt = formats[i];
@ -1193,15 +1200,16 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
} }
} }
if (!tcs->ramresult || fmt) if (!tcs.ramresult || fmt)
{ {
char buf[MAX_PATH]; char buf[MAX_PATH];
if (fmt) if (fmt)
{ {
if (format_str(tcs, fmt, buf, sizeof buf) < 0) if (format_str(&tcs, fmt, buf, sizeof buf) < 0)
{ {
logf("format_str() failed"); logf("format_str() failed");
tagcache_search_finish(&tcs);
return 0; return 0;
} }
} }
@ -1210,7 +1218,7 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
if (fmt) if (fmt)
namebufused += strlen(buf)+1; namebufused += strlen(buf)+1;
else else
namebufused += tcs->result_len; namebufused += tcs.result_len;
if (namebufused >= c->name_buffer_size) if (namebufused >= c->name_buffer_size)
{ {
@ -1222,10 +1230,10 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
if (fmt) if (fmt)
strcpy(dptr->name, buf); strcpy(dptr->name, buf);
else else
strcpy(dptr->name, tcs->result); strcpy(dptr->name, tcs.result);
} }
else else
dptr->name = tcs->result; dptr->name = tcs.result;
dptr++; dptr++;
current_entry_count++; current_entry_count++;
@ -1238,11 +1246,11 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
break ; break ;
} }
if (init && !tcs->ramsearch) if (init && !tcs.ramsearch)
{ {
if (!show_search_progress(false, total_count)) if (!show_search_progress(false, total_count))
{ {
tagcache_search_finish(tcs); tagcache_search_finish(&tcs);
return current_entry_count; return current_entry_count;
} }
} }
@ -1255,13 +1263,13 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
if (!init) if (!init)
{ {
tagcache_search_finish(tcs); tagcache_search_finish(&tcs);
return current_entry_count; return current_entry_count;
} }
while (tagcache_get_next(tcs)) while (tagcache_get_next(&tcs))
{ {
if (!tcs->ramsearch) if (!tcs.ramsearch)
{ {
if (!show_search_progress(false, total_count)) if (!show_search_progress(false, total_count))
break; break;
@ -1269,7 +1277,7 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
total_count++; total_count++;
} }
tagcache_search_finish(tcs); tagcache_search_finish(&tcs);
if (!sort && (sort_inverse || sort_limit)) if (!sort && (sort_inverse || sort_limit))
{ {
@ -1363,7 +1371,7 @@ int tagtree_load(struct tree_context* c)
case NAVIBROWSE: case NAVIBROWSE:
logf("navibrowse..."); logf("navibrowse...");
cpu_boost(true); cpu_boost(true);
count = retrieve_entries(c, &tcs, 0, true); count = retrieve_entries(c, 0, true);
cpu_boost(false); cpu_boost(false);
break; break;
@ -1549,6 +1557,7 @@ void tagtree_exit(struct tree_context* c)
int tagtree_get_filename(struct tree_context* c, char *buf, int buflen) int tagtree_get_filename(struct tree_context* c, char *buf, int buflen)
{ {
struct tagcache_search tcs;
struct tagentry *entry; struct tagentry *entry;
entry = tagtree_get_entry(c, c->selected_item); entry = tagtree_get_entry(c, c->selected_item);
@ -1569,6 +1578,7 @@ int tagtree_get_filename(struct tree_context* c, char *buf, int buflen)
static bool insert_all_playlist(struct tree_context *c, int position, bool queue) static bool insert_all_playlist(struct tree_context *c, int position, bool queue)
{ {
struct tagcache_search tcs;
int i; int i;
char buf[MAX_PATH]; char buf[MAX_PATH];
int from, to, direction; int from, to, direction;
@ -1639,7 +1649,7 @@ bool tagtree_insert_selection_playlist(int position, bool queue)
int dirlevel = tc->dirlevel; int dirlevel = tc->dirlevel;
/* We need to set the table to allsubentries. */ /* We need to set the table to allsubentries. */
show_search_progress(true, 0); show_search_progress(!tagcache_is_busy(), 0);
dptr = tagtree_get_entry(tc, tc->selected_item); dptr = tagtree_get_entry(tc, tc->selected_item);
@ -1732,7 +1742,7 @@ struct tagentry* tagtree_get_entry(struct tree_context *c, int id)
if (realid >= current_entry_count || realid < 0) if (realid >= current_entry_count || realid < 0)
{ {
cpu_boost(true); cpu_boost(true);
if (retrieve_entries(c, &tcs2, MAX(0, id - (current_entry_count / 2)), if (retrieve_entries(c, MAX(0, id - (current_entry_count / 2)),
false) < 0) false) < 0)
{ {
logf("retrieve failed"); logf("retrieve failed");