Performance optimizations for tagcache commit. Still more left to be done.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9721 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
2b18727a8a
commit
fa893c6b88
5 changed files with 282 additions and 126 deletions
157
apps/tagcache.c
157
apps/tagcache.c
|
@ -33,6 +33,7 @@
|
|||
#include "tagcache.h"
|
||||
#include "buffer.h"
|
||||
#include "atoi.h"
|
||||
#include "crc32.h"
|
||||
|
||||
/* Tag Cache thread. */
|
||||
static struct event_queue tagcache_queue;
|
||||
|
@ -66,19 +67,12 @@ static bool tagcache_init_done = false;
|
|||
static int init_step;
|
||||
|
||||
/* Queue commands. */
|
||||
#define Q_STOP_SCAN 0
|
||||
#define Q_START_SCAN 1
|
||||
#define Q_FORCE_UPDATE 2
|
||||
enum tagcache_queue {
|
||||
Q_STOP_SCAN = 0,
|
||||
Q_START_SCAN,
|
||||
Q_FORCE_UPDATE,
|
||||
};
|
||||
|
||||
/* Tag database files. */
|
||||
#define TAGCACHE_FILE_TEMP ROCKBOX_DIR "/tagcache_tmp.tcd"
|
||||
#define TAGCACHE_FILE_MASTER ROCKBOX_DIR "/tagcache_idx.tcd"
|
||||
#define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/tagcache_%d.tcd"
|
||||
|
||||
/* Tag Cache Header version 'TCHxx' */
|
||||
#define TAGCACHE_MAGIC 0x54434802
|
||||
|
||||
#define TAGCACHE_RESERVE 32768
|
||||
|
||||
/* Tag database structures. */
|
||||
|
||||
|
@ -92,6 +86,7 @@ struct tagfile_entry {
|
|||
/* Fixed-size tag entry in master db index. */
|
||||
struct index_entry {
|
||||
long tag_seek[TAG_COUNT];
|
||||
long flag;
|
||||
};
|
||||
|
||||
/* Header is the same in every file. */
|
||||
|
@ -868,6 +863,19 @@ bool tagcache_retrieve(struct tagcache_search *tcs, int idxid,
|
|||
}
|
||||
|
||||
#if 0
|
||||
|
||||
static bool tagcache_delete(const char *filename)
|
||||
{
|
||||
struct index_entry *entry;
|
||||
|
||||
entry = find_entry_disk(filename, true);
|
||||
if (entry == NULL)
|
||||
{
|
||||
logf("not found: %s", filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void tagcache_modify(struct tagcache_search *tcs, int type, const char *text)
|
||||
{
|
||||
struct tagentry *entry;
|
||||
|
@ -1111,7 +1119,7 @@ static bool tempbuf_insert(char *str, int id, int idx_id)
|
|||
return false;
|
||||
|
||||
index[tempbufidx].id = (struct tempbuf_id *)&tempbuf[tempbuf_pos];
|
||||
#ifdef ROCKBOX_STRICT_ALIGN
|
||||
#ifdef TAGCACHE_STRICT_ALIGN
|
||||
/* Make sure the entry is long aligned. */
|
||||
if ((long)index[tempbufidx].id & 0x03)
|
||||
{
|
||||
|
@ -1141,9 +1149,15 @@ static bool tempbuf_unique_insert(char *str, int id)
|
|||
struct tempbuf_searchidx *index = (struct tempbuf_searchidx *)tempbuf;
|
||||
struct tempbuf_id *idp;
|
||||
int i;
|
||||
unsigned crc32;
|
||||
unsigned *crcbuf = (unsigned *)&tempbuf[tempbuf_size-4];
|
||||
|
||||
/* Check if string already exists. */
|
||||
crc32 = crc_32(str, strlen(str), 0xffffffff);
|
||||
|
||||
/* Check if the crc does not exist -> entry does not exist for sure. */
|
||||
for (i = 0; i < tempbufidx; i++)
|
||||
{
|
||||
if (*(crcbuf--) == crc32)
|
||||
{
|
||||
if (!strcasecmp(str, index[i].str))
|
||||
{
|
||||
|
@ -1156,15 +1170,15 @@ static bool tempbuf_unique_insert(char *str, int id)
|
|||
idp = idp->next;
|
||||
|
||||
idp->next = (struct tempbuf_id *)&tempbuf[tempbuf_pos];
|
||||
#ifdef ROCKBOX_STRICT_ALIGN
|
||||
#if TAGCACHE_STRICT_ALIGN
|
||||
/* Make sure the entry is long aligned. */
|
||||
if ((long)idp->next & 0x03)
|
||||
{
|
||||
int fix = 4 - ((long)idp->next & 0x03);
|
||||
tempbuf_left -= fix;
|
||||
tempbuf_pos += fix;
|
||||
idp->next = (struct tempbuf_id *)((
|
||||
(long)idp->next & ~0x03) + 0x04);
|
||||
idp->next = (struct tempbuf_id *)
|
||||
(((long)idp->next & ~0x03) + 0x04);
|
||||
}
|
||||
#endif
|
||||
idp = idp->next;
|
||||
|
@ -1175,7 +1189,11 @@ static bool tempbuf_unique_insert(char *str, int id)
|
|||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert and quit. */
|
||||
*crcbuf = crc32;
|
||||
tempbuf_left -= 4;
|
||||
return tempbuf_insert(str, id, -1);
|
||||
}
|
||||
|
||||
|
@ -1200,7 +1218,7 @@ static int tempbuf_sort(int fd)
|
|||
struct tagfile_entry fe;
|
||||
int i;
|
||||
int length;
|
||||
#ifdef ROCKBOX_STRICT_ALIGN
|
||||
#ifdef TAGCACHE_STRICT_ALIGN
|
||||
int fix;
|
||||
#endif
|
||||
|
||||
|
@ -1213,7 +1231,7 @@ static int tempbuf_sort(int fd)
|
|||
fe.tag_length = length;
|
||||
fe.idx_id = index[i].idx_id;
|
||||
|
||||
#ifdef ROCKBOX_STRICT_ALIGN
|
||||
#ifdef TAGCACHE_STRICT_ALIGN
|
||||
/* Make sure the entry is long aligned. */
|
||||
if (index[i].seek & 0x03)
|
||||
{
|
||||
|
@ -1241,7 +1259,7 @@ static int tempbuf_sort(int fd)
|
|||
return -2;
|
||||
}
|
||||
|
||||
#ifdef ROCKBOX_STRICT_ALIGN
|
||||
#ifdef TAGCACHE_STRICT_ALIGN
|
||||
/* Write some padding. */
|
||||
if (fix)
|
||||
write(fd, "XXX", fix);
|
||||
|
@ -1251,15 +1269,21 @@ static int tempbuf_sort(int fd)
|
|||
return i;
|
||||
}
|
||||
|
||||
|
||||
static struct tempbuf_searchidx* tempbuf_locate(int id)
|
||||
inline static struct tempbuf_searchidx* tempbuf_locate(int id)
|
||||
{
|
||||
struct tempbuf_searchidx *index = (struct tempbuf_searchidx *)tempbuf;
|
||||
struct tempbuf_id *idp;
|
||||
static int last_id = 0;
|
||||
int i;
|
||||
|
||||
try_again:
|
||||
|
||||
if (last_id >= tempbufidx)
|
||||
last_id = 0;
|
||||
|
||||
/* Check if string already exists. */
|
||||
for (i = 0; i < tempbufidx; i++)
|
||||
/* FIXME: This check is extremely slow, O(n^2) */
|
||||
for (i = last_id; i < tempbufidx; i++)
|
||||
{
|
||||
idp = index[i].id;
|
||||
while (idp != NULL)
|
||||
|
@ -1270,11 +1294,14 @@ static struct tempbuf_searchidx* tempbuf_locate(int id)
|
|||
}
|
||||
}
|
||||
|
||||
if (last_id)
|
||||
goto try_again;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int tempbuf_find_location(int id)
|
||||
inline static int tempbuf_find_location(int id)
|
||||
{
|
||||
struct tempbuf_searchidx *entry;
|
||||
|
||||
|
@ -1385,7 +1412,8 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
{
|
||||
int i;
|
||||
struct tagcache_header tch;
|
||||
struct index_entry idx;
|
||||
struct index_entry idxbuf[IDX_BUF_DEPTH];
|
||||
int idxbuf_pos;
|
||||
char buf[MAX_PATH];
|
||||
int fd = -1, masterfd;
|
||||
bool error = false;
|
||||
|
@ -1425,6 +1453,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
*/
|
||||
if (tagcache_is_sorted_tag(index_type))
|
||||
{
|
||||
logf("loading tags...");
|
||||
for (i = 0; i < tch.entry_count; i++)
|
||||
{
|
||||
struct tagfile_entry entry;
|
||||
|
@ -1460,6 +1489,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
tempbuf_insert(buf, loc + TAGFILE_MAX_ENTRIES, entry.idx_id);
|
||||
yield();
|
||||
}
|
||||
logf("done");
|
||||
}
|
||||
else
|
||||
tempbufidx = tch.entry_count;
|
||||
|
@ -1555,6 +1585,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
{
|
||||
lseek(tmpfd, sizeof(struct tagcache_header), SEEK_SET);
|
||||
/* h is the header of the temporary file containing new tags. */
|
||||
logf("inserting new tags...");
|
||||
for (i = 0; i < h->entry_count; i++)
|
||||
{
|
||||
struct temp_file_entry entry;
|
||||
|
@ -1600,6 +1631,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
entry.tag_length[index_type], SEEK_CUR);
|
||||
yield();
|
||||
}
|
||||
logf("done");
|
||||
|
||||
/* Sort the buffer data and write it to the index file. */
|
||||
lseek(fd, sizeof(struct tagcache_header), SEEK_SET);
|
||||
|
@ -1611,66 +1643,84 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
/**
|
||||
* Now update all indexes in the master lookup file.
|
||||
*/
|
||||
logf("updating indices...");
|
||||
lseek(masterfd, sizeof(struct tagcache_header), SEEK_SET);
|
||||
for (i = 0; i < tch.entry_count; i++)
|
||||
for (i = 0; i < tch.entry_count; i += idxbuf_pos)
|
||||
{
|
||||
int j;
|
||||
int loc = lseek(masterfd, 0, SEEK_CUR);
|
||||
|
||||
if (read(masterfd, &idx, sizeof(struct index_entry)) !=
|
||||
sizeof(struct index_entry))
|
||||
idxbuf_pos = MIN(tch.entry_count - i, IDX_BUF_DEPTH);
|
||||
|
||||
if (read(masterfd, idxbuf, sizeof(struct index_entry)*idxbuf_pos) !=
|
||||
(int)sizeof(struct index_entry)*idxbuf_pos)
|
||||
{
|
||||
logf("read fail #2");
|
||||
error = true;
|
||||
goto error_exit ;
|
||||
}
|
||||
idx.tag_seek[index_type] = tempbuf_find_location(
|
||||
idx.tag_seek[index_type]+TAGFILE_MAX_ENTRIES);
|
||||
if (idx.tag_seek[index_type] < 0)
|
||||
{
|
||||
logf("update error: %d/%d", i, tch.entry_count);
|
||||
error = true;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* Write back the updated index. */
|
||||
lseek(masterfd, loc, SEEK_SET);
|
||||
if (write(masterfd, &idx, sizeof(struct index_entry)) !=
|
||||
sizeof(struct index_entry))
|
||||
|
||||
for (j = 0; j < idxbuf_pos; j++)
|
||||
{
|
||||
logf("write fail");
|
||||
idxbuf[j].tag_seek[index_type] = tempbuf_find_location(
|
||||
idxbuf[j].tag_seek[index_type]+TAGFILE_MAX_ENTRIES);
|
||||
|
||||
if (idxbuf[j].tag_seek[index_type] < 0)
|
||||
{
|
||||
logf("update error: %d/%d", i+j, tch.entry_count);
|
||||
error = true;
|
||||
goto error_exit;
|
||||
}
|
||||
yield();
|
||||
}
|
||||
|
||||
/* Write back the updated index. */
|
||||
if (write(masterfd, idxbuf, sizeof(struct index_entry)*idxbuf_pos) !=
|
||||
(int)sizeof(struct index_entry)*idxbuf_pos)
|
||||
{
|
||||
logf("write fail");
|
||||
error = true;
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
logf("done");
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk through the temporary file containing the new tags.
|
||||
*/
|
||||
// build_normal_index(h, tmpfd, masterfd, idx);
|
||||
logf("updating new indices...");
|
||||
lseek(masterfd, masterfd_pos, SEEK_SET);
|
||||
lseek(tmpfd, sizeof(struct tagcache_header), SEEK_SET);
|
||||
lseek(fd, 0, SEEK_END);
|
||||
for (i = 0; i < h->entry_count; i++)
|
||||
for (i = 0; i < h->entry_count; i += idxbuf_pos)
|
||||
{
|
||||
int j;
|
||||
|
||||
idxbuf_pos = MIN(h->entry_count - i, IDX_BUF_DEPTH);
|
||||
if (init)
|
||||
{
|
||||
memset(&idx, 0, sizeof(struct index_entry));
|
||||
memset(idxbuf, 0, sizeof(struct index_entry)*IDX_BUF_DEPTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (read(masterfd, &idx, sizeof(struct index_entry)) !=
|
||||
sizeof(struct index_entry))
|
||||
int loc = lseek(masterfd, 0, SEEK_CUR);
|
||||
|
||||
if (read(masterfd, idxbuf, sizeof(struct index_entry)*idxbuf_pos) !=
|
||||
(int)sizeof(struct index_entry)*idxbuf_pos)
|
||||
{
|
||||
logf("read fail #2");
|
||||
error = true;
|
||||
break ;
|
||||
}
|
||||
lseek(masterfd, -sizeof(struct index_entry), SEEK_CUR);
|
||||
lseek(masterfd, loc, SEEK_SET);
|
||||
}
|
||||
|
||||
/* Read entry headers. */
|
||||
for (j = 0; j < idxbuf_pos; j++)
|
||||
{
|
||||
if (!tagcache_is_sorted_tag(index_type))
|
||||
{
|
||||
struct temp_file_entry entry;
|
||||
|
@ -1706,9 +1756,9 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
}
|
||||
|
||||
/* Write to index file. */
|
||||
idx.tag_seek[index_type] = lseek(fd, 0, SEEK_CUR);
|
||||
idxbuf[j].tag_seek[index_type] = lseek(fd, 0, SEEK_CUR);
|
||||
fe.tag_length = entry.tag_length[index_type];
|
||||
fe.idx_id = tch.entry_count + i;
|
||||
fe.idx_id = tch.entry_count + i + j;
|
||||
write(fd, &fe, sizeof(struct tagfile_entry));
|
||||
write(fd, buf, fe.tag_length);
|
||||
tempbufidx++;
|
||||
|
@ -1720,19 +1770,19 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
else
|
||||
{
|
||||
/* Locate the correct entry from the sorted array. */
|
||||
idx.tag_seek[index_type] = tempbuf_find_location(i);
|
||||
if (idx.tag_seek[index_type] < 0)
|
||||
idxbuf[j].tag_seek[index_type] = tempbuf_find_location(i + j);
|
||||
if (idxbuf[j].tag_seek[index_type] < 0)
|
||||
{
|
||||
logf("entry not found (%d)");
|
||||
error = true;
|
||||
break ;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Write index. */
|
||||
if (write(masterfd, &idx, sizeof(struct index_entry)) !=
|
||||
sizeof(struct index_entry))
|
||||
if (write(masterfd, idxbuf, sizeof(struct index_entry)*idxbuf_pos) !=
|
||||
(int)sizeof(struct index_entry)*idxbuf_pos)
|
||||
{
|
||||
logf("tagcache: write fail #4");
|
||||
error = true;
|
||||
|
@ -1741,6 +1791,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
|
||||
yield();
|
||||
}
|
||||
logf("done");
|
||||
|
||||
/* Finally write the uniqued tag index file. */
|
||||
if (tagcache_is_sorted_tag(index_type))
|
||||
|
|
|
@ -31,16 +31,38 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
|
|||
#define HAVE_TC_RAMCACHE 1
|
||||
#endif
|
||||
|
||||
/* Allow a little drift to the filename ordering. */
|
||||
/* Allow a little drift to the filename ordering (should not be too high/low). */
|
||||
#define POS_HISTORY_COUNT 4
|
||||
|
||||
/* How much to pre-load entries while committing to prevent seeking. */
|
||||
#define IDX_BUF_DEPTH 64
|
||||
|
||||
/* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */
|
||||
#define TAGCACHE_MAGIC 0x54434803
|
||||
|
||||
/* How much to allocate extra space for ramcache. */
|
||||
#define TAGCACHE_RESERVE 32768
|
||||
|
||||
/* How many entries we can create in one tag file (for sorting). */
|
||||
#define TAGFILE_MAX_ENTRIES 20000
|
||||
|
||||
/* How many entries to fetch to the seek table at once while searching. */
|
||||
#define SEEK_LIST_SIZE 50
|
||||
|
||||
/* 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
|
||||
|
||||
/* Tag database files. */
|
||||
#define TAGCACHE_FILE_TEMP ROCKBOX_DIR "/tagcache_tmp.tcd"
|
||||
#define TAGCACHE_FILE_MASTER ROCKBOX_DIR "/tagcache_idx.tcd"
|
||||
#define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/tagcache_%d.tcd"
|
||||
|
||||
/* Flags */
|
||||
#define FLAG_DELETED 0x0001
|
||||
|
||||
enum clause { clause_none, clause_is, clause_gt, clause_gteq, clause_lt,
|
||||
clause_lteq, clause_contains, clause_begins_with, clause_ends_with };
|
||||
enum modifiers { clause_mod_none, clause_mod_not };
|
||||
|
|
|
@ -5,6 +5,7 @@ logf.c
|
|||
backlight.c
|
||||
buffer.c
|
||||
common/atoi.c
|
||||
common/crc32.c
|
||||
common/ctype.c
|
||||
#ifndef SIMULATOR
|
||||
common/dir.c
|
||||
|
|
57
firmware/common/crc32.c
Normal file
57
firmware/common/crc32.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2003 Jörg Hohensohn [IDC]Dragon
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Code copied from firmware_flash plugin. */
|
||||
|
||||
/* Tool function to calculate a CRC32 across some buffer */
|
||||
/* third argument is either 0xFFFFFFFF to start or value from last piece */
|
||||
unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32)
|
||||
{
|
||||
/* CCITT standard polynomial 0x04C11DB7 */
|
||||
static const unsigned crc32_lookup[16] =
|
||||
{ /* lookup table for 4 bits at a time is affordable */
|
||||
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
|
||||
0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
|
||||
0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
|
||||
0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
|
||||
};
|
||||
|
||||
unsigned char byte;
|
||||
unsigned t;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
byte = *buf++; /* get one byte of data */
|
||||
|
||||
/* upper nibble of our data */
|
||||
t = crc32 >> 28; /* extract the 4 most significant bits */
|
||||
t ^= byte >> 4; /* XOR in 4 bits of data into the extracted bits */
|
||||
crc32 <<= 4; /* shift the CRC register left 4 bits */
|
||||
crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
|
||||
|
||||
/* lower nibble of our data */
|
||||
t = crc32 >> 28; /* extract the 4 most significant bits */
|
||||
t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */
|
||||
crc32 <<= 4; /* shift the CRC register left 4 bits */
|
||||
crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
|
||||
}
|
||||
|
||||
return crc32;
|
||||
}
|
||||
|
25
firmware/include/crc32.h
Normal file
25
firmware/include/crc32.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2003 Jörg Hohensohn [IDC]Dragon
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef _CRC32_H
|
||||
#define _CRC32_H
|
||||
|
||||
unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in a new issue