Skip to content

Commit

Permalink
db: turn generated queries array into a simple hash table.
Browse files Browse the repository at this point in the history
Since we have that functionality, let's use it.  Also, make table
const.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Nov 17, 2021
1 parent 53c9d98 commit fcf3d0c
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 27 deletions.
24 changes: 20 additions & 4 deletions devtools/sql-rewrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ def rewrite_single(self, query):

def rewrite(self, queries):
for i, q in enumerate(queries):
if q['name'] is None:
continue
org = q['query']
queries[i]['query'] = self.rewrite_single(org)
eprint("Rewritten statement\n\tfrom {}\n\t to {}".format(org, q['query']))
Expand Down Expand Up @@ -136,30 +138,44 @@ def colname_htable(query):
% endfor
struct db_query db_${f}_queries[] = {
const struct db_query db_${f}_queries[] = {
% for elem in queries:
{
% if elem['name'] is not None:
.name = "${elem['name']}",
.query = "${elem['query']}",
.placeholders = ${elem['placeholders']},
.readonly = ${elem['readonly']},
% if elem['colnames'] is not None:
.colnames = ${elem['colnames']},
.num_colnames = ARRAY_SIZE(${elem['colnames']}),
% endif
% endif
},
% endfor
};
#define DB_${f.upper()}_QUERY_COUNT ${len(queries)}
#endif /* HAVE_${f.upper()} */
#endif /* LIGHTNINGD_WALLET_GEN_DB_${f.upper()} */
""")


def queries_htable(queries):
# Converts a list of queries into a hash table.
tablesize = len(queries) * 2 - 1
htable = [{'name': None}] * tablesize

for q in queries:
pos = hash_djb2(q['name']) % tablesize
while htable[pos]['name'] is not None:
pos = (pos + 1) % tablesize
htable[pos] = q

return htable


def extract_queries(pofile):
# Given a po-file, extract all queries and their associated names, and
# return them as a list.
Expand Down Expand Up @@ -204,7 +220,7 @@ def chunk(pofile):
'readonly': "true" if is_select else "false",
'colnames': colnames,
})
return colhtables, queries
return colhtables, queries_htable(queries)


if __name__ == "__main__":
Expand Down
33 changes: 17 additions & 16 deletions wallet/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -903,12 +903,20 @@ static void db_stmt_free(struct db_stmt *stmt)
assert(stmt->inner_stmt == NULL);
}

/* Matches the hash function used in devtools/sql-rewrite.py */
static u32 hash_djb2(const char *str)
{
u32 hash = 5381;
for (size_t i = 0; str[i]; i++)
hash = ((hash << 5) + hash) ^ str[i];
return hash;
}

struct db_stmt *db_prepare_v2_(const char *location, struct db *db,
const char *query_id)
{
struct db_stmt *stmt = tal(db, struct db_stmt);
size_t num_slots;
stmt->query = NULL;
size_t num_slots, pos;

/* Normalize query_id paths, because unit tests are compiled with this
* prefix. */
Expand All @@ -920,14 +928,16 @@ struct db_stmt *db_prepare_v2_(const char *location, struct db *db,
"transaction: %s", location);

/* Look up the query by its ID */
for (size_t i = 0; i < db->config->num_queries; i++) {
if (streq(query_id, db->config->queries[i].name)) {
stmt->query = &db->config->queries[i];
pos = hash_djb2(query_id) % db->config->query_table_size;
for (;;) {
if (!db->config->query_table[pos].name)
fatal("Could not resolve query %s", query_id);
if (streq(query_id, db->config->query_table[pos].name)) {
stmt->query = &db->config->query_table[pos];
break;
}
pos = (pos + 1) % db->config->query_table_size;
}
if (stmt->query == NULL)
fatal("Could not resolve query %s", query_id);

num_slots = stmt->query->placeholders;
/* Allocate the slots for placeholders/bindings, zeroed next since
Expand Down Expand Up @@ -2335,15 +2345,6 @@ const char **db_changes(struct db *db)
return db->changes;
}

/* Matches the hash function used in devtools/sql-rewrite.py */
static u32 hash_djb2(const char *str)
{
u32 hash = 5381;
for (size_t i = 0; str[i]; i++)
hash = ((hash << 5) + hash) ^ str[i];
return hash;
}

size_t db_query_colnum(const struct db_stmt *stmt,
const char *colname)
{
Expand Down
6 changes: 3 additions & 3 deletions wallet/db_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ struct db_stmt {
struct db *db;

/* Which SQL statement are we trying to execute? */
struct db_query *query;
const struct db_query *query;

/* Which parameters are we binding to the statement? */
struct db_binding *bindings;
Expand All @@ -109,8 +109,8 @@ struct db_stmt {

struct db_config {
const char *name;
struct db_query *queries;
size_t num_queries;
const struct db_query *query_table;
size_t query_table_size;

/* Function used to execute a statement that doesn't result in a
* response. */
Expand Down
4 changes: 2 additions & 2 deletions wallet/db_postgres.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ static bool db_postgres_vacuum(struct db *db)

struct db_config db_postgres_config = {
.name = "postgres",
.queries = db_postgres_queries,
.num_queries = DB_POSTGRES_QUERY_COUNT,
.query_table = db_postgres_queries,
.query_table_size = ARRAY_SIZE(db_postgres_queries),
.exec_fn = db_postgres_exec,
.query_fn = db_postgres_query,
.step_fn = db_postgres_step,
Expand Down
4 changes: 2 additions & 2 deletions wallet/db_sqlite3.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,8 @@ static bool db_sqlite3_vacuum(struct db *db)

struct db_config db_sqlite3_config = {
.name = "sqlite3",
.queries = db_sqlite3_queries,
.num_queries = DB_SQLITE3_QUERY_COUNT,
.query_table = db_sqlite3_queries,
.query_table_size = ARRAY_SIZE(db_sqlite3_queries),
.exec_fn = &db_sqlite3_exec,
.query_fn = &db_sqlite3_query,
.step_fn = &db_sqlite3_step,
Expand Down

0 comments on commit fcf3d0c

Please sign in to comment.