mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-29 00:23:23 -05:00
[library/mpd] Store db update time in admin table and trigger DATABASE
event on init/rescan only if an update/insert occurred
This commit is contained in:
parent
ea0cc64aa3
commit
1cdb9f450d
141
src/library.c
141
src/library.c
@ -90,56 +90,24 @@ static bool scanning;
|
|||||||
static struct timeval library_update_wait = { 5, 0 };
|
static struct timeval library_update_wait = { 5, 0 };
|
||||||
static struct event *updateev;
|
static struct event *updateev;
|
||||||
|
|
||||||
static int library_deferred_commit_interval = 10;
|
// Counts the number of changes made to the database between to DATABASE
|
||||||
static unsigned int library_deferred_updates = 0;
|
// event notifications
|
||||||
static time_t library_deferred_update_time = 0;
|
static unsigned int deferred_update_notifications = 0;
|
||||||
static time_t library_update_time = 0;
|
|
||||||
|
|
||||||
static void
|
static bool
|
||||||
library_update_time_set(int deferred, time_t update_time)
|
handle_deferred_update_notifications(void)
|
||||||
{
|
{
|
||||||
time_t *use_update_time;
|
bool ret = (deferred_update_notifications > 0);
|
||||||
unsigned int last_deferred_count = library_deferred_updates;
|
|
||||||
int persist;
|
|
||||||
time_t now = time(NULL);
|
|
||||||
|
|
||||||
if (deferred)
|
if (ret)
|
||||||
{
|
{
|
||||||
use_update_time = &library_deferred_update_time;
|
DPRINTF(E_DBG, L_LIB, "Database changed (%d changes)\n", deferred_update_notifications);
|
||||||
++library_deferred_updates;
|
|
||||||
persist = (now - library_deferred_update_time) >=
|
deferred_update_notifications = 0;
|
||||||
library_deferred_commit_interval;
|
db_admin_setint64("db_update", (int64_t) time(NULL));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( !update_time && library_deferred_updates)
|
|
||||||
{
|
|
||||||
update_time = library_deferred_update_time;
|
|
||||||
}
|
|
||||||
use_update_time = &library_update_time;
|
|
||||||
library_deferred_updates = 0;
|
|
||||||
persist = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*use_update_time = update_time ? update_time : now;
|
return ret;
|
||||||
|
|
||||||
if ( persist )
|
|
||||||
{
|
|
||||||
/* |:todo:| persist update_time */
|
|
||||||
char stamp[32];
|
|
||||||
strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(use_update_time));
|
|
||||||
DPRINTF(E_LOG, L_LIB, "Store DB update time: %s (%3d)%s\n", stamp, last_deferred_count, deferred ? " (deferred)" : "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
library_handle_deferred_updates(void)
|
|
||||||
{
|
|
||||||
if (!scanning && library_deferred_updates)
|
|
||||||
{
|
|
||||||
library_update_time_set(0, 0);
|
|
||||||
listener_notify(LISTENER_DATABASE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -625,10 +593,13 @@ rescan(void *arg, int *ret)
|
|||||||
purge_cruft(starttime);
|
purge_cruft(starttime);
|
||||||
|
|
||||||
endtime = time(NULL);
|
endtime = time(NULL);
|
||||||
DPRINTF(E_LOG, L_LIB, "Library rescan completed in %.f sec (%d changes)\n", difftime(endtime, starttime), library_deferred_updates);
|
DPRINTF(E_LOG, L_LIB, "Library rescan completed in %.f sec (%d changes)\n", difftime(endtime, starttime), deferred_update_notifications);
|
||||||
scanning = false;
|
scanning = false;
|
||||||
listener_notify(LISTENER_UPDATE);
|
|
||||||
library_handle_deferred_updates();
|
if (handle_deferred_update_notifications())
|
||||||
|
listener_notify(LISTENER_UPDATE | LISTENER_DATABASE);
|
||||||
|
else
|
||||||
|
listener_notify(LISTENER_UPDATE);
|
||||||
|
|
||||||
*ret = 0;
|
*ret = 0;
|
||||||
return COMMAND_END;
|
return COMMAND_END;
|
||||||
@ -663,25 +634,40 @@ fullrescan(void *arg, int *ret)
|
|||||||
}
|
}
|
||||||
|
|
||||||
endtime = time(NULL);
|
endtime = time(NULL);
|
||||||
DPRINTF(E_LOG, L_LIB, "Library full-rescan completed in %.f sec (%d changes)\n", difftime(endtime, starttime), library_deferred_updates);
|
DPRINTF(E_LOG, L_LIB, "Library full-rescan completed in %.f sec (%d changes)\n", difftime(endtime, starttime), deferred_update_notifications);
|
||||||
scanning = false;
|
scanning = false;
|
||||||
listener_notify(LISTENER_UPDATE);
|
|
||||||
library_handle_deferred_updates();
|
if (handle_deferred_update_notifications())
|
||||||
|
listener_notify(LISTENER_UPDATE | LISTENER_DATABASE);
|
||||||
|
else
|
||||||
|
listener_notify(LISTENER_UPDATE);
|
||||||
|
|
||||||
*ret = 0;
|
*ret = 0;
|
||||||
return COMMAND_END;
|
return COMMAND_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback to notify listeners of database changes
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
update_trigger_cb(int fd, short what, void *arg)
|
update_trigger_cb(int fd, short what, void *arg)
|
||||||
{
|
{
|
||||||
library_handle_deferred_updates();
|
if (handle_deferred_update_notifications())
|
||||||
|
{
|
||||||
|
listener_notify(LISTENER_DATABASE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum command_state
|
static enum command_state
|
||||||
update_trigger(void *arg, int *retval)
|
update_trigger(void *arg, int *retval)
|
||||||
{
|
{
|
||||||
evtimer_add(updateev, &library_update_wait);
|
++deferred_update_notifications;
|
||||||
|
|
||||||
|
// Only add the timer event if the update occurred outside a (init-/re-/fullre-) scan.
|
||||||
|
// The scanning functions take care of notifying clients of database changes directly
|
||||||
|
// after the scan finished.
|
||||||
|
if (!scanning)
|
||||||
|
evtimer_add(updateev, &library_update_wait);
|
||||||
|
|
||||||
*retval = 0;
|
*retval = 0;
|
||||||
return COMMAND_END;
|
return COMMAND_END;
|
||||||
@ -750,11 +736,14 @@ initscan()
|
|||||||
}
|
}
|
||||||
|
|
||||||
endtime = time(NULL);
|
endtime = time(NULL);
|
||||||
DPRINTF(E_LOG, L_LIB, "Library init scan completed in %.f sec (%d changes)\n", difftime(endtime, starttime), library_deferred_updates);
|
DPRINTF(E_LOG, L_LIB, "Library init scan completed in %.f sec (%d changes)\n", difftime(endtime, starttime), deferred_update_notifications);
|
||||||
|
|
||||||
scanning = false;
|
scanning = false;
|
||||||
listener_notify(LISTENER_UPDATE);
|
|
||||||
library_handle_deferred_updates();
|
if (handle_deferred_update_notifications())
|
||||||
|
listener_notify(LISTENER_UPDATE | LISTENER_DATABASE);
|
||||||
|
else
|
||||||
|
listener_notify(LISTENER_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -784,23 +773,27 @@ library_is_exiting()
|
|||||||
return scan_exit;
|
return scan_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t
|
/*
|
||||||
library_update_time_get(void)
|
* Trigger for sending the DATABASE event
|
||||||
{
|
*
|
||||||
return library_update_time;
|
* Needs to be called, if an update to the database (library tables) occurred. The DATABASE event
|
||||||
}
|
* is emitted with the delay 'library_update_wait'. It is safe to call this function from any thread.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
library_update_trigger(void)
|
library_update_trigger(void)
|
||||||
{
|
{
|
||||||
library_update_time_set(1, 0);
|
int ret;
|
||||||
|
|
||||||
if (scanning)
|
pthread_t current_thread = pthread_self();
|
||||||
|
if (pthread_equal(current_thread, tid_library))
|
||||||
{
|
{
|
||||||
return;
|
// We are already running in the library thread, it is safe to directly call update_trigger
|
||||||
|
update_trigger(NULL, &ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commands_exec_async(cmdbase, update_trigger, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
commands_exec_async(cmdbase, update_trigger, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum command_state
|
static enum command_state
|
||||||
@ -1011,22 +1004,6 @@ library_init(void)
|
|||||||
|
|
||||||
CHECK_NULL(L_LIB, cmdbase = commands_base_new(evbase_lib, NULL));
|
CHECK_NULL(L_LIB, cmdbase = commands_base_new(evbase_lib, NULL));
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
/* |:todo:| replace with initialization of library_update_time from persistent storage */
|
|
||||||
const char *db_path = cfg_getstr(cfg_getsec(cfg, "general"), "db_path");
|
|
||||||
if (db_path)
|
|
||||||
{
|
|
||||||
struct stat sb;
|
|
||||||
ret = lstat(db_path, &sb);
|
|
||||||
if ( ret == 0 )
|
|
||||||
{
|
|
||||||
library_update_time = sb.st_mtim.tv_sec;
|
|
||||||
DPRINTF(E_DBG, L_LIB, "db_path %s has modified time %ld\n", db_path, library_update_time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK_ERR(L_LIB, pthread_create(&tid_library, NULL, library, NULL));
|
CHECK_ERR(L_LIB, pthread_create(&tid_library, NULL, library, NULL));
|
||||||
|
|
||||||
#if defined(HAVE_PTHREAD_SETNAME_NP)
|
#if defined(HAVE_PTHREAD_SETNAME_NP)
|
||||||
|
@ -115,9 +115,6 @@ library_set_scanning(bool is_scanning);
|
|||||||
bool
|
bool
|
||||||
library_is_exiting();
|
library_is_exiting();
|
||||||
|
|
||||||
time_t
|
|
||||||
library_update_time_get(void);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
library_update_trigger(void);
|
library_update_trigger(void);
|
||||||
|
|
||||||
|
18
src/mpd.c
18
src/mpd.c
@ -829,22 +829,22 @@ mpd_command_stats(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
|||||||
artists = db_files_get_artist_count();
|
artists = db_files_get_artist_count();
|
||||||
albums = db_files_get_album_count();
|
albums = db_files_get_album_count();
|
||||||
|
|
||||||
//TODO [mpd] Implement missing stats attributes (uptime, db_update, playtime)
|
//TODO [mpd] Implement missing stats attributes (uptime, playtime)
|
||||||
evbuffer_add_printf(evbuf,
|
evbuffer_add_printf(evbuf,
|
||||||
"artists: %d\n"
|
"artists: %d\n"
|
||||||
"albums: %d\n"
|
"albums: %d\n"
|
||||||
"songs: %d\n"
|
"songs: %d\n"
|
||||||
"uptime: %d\n" //in seceonds
|
"uptime: %d\n" //in seceonds
|
||||||
"db_playtime: %" PRIu64 "\n"
|
"db_playtime: %" PRIi64 "\n"
|
||||||
"db_update: %ld\n"
|
"db_update: %ld\n"
|
||||||
"playtime: %d\n",
|
"playtime: %d\n",
|
||||||
artists,
|
artists,
|
||||||
albums,
|
albums,
|
||||||
fci.count,
|
fci.count,
|
||||||
4,
|
4,
|
||||||
(fci.length / 1000),
|
(fci.length / 1000),
|
||||||
library_update_time_get(),
|
(time_t) db_admin_getint64("db_update"),
|
||||||
7);
|
7);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user