Replace AVL tree in DAAP query by a static hash using gperf

This commit is contained in:
Julien BLACHE 2011-03-31 18:05:41 +02:00
parent fc90acbc17
commit 303a3329eb
7 changed files with 57 additions and 148 deletions

2
src/.gitignore vendored
View File

@ -7,3 +7,5 @@ DAAP2SQL.[ch]
RSP2SQL.[ch]
*.u
daap_query_hash.c

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2010 Julien BLACHE <jb@jblache.org>
* Copyright (C) 2009-2011 Julien BLACHE <jb@jblache.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -94,7 +94,7 @@ expr returns [ pANTLR3_STRING result, int valid ]
pANTLR3_UINT8 escaped;
ANTLR3_UINT8 op;
int neg_op;
struct dmap_query_field_map *dqfm;
const struct dmap_query_field_map *dqfm;
char *end;
long long llval;
@ -162,7 +162,7 @@ expr returns [ pANTLR3_STRING result, int valid ]
neg_op = 0;
/* Lookup DMAP field in the query field map */
dqfm = daap_query_field_lookup((char *)field);
dqfm = daap_query_field_lookup((char *)field, strlen((char *)field));
if (!dqfm)
{
DPRINTF(E_LOG, L_DAAP, "DMAP field '\%s' is not a valid field in queries\n", field);

View File

@ -21,9 +21,11 @@ if COND_OSS4
OSS4SRC=laudio_oss4.c
endif
GPERF_FILES =
GPERF_FILES = \
daap_query.gperf
GPERF_PRODUCTS =
GPERF_PRODUCTS = \
daap_query_hash.c
ANTLR_GRAMMARS = \
RSP.g RSP2SQL.g \

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2010 Julien BLACHE <jb@jblache.org>
* Copyright (C) 2009-2011 Julien BLACHE <jb@jblache.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -25,8 +25,6 @@
#include <string.h>
#include <errno.h>
#include <avl.h>
#include "logger.h"
#include "misc.h"
#include "daap_query.h"
@ -36,72 +34,9 @@
#include "DAAP2SQL.h"
static struct dmap_query_field_map dmap_query_fields[] =
{
{ 0, 0, "dmap.itemname", "title" },
{ 0, 1, "dmap.itemid", "id" },
{ 0, 0, "daap.songalbum", "album" },
{ 0, 1, "daap.songalbumid", "songalbumid" },
{ 0, 0, "daap.songartist", "artist" },
{ 0, 0, "daap.songalbumartist", "album_artist" },
{ 0, 1, "daap.songbitrate", "bitrate" },
{ 0, 0, "daap.songcomment", "comment" },
{ 0, 1, "daap.songcompilation", "compilation" },
{ 0, 0, "daap.songcomposer", "composer" },
{ 0, 1, "daap.songdatakind", "data_kind" },
{ 0, 0, "daap.songdataurl", "url" },
{ 0, 1, "daap.songdateadded", "time_added" },
{ 0, 1, "daap.songdatemodified", "time_modified" },
{ 0, 0, "daap.songdescription", "description" },
{ 0, 1, "daap.songdisccount", "total_discs" },
{ 0, 1, "daap.songdiscnumber", "disc" },
{ 0, 0, "daap.songformat", "type" },
{ 0, 0, "daap.songgenre", "genre" },
{ 0, 1, "daap.songsamplerate", "samplerate" },
{ 0, 1, "daap.songsize", "file_size" },
{ 0, 1, "daap.songstoptime", "song_length" },
{ 0, 1, "daap.songtime", "song_length" },
{ 0, 1, "daap.songtrackcount", "total_tracks" },
{ 0, 1, "daap.songtracknumber", "track" },
{ 0, 1, "daap.songyear", "year" },
{ 0, 1, "com.apple.itunes.mediakind", "media_kind" },
/* gperf static hash, daap_query.gperf */
#include "daap_query_hash.c"
{ -1, -1, NULL, NULL }
};
static avl_tree_t *dmap_query_fields_hash;
static int
dmap_query_field_map_compare(const void *aa, const void *bb)
{
struct dmap_query_field_map *a = (struct dmap_query_field_map *)aa;
struct dmap_query_field_map *b = (struct dmap_query_field_map *)bb;
if (a->hash < b->hash)
return -1;
if (a->hash > b->hash)
return 1;
return 0;
}
struct dmap_query_field_map *
daap_query_field_lookup(char *field)
{
struct dmap_query_field_map dqfm;
avl_node_t *node;
dqfm.hash = djb_hash(field, strlen(field));
node = avl_search(dmap_query_fields_hash, &dqfm);
if (!node)
return NULL;
return (struct dmap_query_field_map *)node->item;
}
char *
daap_query_parse_sql(const char *daap_query)
@ -214,56 +149,3 @@ daap_query_parse_sql(const char *daap_query)
return ret;
}
int
daap_query_init(void)
{
avl_node_t *node;
struct dmap_query_field_map *dqfm;
int i;
dmap_query_fields_hash = avl_alloc_tree(dmap_query_field_map_compare, NULL);
if (!dmap_query_fields_hash)
{
DPRINTF(E_FATAL, L_DAAP, "DAAP query init could not allocate AVL tree\n");
return -1;
}
for (i = 0; dmap_query_fields[i].hash == 0; i++)
{
dmap_query_fields[i].hash = djb_hash(dmap_query_fields[i].dmap_field, strlen(dmap_query_fields[i].dmap_field));
node = avl_insert(dmap_query_fields_hash, &dmap_query_fields[i]);
if (!node)
{
if (errno != EEXIST)
DPRINTF(E_FATAL, L_DAAP, "DAAP query init failed; AVL insert error: %s\n", strerror(errno));
else
{
node = avl_search(dmap_query_fields_hash, &dmap_query_fields[i]);
dqfm = node->item;
DPRINTF(E_FATAL, L_DAAP, "DAAP query init failed; WARNING: duplicate hash key\n");
DPRINTF(E_FATAL, L_DAAP, "Hash %x, string %s\n", dmap_query_fields[i].hash, dmap_query_fields[i].dmap_field);
DPRINTF(E_FATAL, L_DAAP, "Hash %x, string %s\n", dqfm->hash, dqfm->dmap_field);
}
goto avl_insert_fail;
}
}
return 0;
avl_insert_fail:
avl_free_tree(dmap_query_fields_hash);
return -1;
}
void
daap_query_deinit(void)
{
avl_free_tree(dmap_query_fields_hash);
}

