db/simple: mount points

A SimpleDatabase instance can now "mount" other Database instances at
certain locations.  This is used to use a new SimpleDatabase instance
for each storage mount (issued with the "mount" protocol command).
Each such instance has its own database file, stored in the directory
that is specified with the "cache_directory" option.
This commit is contained in:
Max Kellermann
2014-02-26 08:39:44 +01:00
parent 2a16fc74fd
commit e9a85aa4e4
19 changed files with 603 additions and 24 deletions

View File

@@ -21,10 +21,12 @@
#include "Directory.hxx"
#include "SongSort.hxx"
#include "Song.hxx"
#include "Mount.hxx"
#include "db/LightDirectory.hxx"
#include "db/LightSong.hxx"
#include "db/Uri.hxx"
#include "db/DatabaseLock.hxx"
#include "db/Interface.hxx"
#include "SongFilter.hxx"
#include "lib/icu/Collate.hxx"
#include "fs/Traits.hxx"
@@ -42,7 +44,8 @@ extern "C" {
Directory::Directory(std::string &&_path_utf8, Directory *_parent)
:parent(_parent),
mtime(0), have_stat(false),
path(std::move(_path_utf8))
path(std::move(_path_utf8)),
mounted_database(nullptr)
{
INIT_LIST_HEAD(&children);
INIT_LIST_HEAD(&songs);
@@ -50,6 +53,8 @@ Directory::Directory(std::string &&_path_utf8, Directory *_parent)
Directory::~Directory()
{
delete mounted_database;
Song *song, *ns;
directory_for_each_song_safe(song, ns, *this)
song->Free();
@@ -113,6 +118,11 @@ Directory::PruneEmpty()
Directory *child, *n;
directory_for_each_child_safe(child, n, *this) {
if (child->IsMount())
/* never prune mount points; they're always
empty by definition, but that's ok */
continue;
child->PruneEmpty();
if (child->IsEmpty())
@@ -233,6 +243,22 @@ Directory::Walk(bool recursive, const SongFilter *filter,
{
assert(!error.IsDefined());
if (IsMount()) {
assert(IsEmpty());
/* TODO: eliminate this unlock/lock; it is necessary
because the child's SimpleDatabasePlugin::Visit()
call will lock it again */
db_unlock();
bool result = WalkMount(GetPath(), *mounted_database,
recursive, filter,
visit_directory, visit_song,
visit_playlist,
error);
db_lock();
return result;
}
if (visit_song) {
Song *song;
directory_for_each_song(song, *this) {