/*
This file is part of GNUnet
(C) 2009 Christian Grothoff (and other contributing authors)
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2, or (at your
option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNUnet; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/**
* @file datastore/plugin_datastore_sqlite.c
* @brief sqlite-based datastore backend
* @author Christian Grothoff
*/
#include "platform.h"
#include "gnunet_statistics_service.h"
#include "plugin_datastore.h"
#include <sqlite3.h>
#define DEBUG_SQLITE GNUNET_YES
/**
* After how many payload-changing operations
* do we sync our statistics?
*/
#define MAX_STAT_SYNC_LAG 50
#define QUOTA_STAT_NAME gettext_noop ("file-sharing datastore utilization (in bytes)")
/**
* Die with an error message that indicates
* a failure of the command 'cmd' with the message given
* by strerror(errno).
*/
#define DIE_SQLITE(db, cmd) do { GNUNET_log_from(GNUNET_ERROR_TYPE_ERROR, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); abort(); } while(0)
/**
* Log an error message at log-level 'level' that indicates
* a failure of the command 'cmd' on file 'filename'
* with the message given by strerror(errno).
*/
#define LOG_SQLITE(db, msg, level, cmd) do { GNUNET_log_from (level, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); if (msg != NULL) GNUNET_asprintf(msg, _("`%s' failed with error: %s\n"), cmd, sqlite3_errmsg(db->dbh)); } while(0)
#define SELECT_IT_LOW_PRIORITY_1 \
"SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio = ? AND hash > ?) "\
"ORDER BY hash ASC LIMIT 1"
#define SELECT_IT_LOW_PRIORITY_2 \
"SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio > ?) "\
"ORDER BY prio ASC, hash ASC LIMIT 1"
#define SELECT_IT_NON_ANONYMOUS_1 \
"SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio = ? AND hash < ? AND anonLevel = 0 AND expire > %llu) "\
" ORDER BY hash DESC LIMIT 1"
#define SELECT_IT_NON_ANONYMOUS_2 \
"SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio < ? AND anonLevel = 0 AND expire > %llu)"\
" ORDER BY prio DESC, hash DESC LIMIT 1"
#define SELECT_IT_EXPIRATION_TIME_1 \
"SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (expire = ? AND hash > ?) "\
" ORDER BY hash ASC LIMIT 1"
#define SELECT_IT_EXPIRATION_TIME_2 \
"SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (expire > ?) "\
" ORDER BY expire ASC, hash ASC LIMIT 1"
#define SELECT_IT_MIGRATION_ORDER_1 \
"SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (expire = ? AND hash < ?) "\
" ORDER BY hash DESC LIMIT 1"
#define SELECT_IT_MIGRATION_ORDER_2 \
"SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (expire < ? AND expire > %llu) "\
" ORDER BY expire DESC, hash DESC LIMIT 1"
/**
* After how many ms "busy" should a DB operation fail for good?
* A low value makes sure that we are more responsive to requests
* (especially PUTs). A high value guarantees a higher success
* rate (SELECTs in iterate can take several seconds despite LIMIT=1).
*
* The default value of 250ms should ensure that users do not experience
* huge latencies while at the same time allowing operations to succeed
* with reasonable probability.
*/
#define BUSY_TIMEOUT_MS 250
/**
* Context for all functions in this plugin.
*/
struct Plugin
{
/**
* Our execution environment.
*/
struct GNUNET_DATASTORE_PluginEnvironment *env;
/**
* Database filename.
*/
char *fn;
/**
* Native SQLite database handle.
*/
sqlite3 *dbh;
/**
* Precompiled SQL for update.
*/
sqlite3_stmt *updPrio;
/**
* Precompiled SQL for insertion.
*/
sqlite3_stmt *insertContent;
/**
* Handle to the statistics service.
*/
struct GNUNET_STATISTICS_Handle *statistics;
/**
* How much data are we currently storing
* in the database?
*/
unsigned long long payload;