From 56f4b32ef3c51d3ce8e3340bd2659442f8ed2899 Mon Sep 17 00:00:00 2001 From: chme Date: Sun, 13 Sep 2015 09:10:42 +0200 Subject: [PATCH] Add option to enable memory-mapped I/O --- forked-daapd.conf.in | 10 ++++++ src/cache.c | 19 ++++++++++++ src/conffile.c | 2 ++ src/db.c | 72 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+) diff --git a/forked-daapd.conf.in b/forked-daapd.conf.in index 3cad147b..a80d315a 100644 --- a/forked-daapd.conf.in +++ b/forked-daapd.conf.in @@ -315,6 +315,16 @@ sqlite { # Change the setting of the "synchronous" flag # 0: OFF, 1: NORMAL, 2: FULL (default) # pragma_synchronous = 2 + + # Number of bytes set aside for memory-mapped I/O for the library database + # (requires sqlite 3.7.17 or later) + # 0: disables mmap (default), any other value > 0: number of bytes for mmap +# pragma_mmap_size_library = 0 + + # Number of bytes set aside for memory-mapped I/O for the cache database + # (requires sqlite 3.7.17 or later) + # 0: disables mmap (default), any other value > 0: number of bytes for mmap +# pragma_mmap_size_cache = 0 # Should the database be vacuumed on startup? (increases startup time, # but may reduce database size). Default is yes. diff --git a/src/cache.c b/src/cache.c index e1276a59..d91aae4a 100644 --- a/src/cache.c +++ b/src/cache.c @@ -445,11 +445,13 @@ cache_create(void) #define Q_PRAGMA_CACHE_SIZE "PRAGMA cache_size=%d;" #define Q_PRAGMA_JOURNAL_MODE "PRAGMA journal_mode=%s;" #define Q_PRAGMA_SYNCHRONOUS "PRAGMA synchronous=%d;" +#define Q_PRAGMA_MMAP_SIZE "PRAGMA mmap_size=%d;" char *errmsg; int ret; int cache_size; char *journal_mode; int synchronous; + int mmap_size; char *query; // Open db @@ -534,12 +536,29 @@ cache_create(void) } } + // Set mmap size + mmap_size = cfg_getint(cfg_getsec(cfg, "sqlite"), "pragma_mmap_size_cache"); + if (synchronous > -1) + { + query = sqlite3_mprintf(Q_PRAGMA_MMAP_SIZE, mmap_size); + ret = sqlite3_exec(g_db_hdl, query, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) + { + DPRINTF(E_LOG, L_CACHE, "Error setting pragma_mmap_size: %s\n", errmsg); + + sqlite3_free(errmsg); + sqlite3_close(g_db_hdl); + return -1; + } + } + DPRINTF(E_DBG, L_CACHE, "Cache created\n"); return 0; #undef Q_PRAGMA_CACHE_SIZE #undef Q_PRAGMA_JOURNAL_MODE #undef Q_PRAGMA_SYNCHRONOUS +#undef Q_PRAGMA_MMAP_SIZE } static void diff --git a/src/conffile.c b/src/conffile.c index 302ea57e..a40139ec 100644 --- a/src/conffile.c +++ b/src/conffile.c @@ -151,6 +151,8 @@ static cfg_opt_t sec_sqlite[] = CFG_INT("pragma_cache_size_cache", -1, CFGF_NONE), CFG_STR("pragma_journal_mode", NULL, CFGF_NONE), CFG_INT("pragma_synchronous", -1, CFGF_NONE), + CFG_INT("pragma_mmap_size_library", -1, CFGF_NONE), + CFG_INT("pragma_mmap_size_cache", -1, CFGF_NONE), CFG_BOOL("vacuum", cfg_true, CFGF_NONE), CFG_END() }; diff --git a/src/db.c b/src/db.c index ed179942..1020a62a 100644 --- a/src/db.c +++ b/src/db.c @@ -6037,6 +6037,70 @@ db_pragma_set_synchronous(int synchronous) #undef Q_TMPL } +static int +db_pragma_get_mmap_size() +{ + sqlite3_stmt *stmt; + char *query = "PRAGMA mmap_size;"; + int ret; + + DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query); + + ret = db_blocking_prepare_v2(query, -1, &stmt, NULL); + if (ret != SQLITE_OK) + { + DPRINTF(E_LOG, L_DB, "Could not prepare statement: %s\n", sqlite3_errmsg(hdl)); + + sqlite3_free(query); + return 0; + } + + ret = db_blocking_step(stmt); + if (ret == SQLITE_DONE) + { + DPRINTF(E_DBG, L_DB, "End of query results\n"); + sqlite3_free(query); + return 0; + } + else if (ret != SQLITE_ROW) + { + DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl)); + sqlite3_free(query); + return -1; + } + + ret = sqlite3_column_int(stmt, 0); + + sqlite3_finalize(stmt); + return ret; +} + +static int +db_pragma_set_mmap_size(int mmap_size) +{ +#define Q_TMPL "PRAGMA mmap_size=%d;" + sqlite3_stmt *stmt; + char *query; + int ret; + + query = sqlite3_mprintf(Q_TMPL, mmap_size); + DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query); + + ret = db_blocking_prepare_v2(query, -1, &stmt, NULL); + if (ret != SQLITE_OK) + { + DPRINTF(E_LOG, L_DB, "Could not prepare statement: %s\n", sqlite3_errmsg(hdl)); + + sqlite3_free(query); + return 0; + } + + sqlite3_finalize(stmt); + sqlite3_free(query); + return 0; +#undef Q_TMPL +} + int @@ -6047,6 +6111,7 @@ db_perthread_init(void) int cache_size; char *journal_mode; int synchronous; + int mmap_size; ret = sqlite3_open(db_path, &hdl); if (ret != SQLITE_OK) @@ -6118,6 +6183,13 @@ db_perthread_init(void) DPRINTF(E_DBG, L_DB, "Database synchronous: %d\n", synchronous); } + mmap_size = cfg_getint(cfg_getsec(cfg, "sqlite"), "pragma_mmap_size_library"); + if (mmap_size > -1) + { + db_pragma_set_mmap_size(mmap_size); + mmap_size = db_pragma_get_mmap_size(); + DPRINTF(E_DBG, L_DB, "Database mmap_size: %d\n", mmap_size); + } return 0; }