mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-26 23:25: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
|
*.u
|
||||||
|
|
||||||
daap_query_hash.c
|
daap_query_hash.c
|
||||||
|
rsp_query_hash.c
|
||||||
|
@ -22,10 +22,12 @@ OSS4SRC=laudio_oss4.c
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
GPERF_FILES = \
|
GPERF_FILES = \
|
||||||
daap_query.gperf
|
daap_query.gperf \
|
||||||
|
rsp_query.gperf
|
||||||
|
|
||||||
GPERF_PRODUCTS = \
|
GPERF_PRODUCTS = \
|
||||||
daap_query_hash.c
|
daap_query_hash.c \
|
||||||
|
rsp_query_hash.c
|
||||||
|
|
||||||
ANTLR_GRAMMARS = \
|
ANTLR_GRAMMARS = \
|
||||||
RSP.g RSP2SQL.g \
|
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
|
* 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
|
* 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)
|
: ^(o = strop f = FIELD s = STR)
|
||||||
{
|
{
|
||||||
char *op;
|
char *op;
|
||||||
struct rsp_query_field_map *rqfp;
|
const struct rsp_query_field_map *rqfp;
|
||||||
pANTLR3_STRING field;
|
pANTLR3_STRING field;
|
||||||
char *escaped;
|
char *escaped;
|
||||||
ANTLR3_UINT32 optok;
|
ANTLR3_UINT32 optok;
|
||||||
@ -164,7 +164,7 @@ strcrit returns [ pANTLR3_STRING result, int valid ]
|
|||||||
field = $f->getText($f);
|
field = $f->getText($f);
|
||||||
|
|
||||||
/* Field lookup */
|
/* Field lookup */
|
||||||
rqfp = rsp_query_field_lookup((char *)field->chars);
|
rqfp = rsp_query_field_lookup((char *)field->chars, strlen((char *)field->chars));
|
||||||
if (!rqfp)
|
if (!rqfp)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_RSP, "Field '\%s' is not a valid field in queries\n", field->chars);
|
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)
|
: ^(o = intop f = FIELD i = INT)
|
||||||
{
|
{
|
||||||
char *op;
|
char *op;
|
||||||
struct rsp_query_field_map *rqfp;
|
const struct rsp_query_field_map *rqfp;
|
||||||
pANTLR3_STRING field;
|
pANTLR3_STRING field;
|
||||||
|
|
||||||
op = NULL;
|
op = NULL;
|
||||||
@ -255,7 +255,7 @@ intcrit returns [ pANTLR3_STRING result, int valid ]
|
|||||||
field = $f->getText($f);
|
field = $f->getText($f);
|
||||||
|
|
||||||
/* Field lookup */
|
/* Field lookup */
|
||||||
rqfp = rsp_query_field_lookup((char *)field->chars);
|
rqfp = rsp_query_field_lookup((char *)field->chars, strlen((char *)field->chars));
|
||||||
if (!rqfp)
|
if (!rqfp)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_RSP, "Field '\%s' is not a valid field in queries\n", field->chars);
|
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)
|
: ^(o = dateop f = FIELD d = datespec)
|
||||||
{
|
{
|
||||||
char *op;
|
char *op;
|
||||||
struct rsp_query_field_map *rqfp;
|
const struct rsp_query_field_map *rqfp;
|
||||||
pANTLR3_STRING field;
|
pANTLR3_STRING field;
|
||||||
char buf[32];
|
char buf[32];
|
||||||
int ret;
|
int ret;
|
||||||
@ -319,7 +319,7 @@ datecrit returns [ pANTLR3_STRING result, int valid ]
|
|||||||
field = $f->getText($f);
|
field = $f->getText($f);
|
||||||
|
|
||||||
/* Field lookup */
|
/* Field lookup */
|
||||||
rqfp = rsp_query_field_lookup((char *)field->chars);
|
rqfp = rsp_query_field_lookup((char *)field->chars, strlen((char *)field->chars));
|
||||||
if (!rqfp)
|
if (!rqfp)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_RSP, "Field '\%s' is not a valid field in queries\n", field->chars);
|
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:
|
* Adapted from mt-daapd:
|
||||||
* Copyright (C) 2006-2007 Ron Pedde <ron@pedde.com>
|
* Copyright (C) 2006-2007 Ron Pedde <ron@pedde.com>
|
||||||
@ -903,10 +903,6 @@ rsp_init(void)
|
|||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = rsp_query_init();
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
for (i = 0; rsp_handlers[i].handler; i++)
|
for (i = 0; rsp_handlers[i].handler; i++)
|
||||||
{
|
{
|
||||||
ret = regcomp(&rsp_handlers[i].preg, rsp_handlers[i].regexp, REG_EXTENDED | REG_NOSUB);
|
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));
|
regerror(ret, &rsp_handlers[i].preg, buf, sizeof(buf));
|
||||||
|
|
||||||
DPRINTF(E_FATAL, L_RSP, "RSP init failed; regexp error: %s\n", buf);
|
DPRINTF(E_FATAL, L_RSP, "RSP init failed; regexp error: %s\n", buf);
|
||||||
goto regexp_fail;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
regexp_fail:
|
|
||||||
rsp_query_deinit();
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -932,8 +923,6 @@ rsp_deinit(void)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
rsp_query_deinit();
|
|
||||||
|
|
||||||
for (i = 0; rsp_handlers[i].handler; i++)
|
for (i = 0; rsp_handlers[i].handler; i++)
|
||||||
regfree(&rsp_handlers[i].preg);
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -25,8 +25,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <avl.h>
|
|
||||||
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "rsp_query.h"
|
#include "rsp_query.h"
|
||||||
@ -36,85 +34,9 @@
|
|||||||
#include "RSP2SQL.h"
|
#include "RSP2SQL.h"
|
||||||
|
|
||||||
|
|
||||||
static struct rsp_query_field_map rsp_query_fields[] =
|
/* gperf static hash, rsp_query.gperf */
|
||||||
{
|
#include "rsp_query_hash.c"
|
||||||
{ 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" },
|
|
||||||
|
|
||||||
{ -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 *
|
char *
|
||||||
rsp_query_parse_sql(const char *rsp_query)
|
rsp_query_parse_sql(const char *rsp_query)
|
||||||
@ -227,56 +149,3 @@ rsp_query_parse_sql(const char *rsp_query)
|
|||||||
|
|
||||||
return ret;
|
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
|
#define RSP_TYPE_DATE 2
|
||||||
|
|
||||||
struct rsp_query_field_map {
|
struct rsp_query_field_map {
|
||||||
uint32_t hash;
|
|
||||||
int field_type;
|
|
||||||
char *rsp_field;
|
char *rsp_field;
|
||||||
|
int field_type;
|
||||||
/* RSP fields are named after the DB columns - or vice versa */
|
/* RSP fields are named after the DB columns - or vice versa */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct rsp_query_field_map *
|
/* Generated by gperf - keep in sync, don't alter */
|
||||||
rsp_query_field_lookup(char *field);
|
const struct rsp_query_field_map *
|
||||||
|
rsp_query_field_lookup (register const char *str, register unsigned int len);
|
||||||
|
|
||||||
char *
|
char *
|
||||||
rsp_query_parse_sql(const char *rsp_query);
|
rsp_query_parse_sql(const char *rsp_query);
|
||||||
|
|
||||||
int
|
|
||||||
rsp_query_init(void);
|
|
||||||
|
|
||||||
void
|
|
||||||
rsp_query_deinit(void);
|
|
||||||
|
|
||||||
#endif /* !__RSP_QUERY_H__ */
|
#endif /* !__RSP_QUERY_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user