Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[db] speedup of ResultQueries using string key reuse #7329

Merged
merged 1 commit into from
Jul 4, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 58 additions & 12 deletions xbmc/dbwrappers/dataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "dataset.h"
#include "utils/log.h"
#include <cstring>
#include <algorithm>

#ifndef __GNUC__
#pragma warning (disable:4800)
Expand Down Expand Up @@ -93,6 +94,7 @@ Dataset::Dataset():
frecno = 0;
fbof = feof = true;
autocommit = true;
fieldIndexMapID = ~0;

fields_object = new Fields();

Expand All @@ -110,6 +112,7 @@ Dataset::Dataset(Database *newDb):
frecno = 0;
fbof = feof = true;
autocommit = true;
fieldIndexMapID = ~0;

fields_object = new Fields();

Expand Down Expand Up @@ -205,6 +208,10 @@ void Dataset::close(void) {
frecno = 0;
fbof = feof = true;
active = false;

fieldIndexMap_Entries.clear();
fieldIndexMap_Sorter.clear();
fieldIndexMapID = ~0;
}


Expand Down Expand Up @@ -321,25 +328,64 @@ bool Dataset::set_field_value(const char *f_name, const field_value &value) {
// return false;
}

/********* INDEXMAP SECTION START *********/
bool Dataset::get_index_map_entry(const char *f_name) {
if (~fieldIndexMapID)
{
unsigned int next(fieldIndexMapID+1 >= fieldIndexMap_Entries.size() ? 0 : fieldIndexMapID + 1);
if (fieldIndexMap_Entries[next].strName == f_name) //Yes, our assumption hits.
{
fieldIndexMapID = next;
return true;
}
}
// indexMap not found on the expected way, either first row strange retrival order
FieldIndexMapEntry tmp(f_name);
std::vector<unsigned int>::iterator ins(lower_bound(fieldIndexMap_Sorter.begin(), fieldIndexMap_Sorter.end(), tmp, FieldIndexMapComparator(fieldIndexMap_Entries)));
if (ins == fieldIndexMap_Sorter.end() || (tmp < fieldIndexMap_Entries[*ins])) //new entry
{
//Insert the new item just behind last retrieved item
//In general this should be always end(), but could be different
fieldIndexMap_Sorter.insert(ins, ++fieldIndexMapID);
fieldIndexMap_Entries.insert(fieldIndexMap_Entries.begin() + fieldIndexMapID, tmp);
}
else //entry already existing!
{
fieldIndexMapID = *ins;
return true;
}
return false; //invalid
}
/********* INDEXMAP SECTION END *********/

const field_value Dataset::get_field_value(const char *f_name) {
const char* name=strstr(f_name, ".");
if (name) name++;
if (ds_state != dsInactive) {
if (ds_state != dsInactive)
{
if (ds_state == dsEdit || ds_state == dsInsert){
for (unsigned int i=0; i < edit_object->size(); i++)

This comment was marked as spam.

if (str_compare((*edit_object)[i].props.name.c_str(), f_name)==0) {
return (*edit_object)[i].val;
}
if (str_compare((*edit_object)[i].props.name.c_str(), f_name)==0) {
return (*edit_object)[i].val;
}
throw DbErrors("Field not found: %s",f_name);
}
}
else
{
//Lets try to reuse a string ->index conversation
if (get_index_map_entry(f_name))
return get_field_value(static_cast<int>(fieldIndexMap_Entries[fieldIndexMapID].fieldIndex));

const char* name=strstr(f_name, ".");
if (name)
name++;

for (unsigned int i=0; i < fields_object->size(); i++)
if (str_compare((*fields_object)[i].props.name.c_str(), f_name)==0 || (name && str_compare((*fields_object)[i].props.name.c_str(), name)==0)) {
return (*fields_object)[i].val;
}
throw DbErrors("Field not found: %s",f_name);
}
if (str_compare((*fields_object)[i].props.name.c_str(), f_name) == 0 || (name && str_compare((*fields_object)[i].props.name.c_str(), name) == 0)) {
fieldIndexMap_Entries[fieldIndexMapID].fieldIndex = i;
return (*fields_object)[i].val;
}
}
throw DbErrors("Field not found: %s",f_name);
}
throw DbErrors("Dataset state is Inactive");
//field_value fv;
//return fv;
Expand Down
54 changes: 53 additions & 1 deletion xbmc/dbwrappers/dataset.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ class Dataset {
/* status active is OK query */
virtual bool isActive(void) { return active; }

virtual void setSqlParams(const char *sqlFrmt, sqlType t, ...);
virtual void setSqlParams(const char *sqlFrmt, sqlType t, ...);


/* error handling */
Expand Down Expand Up @@ -406,6 +406,58 @@ class Dataset {
const sql_record* const get_sql_record();

private:

unsigned int fieldIndexMapID;

/* Struct to store an indexMapped field access entry */
struct FieldIndexMapEntry
{
FieldIndexMapEntry(const char *name):fieldIndex(~0), strName(name){};
bool operator < (const FieldIndexMapEntry &other) const {return strName < other.strName;};
unsigned int fieldIndex;
std::string strName;
};

/* Comparator to quickly find an indexMapped field access entry in the unsorted fieldIndexMap_Entries vector */
struct FieldIndexMapComparator
{
FieldIndexMapComparator(const std::vector<FieldIndexMapEntry> &c): c_(c) {};
bool operator()(const unsigned int &v, const FieldIndexMapEntry &o) const
{
return c_[v] < o;
};
bool operator()(const unsigned int &v1, const unsigned int &v2) const
{
return c_[v1] < c_[v2];
};
bool operator()(const FieldIndexMapEntry &o, const unsigned int &v) const
{
return o < c_[v];
};
private:
const std::vector<FieldIndexMapEntry> &c_;
};

/* Store string to field index translation in the same order
fields are accessed by field_value([string]).
Idea behind it:
- Open a SELECT query with many results
- track field access of the first row
- use this information for the following rows by just looking at the next
element in this vector
*/
std::vector<FieldIndexMapEntry> fieldIndexMap_Entries;

/* Hold the sorting order regarding FieldIndexMapEntry::strName in the
fieldIndexMap_Entries vector.
If "next element" in fieldIndexMap_Entries does not match,
do a fast binary search inside it using the fieldIndexMap_Sorter.
*/
std::vector<unsigned int> fieldIndexMap_Sorter;

/* Get the column index from a string field_value request */
bool get_index_map_entry(const char *f_name);

void set_ds_state(dsStates new_state) {ds_state = new_state;};
public:
/* return ds_state value */
Expand Down