39
src/daap_query.gperf Normal file
View File

@ -0,0 +1,39 @@
%language=ANSI-C
%readonly-tables
%enum
%switch=1
%compare-lengths
%define hash-function-name daap_query_field_hash
%define lookup-function-name daap_query_field_lookup
%define slot-name dmap_field
%struct-type
%omit-struct-type
struct dmap_query_field_map;
%%
"dmap.itemname", "title", 0
"dmap.itemid", "id", 1
"daap.songalbum", "album", 0
"daap.songalbumid", "songalbumid", 1
"daap.songartist", "artist", 0
"daap.songalbumartist", "album_artist", 0
"daap.songbitrate", "bitrate", 1
"daap.songcomment", "comment", 0
"daap.songcompilation", "compilation", 1
"daap.songcomposer", "composer", 0
"daap.songdatakind", "data_kind", 1
"daap.songdataurl", "url", 0
"daap.songdateadded", "time_added", 1
"daap.songdatemodified", "time_modified", 1
"daap.songdescription", "description", 0
"daap.songdisccount", "total_discs", 1
"daap.songdiscnumber", "disc", 1
"daap.songformat", "type", 0
"daap.songgenre", "genre", 0
"daap.songsamplerate", "samplerate", 1
"daap.songsize", "file_size", 1
"daap.songstoptime", "song_length", 1
"daap.songtime", "song_length", 1
"daap.songtrackcount", "total_tracks", 1
"daap.songtracknumber", "track", 1
"daap.songyear", "year", 1
"com.apple.itunes.mediakind", "media_kind", 1

View File

@ -2,29 +2,21 @@
#ifndef __DAAP_QUERY_H__
#define __DAAP_QUERY_H__
#include <stdint.h>
#include "logger.h"
#include "misc.h"
struct dmap_query_field_map {
uint32_t hash;
int as_int;
char *dmap_field;
char *db_col;
int as_int;
};
struct dmap_query_field_map *
daap_query_field_lookup(char *field);
/* Generated by gperf - keep in sync, don't alter */
const struct dmap_query_field_map *
daap_query_field_lookup (register const char *str, register unsigned int len);
char *
daap_query_parse_sql(const char *daap_query);
int
daap_query_init(void);
void
daap_query_deinit(void);
#endif /* !__DAAP_QUERY_H__ */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2010 Julien BLACHE <jb@jblache.org>
* Copyright (C) 2009-2011 Julien BLACHE <jb@jblache.org>
* Copyright (C) 2010 Kai Elwert <elwertk@googlemail.com>
*
* Adapted from mt-daapd:
@ -3174,10 +3174,6 @@ daap_init(void)
next_session_id = 100; /* gotta start somewhere, right? */
update_requests = NULL;
ret = daap_query_init();
if (ret < 0)
return ret;
for (i = 0; daap_handlers[i].handler; i++)
{
ret = regcomp(&daap_handlers[i].preg, daap_handlers[i].regexp, REG_EXTENDED | REG_NOSUB);
@ -3186,7 +3182,7 @@ daap_init(void)
regerror(ret, &daap_handlers[i].preg, buf, sizeof(buf));
DPRINTF(E_FATAL, L_DAAP, "DAAP init failed; regexp error: %s\n", buf);
goto regexp_fail;
return -1;
}
}
@ -3239,8 +3235,6 @@ daap_init(void)
daap_avl_alloc_fail:
for (i = 0; daap_handlers[i].handler; i++)
regfree(&daap_handlers[i].preg);
regexp_fail:
daap_query_deinit();
return -1;
}
@ -3251,8 +3245,6 @@ daap_deinit(void)
struct daap_update_request *ur;
int i;
daap_query_deinit();
for (i = 0; daap_handlers[i].handler; i++)
regfree(&daap_handlers[i].preg);