mirror of
https://github.com/owntone/owntone-server.git
synced 2025-04-15 16:48:22 -04:00
Fix filescanner bugs:
- stop init-rescan/full-rescan from running twice - set thread priority to batch - don't request libevent to loop when the loop is already running
This commit is contained in:
commit
8c9793d9ef
@ -76,6 +76,20 @@
|
|||||||
#define F_SCAN_FAST (1 << 2)
|
#define F_SCAN_FAST (1 << 2)
|
||||||
#define F_SCAN_MOVED (1 << 3)
|
#define F_SCAN_MOVED (1 << 3)
|
||||||
|
|
||||||
|
enum file_type {
|
||||||
|
FILE_UNKNOWN = 0,
|
||||||
|
FILE_IGNORE,
|
||||||
|
FILE_REGULAR,
|
||||||
|
FILE_PLAYLIST,
|
||||||
|
FILE_ITUNES,
|
||||||
|
FILE_ARTWORK,
|
||||||
|
FILE_CTRL_REMOTE,
|
||||||
|
FILE_CTRL_LASTFM,
|
||||||
|
FILE_CTRL_SPOTIFY,
|
||||||
|
FILE_CTRL_INITSCAN,
|
||||||
|
FILE_CTRL_FULLSCAN,
|
||||||
|
};
|
||||||
|
|
||||||
struct deferred_pl {
|
struct deferred_pl {
|
||||||
char *path;
|
char *path;
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
@ -156,8 +170,9 @@ pop_dir(struct stacked_dir **s)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Checks if the file extension is in the ignore list */
|
||||||
static int
|
static int
|
||||||
ignore_filetype(char *ext)
|
file_type_ignore(const char *ext)
|
||||||
{
|
{
|
||||||
cfg_t *lib;
|
cfg_t *lib;
|
||||||
int n;
|
int n;
|
||||||
@ -175,6 +190,66 @@ ignore_filetype(char *ext)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum file_type
|
||||||
|
file_type_get(const char *path) {
|
||||||
|
const char *filename;
|
||||||
|
const char *ext;
|
||||||
|
|
||||||
|
filename = strrchr(path, '/');
|
||||||
|
if ((!filename) || (strlen(filename) == 1))
|
||||||
|
filename = path;
|
||||||
|
else
|
||||||
|
filename++;
|
||||||
|
|
||||||
|
ext = strrchr(path, '.');
|
||||||
|
if (!ext || (strlen(ext) == 1))
|
||||||
|
return FILE_REGULAR;
|
||||||
|
|
||||||
|
if ((strcasecmp(ext, ".m3u") == 0) || (strcasecmp(ext, ".pls") == 0))
|
||||||
|
return FILE_PLAYLIST;
|
||||||
|
|
||||||
|
if ((strcasecmp(ext, ".png") == 0) || (strcasecmp(ext, ".jpg") == 0))
|
||||||
|
return FILE_ARTWORK;
|
||||||
|
|
||||||
|
#ifdef ITUNES
|
||||||
|
if (strcasecmp(ext, ".xml") == 0)
|
||||||
|
return FILE_ITUNES;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (strcasecmp(ext, ".remote") == 0)
|
||||||
|
return FILE_CTRL_REMOTE;
|
||||||
|
|
||||||
|
#ifdef LASTFM
|
||||||
|
if (strcasecmp(ext, ".lastfm") == 0)
|
||||||
|
return FILE_CTRL_LASTFM;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SPOTIFY_H
|
||||||
|
if (strcasecmp(ext, ".spotify") == 0)
|
||||||
|
return FILE_CTRL_SPOTIFY;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (strcasecmp(ext, ".init-rescan") == 0)
|
||||||
|
return FILE_CTRL_INITSCAN;
|
||||||
|
|
||||||
|
if (strcasecmp(ext, ".full-rescan") == 0)
|
||||||
|
return FILE_CTRL_FULLSCAN;
|
||||||
|
|
||||||
|
if (strcasecmp(ext, ".url") == 0)
|
||||||
|
{
|
||||||
|
DPRINTF(E_INFO, L_SCAN, "No support for .url, use .m3u or .pls\n");
|
||||||
|
return FILE_IGNORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_type_ignore(ext))
|
||||||
|
return FILE_IGNORE;
|
||||||
|
|
||||||
|
if ((filename[0] == '_') || (filename[0] == '.'))
|
||||||
|
return FILE_IGNORE;
|
||||||
|
|
||||||
|
return FILE_REGULAR;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sort_tag_create(char **sort_tag, char *src_tag)
|
sort_tag_create(char **sort_tag, char *src_tag)
|
||||||
{
|
{
|
||||||
@ -445,7 +520,6 @@ filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct
|
|||||||
{
|
{
|
||||||
struct media_file_info *mfi;
|
struct media_file_info *mfi;
|
||||||
char *filename;
|
char *filename;
|
||||||
char *ext;
|
|
||||||
time_t stamp;
|
time_t stamp;
|
||||||
int id;
|
int id;
|
||||||
int ret;
|
int ret;
|
||||||
@ -456,33 +530,6 @@ filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct
|
|||||||
else
|
else
|
||||||
filename++;
|
filename++;
|
||||||
|
|
||||||
/* File types which should never be processed */
|
|
||||||
ext = strrchr(path, '.');
|
|
||||||
if (ext)
|
|
||||||
{
|
|
||||||
if (strcasecmp(ext, ".url") == 0)
|
|
||||||
{
|
|
||||||
DPRINTF(E_INFO, L_SCAN, "No support for .url in this version, use .m3u or .pls\n");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if ((strcasecmp(ext, ".png") == 0) || (strcasecmp(ext, ".jpg") == 0))
|
|
||||||
{
|
|
||||||
/* Artwork files - don't scan */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if ((filename[0] == '_') || (filename[0] == '.'))
|
|
||||||
{
|
|
||||||
/* Hidden files - don't scan */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (ignore_filetype(ext))
|
|
||||||
{
|
|
||||||
/* File extension is in ignore list - don't scan */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
db_file_stamp_bypath(path, &stamp, &id);
|
db_file_stamp_bypath(path, &stamp, &id);
|
||||||
|
|
||||||
if (stamp && (stamp >= mtime))
|
if (stamp && (stamp >= mtime))
|
||||||
@ -593,20 +640,15 @@ filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct
|
|||||||
static void
|
static void
|
||||||
process_playlist(char *file, time_t mtime)
|
process_playlist(char *file, time_t mtime)
|
||||||
{
|
{
|
||||||
char *ext;
|
enum file_type ft;
|
||||||
|
|
||||||
ext = strrchr(file, '.');
|
ft = file_type_get(file);
|
||||||
if (ext)
|
if (ft == FILE_PLAYLIST)
|
||||||
{
|
scan_playlist(file, mtime);
|
||||||
if (strcasecmp(ext, ".m3u") == 0)
|
|
||||||
scan_playlist(file, mtime);
|
|
||||||
else if (strcasecmp(ext, ".pls") == 0)
|
|
||||||
scan_playlist(file, mtime);
|
|
||||||
#ifdef ITUNES
|
#ifdef ITUNES
|
||||||
else if (strcasecmp(ext, ".xml") == 0)
|
else if (ft == FILE_ITUNES)
|
||||||
scan_itunes_itml(file);
|
scan_itunes_itml(file);
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Thread: scan */
|
/* Thread: scan */
|
||||||
@ -656,9 +698,6 @@ process_deferred_playlists(void)
|
|||||||
free(pl->path);
|
free(pl->path);
|
||||||
free(pl);
|
free(pl);
|
||||||
|
|
||||||
/* Run the event loop */
|
|
||||||
event_base_loop(evbase_scan, EVLOOP_ONCE | EVLOOP_NONBLOCK);
|
|
||||||
|
|
||||||
if (scan_exit)
|
if (scan_exit)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -668,94 +707,76 @@ process_deferred_playlists(void)
|
|||||||
static void
|
static void
|
||||||
process_file(char *file, time_t mtime, off_t size, int type, int flags)
|
process_file(char *file, time_t mtime, off_t size, int type, int flags)
|
||||||
{
|
{
|
||||||
char *ext;
|
switch (file_type_get(file))
|
||||||
|
|
||||||
ext = strrchr(file, '.');
|
|
||||||
if (ext)
|
|
||||||
{
|
{
|
||||||
if ((strcasecmp(ext, ".m3u") == 0)
|
case FILE_REGULAR:
|
||||||
|| (strcasecmp(ext, ".pls") == 0)
|
filescanner_process_media(file, mtime, size, type, NULL);
|
||||||
#ifdef ITUNES
|
|
||||||
|| (strcasecmp(ext, ".xml") == 0)
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (flags & F_SCAN_BULK)
|
|
||||||
defer_playlist(file, mtime);
|
|
||||||
else
|
|
||||||
process_playlist(file, mtime);
|
|
||||||
|
|
||||||
return;
|
counter++;
|
||||||
}
|
|
||||||
else if (strcmp(ext, ".remote") == 0)
|
/* When in bulk mode, split transaction in pieces of 200 */
|
||||||
{
|
if ((flags & F_SCAN_BULK) && (counter % 200 == 0))
|
||||||
remote_pairing_read_pin(file);
|
{
|
||||||
|
DPRINTF(E_LOG, L_SCAN, "Scanned %d files...\n", counter);
|
||||||
|
db_transaction_end();
|
||||||
|
db_transaction_begin();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FILE_PLAYLIST:
|
||||||
|
case FILE_ITUNES:
|
||||||
|
if (flags & F_SCAN_BULK)
|
||||||
|
defer_playlist(file, mtime);
|
||||||
|
else
|
||||||
|
process_playlist(file, mtime);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FILE_CTRL_REMOTE:
|
||||||
|
remote_pairing_read_pin(file);
|
||||||
|
break;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#ifdef LASTFM
|
#ifdef LASTFM
|
||||||
else if (strcmp(ext, ".lastfm") == 0)
|
case FILE_CTRL_LASTFM:
|
||||||
{
|
lastfm_login(file);
|
||||||
lastfm_login(file);
|
break;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SPOTIFY_H
|
#ifdef HAVE_SPOTIFY_H
|
||||||
else if (strcmp(ext, ".spotify") == 0)
|
case FILE_CTRL_SPOTIFY:
|
||||||
{
|
spotify_login(file);
|
||||||
spotify_login(file);
|
break;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
else if (strcmp(ext, ".full-rescan") == 0)
|
|
||||||
{
|
|
||||||
if (flags & F_SCAN_BULK)
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_SCAN, "Forcing full rescan, found full-rescan file: %s\n", file);
|
|
||||||
player_playback_stop();
|
|
||||||
player_queue_clear();
|
|
||||||
inofd_event_unset(); // Clears all inotify watches
|
|
||||||
db_purge_all(); // Clears files, playlists, playlistitems, inotify and groups
|
|
||||||
|
|
||||||
inofd_event_set();
|
case FILE_CTRL_INITSCAN:
|
||||||
bulk_scan(F_SCAN_BULK);
|
if (flags & F_SCAN_BULK)
|
||||||
|
break;
|
||||||
|
|
||||||
return;
|
DPRINTF(E_LOG, L_SCAN, "Startup rescan triggered, found init-rescan file: %s\n", file);
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(ext, ".init-rescan") == 0)
|
|
||||||
{
|
|
||||||
if (flags & F_SCAN_BULK)
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_SCAN, "Forcing startup rescan, found init-rescan file: %s\n", file);
|
|
||||||
inofd_event_unset(); // Clears all inotify watches
|
|
||||||
db_watch_clear();
|
|
||||||
|
|
||||||
inofd_event_set();
|
inofd_event_unset(); // Clears all inotify watches
|
||||||
bulk_scan(F_SCAN_BULK | F_SCAN_RESCAN);
|
db_watch_clear();
|
||||||
|
|
||||||
return;
|
inofd_event_set();
|
||||||
}
|
bulk_scan(F_SCAN_BULK | F_SCAN_RESCAN);
|
||||||
}
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
/* Not any kind of special file, so let's see if it's a media file */
|
case FILE_CTRL_FULLSCAN:
|
||||||
filescanner_process_media(file, mtime, size, type, NULL);
|
if (flags & F_SCAN_BULK)
|
||||||
|
break;
|
||||||
|
|
||||||
counter++;
|
DPRINTF(E_LOG, L_SCAN, "Full rescan triggered, found full-rescan file: %s\n", file);
|
||||||
|
|
||||||
/* When in bulk mode, split transaction in pieces of 200 */
|
player_playback_stop();
|
||||||
if ((flags & F_SCAN_BULK) && (counter % 200 == 0))
|
player_queue_clear();
|
||||||
{
|
inofd_event_unset(); // Clears all inotify watches
|
||||||
DPRINTF(E_LOG, L_SCAN, "Scanned %d files...\n", counter);
|
db_purge_all(); // Clears files, playlists, playlistitems, inotify and groups
|
||||||
db_transaction_end();
|
|
||||||
db_transaction_begin();
|
inofd_event_set();
|
||||||
|
bulk_scan(F_SCAN_BULK);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DPRINTF(E_WARN, L_SCAN, "Ignoring file: %s\n", file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -782,7 +803,6 @@ check_speciallib(char *path, const char *libtype)
|
|||||||
static void
|
static void
|
||||||
process_directory(char *path, int flags)
|
process_directory(char *path, int flags)
|
||||||
{
|
{
|
||||||
struct stacked_dir *bulkstack;
|
|
||||||
DIR *dirp;
|
DIR *dirp;
|
||||||
struct dirent buf;
|
struct dirent buf;
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
@ -796,24 +816,6 @@ process_directory(char *path, int flags)
|
|||||||
int type;
|
int type;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (flags & F_SCAN_BULK)
|
|
||||||
{
|
|
||||||
/* Save our directory stack so it won't get handled inside
|
|
||||||
* the event loop - not its business, we're in bulk mode here.
|
|
||||||
*/
|
|
||||||
bulkstack = dirstack;
|
|
||||||
dirstack = NULL;
|
|
||||||
|
|
||||||
/* Run the event loop */
|
|
||||||
event_base_loop(evbase_scan, EVLOOP_ONCE | EVLOOP_NONBLOCK);
|
|
||||||
|
|
||||||
/* Restore our directory stack */
|
|
||||||
dirstack = bulkstack;
|
|
||||||
|
|
||||||
if (scan_exit)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_SCAN, "Processing directory %s (flags = 0x%x)\n", path, flags);
|
DPRINTF(E_DBG, L_SCAN, "Processing directory %s (flags = 0x%x)\n", path, flags);
|
||||||
|
|
||||||
dirp = opendir(path);
|
dirp = opendir(path);
|
||||||
@ -835,6 +837,9 @@ process_directory(char *path, int flags)
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
if (scan_exit)
|
||||||
|
break;
|
||||||
|
|
||||||
ret = readdir_r(dirp, &buf, &de);
|
ret = readdir_r(dirp, &buf, &de);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
@ -1074,8 +1079,20 @@ bulk_scan(int flags)
|
|||||||
static void *
|
static void *
|
||||||
filescanner(void *arg)
|
filescanner(void *arg)
|
||||||
{
|
{
|
||||||
|
struct sched_param param;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* Lower the priority of the thread so forked-daapd may still respond
|
||||||
|
* during file scan on low power devices. Param must be 0 for the SCHED_BATCH
|
||||||
|
* policy.
|
||||||
|
*/
|
||||||
|
memset(¶m, 0, sizeof(struct sched_param));
|
||||||
|
ret = pthread_setschedparam(pthread_self(), SCHED_BATCH, ¶m);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_SCAN, "Warning: Could not set thread priority to SCHED_BATCH\n");
|
||||||
|
}
|
||||||
|
|
||||||
ret = db_perthread_init();
|
ret = db_perthread_init();
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
@ -1112,12 +1129,12 @@ filescanner(void *arg)
|
|||||||
else
|
else
|
||||||
bulk_scan(F_SCAN_BULK);
|
bulk_scan(F_SCAN_BULK);
|
||||||
|
|
||||||
#ifdef HAVE_SPOTIFY_H
|
|
||||||
spotify_login(NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!scan_exit)
|
if (!scan_exit)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_SPOTIFY_H
|
||||||
|
spotify_login(NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Enable inotify */
|
/* Enable inotify */
|
||||||
event_add(&inoev, NULL);
|
event_add(&inoev, NULL);
|
||||||
|
|
||||||
@ -1340,7 +1357,7 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
|
|||||||
|
|
||||||
db_file_delete_bypath(path);;
|
db_file_delete_bypath(path);;
|
||||||
}
|
}
|
||||||
else if (db_file_id_bypath(path) <= 0)
|
else if ((file_type_get(path) == FILE_REGULAR) && (db_file_id_bypath(path) <= 0)) // TODO Playlists
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_SCAN, "File access to '%s' achieved\n", path);
|
DPRINTF(E_LOG, L_SCAN, "File access to '%s' achieved\n", path);
|
||||||
|
|
||||||
@ -1787,13 +1804,6 @@ exit_cb(int fd, short event, void *arg)
|
|||||||
scan_exit = 1;
|
scan_exit = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
filescanner_status(void)
|
|
||||||
{
|
|
||||||
return scan_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Thread: main */
|
/* Thread: main */
|
||||||
int
|
int
|
||||||
filescanner_init(void)
|
filescanner_init(void)
|
||||||
@ -1897,6 +1907,8 @@ filescanner_deinit(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
scan_exit = 1;
|
||||||
|
|
||||||
ret = pthread_join(tid_scan, NULL);
|
ret = pthread_join(tid_scan, NULL);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
|
@ -18,9 +18,6 @@ filescanner_init(void);
|
|||||||
void
|
void
|
||||||
filescanner_deinit(void);
|
filescanner_deinit(void);
|
||||||
|
|
||||||
int
|
|
||||||
filescanner_status(void);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct media_file_info *external_mfi);
|
filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct media_file_info *external_mfi);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user