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_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 {
|
||||
char *path;
|
||||
time_t mtime;
|
||||
|
@ -156,8 +170,9 @@ pop_dir(struct stacked_dir **s)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Checks if the file extension is in the ignore list */
|
||||
static int
|
||||
ignore_filetype(char *ext)
|
||||
file_type_ignore(const char *ext)
|
||||
{
|
||||
cfg_t *lib;
|
||||
int n;
|
||||
|
@ -175,6 +190,66 @@ ignore_filetype(char *ext)
|
|||
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
|
||||
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;
|
||||
char *filename;
|
||||
char *ext;
|
||||
time_t stamp;
|
||||
int id;
|
||||
int ret;
|
||||
|
@ -456,33 +530,6 @@ filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct
|
|||
else
|
||||
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);
|
||||
|
||||
if (stamp && (stamp >= mtime))
|
||||
|
@ -593,20 +640,15 @@ filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct
|
|||
static void
|
||||
process_playlist(char *file, time_t mtime)
|
||||
{
|
||||
char *ext;
|
||||
enum file_type ft;
|
||||
|
||||
ext = strrchr(file, '.');
|
||||
if (ext)
|
||||
{
|
||||
if (strcasecmp(ext, ".m3u") == 0)
|
||||
scan_playlist(file, mtime);
|
||||
else if (strcasecmp(ext, ".pls") == 0)
|
||||
scan_playlist(file, mtime);
|
||||
ft = file_type_get(file);
|
||||
if (ft == FILE_PLAYLIST)
|
||||
scan_playlist(file, mtime);
|
||||
#ifdef ITUNES
|
||||
else if (strcasecmp(ext, ".xml") == 0)
|
||||
scan_itunes_itml(file);
|
||||
else if (ft == FILE_ITUNES)
|
||||
scan_itunes_itml(file);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Thread: scan */
|
||||
|
@ -656,9 +698,6 @@ process_deferred_playlists(void)
|
|||
free(pl->path);
|
||||
free(pl);
|
||||
|
||||
/* Run the event loop */
|
||||
event_base_loop(evbase_scan, EVLOOP_ONCE | EVLOOP_NONBLOCK);
|
||||
|
||||
if (scan_exit)
|
||||
return;
|
||||
}
|
||||
|
@ -668,94 +707,76 @@ process_deferred_playlists(void)
|
|||
static void
|
||||
process_file(char *file, time_t mtime, off_t size, int type, int flags)
|
||||
{
|
||||
char *ext;
|
||||
|
||||
ext = strrchr(file, '.');
|
||||
if (ext)
|
||||
switch (file_type_get(file))
|
||||
{
|
||||
if ((strcasecmp(ext, ".m3u") == 0)
|
||||
|| (strcasecmp(ext, ".pls") == 0)
|
||||
#ifdef ITUNES
|
||||
|| (strcasecmp(ext, ".xml") == 0)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (flags & F_SCAN_BULK)
|
||||
defer_playlist(file, mtime);
|
||||
else
|
||||
process_playlist(file, mtime);
|
||||
case FILE_REGULAR:
|
||||
filescanner_process_media(file, mtime, size, type, NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (strcmp(ext, ".remote") == 0)
|
||||
{
|
||||
remote_pairing_read_pin(file);
|
||||
counter++;
|
||||
|
||||
/* When in bulk mode, split transaction in pieces of 200 */
|
||||
if ((flags & F_SCAN_BULK) && (counter % 200 == 0))
|
||||
{
|
||||
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
|
||||
else if (strcmp(ext, ".lastfm") == 0)
|
||||
{
|
||||
lastfm_login(file);
|
||||
|
||||
return;
|
||||
}
|
||||
case FILE_CTRL_LASTFM:
|
||||
lastfm_login(file);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SPOTIFY_H
|
||||
else if (strcmp(ext, ".spotify") == 0)
|
||||
{
|
||||
spotify_login(file);
|
||||
|
||||
return;
|
||||
}
|
||||
case FILE_CTRL_SPOTIFY:
|
||||
spotify_login(file);
|
||||
break;
|
||||
#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();
|
||||
bulk_scan(F_SCAN_BULK);
|
||||
case FILE_CTRL_INITSCAN:
|
||||
if (flags & F_SCAN_BULK)
|
||||
break;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
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();
|
||||
DPRINTF(E_LOG, L_SCAN, "Startup rescan triggered, found init-rescan file: %s\n", file);
|
||||
|
||||
inofd_event_set();
|
||||
bulk_scan(F_SCAN_BULK | F_SCAN_RESCAN);
|
||||
inofd_event_unset(); // Clears all inotify watches
|
||||
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 */
|
||||
filescanner_process_media(file, mtime, size, type, NULL);
|
||||
case FILE_CTRL_FULLSCAN:
|
||||
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 */
|
||||
if ((flags & F_SCAN_BULK) && (counter % 200 == 0))
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Scanned %d files...\n", counter);
|
||||
db_transaction_end();
|
||||
db_transaction_begin();
|
||||
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();
|
||||
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
|
||||
process_directory(char *path, int flags)
|
||||
{
|
||||
struct stacked_dir *bulkstack;
|
||||
DIR *dirp;
|
||||
struct dirent buf;
|
||||
struct dirent *de;
|
||||
|
@ -796,24 +816,6 @@ process_directory(char *path, int flags)
|
|||
int type;
|
||||
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);
|
||||
|
||||
dirp = opendir(path);
|
||||
|
@ -835,6 +837,9 @@ process_directory(char *path, int flags)
|
|||
|
||||
for (;;)
|
||||
{
|
||||
if (scan_exit)
|
||||
break;
|
||||
|
||||
ret = readdir_r(dirp, &buf, &de);
|
||||
if (ret != 0)
|
||||
{
|
||||
|
@ -1074,8 +1079,20 @@ bulk_scan(int flags)
|
|||
static void *
|
||||
filescanner(void *arg)
|
||||
{
|
||||
struct sched_param param;
|
||||
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();
|
||||
if (ret < 0)
|
||||
{
|
||||
|
@ -1112,12 +1129,12 @@ filescanner(void *arg)
|
|||
else
|
||||
bulk_scan(F_SCAN_BULK);
|
||||
|
||||
#ifdef HAVE_SPOTIFY_H
|
||||
spotify_login(NULL);
|
||||
#endif
|
||||
|
||||
if (!scan_exit)
|
||||
{
|
||||
#ifdef HAVE_SPOTIFY_H
|
||||
spotify_login(NULL);
|
||||
#endif
|
||||
|
||||
/* Enable inotify */
|
||||
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);;
|
||||
}
|
||||
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);
|
||||
|
||||
|
@ -1787,13 +1804,6 @@ exit_cb(int fd, short event, void *arg)
|
|||
scan_exit = 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
filescanner_status(void)
|
||||
{
|
||||
return scan_exit;
|
||||
}
|
||||
|
||||
/* Thread: main */
|
||||
int
|
||||
filescanner_init(void)
|
||||
|
@ -1897,6 +1907,8 @@ filescanner_deinit(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
scan_exit = 1;
|
||||
|
||||
ret = pthread_join(tid_scan, NULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
|
|
|
@ -18,9 +18,6 @@ filescanner_init(void);
|
|||
void
|
||||
filescanner_deinit(void);
|
||||
|
||||
int
|
||||
filescanner_status(void);
|
||||
|
||||
void
|
||||
filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct media_file_info *external_mfi);
|
||||
|
||||
|
|
Loading…
Reference in New Issue