64
58
#define F_SCAN_BULK (1 << 0)
65
59
#define F_SCAN_RESCAN (1 << 1)
69
struct deferred_pl *next;
60
#define F_SCAN_NODUP (1 << 2)
63
static dispatch_group_t scanner_grp;
64
static dispatch_queue_t deferred_pl_sq;
66
static dispatch_source_t ino_src;
69
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
72
70
struct stacked_dir {
74
72
struct stacked_dir *next;
81
static int exit_pipe[2];
85
static struct event_base *evbase_scan;
86
static struct event inoev;
87
static struct event exitev;
88
static pthread_t tid_scan;
89
static struct deferred_pl *playlists;
90
static struct stacked_dir *dirstack;
94
76
push_dir(struct stacked_dir **s, char *path)
424
408
defer_playlist(char *path)
426
struct deferred_pl *pl;
428
pl = (struct deferred_pl *)malloc(sizeof(struct deferred_pl));
431
DPRINTF(E_WARN, L_SCAN, "Out of memory for deferred playlist\n");
436
memset(pl, 0, sizeof(struct deferred_pl));
438
pl->path = strdup(path);
441
DPRINTF(E_WARN, L_SCAN, "Out of memory for deferred playlist\n");
447
pl->next = playlists;
412
pl_path = strdup(path);
415
DPRINTF(E_WARN, L_SCAN, "Out of memory for deferred playlist\n");
420
/* Not using dispatch_group_async() on the scanner_grp as deferred playlists
421
* processing is triggered by scanner_grp being empty at the end of the bulk
424
dispatch_retain(scanner_grp);
425
dispatch_async(deferred_pl_sq,
435
/* In case deinit() happens after the bulk scan */
436
dispatch_group_enter(scanner_grp);
441
DPRINTF(E_LOG, L_SCAN, "Could not acquire database connection; skipping playlist %s\n", pl_path);
447
process_playlist(pl_path);
452
dispatch_group_leave(scanner_grp);
453
dispatch_release(scanner_grp);
450
456
DPRINTF(E_INFO, L_SCAN, "Deferred playlist %s\n", path);
453
/* Thread: scan (bulk only) */
455
process_deferred_playlists(void)
457
struct deferred_pl *pl;
459
while ((pl = playlists))
461
playlists = pl->next;
463
process_playlist(pl->path);
468
/* Run the event loop */
469
event_base_loop(evbase_scan, EVLOOP_ONCE | EVLOOP_NONBLOCK);
478
461
process_file(char *file, time_t mtime, off_t size, int compilation, int flags)
641
611
if (S_ISREG(sb.st_mode))
642
612
process_file(entry, sb.st_mtime, sb.st_size, compilation, flags);
643
613
else if (S_ISDIR(sb.st_mode))
644
push_dir(&dirstack, entry);
614
process_directory_async(entry, flags);
646
616
DPRINTF(E_LOG, L_SCAN, "Skipping %s, not a directory, symlink nor regular file\n", entry);
651
624
memset(&wi, 0, sizeof(struct watch_info));
653
626
#if defined(__linux__)
654
627
/* Add inotify watch */
655
wi.wd = inotify_add_watch(inofd, path, IN_CREATE | IN_DELETE | IN_MODIFY | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_MOVE_SELF);
628
wi.wd = inotify_add_watch(ino_fd, path, IN_CREATE | IN_DELETE | IN_MODIFY | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_MOVE_SELF);
658
631
DPRINTF(E_WARN, L_SCAN, "Could not create inotify watch for %s: %s\n", path, strerror(errno));
683
656
EV_SET(&kev, wi.wd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_WRITE | NOTE_RENAME, 0, NULL);
685
ret = kevent(inofd, &kev, 1, NULL, 0, NULL);
658
ret = kevent(ino_fd, &kev, 1, NULL, 0, NULL);
688
661
DPRINTF(E_WARN, L_SCAN, "Could not add kevent for %s: %s\n", path, strerror(errno));
703
process_directories(char *root, int flags)
676
process_directory_async(char *path, int flags)
707
process_directory(root, flags);
712
while ((path = pop_dir(&dirstack)))
714
process_directory(path, flags);
682
if (flags & F_SCAN_NODUP)
688
if (flags & F_SCAN_NODUP)
692
flags &= ~F_SCAN_NODUP;
696
my_path = strdup(path);
699
DPRINTF(E_LOG, L_SCAN, "Skipping %s, out of memory\n", path);
705
dispatch_group_async(scanner_grp, dispatch_get_current_queue(),
718
DPRINTF(E_LOG, L_SCAN, "Could not acquire database connection; skipping %s\n", my_path);
724
process_directory(my_path, flags);
755
process_directories(deref, F_SCAN_BULK);
759
process_directory_async(deref, F_SCAN_BULK | F_SCAN_NODUP);
764
process_deferred_playlists();
770
DPRINTF(E_LOG, L_SCAN, "WARNING: unhandled leftover directories\n");
772
DPRINTF(E_DBG, L_SCAN, "Purging old database content\n");
773
db_purge_cruft(start);
762
/* Wait for the scanner group to be empty, then queue db_purge_cruft()
763
* on the deferred playlists queue and resume that queue.
764
* In a nutshell: wait until initial bulk scan is done, then
765
* process deferred playlists, then purge the database.
767
dispatch_retain(scanner_grp);
768
dispatch_group_notify(scanner_grp, dispatch_get_current_queue(),
770
dispatch_async(deferred_pl_sq,
777
/* In case deinit() happens after the bulk scan */
778
dispatch_group_enter(scanner_grp);
783
DPRINTF(E_LOG, L_SCAN, "Could not acquire database connection; DB purge aborted\n");
788
DPRINTF(E_DBG, L_SCAN, "Purging old database content\n");
789
db_purge_cruft(start);
795
dispatch_group_leave(scanner_grp);
796
dispatch_release(scanner_grp);
799
DPRINTF(E_DBG, L_SCAN, "Now processing deferred playlists from bulk scan\n");
801
dispatch_resume(deferred_pl_sq);
802
dispatch_release(deferred_pl_sq);
803
deferred_pl_sq = NULL;
779
filescanner(void *arg)
810
startup_task(void *arg)
783
ret = db_perthread_init();
786
DPRINTF(E_LOG, L_SCAN, "Error: DB init failed\n");
817
DPRINTF(E_LOG, L_SCAN, "Startup failed: could not acquire database connection\n");
791
822
ret = db_watch_clear();
1316
1330
while ((path = pop_dir(&rescan)))
1318
process_directories(path, 0);
1323
DPRINTF(E_LOG, L_SCAN, "WARNING: unhandled leftover directories\n");
1326
event_add(&inoev, NULL);
1331
process_directory_async(path, F_SCAN_NODUP);
1328
1333
#endif /* __FreeBSD__ || __FreeBSD_kernel__ */
1333
exit_cb(int fd, short event, void *arg)
1335
event_base_loopbreak(evbase_scan);
1341
1336
/* Thread: main */
1343
1338
filescanner_init(void)
1349
evbase_scan = event_base_new();
1340
dispatch_queue_t global_q;
1344
scanner_grp = dispatch_group_create();
1352
DPRINTF(E_FATAL, L_SCAN, "Could not create an event base\n");
1347
DPRINTF(E_FATAL, L_SCAN, "Could not create dispatch group\n");
1358
exit_efd = eventfd(0, EFD_CLOEXEC);
1361
DPRINTF(E_FATAL, L_SCAN, "Could not create eventfd: %s\n", strerror(errno));
1366
# if defined(__linux__)
1367
ret = pipe2(exit_pipe, O_CLOEXEC);
1369
ret = pipe(exit_pipe);
1373
DPRINTF(E_FATAL, L_SCAN, "Could not create pipe: %s\n", strerror(errno));
1377
#endif /* USE_EVENTFD */
1352
deferred_pl_sq = dispatch_queue_create("org.forked-daapd.deferred-pl", NULL);
1353
if (!deferred_pl_sq)
1355
DPRINTF(E_FATAL, L_SCAN, "Could not create dispatch queue for deferred playlists\n");
1360
dispatch_suspend(deferred_pl_sq);
1379
1362
#if defined(__linux__)
1380
inofd = inotify_init1(IN_CLOEXEC);
1363
ino_fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
1383
1366
DPRINTF(E_FATAL, L_SCAN, "Could not create inotify fd: %s\n", strerror(errno));
1388
event_set(&inoev, inofd, EV_READ, inotify_cb, NULL);
1390
1370
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1395
1375
DPRINTF(E_FATAL, L_SCAN, "Could not create kqueue: %s\n", strerror(errno));
1400
event_set(&inoev, inofd, EV_READ, kqueue_cb, NULL);
1403
event_base_set(evbase_scan, &inoev);
1406
event_set(&exitev, exit_efd, EV_READ, exit_cb, NULL);
1408
event_set(&exitev, exit_pipe[0], EV_READ, exit_cb, NULL);
1410
event_base_set(evbase_scan, &exitev);
1411
event_add(&exitev, NULL);
1413
ret = pthread_create(&tid_scan, NULL, filescanner, NULL);
1416
DPRINTF(E_FATAL, L_SCAN, "Could not spawn filescanner thread: %s\n", strerror(errno));
1381
global_q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1384
DPRINTF(E_FATAL, L_SCAN, "Could not get global dispatch queue\n");
1389
ino_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, ino_fd, 0, global_q);
1392
DPRINTF(E_FATAL, L_SCAN, "Could not create dispatch source for inotify\n");
1397
dispatch_source_set_event_handler(ino_src,
1401
dispatch_group_enter(scanner_grp);
1405
dispatch_group_leave(scanner_grp);
1409
ret = db_pool_get();
1412
DPRINTF(E_LOG, L_SCAN, "Could not acquire database connection; inotify event aborted\n");
1414
dispatch_group_leave(scanner_grp);
1418
process_fs_events();
1421
dispatch_group_leave(scanner_grp);
1424
dispatch_source_set_cancel_handler(ino_src,
1429
dispatch_resume(ino_src);
1431
dispatch_group_async_f(scanner_grp, global_q, NULL, startup_task);
1429
close(exit_pipe[0]);
1430
close(exit_pipe[1]);
1433
event_base_free(evbase_scan);
1438
dispatch_release(deferred_pl_sq);
1440
dispatch_release(scanner_grp);
1440
1447
filescanner_deinit(void)
1445
ret = eventfd_write(exit_efd, 1);
1448
DPRINTF(E_FATAL, L_SCAN, "Could not send exit event: %s\n", strerror(errno));
1455
ret = write(exit_pipe[1], &dummy, sizeof(dummy));
1456
if (ret != sizeof(dummy))
1458
DPRINTF(E_FATAL, L_SCAN, "Could not write to exit fd: %s\n", strerror(errno));
1464
ret = pthread_join(tid_scan, NULL);
1451
dispatch_source_cancel(ino_src);
1452
dispatch_release(ino_src);
1456
DPRINTF(E_INFO, L_SCAN, "Waiting for filescanner jobs to finish...\n");
1458
ret = dispatch_group_wait(scanner_grp, DISPATCH_TIME_FOREVER);
1459
dispatch_release(scanner_grp);
1467
DPRINTF(E_FATAL, L_SCAN, "Could not join filescanner thread: %s\n", strerror(errno));
1477
close(exit_pipe[0]);
1478
close(exit_pipe[1]);
1481
event_base_free(evbase_scan);
1462
DPRINTF(E_LOG, L_SCAN, "Error waiting for dispatch group\n");
1464
/* deferred_pl_sq resumed & released after completion of the bulk scan */