aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2014-01-29 20:16:43 +0100
committerMax Kellermann <max@duempel.org>2014-01-30 18:47:05 +0100
commitc6725884bc155da431889468c86c546f0f64f9a1 (patch)
tree61d89751ecc98db9600620ac1788f32dea9214e1
parenta31738f6f1473f4f621bc16513ed0c6024749389 (diff)
downloadmpd-c6725884bc155da431889468c86c546f0f64f9a1.tar.gz
mpd-c6725884bc155da431889468c86c546f0f64f9a1.tar.xz
mpd-c6725884bc155da431889468c86c546f0f64f9a1.zip
db/update: convert to OO API
Move global variables into the new classes. That may allow multiple update threads for multiple databases one day.
-rw-r--r--Makefile.am18
-rw-r--r--src/GlobalEvents.hxx3
-rw-r--r--src/Instance.hxx3
-rw-r--r--src/Main.cxx17
-rw-r--r--src/command/OtherCommands.cxx21
-rw-r--r--src/command/PlayerCommands.cxx10
-rw-r--r--src/db/update/Archive.cxx (renamed from src/db/update/UpdateArchive.cxx)68
-rw-r--r--src/db/update/Container.cxx (renamed from src/db/update/UpdateContainer.cxx)33
-rw-r--r--src/db/update/Editor.cxx (renamed from src/db/update/UpdateDatabase.cxx)26
-rw-r--r--src/db/update/Editor.hxx (renamed from src/db/update/UpdateDatabase.hxx)48
-rw-r--r--src/db/update/InotifyQueue.cxx4
-rw-r--r--src/db/update/InotifyQueue.hxx7
-rw-r--r--src/db/update/InotifyUpdate.cxx4
-rw-r--r--src/db/update/InotifyUpdate.hxx7
-rw-r--r--src/db/update/Queue.cxx (renamed from src/db/update/UpdateQueue.cxx)13
-rw-r--r--src/db/update/Queue.hxx (renamed from src/db/update/UpdateQueue.hxx)15
-rw-r--r--src/db/update/Remove.cxx (renamed from src/db/update/UpdateRemove.cxx)21
-rw-r--r--src/db/update/Remove.hxx (renamed from src/db/update/UpdateRemove.hxx)35
-rw-r--r--src/db/update/Service.cxx (renamed from src/db/update/UpdateInternal.hxx)11
-rw-r--r--src/db/update/Service.hxx89
-rw-r--r--src/db/update/UpdateArchive.hxx50
-rw-r--r--src/db/update/UpdateContainer.hxx36
-rw-r--r--src/db/update/UpdateGlue.cxx82
-rw-r--r--src/db/update/UpdateGlue.hxx43
-rw-r--r--src/db/update/UpdateSong.cxx29
-rw-r--r--src/db/update/UpdateSong.hxx34
-rw-r--r--src/db/update/UpdateWalk.hxx37
-rw-r--r--src/db/update/Walk.cxx (renamed from src/db/update/UpdateWalk.cxx)136
-rw-r--r--src/db/update/Walk.hxx134
29 files changed, 514 insertions, 520 deletions
diff --git a/Makefile.am b/Makefile.am
index c51a12e6b..a8850ce29 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -124,15 +124,15 @@ src_mpd_SOURCES = \
src/filter/FilterInternal.hxx \
src/filter/FilterRegistry.cxx src/filter/FilterRegistry.hxx \
src/db/update/UpdateDomain.cxx src/db/update/UpdateDomain.hxx \
- src/db/update/UpdateGlue.cxx src/db/update/UpdateGlue.hxx \
- src/db/update/UpdateQueue.cxx src/db/update/UpdateQueue.hxx \
+ src/db/update/Service.cxx src/db/update/Service.hxx \
+ src/db/update/UpdateGlue.cxx \
+ src/db/update/Queue.cxx src/db/update/Queue.hxx \
src/db/update/UpdateIO.cxx src/db/update/UpdateIO.hxx \
- src/db/update/UpdateDatabase.cxx src/db/update/UpdateDatabase.hxx \
- src/db/update/UpdateWalk.cxx src/db/update/UpdateWalk.hxx \
- src/db/update/UpdateSong.cxx src/db/update/UpdateSong.hxx \
- src/db/update/UpdateContainer.cxx src/db/update/UpdateContainer.hxx \
- src/db/update/UpdateInternal.hxx \
- src/db/update/UpdateRemove.cxx src/db/update/UpdateRemove.hxx \
+ src/db/update/Editor.cxx src/db/update/Editor.hxx \
+ src/db/update/Walk.cxx src/db/update/Walk.hxx \
+ src/db/update/UpdateSong.cxx \
+ src/db/update/Container.cxx \
+ src/db/update/Remove.cxx src/db/update/Remove.hxx \
src/db/update/ExcludeList.cxx src/db/update/ExcludeList.hxx \
src/client/Client.cxx src/client/Client.hxx \
src/client/ClientInternal.hxx \
@@ -486,7 +486,7 @@ if ENABLE_ARCHIVE
noinst_LIBRARIES += libarchive.a
src_mpd_SOURCES += \
- src/db/update/UpdateArchive.cxx src/db/update/UpdateArchive.hxx
+ src/db/update/Archive.cxx
libarchive_a_SOURCES = \
src/archive/ArchiveDomain.cxx src/archive/ArchiveDomain.hxx \
diff --git a/src/GlobalEvents.hxx b/src/GlobalEvents.hxx
index 106eeb8f8..98aa4850f 100644
--- a/src/GlobalEvents.hxx
+++ b/src/GlobalEvents.hxx
@@ -33,9 +33,6 @@ class EventLoop;
namespace GlobalEvents {
enum Event {
- /** database update was finished */
- UPDATE,
-
/** during database update, a song was deleted */
DELETE,
diff --git a/src/Instance.hxx b/src/Instance.hxx
index a14719839..d67ff9a51 100644
--- a/src/Instance.hxx
+++ b/src/Instance.hxx
@@ -29,6 +29,7 @@
class NeighborGlue;
#endif
+class UpdateService;
class ClientList;
struct Partition;
@@ -42,6 +43,8 @@ struct Instance final
NeighborGlue *neighbors;
#endif
+ UpdateService *update;
+
ClientList *client_list;
Partition *partition;
diff --git a/src/Main.cxx b/src/Main.cxx
index ab70c875c..2c5d183ea 100644
--- a/src/Main.cxx
+++ b/src/Main.cxx
@@ -23,7 +23,7 @@
#include "CommandLine.hxx"
#include "PlaylistFile.hxx"
#include "PlaylistGlobal.hxx"
-#include "db/update/UpdateGlue.hxx"
+#include "db/update/Service.hxx"
#include "MusicChunk.hxx"
#include "StateFile.hxx"
#include "PlayerThread.hxx"
@@ -448,10 +448,13 @@ int mpd_main(int argc, char *argv[])
}
decoder_plugin_init_all();
- update_global_init();
const bool create_db = !glue_db_init_and_load();
+ instance->update = db_is_simple()
+ ? new UpdateService(*main_loop)
+ : nullptr;
+
glue_sticker_init();
command_init();
@@ -490,7 +493,7 @@ int mpd_main(int argc, char *argv[])
if (create_db) {
/* the database failed to load: recreate the
database */
- unsigned job = update_enqueue("", true);
+ unsigned job = instance->update->Enqueue("", true);
if (job == 0)
FatalError("directory update failed");
}
@@ -504,8 +507,9 @@ int mpd_main(int argc, char *argv[])
if (config_get_bool(CONF_AUTO_UPDATE, false)) {
#ifdef ENABLE_INOTIFY
- if (mapper_has_music_directory())
- mpd_inotify_init(*main_loop,
+ if (mapper_has_music_directory() &&
+ instance->update != nullptr)
+ mpd_inotify_init(*main_loop, *instance->update,
config_get_unsigned(CONF_AUTO_UPDATE_DEPTH,
G_MAXUINT));
#else
@@ -558,6 +562,8 @@ int mpd_main(int argc, char *argv[])
}
#endif
+ delete instance->update;
+
const clock_t start = clock();
DatabaseGlobalDeinit();
FormatDebug(main_domain,
@@ -575,7 +581,6 @@ int mpd_main(int argc, char *argv[])
mapper_finish();
delete instance->partition;
command_finish();
- update_global_finish();
decoder_plugin_deinit_all();
#ifdef ENABLE_ARCHIVE
archive_plugin_deinit_all();
diff --git a/src/command/OtherCommands.cxx b/src/command/OtherCommands.cxx
index f8976e561..2aa67f22c 100644
--- a/src/command/OtherCommands.cxx
+++ b/src/command/OtherCommands.cxx
@@ -20,7 +20,7 @@
#include "config.h"
#include "OtherCommands.hxx"
#include "DatabaseCommands.hxx"
-#include "db/update/UpdateGlue.hxx"
+#include "db/update/Service.hxx"
#include "CommandError.hxx"
#include "db/Uri.hxx"
#include "DetachedSong.hxx"
@@ -46,6 +46,7 @@
#include "client/ClientFile.hxx"
#include "client/Client.hxx"
#include "Partition.hxx"
+#include "Instance.hxx"
#include "Idle.hxx"
#include <assert.h>
@@ -186,7 +187,6 @@ CommandResult
handle_update(Client &client, gcc_unused int argc, char *argv[])
{
const char *path = "";
- unsigned ret;
assert(argc <= 2);
if (argc == 2) {
@@ -202,7 +202,13 @@ handle_update(Client &client, gcc_unused int argc, char *argv[])
}
}
- ret = update_enqueue(path, false);
+ UpdateService *update = client.partition.instance.update;
+ if (update == nullptr) {
+ command_error(client, ACK_ERROR_NO_EXIST, "No database");
+ return CommandResult::ERROR;
+ }
+
+ unsigned ret = update->Enqueue(path, false);
if (ret > 0) {
client_printf(client, "updating_db: %i\n", ret);
return CommandResult::OK;
@@ -217,7 +223,6 @@ CommandResult
handle_rescan(Client &client, gcc_unused int argc, char *argv[])
{
const char *path = "";
- unsigned ret;
assert(argc <= 2);
if (argc == 2) {
@@ -230,7 +235,13 @@ handle_rescan(Client &client, gcc_unused int argc, char *argv[])
}
}
- ret = update_enqueue(path, true);
+ UpdateService *update = client.partition.instance.update;
+ if (update == nullptr) {
+ command_error(client, ACK_ERROR_NO_EXIST, "No database");
+ return CommandResult::ERROR;
+ }
+
+ unsigned ret = update->Enqueue(path, true);
if (ret > 0) {
client_printf(client, "updating_db: %i\n", ret);
return CommandResult::OK;
diff --git a/src/command/PlayerCommands.cxx b/src/command/PlayerCommands.cxx
index 5dc55b485..d51dbdc3d 100644
--- a/src/command/PlayerCommands.cxx
+++ b/src/command/PlayerCommands.cxx
@@ -22,10 +22,11 @@
#include "CommandError.hxx"
#include "Playlist.hxx"
#include "PlaylistPrint.hxx"
-#include "db/update/UpdateGlue.hxx"
+#include "db/update/Service.hxx"
#include "client/Client.hxx"
#include "mixer/Volume.hxx"
#include "Partition.hxx"
+#include "Instance.hxx"
#include "protocol/Result.hxx"
#include "protocol/ArgParser.hxx"
#include "AudioFormat.hxx"
@@ -111,7 +112,6 @@ handle_status(Client &client,
gcc_unused int argc, gcc_unused char *argv[])
{
const char *state = nullptr;
- int updateJobId;
int song;
const auto player_status = client.player_control.GetStatus();
@@ -187,7 +187,11 @@ handle_status(Client &client,
}
}
- if ((updateJobId = isUpdatingDB())) {
+ const UpdateService *update_service = client.partition.instance.update;
+ unsigned updateJobId = update_service != nullptr
+ ? update_service->GetId()
+ : 0;
+ if (updateJobId != 0) {
client_printf(client,
COMMAND_STATUS_UPDATING_DB ": %i\n",
updateJobId);
diff --git a/src/db/update/UpdateArchive.cxx b/src/db/update/Archive.cxx
index 5e733202d..6d47ae0d1 100644
--- a/src/db/update/UpdateArchive.cxx
+++ b/src/db/update/Archive.cxx
@@ -18,8 +18,7 @@
*/
#include "config.h" /* must be first for large file support */
-#include "UpdateArchive.hxx"
-#include "UpdateInternal.hxx"
+#include "Walk.hxx"
#include "UpdateDomain.hxx"
#include "db/DatabaseLock.hxx"
#include "db/Directory.hxx"
@@ -35,10 +34,11 @@
#include <string>
+#include <sys/stat.h>
#include <string.h>
-static void
-update_archive_tree(Directory &directory, const char *name)
+void
+UpdateWalk::UpdateArchiveTree(Directory &directory, const char *name)
{
const char *tmp = strchr(name, '/');
if (tmp) {
@@ -51,7 +51,7 @@ update_archive_tree(Directory &directory, const char *name)
db_unlock();
//create directories first
- update_archive_tree(*subdir, tmp+1);
+ UpdateArchiveTree(*subdir, tmp + 1);
} else {
if (strlen(name) == 0) {
LogWarning(update_domain,
@@ -78,6 +78,21 @@ update_archive_tree(Directory &directory, const char *name)
}
}
+class UpdateArchiveVisitor final : public ArchiveVisitor {
+ UpdateWalk &walk;
+ Directory *directory;
+
+ public:
+ UpdateArchiveVisitor(UpdateWalk &_walk, Directory *_directory)
+ :walk(_walk), directory(_directory) {}
+
+ virtual void VisitArchiveEntry(const char *path_utf8) override {
+ FormatDebug(update_domain,
+ "adding archive file: %s", path_utf8);
+ walk.UpdateArchiveTree(*directory, path_utf8);
+ }
+};
+
/**
* Updates the file listing from an archive file.
*
@@ -86,10 +101,10 @@ update_archive_tree(Directory &directory, const char *name)
* @param st stat() information on the archive file
* @param plugin the archive plugin which fits this archive type
*/
-static void
-update_archive_file2(Directory &parent, const char *name,
- const struct stat *st,
- const struct archive_plugin *plugin)
+void
+UpdateWalk::UpdateArchiveFile(Directory &parent, const char *name,
+ const struct stat *st,
+ const archive_plugin &plugin)
{
db_lock();
Directory *directory = parent.FindChild(name);
@@ -105,7 +120,7 @@ update_archive_file2(Directory &parent, const char *name,
/* open archive */
Error error;
- ArchiveFile *file = archive_file_open(plugin, path_fs.c_str(), error);
+ ArchiveFile *file = archive_file_open(&plugin, path_fs.c_str(), error);
if (file == nullptr) {
LogError(error);
return;
@@ -126,44 +141,21 @@ update_archive_file2(Directory &parent, const char *name,
directory->mtime = st->st_mtime;
- class UpdateArchiveVisitor final : public ArchiveVisitor {
- Directory *directory;
-
- public:
- UpdateArchiveVisitor(Directory *_directory)
- :directory(_directory) {}
-
- virtual void VisitArchiveEntry(const char *path_utf8) override {
- FormatDebug(update_domain,
- "adding archive file: %s", path_utf8);
- update_archive_tree(*directory, path_utf8);
- }
- };
-
- UpdateArchiveVisitor visitor(directory);
+ UpdateArchiveVisitor visitor(*this, directory);
file->Visit(visitor);
file->Close();
}
bool
-update_archive_file(Directory &directory,
- const char *name, const char *suffix,
- const struct stat *st)
+UpdateWalk::UpdateArchiveFile(Directory &directory,
+ const char *name, const char *suffix,
+ const struct stat *st)
{
-#ifdef ENABLE_ARCHIVE
const struct archive_plugin *plugin =
archive_plugin_from_suffix(suffix);
if (plugin == nullptr)
return false;
- update_archive_file2(directory, name, st, plugin);
+ UpdateArchiveFile(directory, name, st, *plugin);
return true;
-#else
- (void)directory;
- (void)name;
- (void)suffix;
- (void)st;
-
- return false;
-#endif
}
diff --git a/src/db/update/UpdateContainer.cxx b/src/db/update/Container.cxx
index c03d88748..38aacea0a 100644
--- a/src/db/update/UpdateContainer.cxx
+++ b/src/db/update/Container.cxx
@@ -18,9 +18,7 @@
*/
#include "config.h" /* must be first for large file support */
-#include "UpdateContainer.hxx"
-#include "UpdateInternal.hxx"
-#include "UpdateDatabase.hxx"
+#include "Walk.hxx"
#include "UpdateDomain.hxx"
#include "db/DatabaseLock.hxx"
#include "db/Directory.hxx"
@@ -33,19 +31,13 @@
#include "tag/TagBuilder.hxx"
#include "Log.hxx"
+#include <sys/stat.h>
+
#include <glib.h>
-/**
- * Create the specified directory object if it does not exist already
- * or if the #stat object indicates that it has been modified since
- * the last update. Returns nullptr when it exists already and is
- * unmodified.
- *
- * The caller must lock the database.
- */
-static Directory *
-make_directory_if_modified(Directory &parent, const char *name,
- const struct stat *st)
+Directory *
+UpdateWalk::MakeDirectoryIfModified(Directory &parent, const char *name,
+ const struct stat *st)
{
Directory *directory = parent.FindChild(name);
@@ -56,7 +48,7 @@ make_directory_if_modified(Directory &parent, const char *name,
return nullptr;
}
- delete_directory(directory);
+ editor.DeleteDirectory(directory);
modified = true;
}
@@ -73,10 +65,9 @@ SupportsContainerSuffix(const DecoderPlugin &plugin, const char *suffix)
}
bool
-update_container_file(Directory &directory,
- const char *name,
- const struct stat *st,
- const char *suffix)
+UpdateWalk::UpdateContainerFile(Directory &directory,
+ const char *name, const char *suffix,
+ const struct stat *st)
{
const DecoderPlugin *_plugin = decoder_plugins_find([suffix](const DecoderPlugin &plugin){
return SupportsContainerSuffix(plugin, suffix);
@@ -86,7 +77,7 @@ update_container_file(Directory &directory,
const DecoderPlugin &plugin = *_plugin;
db_lock();
- Directory *contdir = make_directory_if_modified(directory, name, st);
+ Directory *contdir = MakeDirectoryIfModified(directory, name, st);
if (contdir == nullptr) {
/* not modified */
db_unlock();
@@ -128,7 +119,7 @@ update_container_file(Directory &directory,
if (tnum == 1) {
db_lock();
- delete_directory(contdir);
+ editor.DeleteDirectory(contdir);
db_unlock();
return false;
} else
diff --git a/src/db/update/UpdateDatabase.cxx b/src/db/update/Editor.cxx
index 72a68de14..369bad24b 100644
--- a/src/db/update/UpdateDatabase.cxx
+++ b/src/db/update/Editor.cxx
@@ -18,8 +18,8 @@
*/
#include "config.h" /* must be first for large file support */
-#include "UpdateDatabase.hxx"
-#include "UpdateRemove.hxx"
+#include "Editor.hxx"
+#include "Remove.hxx"
#include "db/PlaylistVector.hxx"
#include "db/Directory.hxx"
#include "db/Song.hxx"
@@ -29,7 +29,7 @@
#include <stddef.h>
void
-delete_song(Directory &dir, Song *del)
+DatabaseEditor::DeleteSong(Directory &dir, Song *del)
{
assert(del->parent == &dir);
@@ -39,7 +39,7 @@ delete_song(Directory &dir, Song *del)
db_unlock(); /* temporary unlock, because update_remove_song() blocks */
/* now take it out of the playlist (in the main_task) */
- update_remove_song(del);
+ remove.Remove(del);
/* finally, all possible references gone, free it */
del->Free();
@@ -53,32 +53,32 @@ delete_song(Directory &dir, Song *del)
*
* Caller must lock the #db_mutex.
*/
-static void
-clear_directory(Directory &directory)
+inline void
+DatabaseEditor::ClearDirectory(Directory &directory)
{
Directory *child, *n;
directory_for_each_child_safe(child, n, directory)
- delete_directory(child);
+ DeleteDirectory(child);
Song *song, *ns;
directory_for_each_song_safe(song, ns, directory) {
assert(song->parent == &directory);
- delete_song(directory, song);
+ DeleteSong(directory, song);
}
}
void
-delete_directory(Directory *directory)
+DatabaseEditor::DeleteDirectory(Directory *directory)
{
assert(directory->parent != nullptr);
- clear_directory(*directory);
+ ClearDirectory(*directory);
directory->Delete();
}
bool
-delete_name_in(Directory &parent, const char *name)
+DatabaseEditor::DeleteNameIn(Directory &parent, const char *name)
{
bool modified = false;
@@ -86,13 +86,13 @@ delete_name_in(Directory &parent, const char *name)
Directory *directory = parent.FindChild(name);
if (directory != nullptr) {
- delete_directory(directory);
+ DeleteDirectory(directory);
modified = true;
}
Song *song = parent.FindSong(name);
if (song != nullptr) {
- delete_song(parent, song);
+ DeleteSong(parent, song);
modified = true;
}
diff --git a/src/db/update/UpdateDatabase.hxx b/src/db/update/Editor.hxx
index bd7c395f2..a9093d662 100644
--- a/src/db/update/UpdateDatabase.hxx
+++ b/src/db/update/Editor.hxx
@@ -21,30 +21,40 @@
#define MPD_UPDATE_DATABASE_HXX
#include "check.h"
+#include "Remove.hxx"
struct Directory;
struct Song;
+class UpdateRemoveService;
-/**
- * Caller must lock the #db_mutex.
- */
-void
-delete_song(Directory &parent, Song *song);
+class DatabaseEditor final {
+ UpdateRemoveService remove;
-/**
- * Recursively free a directory and all its contents.
- *
- * Caller must lock the #db_mutex.
- */
-void
-delete_directory(Directory *directory);
+public:
+ DatabaseEditor(EventLoop &_loop)
+ :remove(_loop) {}
-/**
- * Caller must NOT lock the #db_mutex.
- *
- * @return true if the database was modified
- */
-bool
-delete_name_in(Directory &parent, const char *name);
+ /**
+ * Caller must lock the #db_mutex.
+ */
+ void DeleteSong(Directory &parent, Song *song);
+
+ /**
+ * Recursively free a directory and all its contents.
+ *
+ * Caller must lock the #db_mutex.
+ */
+ void DeleteDirectory(Directory *directory);
+
+ /**
+ * Caller must NOT lock the #db_mutex.
+ *
+ * @return true if the database was modified
+ */
+ bool DeleteNameIn(Directory &parent, const char *name);
+
+private:
+ void ClearDirectory(Directory &directory);
+};
#endif
diff --git a/src/db/update/InotifyQueue.cxx b/src/db/update/InotifyQueue.cxx
index f4bccf7ae..013200f98 100644
--- a/src/db/update/InotifyQueue.cxx
+++ b/src/db/update/InotifyQueue.cxx
@@ -20,7 +20,7 @@
#include "config.h"
#include "InotifyQueue.hxx"
#include "InotifyDomain.hxx"
-#include "UpdateGlue.hxx"
+#include "Service.hxx"
#include "Log.hxx"
#include <string.h>
@@ -40,7 +40,7 @@ InotifyQueue::OnTimeout()
while (!queue.empty()) {
const char *uri_utf8 = queue.front().c_str();
- id = update_enqueue(uri_utf8, false);
+ id = update.Enqueue(uri_utf8, false);
if (id == 0) {
/* retry later */
ScheduleSeconds(INOTIFY_UPDATE_DELAY_S);
diff --git a/src/db/update/InotifyQueue.hxx b/src/db/update/InotifyQueue.hxx
index 99e2635b1..a9abc2969 100644
--- a/src/db/update/InotifyQueue.hxx
+++ b/src/db/update/InotifyQueue.hxx
@@ -26,11 +26,16 @@
#include <list>
#include <string>
+class UpdateService;
+
class InotifyQueue final : private TimeoutMonitor {
+ UpdateService &update;
+
std::list<std::string> queue;
public:
- InotifyQueue(EventLoop &_loop):TimeoutMonitor(_loop) {}
+ InotifyQueue(EventLoop &_loop, UpdateService &_update)
+ :TimeoutMonitor(_loop), update(_update) {}
void Enqueue(const char *uri_utf8);
diff --git a/src/db/update/InotifyUpdate.cxx b/src/db/update/InotifyUpdate.cxx
index 72f22ceb1..3ba92ebf0 100644
--- a/src/db/update/InotifyUpdate.cxx
+++ b/src/db/update/InotifyUpdate.cxx
@@ -285,7 +285,7 @@ mpd_inotify_callback(int wd, unsigned mask,
}
void
-mpd_inotify_init(EventLoop &loop, unsigned max_depth)
+mpd_inotify_init(EventLoop &loop, UpdateService &update, unsigned max_depth)
{
LogDebug(inotify_domain, "initializing inotify");
@@ -320,7 +320,7 @@ mpd_inotify_init(EventLoop &loop, unsigned max_depth)
recursive_watch_subdirectories(inotify_root, path, 0);
- inotify_queue = new InotifyQueue(loop);
+ inotify_queue = new InotifyQueue(loop, update);
LogDebug(inotify_domain, "watching music directory");
}
diff --git a/src/db/update/InotifyUpdate.hxx b/src/db/update/InotifyUpdate.hxx
index 7cf486e5a..0260a4ff5 100644
--- a/src/db/update/InotifyUpdate.hxx
+++ b/src/db/update/InotifyUpdate.hxx
@@ -24,11 +24,12 @@
#include "Compiler.h"
class EventLoop;
+class UpdateService;
#ifdef HAVE_INOTIFY_INIT
void
-mpd_inotify_init(EventLoop &loop, unsigned max_depth);
+mpd_inotify_init(EventLoop &loop, UpdateService &update, unsigned max_depth);
void
mpd_inotify_finish(void);
@@ -36,7 +37,9 @@ mpd_inotify_finish(void);
#else /* !HAVE_INOTIFY_INIT */
static inline void
-mpd_inotify_init(gcc_unused EventLoop &loop, gcc_unused unsigned max_depth)
+mpd_inotify_init(gcc_unused EventLoop &loop,
+ gcc_unused UpdateService &update,
+ gcc_unused unsigned max_depth)
{
}
diff --git a/src/db/update/UpdateQueue.cxx b/src/db/update/Queue.cxx
index a6002f854..4bb0ae725 100644
--- a/src/db/update/UpdateQueue.cxx
+++ b/src/db/update/Queue.cxx
@@ -18,17 +18,10 @@
*/
#include "config.h"
-#include "UpdateQueue.hxx"
-
-#include <queue>
-#include <list>
-
-static constexpr unsigned MAX_UPDATE_QUEUE_SIZE = 32;
-
-static std::queue<UpdateQueueItem, std::list<UpdateQueueItem>> update_queue;
+#include "Queue.hxx"
bool
-update_queue_push(const char *path, bool discard, unsigned id)
+UpdateQueue::Push(const char *path, bool discard, unsigned id)
{
if (update_queue.size() >= MAX_UPDATE_QUEUE_SIZE)
return false;
@@ -38,7 +31,7 @@ update_queue_push(const char *path, bool discard, unsigned id)
}
UpdateQueueItem
-update_queue_shift()
+UpdateQueue::Pop()
{
if (update_queue.empty())
return UpdateQueueItem();
diff --git a/src/db/update/UpdateQueue.hxx b/src/db/update/Queue.hxx
index e4228f5ed..a5b2aa9ac 100644
--- a/src/db/update/UpdateQueue.hxx
+++ b/src/db/update/Queue.hxx
@@ -23,6 +23,8 @@
#include "check.h"
#include <string>
+#include <queue>
+#include <list>
struct UpdateQueueItem {
std::string path_utf8;
@@ -39,10 +41,15 @@ struct UpdateQueueItem {
}
};
-bool
-update_queue_push(const char *path, bool discard, unsigned id);
+class UpdateQueue {
+ static constexpr unsigned MAX_UPDATE_QUEUE_SIZE = 32;
-UpdateQueueItem
-update_queue_shift();
+ std::queue<UpdateQueueItem, std::list<UpdateQueueItem>> update_queue;
+
+public:
+ bool Push(const char *path, bool discard, unsigned id);
+
+ UpdateQueueItem Pop();
+};
#endif
diff --git a/src/db/update/UpdateRemove.cxx b/src/db/update/Remove.cxx
index c57758aef..e2c172a4b 100644
--- a/src/db/update/UpdateRemove.cxx
+++ b/src/db/update/Remove.cxx
@@ -18,7 +18,7 @@
*/
#include "config.h" /* must be first for large file support */
-#include "UpdateRemove.hxx"
+#include "Remove.hxx"
#include "UpdateDomain.hxx"
#include "GlobalEvents.hxx"
#include "thread/Mutex.hxx"
@@ -36,17 +36,12 @@
#include <assert.h>
-static const Song *removed_song;
-
-static Mutex remove_mutex;
-static Cond remove_cond;
-
/**
* Safely remove a song from the database. This must be done in the
* main task, to be sure that there is no pointer left to it.
*/
-static void
-song_remove_event(void)
+void
+UpdateRemoveService::RunDeferred()
{
assert(removed_song != nullptr);
@@ -74,19 +69,13 @@ song_remove_event(void)
}
void
-update_remove_global_init(void)
-{
- GlobalEvents::Register(GlobalEvents::DELETE, song_remove_event);
-}
-
-void
-update_remove_song(const Song *song)
+UpdateRemoveService::Remove(const Song *song)
{
assert(removed_song == nullptr);
removed_song = song;
- GlobalEvents::Emit(GlobalEvents::DELETE);
+ DeferredMonitor::Schedule();
remove_mutex.lock();
diff --git a/src/db/update/UpdateRemove.hxx b/src/db/update/Remove.hxx
index d54e3aa80..1970c0a07 100644
--- a/src/db/update/UpdateRemove.hxx
+++ b/src/db/update/Remove.hxx
@@ -21,18 +21,37 @@
#define MPD_UPDATE_REMOVE_HXX
#include "check.h"
+#include "event/DeferredMonitor.hxx"
+#include "thread/Mutex.hxx"
+#include "thread/Cond.hxx"
struct Song;
-void
-update_remove_global_init(void);
-
/**
- * Sends a signal to the main thread which will in turn remove the
- * song: from the sticker database and from the playlist. This
- * serialized access is implemented to avoid excessive locking.
+ * This class handles #Song removal. It defers the action to the main
+ * thread to ensure that all references to the #Song are gone.
*/
-void
-update_remove_song(const Song *song);
+class UpdateRemoveService final : DeferredMonitor {
+ Mutex remove_mutex;
+ Cond remove_cond;
+
+ const Song *removed_song;
+
+public:
+ UpdateRemoveService(EventLoop &_loop)
+ :DeferredMonitor(_loop) {}
+
+ /**
+ * Sends a signal to the main thread which will in turn remove
+ * the song: from the sticker database and from the playlist.
+ * This serialized access is implemented to avoid excessive
+ * locking.
+ */
+ void Remove(const Song *song);
+
+private:
+ /* virtual methods from class DeferredMonitor */
+ virtual void RunDeferred() override;
+};
#endif
diff --git a/src/db/update/UpdateInternal.hxx b/src/db/update/Service.cxx
index 2e373bd06..cc2a86968 100644
--- a/src/db/update/UpdateInternal.hxx
+++ b/src/db/update/Service.cxx
@@ -17,12 +17,5 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_UPDATE_INTERNAL_H
-#define MPD_UPDATE_INTERNAL_H
-
-#include "check.h"
-
-extern bool walk_discard;
-extern bool modified;
-
-#endif
+#include "config.h"
+#include "Service.hxx"
diff --git a/src/db/update/Service.hxx b/src/db/update/Service.hxx
new file mode 100644
index 000000000..3ea4baea1
--- /dev/null
+++ b/src/db/update/Service.hxx
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_UPDATE_SERVICE_HXX
+#define MPD_UPDATE_SERVICE_HXX
+
+#include "check.h"
+#include "Queue.hxx"
+#include "Walk.hxx"
+#include "event/DeferredMonitor.hxx"
+#include "thread/Thread.hxx"
+
+/**
+ * This class manages the update queue and runs the update thread.
+ */
+class UpdateService final : DeferredMonitor {
+ enum Progress {
+ UPDATE_PROGRESS_IDLE = 0,
+ UPDATE_PROGRESS_RUNNING = 1,
+ UPDATE_PROGRESS_DONE = 2
+ };
+
+ Progress progress;
+
+ bool modified;
+
+ Thread update_thread;
+
+ static const unsigned update_task_id_max = 1 << 15;
+
+ unsigned update_task_id;
+
+ UpdateQueue queue;
+
+ UpdateQueueItem next;
+
+ UpdateWalk walk;
+
+public:
+ UpdateService(EventLoop &_loop);
+
+ /**
+ * Returns a non-zero job id when we are currently updating
+ * the database.
+ */
+ unsigned GetId() const {
+ return next.id;
+ }
+
+ /**
+ * Add this path to the database update queue.
+ *
+ * @param path a path to update; if an empty string,
+ * the whole music directory is updated
+ * @return the job id, or 0 on error
+ */
+ gcc_nonnull_all
+ unsigned Enqueue(const char *path, bool discard);
+
+private:
+ /* virtual methods from class DeferredMonitor */
+ virtual void RunDeferred() override;
+
+ /* the update thread */
+ void Task();
+ static void Task(void *ctx);
+
+ void StartThread(UpdateQueueItem &&i);
+
+ unsigned GenerateId();
+};
+
+#endif
diff --git a/src/db/update/UpdateArchive.hxx b/src/db/update/UpdateArchive.hxx
deleted file mode 100644
index 1fc9af349..000000000
--- a/src/db/update/UpdateArchive.hxx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPD_UPDATE_ARCHIVE_HXX
-#define MPD_UPDATE_ARCHIVE_HXX
-
-#include "check.h"
-#include "Compiler.h"
-
-#include <sys/stat.h>
-
-struct Directory;
-
-#ifdef ENABLE_ARCHIVE
-
-bool
-update_archive_file(Directory &directory,
- const char *name, const char *suffix,
- const struct stat *st);
-
-#else
-
-static inline bool
-update_archive_file(gcc_unused Directory &directory,
- gcc_unused const char *name,
- gcc_unused const char *suffix,
- gcc_unused const struct stat *st)
-{
- return false;
-}
-
-#endif
-
-#endif
diff --git a/src/db/update/UpdateContainer.hxx b/src/db/update/UpdateContainer.hxx
deleted file mode 100644
index 8125f71ee..000000000
--- a/src/db/update/UpdateContainer.hxx
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPD_UPDATE_CONTAINER_HXX
-#define MPD_UPDATE_CONTAINER_HXX
-
-#include "check.h"
-
-#include <sys/stat.h>
-
-struct Directory;
-struct DecoderPlugin;
-
-bool
-update_container_file(Directory &directory,
- const char *name,
- const struct stat *st,
- const char *suffix);
-
-#endif
diff --git a/src/db/update/UpdateGlue.cxx b/src/db/update/UpdateGlue.cxx
index d18747ba1..2214bb2f7 100644
--- a/src/db/update/UpdateGlue.cxx
+++ b/src/db/update/UpdateGlue.cxx
@@ -18,15 +18,11 @@
*/
#include "config.h"
-#include "UpdateGlue.hxx"
-#include "UpdateQueue.hxx"
-#include "UpdateWalk.hxx"
-#include "UpdateRemove.hxx"
+#include "Service.hxx"
#include "UpdateDomain.hxx"
#include "Mapper.hxx"
#include "db/DatabaseSimple.hxx"
#include "Idle.hxx"
-#include "GlobalEvents.hxx"
#include "util/Error.hxx"
#include "Log.hxx"
#include "Main.hxx"
@@ -38,30 +34,8 @@
#include <assert.h>
-static enum update_progress {
- UPDATE_PROGRESS_IDLE = 0,
- UPDATE_PROGRESS_RUNNING = 1,
- UPDATE_PROGRESS_DONE = 2
-} progress;
-
-static bool modified;
-
-static Thread update_thread;
-
-static const unsigned update_task_id_max = 1 << 15;
-
-static unsigned update_task_id;
-
-static UpdateQueueItem next;
-
-unsigned
-isUpdatingDB(void)
-{
- return next.id;
-}
-
-static void
-update_task(gcc_unused void *ctx)
+inline void
+UpdateService::Task()
{
if (!next.path_utf8.empty())
FormatDebug(update_domain, "starting: %s",
@@ -71,7 +45,7 @@ update_task(gcc_unused void *ctx)
SetThreadIdlePriority();
- modified = update_walk(next.path_utf8.c_str(), next.discard);
+ modified = walk.Walk(next.path_utf8.c_str(), next.discard);
if (modified || !db_exists()) {
Error error;
@@ -86,11 +60,18 @@ update_task(gcc_unused void *ctx)
LogDebug(update_domain, "finished");
progress = UPDATE_PROGRESS_DONE;
- GlobalEvents::Emit(GlobalEvents::UPDATE);
+ DeferredMonitor::Schedule();
}
-static void
-spawn_update_task(UpdateQueueItem &&i)
+void
+UpdateService::Task(void *ctx)
+{
+ UpdateService &service = *(UpdateService *)ctx;
+ return service.Task();
+}
+
+void
+UpdateService::StartThread(UpdateQueueItem &&i)
{
assert(main_thread.IsInside());
@@ -100,15 +81,15 @@ spawn_update_task(UpdateQueueItem &&i)
next = std::move(i);
Error error;
- if (!update_thread.Start(update_task, nullptr, error))
+ if (!update_thread.Start(Task, this, error))
FatalError(error);
FormatDebug(update_domain,
"spawned thread for update job id %i", next.id);
}
-static unsigned
-generate_update_id()
+unsigned
+UpdateService::GenerateId()
{
unsigned id = update_task_id + 1;
if (id > update_task_id_max)
@@ -117,7 +98,7 @@ generate_update_id()
}
unsigned
-update_enqueue(const char *path, bool discard)
+UpdateService::Enqueue(const char *path, bool discard)
{
assert(main_thread.IsInside());
@@ -125,16 +106,16 @@ update_enqueue(const char *path, bool discard)
return 0;
if (progress != UPDATE_PROGRESS_IDLE) {
- const unsigned id = generate_update_id();
- if (!update_queue_push(path, discard, id))
+ const unsigned id = GenerateId();
+ if (!queue.Push(path, discard, id))
return 0;
update_task_id = id;
return id;
}
- const unsigned id = update_task_id = generate_update_id();
- spawn_update_task(UpdateQueueItem(path, discard, id));
+ const unsigned id = update_task_id = GenerateId();
+ StartThread(UpdateQueueItem(path, discard, id));
idle_add(IDLE_UPDATE);
@@ -144,7 +125,8 @@ update_enqueue(const char *path, bool discard)
/**
* Called in the main thread after the database update is finished.
*/
-static void update_finished_event(void)
+void
+UpdateService::RunDeferred()
{
assert(progress == UPDATE_PROGRESS_DONE);
assert(next.IsDefined());
@@ -158,24 +140,16 @@ static void update_finished_event(void)
/* send "idle" events */
instance->DatabaseModified();
- auto i = update_queue_shift();
+ auto i = queue.Pop();
if (i.IsDefined()) {
/* schedule the next path */
- spawn_update_task(std::move(i));
+ StartThread(std::move(i));
} else {
progress = UPDATE_PROGRESS_IDLE;
}
}
-void update_global_init(void)
-{
- GlobalEvents::Register(GlobalEvents::UPDATE, update_finished_event);
-
- update_remove_global_init();
- update_walk_global_init();
-}
-
-void update_global_finish(void)
+UpdateService::UpdateService(EventLoop &_loop)
+ :DeferredMonitor(_loop), walk(_loop)
{
- update_walk_global_finish();
}
diff --git a/src/db/update/UpdateGlue.hxx b/src/db/update/UpdateGlue.hxx
deleted file mode 100644
index 6e247414e..000000000
--- a/src/db/update/UpdateGlue.hxx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPD_UPDATE_GLUE_HXX
-#define MPD_UPDATE_GLUE_HXX
-
-#include "Compiler.h"
-
-void update_global_init(void);
-
-void update_global_finish(void);
-
-unsigned
-isUpdatingDB(void);
-
-/**
- * Add this path to the database update queue.
- *
- * @param path a path to update; if an empty string,
- * the whole music directory is updated
- * @return the job id, or 0 on error
- */
-gcc_nonnull_all
-unsigned
-update_enqueue(const char *path, bool discard);
-
-#endif
diff --git a/src/db/update/UpdateSong.cxx b/src/db/update/UpdateSong.cxx
index ac2d01cd2..afd609f9a 100644
--- a/src/db/update/UpdateSong.cxx
+++ b/src/db/update/UpdateSong.cxx
@@ -18,11 +18,8 @@
*/
#include "config.h" /* must be first for large file support */
-#include "UpdateSong.hxx"
-#include "UpdateInternal.hxx"
+#include "Service.hxx"
#include "UpdateIO.hxx"
-#include "UpdateDatabase.hxx"
-#include "UpdateContainer.hxx"
#include "UpdateDomain.hxx"
#include "db/DatabaseLock.hxx"
#include "db/Directory.hxx"
@@ -32,10 +29,10 @@
#include <unistd.h>
-static void
-update_song_file2(Directory &directory,
- const char *name, const struct stat *st,
- const char *suffix)
+inline void
+UpdateWalk::UpdateSongFile2(Directory &directory,
+ const char *name, const char *suffix,
+ const struct stat *st)
{
db_lock();
Song *song = directory.FindSong(name);
@@ -47,7 +44,7 @@ update_song_file2(Directory &directory,
directory.GetPath(), name);
if (song != nullptr) {
db_lock();
- delete_song(directory, song);
+ editor.DeleteSong(directory, song);
db_unlock();
}
@@ -56,10 +53,10 @@ update_song_file2(Directory &directory,
if (!(song != nullptr && st->st_mtime == song->mtime &&
!walk_discard) &&
- update_container_file(directory, name, st, suffix)) {
+ UpdateContainerFile(directory, name, suffix, st)) {
if (song != nullptr) {
db_lock();
- delete_song(directory, song);
+ editor.DeleteSong(directory, song);
db_unlock();
}
@@ -92,7 +89,7 @@ update_song_file2(Directory &directory,
"deleting unrecognized file %s/%s",
directory.GetPath(), name);
db_lock();
- delete_song(directory, song);
+ editor.DeleteSong(directory, song);
db_unlock();
}
@@ -101,13 +98,13 @@ update_song_file2(Directory &directory,
}
bool
-update_song_file(Directory &directory,
- const char *name, const char *suffix,
- const struct stat *st)
+UpdateWalk::UpdateSongFile(Directory &directory,
+ const char *name, const char *suffix,
+ const struct stat *st)
{
if (!decoder_plugins_supports_suffix(suffix))
return false;
- update_song_file2(directory, name, st, suffix);
+ UpdateSongFile2(directory, name, suffix, st);
return true;
}
diff --git a/src/db/update/UpdateSong.hxx b/src/db/update/UpdateSong.hxx
deleted file mode 100644
index 5feb01928..000000000
--- a/src/db/update/UpdateSong.hxx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPD_UPDATE_SONG_HXX
-#define MPD_UPDATE_SONG_HXX
-
-#include "check.h"
-
-#include <sys/stat.h>
-
-struct Directory;
-
-bool
-update_song_file(Directory &directory,
- const char *name, const char *suffix,
- const struct stat *st);
-
-#endif
diff --git a/src/db/update/UpdateWalk.hxx b/src/db/update/UpdateWalk.hxx
deleted file mode 100644
index e908829e3..000000000
--- a/src/db/update/UpdateWalk.hxx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPD_UPDATE_WALK_HXX
-#define MPD_UPDATE_WALK_HXX
-
-#include "check.h"
-
-void
-update_walk_global_init(void);
-
-void
-update_walk_global_finish(void);
-
-/**
- * Returns true if the database was modified.
- */
-bool
-update_walk(const char *path, bool discard);
-
-#endif
diff --git a/src/db/update/UpdateWalk.cxx b/src/db/update/Walk.cxx
index 95c7e6a81..5a799d8f7 100644
--- a/src/db/update/UpdateWalk.cxx
+++ b/src/db/update/Walk.cxx
@@ -18,11 +18,9 @@
*/
#include "config.h" /* must be first for large file support */
-#include "UpdateWalk.hxx"
+#include "Walk.hxx"
#include "UpdateIO.hxx"
-#include "UpdateDatabase.hxx"
-#include "UpdateSong.hxx"
-#include "UpdateArchive.hxx"
+#include "Editor.hxx"
#include "UpdateDomain.hxx"
#include "db/DatabaseLock.hxx"
#include "db/DatabaseSimple.hxx"
@@ -49,21 +47,8 @@
#include <stdlib.h>
#include <errno.h>
-bool walk_discard;
-bool modified;
-
-#ifndef WIN32
-
-static constexpr bool DEFAULT_FOLLOW_INSIDE_SYMLINKS = true;
-static constexpr bool DEFAULT_FOLLOW_OUTSIDE_SYMLINKS = true;
-
-static bool follow_inside_symlinks;
-static bool follow_outside_symlinks;
-
-#endif
-
-void
-update_walk_global_init(void)
+UpdateWalk::UpdateWalk(EventLoop &_loop)
+ :editor(_loop)
{
#ifndef WIN32
follow_inside_symlinks =
@@ -76,11 +61,6 @@ update_walk_global_init(void)
#endif
}
-void
-update_walk_global_finish(void)
-{
-}
-
static void
directory_set_stat(Directory &dir, const struct stat *st)
{
@@ -89,9 +69,9 @@ directory_set_stat(Directory &dir, const struct stat *st)
dir.have_stat = true;
}
-static void
-remove_excluded_from_directory(Directory &directory,
- const ExcludeList &exclude_list)
+inline void
+UpdateWalk::RemoveExcludedFromDirectory(Directory &directory,
+ const ExcludeList &exclude_list)
{
db_lock();
@@ -100,7 +80,7 @@ remove_excluded_from_directory(Directory &directory,
const auto name_fs = AllocatedPath::FromUTF8(child->GetName());
if (name_fs.IsNull() || exclude_list.Check(name_fs)) {
- delete_directory(child);
+ editor.DeleteDirectory(child);
modified = true;
}
}
@@ -111,7 +91,7 @@ remove_excluded_from_directory(Directory &directory,
const auto name_fs = AllocatedPath::FromUTF8(song->uri);
if (name_fs.IsNull() || exclude_list.Check(name_fs)) {
- delete_song(directory, song);
+ editor.DeleteSong(directory, song);
modified = true;
}
}
@@ -119,8 +99,8 @@ remove_excluded_from_directory(Directory &directory,
db_unlock();
}
-static void
-purge_deleted_from_directory(Directory &directory)
+inline void
+UpdateWalk::PurgeDeletedFromDirectory(Directory &directory)
{
Directory *child, *n;
directory_for_each_child_safe(child, n, directory) {
@@ -128,7 +108,7 @@ purge_deleted_from_directory(Directory &directory)
continue;
db_lock();
- delete_directory(child);
+ editor.DeleteDirectory(child);
db_unlock();
modified = true;
@@ -139,7 +119,7 @@ purge_deleted_from_directory(Directory &directory)
const auto path = map_song_fs(*song);
if (path.IsNull() || !FileExists(path)) {
db_lock();
- delete_song(directory, song);
+ editor.DeleteSong(directory, song);
db_unlock();
modified = true;
@@ -195,10 +175,10 @@ find_inode_ancestor(Directory *parent, ino_t inode, dev_t device)
return 0;
}
-static bool
-update_playlist_file2(Directory &directory,
- const char *name, const char *suffix,
- const struct stat *st)
+inline bool
+UpdateWalk::UpdatePlaylistFile(Directory &directory,
+ const char *name, const char *suffix,
+ const struct stat *st)
{
if (!playlist_suffix_supported(suffix))
return false;
@@ -212,30 +192,27 @@ update_playlist_file2(Directory &directory,
return true;
}
-static bool
-update_regular_file(Directory &directory,
- const char *name, const struct stat *st)
+inline bool
+UpdateWalk::UpdateRegularFile(Directory &directory,
+ const char *name, const struct stat *st)
{
const char *suffix = uri_get_suffix(name);
if (suffix == nullptr)
return false;
- return update_song_file(directory, name, suffix, st) ||
- update_archive_file(directory, name, suffix, st) ||
- update_playlist_file2(directory, name, suffix, st);
+ return UpdateSongFile(directory, name, suffix, st) ||
+ UpdateArchiveFile(directory, name, suffix, st) ||
+ UpdatePlaylistFile(directory, name, suffix, st);
}
-static bool
-update_directory(Directory &directory, const struct stat *st);
-
-static void
-update_directory_child(Directory &directory,
- const char *name, const struct stat *st)
+void
+UpdateWalk::UpdateDirectoryChild(Directory &directory,
+ const char *name, const struct stat *st)
{
assert(strchr(name, '/') == nullptr);
if (S_ISREG(st->st_mode)) {
- update_regular_file(directory, name, st);
+ UpdateRegularFile(directory, name, st);
} else if (S_ISDIR(st->st_mode)) {
if (find_inode_ancestor(&directory, st->st_ino, st->st_dev))
return;
@@ -246,9 +223,9 @@ update_directory_child(Directory &directory,
assert(&directory == subdir->parent);
- if (!update_directory(*subdir, st)) {
+ if (!UpdateDirectory(*subdir, st)) {
db_lock();
- delete_directory(subdir);
+ editor.DeleteDirectory(subdir);
db_unlock();
}
} else {
@@ -268,8 +245,9 @@ static bool skip_path(Path path_fs)
}
gcc_pure
-static bool
-skip_symlink(const Directory *directory, const char *utf8_name)
+bool
+UpdateWalk::SkipSymlink(const Directory *directory,
+ const char *utf8_name) const
{
#ifndef WIN32
const auto path_fs = map_directory_child_fs(*directory, utf8_name);
@@ -333,8 +311,8 @@ skip_symlink(const Directory *directory, const char *utf8_name)
#endif
}
-static bool
-update_directory(Directory &directory, const struct stat *st)
+bool
+UpdateWalk::UpdateDirectory(Directory &directory, const struct stat *st)
{
assert(S_ISDIR(st->st_mode));
@@ -358,9 +336,9 @@ update_directory(Directory &directory, const struct stat *st)
exclude_list.LoadFile(AllocatedPath::Build(path_fs, ".mpdignore"));
if (!exclude_list.IsEmpty())
- remove_excluded_from_directory(directory, exclude_list);
+ RemoveExcludedFromDirectory(directory, exclude_list);
- purge_deleted_from_directory(directory);
+ PurgeDeletedFromDirectory(directory);
while (reader.ReadEntry()) {
std::string utf8;
@@ -375,15 +353,15 @@ update_directory(Directory &directory, const struct stat *st)
if (utf8.empty())
continue;
- if (skip_symlink(&directory, utf8.c_str())) {
- modified |= delete_name_in(directory, utf8.c_str());
+ if (SkipSymlink(&directory, utf8.c_str())) {
+ modified |= editor.DeleteNameIn(directory, utf8.c_str());
continue;
}
if (stat_directory_child(directory, utf8.c_str(), &st2) == 0)
- update_directory_child(directory, utf8.c_str(), &st2);
+ UpdateDirectoryChild(directory, utf8.c_str(), &st2);
else
- modified |= delete_name_in(directory, utf8.c_str());
+ modified |= editor.DeleteNameIn(directory, utf8.c_str());
}
directory.mtime = st->st_mtime;
@@ -391,8 +369,8 @@ update_directory(Directory &directory, const struct stat *st)
return true;
}
-static Directory *
-directory_make_child_checked(Directory &parent, const char *name_utf8)
+inline Directory *
+UpdateWalk::DirectoryMakeChildChecked(Directory &parent, const char *name_utf8)
{
db_lock();
Directory *directory = parent.FindChild(name_utf8);
@@ -406,7 +384,7 @@ directory_make_child_checked(Directory &parent, const char *name_utf8)
find_inode_ancestor(&parent, st.st_ino, st.st_dev))
return nullptr;
- if (skip_symlink(&parent, name_utf8))
+ if (SkipSymlink(&parent, name_utf8))
return nullptr;
/* if we're adding directory paths, make sure to delete filenames
@@ -414,7 +392,7 @@ directory_make_child_checked(Directory &parent, const char *name_utf8)
db_lock();
Song *conflicting = parent.FindSong(name_utf8);
if (conflicting)
- delete_song(parent, conflicting);
+ editor.DeleteSong(parent, conflicting);
directory = parent.CreateChild(name_utf8);
db_unlock();
@@ -423,8 +401,8 @@ directory_make_child_checked(Directory &parent, const char *name_utf8)
return directory;
}
-static Directory *
-directory_make_uri_parent_checked(const char *uri)
+inline Directory *
+UpdateWalk::DirectoryMakeUriParentChecked(const char *uri)
{
Directory *directory = db_get_root();
char *duplicated = xstrdup(uri);
@@ -436,8 +414,8 @@ directory_make_uri_parent_checked(const char *uri)
if (*name_utf8 == 0)
continue;
- directory = directory_make_child_checked(*directory,
- name_utf8);
+ directory = DirectoryMakeChildChecked(*directory,
+ name_utf8);
if (directory == nullptr)
break;
@@ -448,37 +426,37 @@ directory_make_uri_parent_checked(const char *uri)
return directory;
}
-static void
-update_uri(const char *uri)
+inline void
+UpdateWalk::UpdateUri(const char *uri)
{
- Directory *parent = directory_make_uri_parent_checked(uri);
+ Directory *parent = DirectoryMakeUriParentChecked(uri);
if (parent == nullptr)
return;
const char *name = PathTraitsUTF8::GetBase(uri);
struct stat st;
- if (!skip_symlink(parent, name) &&
+ if (!SkipSymlink(parent, name) &&
stat_directory_child(*parent, name, &st) == 0)
- update_directory_child(*parent, name, &st);
+ UpdateDirectoryChild(*parent, name, &st);
else
- modified |= delete_name_in(*parent, name);
+ modified |= editor.DeleteNameIn(*parent, name);
}
bool
-update_walk(const char *path, bool discard)
+UpdateWalk::Walk(const char *path, bool discard)
{
walk_discard = discard;
modified = false;
if (path != nullptr && !isRootDirectory(path)) {
- update_uri(path);
+ UpdateUri(path);
} else {
Directory *directory = db_get_root();
struct stat st;
if (stat_directory(*directory, &st) == 0)
- update_directory(*directory, &st);
+ UpdateDirectory(*directory, &st);
}
return modified;
diff --git a/src/db/update/Walk.hxx b/src/db/update/Walk.hxx
new file mode 100644
index 000000000..12274ccdf
--- /dev/null
+++ b/src/db/update/Walk.hxx
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_UPDATE_WALK_HXX
+#define MPD_UPDATE_WALK_HXX
+
+#include "check.h"
+#include "Editor.hxx"
+
+#include <sys/stat.h>
+
+struct stat;
+struct Directory;
+struct archive_plugin;
+class ExcludeList;
+
+class UpdateWalk final {
+#ifdef ENABLE_ARCHIVE
+ friend class UpdateArchiveVisitor;
+#endif
+
+#ifndef WIN32
+ static constexpr bool DEFAULT_FOLLOW_INSIDE_SYMLINKS = true;
+ static constexpr bool DEFAULT_FOLLOW_OUTSIDE_SYMLINKS = true;
+
+ bool follow_inside_symlinks;
+ bool follow_outside_symlinks;
+#endif
+
+ bool walk_discard;
+ bool modified;
+
+ DatabaseEditor editor;
+
+public:
+ UpdateWalk(EventLoop &_loop);
+
+ /**
+ * Returns true if the database was modified.
+ */
+ bool Walk(const char *path, bool discard);
+
+private:
+ gcc_pure
+ bool SkipSymlink(const Directory *directory,
+ const char *utf8_name) const;
+
+ void RemoveExcludedFromDirectory(Directory &directory,
+ const ExcludeList &exclude_list);
+
+ void PurgeDeletedFromDirectory(Directory &directory);
+
+ void UpdateSongFile2(Directory &directory,
+ const char *name, const char *suffix,
+ const struct stat *st);
+
+ bool UpdateSongFile(Directory &directory,
+ const char *name, const char *suffix,
+ const struct stat *st);
+
+ bool UpdateContainerFile(Directory &directory,
+ const char *name, const char *suffix,
+ const struct stat *st);
+
+
+#ifdef ENABLE_ARCHIVE
+ void UpdateArchiveTree(Directory &parent, const char *name);
+
+ bool UpdateArchiveFile(Directory &directory,
+ const char *name, const char *suffix,
+ const struct stat *st);
+
+ void UpdateArchiveFile(Directory &directory, const char *name,
+ const struct stat *st,
+ const archive_plugin &plugin);
+
+
+#else
+ bool UpdateArchiveFile(gcc_unused Directory &directory,
+ gcc_unused const char *name,
+ gcc_unused const char *suffix,
+ gcc_unused const struct stat *st) {
+ return false;
+ }
+#endif
+
+ bool UpdatePlaylistFile(Directory &directory,
+ const char *name, const char *suffix,
+ const struct stat *st);
+
+ bool UpdateRegularFile(Directory &directory,
+ const char *name, const struct stat *st);
+
+ void UpdateDirectoryChild(Directory &directory,
+ const char *name, const struct stat *st);
+
+ bool UpdateDirectory(Directory &directory, const struct stat *st);
+
+ /**
+ * Create the specified directory object if it does not exist
+ * already or if the #stat object indicates that it has been
+ * modified since the last update. Returns nullptr when it
+ * exists already and is unmodified.
+ *
+ * The caller must lock the database.
+ */
+ Directory *MakeDirectoryIfModified(Directory &parent, const char *name,
+ const struct stat *st);
+
+ Directory *DirectoryMakeChildChecked(Directory &parent,
+ const char *name_utf8);
+
+ Directory *DirectoryMakeUriParentChecked(const char *uri);
+
+ void UpdateUri(const char *uri);
+};
+
+#endif