diff --git a/daemon/cli.c b/daemon/cli.c index 906fa9ed3..46c91dbf0 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -1831,7 +1831,12 @@ static void cli_incoming_media_list_files(str *instr, struct cli_writer *cw, con str_q list = media_player_list_files(); while (list.head) { str *name = t_queue_pop_head(&list); - cw->cw_printf(cw, STR_FORMAT "\n", STR_FMT(name)); + time_t atime, mtime; + if (media_player_get_file_times(name, &mtime, &atime)) + cw->cw_printf(cw, STR_FORMAT ", loaded %lu s ago, last used %lu s ago\n", + STR_FMT(name), + (long) rtpe_now.tv_sec - mtime, + (long) rtpe_now.tv_sec - atime); str_free(name); } } @@ -1839,8 +1844,13 @@ static void cli_incoming_media_list_files(str *instr, struct cli_writer *cw, con static void cli_incoming_media_list_dbs(str *instr, struct cli_writer *cw, const cli_handler_t *handler) { GQueue list = media_player_list_dbs(); while (list.head) { - void *id = g_queue_pop_head(&list); - cw->cw_printf(cw, "%llu\n", (unsigned long long) GPOINTER_TO_UINT(id)); + void *idp = g_queue_pop_head(&list); + unsigned long long id = GPOINTER_TO_UINT(idp); + time_t atime, mtime; + if (media_player_get_db_times(id, &mtime, &atime)) + cw->cw_printf(cw, "%llu, loaded %lu s ago, last used %lu s ago\n", id, + (long) rtpe_now.tv_sec - mtime, + (long) rtpe_now.tv_sec - atime); } } @@ -2001,8 +2011,13 @@ static void cli_incoming_media_evict_dbs(str *instr, struct cli_writer *cw, cons static void cli_incoming_media_list_caches(str *instr, struct cli_writer *cw, const cli_handler_t *handler) { GQueue list = media_player_list_caches(); while (list.head) { - void *id = g_queue_pop_head(&list); - cw->cw_printf(cw, "%llu\n", (unsigned long long) GPOINTER_TO_UINT(id)); + void *idp = g_queue_pop_head(&list); + unsigned long long id = GPOINTER_TO_UINT(idp); + time_t atime, mtime; + if (media_player_get_cache_times(id, &mtime, &atime)) + cw->cw_printf(cw, "%llu, loaded %lu s ago, last used %lu s ago\n", id, + (long) rtpe_now.tv_sec - mtime, + (long) rtpe_now.tv_sec - atime); } } diff --git a/daemon/media_player.c b/daemon/media_player.c index 45a3a9a4e..de0fa1246 100644 --- a/daemon/media_player.c +++ b/daemon/media_player.c @@ -97,7 +97,8 @@ struct media_player_media_file { str_list *str_link; GList *gen_link; }; - time_t ts; + time_t mtime; + time_t atime; }; static mutex_t media_player_cache_lock = MUTEX_STATIC_INIT; @@ -1239,7 +1240,7 @@ static struct media_player_media_file *media_player_media_file_new(str blob) { fo->blob = blob; fo->blob.dup = call_ref; // string is allocated by reference on `fo` RTPE_GAUGE_ADD(media_cache, blob.len); - fo->ts = time(NULL); + fo->atime = fo->mtime = rtpe_now.tv_sec; return fo; } @@ -1287,6 +1288,7 @@ static struct media_player_media_file *media_player_media_files_get_only(const s return NULL; obj_hold(fo); + fo->atime = rtpe_now.tv_sec; } return fo; @@ -1305,6 +1307,7 @@ static struct media_player_media_file *media_player_db_id_get_only(unsigned long return NULL; obj_hold(fo); + fo->atime = rtpe_now.tv_sec; } return fo; @@ -1900,6 +1903,10 @@ static mp_cached_code __media_player_add_db(struct media_player *mp, // use a `media_player_media_file` object to hold a reference on the g_malloc'd // data to avoid having to memcpy it fo = media_player_media_file_new(STR_LEN(buf, len)); + utimensat(AT_FDCWD, fn, + (struct timespec[2]) + { { .tv_nsec = UTIME_NOW }, { .tv_nsec = UTIME_OMIT } }, + 0); return media_player_set_media_file(mp, opts, dst_pt, fo); } if (ret) // zero-length file @@ -2212,7 +2219,7 @@ bool media_player_reload_file(str *name) { if (fail) ilog(LOG_WARN, "Failed to stat() media file '" STR_FORMAT "': %s", STR_FMT(name), strerror(errno)); - else if (sb.st_mtim.tv_sec > fo->ts) { + else if (sb.st_mtim.tv_sec > fo->mtime) { __auto_type fonew = media_player_media_file_read_c(file_s); if (fonew) { // got a new entry. swap it out against the old one @@ -2475,6 +2482,34 @@ GQueue media_player_list_dbs(void) { return ret; } +bool media_player_get_file_times(const str *s, time_t *mtime, time_t *atime) { +#ifdef WITH_TRANSCODING + LOCK(&media_player_media_files_lock); + __auto_type fo = t_hash_table_lookup(media_player_media_files, s); + if (!fo) + return false; + *mtime = fo->mtime; + *atime = fo->atime; + return true; +#else + return false; +#endif +} + +bool media_player_get_db_times(unsigned long long id, time_t *mtime, time_t *atime) { +#ifdef WITH_TRANSCODING + LOCK(&media_player_db_media_lock); + __auto_type fo = t_hash_table_lookup(media_player_db_media, GUINT_TO_POINTER(id)); + if (!fo) + return false; + *mtime = fo->mtime; + *atime = fo->atime; + return true; +#else + return false; +#endif +} + G_DEFINE_AUTOPTR_CLEANUP_FUNC(DIR, closedir) typedef union { @@ -2516,6 +2551,21 @@ GQueue media_player_list_caches(void) { return ret; } +bool media_player_get_cache_times(unsigned long long id, time_t *mtime, time_t *atime) { +#ifdef WITH_TRANSCODING + g_autoptr(char) fn = media_player_make_cache_entry_name(id); + struct stat sb; + int fail = stat(fn, &sb); + if (fail) + return false; + *mtime = sb.st_mtim.tv_sec; + *atime = sb.st_atim.tv_sec; + return true; +#else + return false; +#endif +} + bool media_player_evict_cache(unsigned long long id) { #ifdef WITH_TRANSCODING g_autoptr(char) fn = media_player_make_cache_entry_name(id); diff --git a/include/media_player.h b/include/media_player.h index d1df3753f..6bdef6d8d 100644 --- a/include/media_player.h +++ b/include/media_player.h @@ -166,6 +166,9 @@ unsigned int media_player_evict_db_medias(void); str_q media_player_list_files(void); GQueue media_player_list_dbs(void); GQueue media_player_list_caches(void); +bool media_player_get_file_times(const str *, time_t *mtime, time_t *atime); +bool media_player_get_db_times(unsigned long long, time_t *mtime, time_t *atime); +bool media_player_get_cache_times(unsigned long long, time_t *mtime, time_t *atime); bool media_player_evict_cache(unsigned long long); unsigned int media_player_evict_caches(void); bool media_player_preload_cache(char **);