mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-25 22:55:56 -05:00
Replace AVL tree in RSP query by a static hash using gperf
This commit is contained in:
parent
b8758a2aa2
commit
cc0555d986
1
src/.gitignore
vendored
1
src/.gitignore
vendored
@ -9,3 +9,4 @@ RSP2SQL.[ch]
|
||||
*.u
|
||||
|
||||
daap_query_hash.c
|
||||
rsp_query_hash.c
|
||||
|
@ -22,10 +22,12 @@ OSS4SRC=laudio_oss4.c
|
||||
endif
|
||||
|
||||
GPERF_FILES = \
|
||||
daap_query.gperf
|
||||
daap_query.gperf \
|
||||
rsp_query.gperf
|
||||
|
||||
GPERF_PRODUCTS = \
|
||||
daap_query_hash.c
|
||||
daap_query_hash.c \
|
||||
rsp_query_hash.c
|
||||
|
||||
ANTLR_GRAMMARS = \
|
||||
RSP.g RSP2SQL.g \
|
||||
|
@ -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
|
||||
@ -139,7 +139,7 @@ strcrit returns [ pANTLR3_STRING result, int valid ]
|
||||
: ^(o = strop f = FIELD s = STR)
|
||||
{
|
||||
char *op;
|
||||
struct rsp_query_field_map *rqfp;
|
||||
const struct rsp_query_field_map *rqfp;
|
||||
pANTLR3_STRING field;
|
||||
char *escaped;
|
||||
ANTLR3_UINT32 optok;
|
||||
@ -164,7 +164,7 @@ strcrit returns [ pANTLR3_STRING result, int valid ]
|
||||
field = $f->getText($f);
|
||||
|
||||
/* Field lookup */
|
||||
rqfp = rsp_query_field_lookup((char *)field->chars);
|
||||
rqfp = rsp_query_field_lookup((char *)field->chars, strlen((char *)field->chars));
|
||||
if (!rqfp)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RSP, "Field '\%s' is not a valid field in queries\n", field->chars);
|
||||
@ -225,7 +225,7 @@ intcrit returns [ pANTLR3_STRING result, int valid ]
|
||||
: ^(o = intop f = FIELD i = INT)
|
||||
{
|
||||
char *op;
|
||||
struct rsp_query_field_map *rqfp;
|
||||
const struct rsp_query_field_map *rqfp;
|
||||
pANTLR3_STRING field;
|
||||
|
||||
op = NULL;
|
||||
@ -255,7 +255,7 @@ intcrit returns [ pANTLR3_STRING result, int valid ]
|
||||
field = $f->getText($f);
|
||||
|
||||
/* Field lookup */
|
||||
rqfp = rsp_query_field_lookup((char *)field->chars);
|
||||
rqfp = rsp_query_field_lookup((char *)field->chars, strlen((char *)field->chars));
|
||||
if (!rqfp)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RSP, "Field '\%s' is not a valid field in queries\n", field->chars);
|
||||
@ -299,7 +299,7 @@ datecrit returns [ pANTLR3_STRING result, int valid ]
|
||||
: ^(o = dateop f = FIELD d = datespec)
|
||||
{
|
||||
char *op;
|
||||
struct rsp_query_field_map *rqfp;
|
||||
const struct rsp_query_field_map *rqfp;
|
||||
pANTLR3_STRING field;
|
||||
char buf[32];
|
||||
int ret;
|
||||
@ -319,7 +319,7 @@ datecrit returns [ pANTLR3_STRING result, int valid ]
|
||||
field = $f->getText($f);
|
||||
|
||||
/* Field lookup */
|
||||
rqfp = rsp_query_field_lookup((char *)field->chars);
|
||||
rqfp = rsp_query_field_lookup((char *)field->chars, strlen((char *)field->chars));
|
||||
if (!rqfp)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RSP, "Field '\%s' is not a valid field in queries\n", field->chars);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2010 Julien BLACHE <jb@jblache.org>
|
||||
* Copyright (C) 2009-2011 Julien BLACHE <jb@jblache.org>
|
||||
*
|
||||
* Adapted from mt-daapd:
|
||||
* Copyright (C) 2006-2007 Ron Pedde <ron@pedde.com>
|
||||
@ -903,10 +903,6 @@ rsp_init(void)
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = rsp_query_init();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; rsp_handlers[i].handler; i++)
|
||||
{
|
||||
ret = regcomp(&rsp_handlers[i].preg, rsp_handlers[i].regexp, REG_EXTENDED | REG_NOSUB);
|
||||
@ -915,16 +911,11 @@ rsp_init(void)
|
||||
regerror(ret, &rsp_handlers[i].preg, buf, sizeof(buf));
|
||||
|
||||
DPRINTF(E_FATAL, L_RSP, "RSP init failed; regexp error: %s\n", buf);
|
||||
goto regexp_fail;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
regexp_fail:
|
||||
rsp_query_deinit();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
@ -932,8 +923,6 @@ rsp_deinit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
rsp_query_deinit();
|
||||
|
||||
for (i = 0; rsp_handlers[i].handler; i++)
|
||||
regfree(&rsp_handlers[i].preg);
|
||||
}
|
||||
|
137
src/rsp_query.c
137
src/rsp_query.c
@ -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 "rsp_query.h"
|
||||
@ -36,85 +34,9 @@
|
||||
#include "RSP2SQL.h"
|
||||
|
||||
|
||||
static struct rsp_query_field_map rsp_query_fields[] =
|
||||
{
|
||||
{ 0, RSP_TYPE_INT, "id" },
|
||||
{ 0, RSP_TYPE_STRING, "path" },
|
||||
{ 0, RSP_TYPE_STRING, "fname" },
|
||||
{ 0, RSP_TYPE_STRING, "title" },
|
||||
{ 0, RSP_TYPE_STRING, "artist" },
|
||||
{ 0, RSP_TYPE_STRING, "album" },
|
||||
{ 0, RSP_TYPE_STRING, "genre" },
|
||||
{ 0, RSP_TYPE_STRING, "comment" },
|
||||
{ 0, RSP_TYPE_STRING, "type" },
|
||||
{ 0, RSP_TYPE_STRING, "composer" },
|
||||
{ 0, RSP_TYPE_STRING, "orchestra" },
|
||||
{ 0, RSP_TYPE_STRING, "grouping" },
|
||||
{ 0, RSP_TYPE_STRING, "url" },
|
||||
{ 0, RSP_TYPE_INT, "bitrate" },
|
||||
{ 0, RSP_TYPE_INT, "samplerate" },
|
||||
{ 0, RSP_TYPE_INT, "song_length" },
|
||||
{ 0, RSP_TYPE_INT, "file_size" },
|
||||
{ 0, RSP_TYPE_INT, "year" },
|
||||
{ 0, RSP_TYPE_INT, "track" },
|
||||
{ 0, RSP_TYPE_INT, "total_tracks" },
|
||||
{ 0, RSP_TYPE_INT, "disc" },
|
||||
{ 0, RSP_TYPE_INT, "total_discs" },
|
||||
{ 0, RSP_TYPE_INT, "bpm" },
|
||||
{ 0, RSP_TYPE_INT, "compilation" },
|
||||
{ 0, RSP_TYPE_INT, "rating" },
|
||||
{ 0, RSP_TYPE_INT, "play_count" },
|
||||
{ 0, RSP_TYPE_INT, "data_kind" },
|
||||
{ 0, RSP_TYPE_INT, "item_kind" },
|
||||
{ 0, RSP_TYPE_STRING, "description" },
|
||||
{ 0, RSP_TYPE_DATE, "time_added" },
|
||||
{ 0, RSP_TYPE_DATE, "time_modified" },
|
||||
{ 0, RSP_TYPE_DATE, "time_played" },
|
||||
{ 0, RSP_TYPE_DATE, "db_timestamp" },
|
||||
{ 0, RSP_TYPE_INT, "sample_count" },
|
||||
{ 0, RSP_TYPE_STRING, "codectype" },
|
||||
{ 0, RSP_TYPE_INT, "idx" },
|
||||
{ 0, RSP_TYPE_INT, "has_video" },
|
||||
{ 0, RSP_TYPE_INT, "contentrating" },
|
||||
{ 0, RSP_TYPE_INT, "bits_per_sample" },
|
||||
{ 0, RSP_TYPE_STRING, "album_artist" },
|
||||
/* gperf static hash, rsp_query.gperf */
|
||||
#include "rsp_query_hash.c"
|
||||
|
||||
{ -1, -1, NULL }
|
||||
};
|
||||
|
||||
static avl_tree_t *rsp_query_fields_hash;
|
||||
|
||||
|
||||
static int
|
||||
rsp_query_field_map_compare(const void *aa, const void *bb)
|
||||
{
|
||||
struct rsp_query_field_map *a = (struct rsp_query_field_map *)aa;
|
||||
struct rsp_query_field_map *b = (struct rsp_query_field_map *)bb;
|
||||
|
||||
if (a->hash < b->hash)
|
||||
return -1;
|
||||
|
||||
if (a->hash > b->hash)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct rsp_query_field_map *
|
||||
rsp_query_field_lookup(char *field)
|
||||
{
|
||||
struct rsp_query_field_map rqfm;
|
||||
avl_node_t *node;
|
||||
|
||||
rqfm.hash = djb_hash(field, strlen(field));
|
||||
|
||||
node = avl_search(rsp_query_fields_hash, &rqfm);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
return (struct rsp_query_field_map *)node->item;
|
||||
}
|
||||
|
||||
char *
|
||||
rsp_query_parse_sql(const char *rsp_query)
|
||||
@ -227,56 +149,3 @@ rsp_query_parse_sql(const char *rsp_query)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
rsp_query_init(void)
|
||||
{
|
||||
avl_node_t *node;
|
||||
struct rsp_query_field_map *rqfm;
|
||||
int i;
|
||||
|
||||
rsp_query_fields_hash = avl_alloc_tree(rsp_query_field_map_compare, NULL);
|
||||
if (!rsp_query_fields_hash)
|
||||
{
|
||||
DPRINTF(E_FATAL, L_RSP, "RSP query init could not allocate AVL tree\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; rsp_query_fields[i].hash == 0; i++)
|
||||
{
|
||||
rsp_query_fields[i].hash = djb_hash(rsp_query_fields[i].rsp_field, strlen(rsp_query_fields[i].rsp_field));
|
||||
|
||||
node = avl_insert(rsp_query_fields_hash, &rsp_query_fields[i]);
|
||||
if (!node)
|
||||
{
|
||||
if (errno != EEXIST)
|
||||
DPRINTF(E_FATAL, L_RSP, "RSP query init failed; AVL insert error: %s\n", strerror(errno));
|
||||
else
|
||||
{
|
||||
node = avl_search(rsp_query_fields_hash, &rsp_query_fields[i]);
|
||||
rqfm = node->item;
|
||||
|
||||
DPRINTF(E_FATAL, L_RSP, "RSP query init failed; WARNING: duplicate hash key\n");
|
||||
DPRINTF(E_FATAL, L_RSP, "Hash %x, string %s\n", rsp_query_fields[i].hash, rsp_query_fields[i].rsp_field);
|
||||
|
||||
DPRINTF(E_FATAL, L_RSP, "Hash %x, string %s\n", rqfm->hash, rqfm->rsp_field);
|
||||
}
|
||||
|
||||
goto avl_insert_fail;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
avl_insert_fail:
|
||||
avl_free_tree(rsp_query_fields_hash);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
rsp_query_deinit(void)
|
||||
{
|
||||
avl_free_tree(rsp_query_fields_hash);
|
||||
}
|
||||
|
52
src/rsp_query.gperf
Normal file
52
src/rsp_query.gperf
Normal file
@ -0,0 +1,52 @@
|
||||
%language=ANSI-C
|
||||
%readonly-tables
|
||||
%enum
|
||||
%switch=1
|
||||
%compare-lengths
|
||||
%define hash-function-name rsp_query_field_hash
|
||||
%define lookup-function-name rsp_query_field_lookup
|
||||
%define slot-name rsp_field
|
||||
%struct-type
|
||||
%omit-struct-type
|
||||
struct rsp_query_field_map;
|
||||
%%
|
||||
"id", RSP_TYPE_INT
|
||||
"path", RSP_TYPE_STRING
|
||||
"fname", RSP_TYPE_STRING
|
||||
"title", RSP_TYPE_STRING
|
||||
"artist", RSP_TYPE_STRING
|
||||
"album", RSP_TYPE_STRING
|
||||
"genre", RSP_TYPE_STRING
|
||||
"comment", RSP_TYPE_STRING
|
||||
"type", RSP_TYPE_STRING
|
||||
"composer", RSP_TYPE_STRING
|
||||
"orchestra", RSP_TYPE_STRING
|
||||
"grouping", RSP_TYPE_STRING
|
||||
"url", RSP_TYPE_STRING
|
||||
"bitrate", RSP_TYPE_INT
|
||||
"samplerate", RSP_TYPE_INT
|
||||
"song_length", RSP_TYPE_INT
|
||||
"file_size", RSP_TYPE_INT
|
||||
"year", RSP_TYPE_INT
|
||||
"track", RSP_TYPE_INT
|
||||
"total_tracks", RSP_TYPE_INT
|
||||
"disc", RSP_TYPE_INT
|
||||
"total_discs", RSP_TYPE_INT
|
||||
"bpm", RSP_TYPE_INT
|
||||
"compilation", RSP_TYPE_INT
|
||||
"rating", RSP_TYPE_INT
|
||||
"play_count", RSP_TYPE_INT
|
||||
"data_kind", RSP_TYPE_INT
|
||||
"item_kind", RSP_TYPE_INT
|
||||
"description", RSP_TYPE_STRING
|
||||
"time_added", RSP_TYPE_DATE
|
||||
"time_modified", RSP_TYPE_DATE
|
||||
"time_played", RSP_TYPE_DATE
|
||||
"db_timestamp", RSP_TYPE_DATE
|
||||
"sample_count", RSP_TYPE_INT
|
||||
"codectype", RSP_TYPE_STRING
|
||||
"idx", RSP_TYPE_INT
|
||||
"has_video", RSP_TYPE_INT
|
||||
"contentrating", RSP_TYPE_INT
|
||||
"bits_per_sample", RSP_TYPE_INT
|
||||
"album_artist", RSP_TYPE_STRING
|
@ -9,23 +9,17 @@
|
||||
#define RSP_TYPE_DATE 2
|
||||
|
||||
struct rsp_query_field_map {
|
||||
uint32_t hash;
|
||||
int field_type;
|
||||
char *rsp_field;
|
||||
int field_type;
|
||||
/* RSP fields are named after the DB columns - or vice versa */
|
||||
};
|
||||
|
||||
|
||||
struct rsp_query_field_map *
|
||||
rsp_query_field_lookup(char *field);
|
||||
/* Generated by gperf - keep in sync, don't alter */
|
||||
const struct rsp_query_field_map *
|
||||
rsp_query_field_lookup (register const char *str, register unsigned int len);
|
||||
|
||||
char *
|
||||
rsp_query_parse_sql(const char *rsp_query);
|
||||
|
||||
int
|
||||
rsp_query_init(void);
|
||||
|
||||
void
|
||||
rsp_query_deinit(void);
|
||||
|
||||
#endif /* !__RSP_QUERY_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user