input/cache: first draft of the file cache
This commit is contained in:
@@ -152,6 +152,18 @@ BufferingInputStream::RunThreadLocked(std::unique_lock<Mutex> &lock)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* enforce an upper limit for each
|
||||
InputStream::Read() call; this is necessary
|
||||
for plugins which are unable to do partial
|
||||
reads, e.g. when reading local files, the
|
||||
read() system call will not return until
|
||||
all requested bytes have been read from the
|
||||
hard disk, instead of returning when "some"
|
||||
data has been read */
|
||||
constexpr size_t MAX_READ = 64 * 1024;
|
||||
if (w.size > MAX_READ)
|
||||
w.size = MAX_READ;
|
||||
|
||||
size_t nbytes = input->Read(lock, w.data, w.size);
|
||||
buffer.Commit(read_offset, read_offset + nbytes);
|
||||
|
||||
|
35
src/input/cache/Config.cxx
vendored
Normal file
35
src/input/cache/Config.cxx
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2003-2019 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.
|
||||
*/
|
||||
|
||||
#include "Config.hxx"
|
||||
#include "config/Block.hxx"
|
||||
#include "config/Parser.hxx"
|
||||
|
||||
static constexpr size_t KILOBYTE = 1024;
|
||||
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
|
||||
|
||||
InputCacheConfig::InputCacheConfig(const ConfigBlock &block)
|
||||
{
|
||||
size = 256 * MEGABYTE;
|
||||
const auto *size_param = block.GetBlockParam("size");
|
||||
if (size_param != nullptr)
|
||||
size = size_param->With([](const char *s){
|
||||
return ParseSize(s);
|
||||
});
|
||||
}
|
33
src/input/cache/Config.hxx
vendored
Normal file
33
src/input/cache/Config.hxx
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2003-2019 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_INPUT_CACHE_CONFIG_HXX
|
||||
#define MPD_INPUT_CACHE_CONFIG_HXX
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct ConfigBlock;
|
||||
|
||||
struct InputCacheConfig {
|
||||
size_t size;
|
||||
|
||||
explicit InputCacheConfig(const ConfigBlock &block);
|
||||
};
|
||||
|
||||
#endif
|
62
src/input/cache/Item.cxx
vendored
Normal file
62
src/input/cache/Item.cxx
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2003-2019 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.
|
||||
*/
|
||||
|
||||
#include "Item.hxx"
|
||||
#include "Lease.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
InputCacheItem::InputCacheItem(InputStreamPtr _input) noexcept
|
||||
:BufferingInputStream(std::move(_input)),
|
||||
uri(GetInput().GetURI())
|
||||
{
|
||||
}
|
||||
|
||||
InputCacheItem::~InputCacheItem() noexcept
|
||||
{
|
||||
assert(leases.empty());
|
||||
}
|
||||
|
||||
void
|
||||
InputCacheItem::AddLease(InputCacheLease &lease) noexcept
|
||||
{
|
||||
const std::lock_guard<Mutex> lock(mutex);
|
||||
leases.push_back(lease);
|
||||
}
|
||||
|
||||
void
|
||||
InputCacheItem::RemoveLease(InputCacheLease &lease) noexcept
|
||||
{
|
||||
const std::lock_guard<Mutex> lock(mutex);
|
||||
auto i = leases.iterator_to(lease);
|
||||
if (i == next_lease)
|
||||
++next_lease;
|
||||
leases.erase(i);
|
||||
|
||||
// TODO: ensure that OnBufferAvailable() isn't currently running
|
||||
}
|
||||
|
||||
void
|
||||
InputCacheItem::OnBufferAvailable() noexcept
|
||||
{
|
||||
for (auto i = leases.begin(); i != leases.end(); i = next_lease) {
|
||||
next_lease = std::next(i);
|
||||
i->OnInputCacheAvailable();
|
||||
}
|
||||
}
|
80
src/input/cache/Item.hxx
vendored
Normal file
80
src/input/cache/Item.hxx
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2003-2019 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_INPUT_CACHE_ITEM_HXX
|
||||
#define MPD_INPUT_CACHE_ITEM_HXX
|
||||
|
||||
#include "input/BufferingInputStream.hxx"
|
||||
#include "thread/Mutex.hxx"
|
||||
#include "util/SparseBuffer.hxx"
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <boost/intrusive/set_hook.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class InputCacheLease;
|
||||
|
||||
/**
|
||||
* An item in the #InputCacheManager. It caches the contents of a
|
||||
* file, and reading and managing it through the base class
|
||||
* #BufferingInputStream.
|
||||
*
|
||||
* Use the class #CacheInputStream to read from it.
|
||||
*/
|
||||
class InputCacheItem final
|
||||
: public BufferingInputStream,
|
||||
public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>,
|
||||
public boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>
|
||||
{
|
||||
const std::string uri;
|
||||
|
||||
using LeaseList =
|
||||
boost::intrusive::list<InputCacheLease,
|
||||
boost::intrusive::base_hook<boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>>,
|
||||
boost::intrusive::constant_time_size<false>>;
|
||||
|
||||
LeaseList leases;
|
||||
LeaseList::iterator next_lease = leases.end();
|
||||
|
||||
public:
|
||||
explicit InputCacheItem(InputStreamPtr _input) noexcept;
|
||||
~InputCacheItem() noexcept;
|
||||
|
||||
const char *GetUri() const noexcept {
|
||||
return uri.c_str();
|
||||
}
|
||||
|
||||
using BufferingInputStream::size;
|
||||
|
||||
bool IsInUse() const noexcept {
|
||||
const std::lock_guard<Mutex> lock(mutex);
|
||||
return !leases.empty();
|
||||
}
|
||||
|
||||
void AddLease(InputCacheLease &lease) noexcept;
|
||||
void RemoveLease(InputCacheLease &lease) noexcept;
|
||||
|
||||
private:
|
||||
/* virtual methods from class BufferingInputStream */
|
||||
void OnBufferAvailable() noexcept override;
|
||||
};
|
||||
|
||||
#endif
|
94
src/input/cache/Lease.hxx
vendored
Normal file
94
src/input/cache/Lease.hxx
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2003-2019 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_INPUT_CACHE_LEASE_HXX
|
||||
#define MPD_INPUT_CACHE_LEASE_HXX
|
||||
|
||||
#include "Item.hxx"
|
||||
|
||||
#include <boost/intrusive/list_hook.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
* A lease for an #InputCacheItem.
|
||||
*/
|
||||
class InputCacheLease
|
||||
: public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>
|
||||
{
|
||||
InputCacheItem *item = nullptr;
|
||||
|
||||
public:
|
||||
InputCacheLease() = default;
|
||||
|
||||
explicit InputCacheLease(InputCacheItem &_item) noexcept
|
||||
:item(&_item)
|
||||
{
|
||||
item->AddLease(*this);
|
||||
}
|
||||
|
||||
InputCacheLease(InputCacheLease &&src) noexcept
|
||||
:item(std::exchange(src.item, nullptr))
|
||||
{
|
||||
if (item != nullptr) {
|
||||
item->RemoveLease(src);
|
||||
item->AddLease(*this);
|
||||
}
|
||||
}
|
||||
|
||||
~InputCacheLease() noexcept {
|
||||
if (item != nullptr)
|
||||
item->RemoveLease(*this);
|
||||
}
|
||||
|
||||
InputCacheLease &operator=(InputCacheLease &&src) noexcept {
|
||||
using std::swap;
|
||||
swap(item, src.item);
|
||||
|
||||
if (item != nullptr) {
|
||||
item->RemoveLease(src);
|
||||
item->AddLease(*this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const noexcept {
|
||||
return item != nullptr;
|
||||
}
|
||||
|
||||
auto &operator*() const noexcept {
|
||||
return *item;
|
||||
}
|
||||
|
||||
auto *operator->() const noexcept {
|
||||
return item;
|
||||
}
|
||||
|
||||
auto &GetCacheItem() const noexcept {
|
||||
return *item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caller locks #InputCacheItem::mutex.
|
||||
*/
|
||||
virtual void OnInputCacheAvailable() noexcept {}
|
||||
};
|
||||
|
||||
#endif
|
163
src/input/cache/Manager.cxx
vendored
Normal file
163
src/input/cache/Manager.cxx
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2003-2019 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.
|
||||
*/
|
||||
|
||||
#include "Manager.hxx"
|
||||
#include "Config.hxx"
|
||||
#include "Item.hxx"
|
||||
#include "Lease.hxx"
|
||||
#include "input/InputStream.hxx"
|
||||
#include "fs/Traits.hxx"
|
||||
#include "util/DeleteDisposer.hxx"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
inline bool
|
||||
InputCacheManager::ItemCompare::operator()(const InputCacheItem &a,
|
||||
const char *b) const noexcept
|
||||
{
|
||||
return strcmp(a.GetUri(), b) < 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
InputCacheManager::ItemCompare::operator()(const char *a,
|
||||
const InputCacheItem &b) const noexcept
|
||||
{
|
||||
return strcmp(a, b.GetUri()) < 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
InputCacheManager::ItemCompare::operator()(const InputCacheItem &a,
|
||||
const InputCacheItem &b) const noexcept
|
||||
{
|
||||
return strcmp(a.GetUri(), b.GetUri()) < 0;
|
||||
}
|
||||
|
||||
InputCacheManager::InputCacheManager(const InputCacheConfig &config) noexcept
|
||||
:max_total_size(config.size)
|
||||
{
|
||||
}
|
||||
|
||||
InputCacheManager::~InputCacheManager() noexcept
|
||||
{
|
||||
items_by_time.clear_and_dispose(DeleteDisposer());
|
||||
}
|
||||
|
||||
bool
|
||||
InputCacheManager::IsEligible(const InputStream &input) noexcept
|
||||
{
|
||||
assert(input.IsReady());
|
||||
|
||||
return input.IsSeekable() && input.KnownSize() &&
|
||||
input.GetSize() > 0 &&
|
||||
input.GetSize() <= max_total_size / 2;
|
||||
}
|
||||
|
||||
bool
|
||||
InputCacheManager::Contains(const char *uri) noexcept
|
||||
{
|
||||
return Get(uri, false);
|
||||
}
|
||||
|
||||
InputCacheLease
|
||||
InputCacheManager::Get(const char *uri, bool create)
|
||||
{
|
||||
// TODO: allow caching remote files
|
||||
if (!PathTraitsUTF8::IsAbsolute(uri))
|
||||
return {};
|
||||
|
||||
UriMap::insert_commit_data hint;
|
||||
auto result = items_by_uri.insert_check(uri, items_by_uri.key_comp(),
|
||||
hint);
|
||||
if (!result.second) {
|
||||
auto &item = *result.first;
|
||||
|
||||
/* refresh */
|
||||
items_by_time.erase(items_by_time.iterator_to(item));
|
||||
items_by_time.push_back(item);
|
||||
|
||||
// TODO revalidate the cache item using the file's mtime?
|
||||
// TODO if cache item contains error, retry now?
|
||||
|
||||
return InputCacheLease(item);
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return {};
|
||||
|
||||
// TODO: wait for "ready" without blocking here
|
||||
auto is = InputStream::OpenReady(uri, mutex);
|
||||
|
||||
if (!IsEligible(*is))
|
||||
return {};
|
||||
|
||||
const size_t size = is->GetSize();
|
||||
total_size += size;
|
||||
|
||||
while (total_size > max_total_size && EvictOldestUnused()) {}
|
||||
|
||||
auto *item = new InputCacheItem(std::move(is));
|
||||
items_by_uri.insert_commit(*item, hint);
|
||||
items_by_time.push_back(*item);
|
||||
|
||||
return InputCacheLease(*item);
|
||||
}
|
||||
|
||||
void
|
||||
InputCacheManager::Prefetch(const char *uri)
|
||||
{
|
||||
Get(uri, true);
|
||||
}
|
||||
|
||||
void
|
||||
InputCacheManager::Remove(InputCacheItem &item) noexcept
|
||||
{
|
||||
assert(total_size >= item.size());
|
||||
total_size -= item.size();
|
||||
|
||||
items_by_time.erase(items_by_time.iterator_to(item));
|
||||
items_by_uri.erase(items_by_uri.iterator_to(item));
|
||||
}
|
||||
|
||||
void
|
||||
InputCacheManager::Delete(InputCacheItem *item) noexcept
|
||||
{
|
||||
Remove(*item);
|
||||
delete item;
|
||||
}
|
||||
|
||||
InputCacheItem *
|
||||
InputCacheManager::FindOldestUnused() noexcept
|
||||
{
|
||||
for (auto &i : items_by_time)
|
||||
if (!i.IsInUse())
|
||||
return &i;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
InputCacheManager::EvictOldestUnused() noexcept
|
||||
{
|
||||
auto *item = FindOldestUnused();
|
||||
if (item == nullptr)
|
||||
return false;
|
||||
|
||||
Delete(item);
|
||||
return true;
|
||||
}
|
114
src/input/cache/Manager.hxx
vendored
Normal file
114
src/input/cache/Manager.hxx
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2003-2019 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_INPUT_CACHE_MANAGER_HXX
|
||||
#define MPD_INPUT_CACHE_MANAGER_HXX
|
||||
|
||||
#include "input/Offset.hxx"
|
||||
#include "thread/Mutex.hxx"
|
||||
#include "util/Compiler.h"
|
||||
|
||||
#include <boost/intrusive/set.hpp>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
|
||||
class InputStream;
|
||||
class InputCacheItem;
|
||||
class InputCacheLease;
|
||||
struct InputCacheConfig;
|
||||
|
||||
/**
|
||||
* A class which caches files in RAM. It is supposed to prefetch
|
||||
* files before they are played.
|
||||
*/
|
||||
class InputCacheManager {
|
||||
const size_t max_total_size;
|
||||
|
||||
mutable Mutex mutex;
|
||||
|
||||
size_t total_size = 0;
|
||||
|
||||
struct ItemCompare {
|
||||
gcc_pure
|
||||
bool operator()(const InputCacheItem &a,
|
||||
const char *b) const noexcept;
|
||||
|
||||
gcc_pure
|
||||
bool operator()(const char *a,
|
||||
const InputCacheItem &b) const noexcept;
|
||||
|
||||
gcc_pure
|
||||
bool operator()(const InputCacheItem &a,
|
||||
const InputCacheItem &b) const noexcept;
|
||||
};
|
||||
|
||||
boost::intrusive::list<InputCacheItem,
|
||||
boost::intrusive::base_hook<boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>>,
|
||||
boost::intrusive::constant_time_size<false>> items_by_time;
|
||||
|
||||
using UriMap =
|
||||
boost::intrusive::set<InputCacheItem,
|
||||
boost::intrusive::base_hook<boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>>,
|
||||
boost::intrusive::compare<ItemCompare>,
|
||||
boost::intrusive::constant_time_size<false>>;
|
||||
|
||||
UriMap items_by_uri;
|
||||
|
||||
public:
|
||||
explicit InputCacheManager(const InputCacheConfig &config) noexcept;
|
||||
~InputCacheManager() noexcept;
|
||||
|
||||
gcc_pure
|
||||
bool Contains(const char *uri) noexcept;
|
||||
|
||||
/**
|
||||
* Throws if opening the #InputStream fails.
|
||||
*
|
||||
* @param create if true, then the cache item will be created
|
||||
* if it did not exist
|
||||
* @return a lease of the new item or nullptr if the file is
|
||||
* not eligible for caching
|
||||
*/
|
||||
InputCacheLease Get(const char *uri, bool create);
|
||||
|
||||
/**
|
||||
* Shortcut for "Get(uri,true)", discarding the returned
|
||||
* lease.
|
||||
*/
|
||||
void Prefetch(const char *uri);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Check whether the given #InputStream can be stored in this
|
||||
* cache.
|
||||
*/
|
||||
bool IsEligible(const InputStream &input) noexcept;
|
||||
|
||||
void Remove(InputCacheItem &item) noexcept;
|
||||
void Delete(InputCacheItem *item) noexcept;
|
||||
|
||||
InputCacheItem *FindOldestUnused() noexcept;
|
||||
|
||||
/**
|
||||
* @return true if one item has been evicted, false if no
|
||||
* unused item was found
|
||||
*/
|
||||
bool EvictOldestUnused() noexcept;
|
||||
};
|
||||
|
||||
#endif
|
96
src/input/cache/Stream.cxx
vendored
Normal file
96
src/input/cache/Stream.cxx
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2003-2019 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.
|
||||
*/
|
||||
|
||||
#include "Stream.hxx"
|
||||
|
||||
CacheInputStream::CacheInputStream(InputCacheLease _lease,
|
||||
Mutex &_mutex) noexcept
|
||||
:InputStream(_lease->GetUri(), _mutex),
|
||||
InputCacheLease(std::move(_lease))
|
||||
{
|
||||
auto &i = GetCacheItem();
|
||||
size = i.size();
|
||||
seekable = true;
|
||||
SetReady();
|
||||
}
|
||||
|
||||
void
|
||||
CacheInputStream::Check()
|
||||
{
|
||||
const ScopeUnlock unlock(mutex);
|
||||
|
||||
auto &i = GetCacheItem();
|
||||
const std::lock_guard<Mutex> protect(i.mutex);
|
||||
|
||||
i.Check();
|
||||
}
|
||||
|
||||
void
|
||||
CacheInputStream::Seek(std::unique_lock<Mutex> &, offset_type new_offset)
|
||||
{
|
||||
offset = new_offset;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheInputStream::IsEOF() const noexcept
|
||||
{
|
||||
return offset == size;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheInputStream::IsAvailable() const noexcept
|
||||
{
|
||||
const auto _offset = offset;
|
||||
const ScopeUnlock unlock(mutex);
|
||||
|
||||
auto &i = GetCacheItem();
|
||||
const std::lock_guard<Mutex> protect(i.mutex);
|
||||
|
||||
return i.IsAvailable(_offset);
|
||||
}
|
||||
|
||||
size_t
|
||||
CacheInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||
void *ptr, size_t read_size)
|
||||
{
|
||||
const auto _offset = offset;
|
||||
auto &i = GetCacheItem();
|
||||
|
||||
size_t nbytes;
|
||||
|
||||
{
|
||||
const ScopeUnlock unlock(mutex);
|
||||
const std::lock_guard<Mutex> protect(i.mutex);
|
||||
|
||||
nbytes = i.Read(lock, _offset, ptr, read_size);
|
||||
}
|
||||
|
||||
offset += nbytes;
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
void
|
||||
CacheInputStream::OnInputCacheAvailable() noexcept
|
||||
{
|
||||
auto &i = GetCacheItem();
|
||||
const ScopeUnlock unlock(i.mutex);
|
||||
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
InvokeOnAvailable();
|
||||
}
|
52
src/input/cache/Stream.hxx
vendored
Normal file
52
src/input/cache/Stream.hxx
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2003-2019 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_CACHE_INPUT_STREAM_HXX
|
||||
#define MPD_CACHE_INPUT_STREAM_HXX
|
||||
|
||||
#include "Lease.hxx"
|
||||
#include "input/InputStream.hxx"
|
||||
|
||||
/**
|
||||
* An #InputStream implementation which reads data from an
|
||||
* #InputCacheItem.
|
||||
*/
|
||||
class CacheInputStream final : public InputStream, InputCacheLease {
|
||||
public:
|
||||
CacheInputStream(InputCacheLease _lease, Mutex &_mutex) noexcept;
|
||||
|
||||
/* virtual methods from class InputStream */
|
||||
void Check() override;
|
||||
/* we don't need to implement Update() because all attributes
|
||||
have been copied already in our constructor */
|
||||
//void Update() noexcept;
|
||||
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
||||
bool IsEOF() const noexcept override;
|
||||
/* we don't support tags */
|
||||
// std::unique_ptr<Tag> ReadTag() override;
|
||||
bool IsAvailable() const noexcept override;
|
||||
size_t Read(std::unique_lock<Mutex> &lock,
|
||||
void *ptr, size_t size) override;
|
||||
|
||||
private:
|
||||
/* virtual methods from class InputCacheLease */
|
||||
void OnInputCacheAvailable() noexcept override;
|
||||
};
|
||||
|
||||
#endif
|
@@ -35,6 +35,10 @@ input_glue = static_library(
|
||||
'BufferingInputStream.cxx',
|
||||
'BufferedInputStream.cxx',
|
||||
'MaybeBufferedInputStream.cxx',
|
||||
'cache/Config.cxx',
|
||||
'cache/Manager.cxx',
|
||||
'cache/Item.cxx',
|
||||
'cache/Stream.cxx',
|
||||
include_directories: inc,
|
||||
)
|
||||
|
||||
|
Reference in New Issue
Block a user