Commit 539c0ed1 authored by Max Kellermann's avatar Max Kellermann

{input,storage}/nfs: use C++ exceptions instead of class Error

parent 553365b9
......@@ -671,8 +671,7 @@ NFS_SOURCES = \
src/lib/nfs/Glue.cxx src/lib/nfs/Glue.hxx \
src/lib/nfs/Base.cxx src/lib/nfs/Base.hxx \
src/lib/nfs/FileReader.cxx src/lib/nfs/FileReader.hxx \
src/lib/nfs/Blocking.cxx src/lib/nfs/Blocking.hxx \
src/lib/nfs/Domain.cxx src/lib/nfs/Domain.hxx
src/lib/nfs/Blocking.cxx src/lib/nfs/Blocking.hxx
if ENABLE_DATABASE
......
......@@ -21,7 +21,6 @@
#include "NfsInputPlugin.hxx"
#include "../AsyncInputStream.hxx"
#include "../InputPlugin.hxx"
#include "lib/nfs/Domain.hxx"
#include "lib/nfs/Glue.hxx"
#include "lib/nfs/FileReader.hxx"
#include "util/StringCompare.hxx"
......@@ -64,7 +63,7 @@ public:
}
private:
bool DoRead();
void DoRead();
protected:
/* virtual methods from AsyncInputStream */
......@@ -75,41 +74,34 @@ private:
/* virtual methods from NfsFileReader */
void OnNfsFileOpen(uint64_t size) override;
void OnNfsFileRead(const void *data, size_t size) override;
void OnNfsFileError(Error &&error) override;
void OnNfsFileError(std::exception_ptr &&e) override;
};
bool
void
NfsInputStream::DoRead()
{
assert(NfsFileReader::IsIdle());
int64_t remaining = size - next_offset;
if (remaining <= 0)
return true;
return;
const size_t buffer_space = GetBufferSpace();
if (buffer_space == 0) {
Pause();
return true;
return;
}
size_t nbytes = std::min<size_t>(std::min<uint64_t>(remaining, 32768),
buffer_space);
Error error;
bool success;
{
try {
const ScopeUnlock unlock(mutex);
success = NfsFileReader::Read(next_offset, nbytes, error);
}
if (!success) {
PostponeError(std::move(error));
return false;
NfsFileReader::Read(next_offset, nbytes);
} catch (...) {
postponed_exception = std::current_exception();
cond.broadcast();
}
return true;
}
void
......@@ -182,7 +174,7 @@ NfsInputStream::OnNfsFileRead(const void *data, size_t data_size)
}
void
NfsInputStream::OnNfsFileError(Error &&error)
NfsInputStream::OnNfsFileError(std::exception_ptr &&e)
{
const ScopeLock protect(mutex);
......@@ -197,7 +189,7 @@ NfsInputStream::OnNfsFileError(Error &&error)
return;
}
postponed_error = std::move(error);
postponed_exception = std::move(e);
if (IsSeekPending())
SeekDone();
......
......@@ -20,12 +20,10 @@
#include "config.h"
#include "Blocking.hxx"
#include "Connection.hxx"
#include "Domain.hxx"
#include "event/Call.hxx"
#include "util/Error.hxx"
bool
BlockingNfsOperation::Run(Error &_error)
void
BlockingNfsOperation::Run()
{
/* subscribe to the connection, which will invoke either
OnNfsConnectionReady() or OnNfsConnectionFailed() */
......@@ -33,40 +31,37 @@ BlockingNfsOperation::Run(Error &_error)
[this](){ connection.AddLease(*this); });
/* wait for completion */
if (!LockWaitFinished()) {
_error.Set(nfs_domain, 0, "Timeout");
return false;
}
if (!LockWaitFinished())
throw std::runtime_error("Timeout");
/* check for error */
if (error.IsDefined()) {
_error = std::move(error);
return false;
}
return true;
if (error)
std::rethrow_exception(std::move(error));
}
void
BlockingNfsOperation::OnNfsConnectionReady()
{
if (!Start(error)) {
try {
Start();
} catch (...) {
error = std::current_exception();
connection.RemoveLease(*this);
LockSetFinished();
}
}
void
BlockingNfsOperation::OnNfsConnectionFailed(const Error &_error)
BlockingNfsOperation::OnNfsConnectionFailed(std::exception_ptr e)
{
error.Set(_error);
error = std::move(e);
LockSetFinished();
}
void
BlockingNfsOperation::OnNfsConnectionDisconnected(const Error &_error)
BlockingNfsOperation::OnNfsConnectionDisconnected(std::exception_ptr e)
{
error.Set(_error);
error = std::move(e);
LockSetFinished();
}
......@@ -80,10 +75,10 @@ BlockingNfsOperation::OnNfsCallback(unsigned status, void *data)
}
void
BlockingNfsOperation::OnNfsError(Error &&_error)
BlockingNfsOperation::OnNfsError(std::exception_ptr &&e)
{
connection.RemoveLease(*this);
error = std::move(_error);
error = std::move(e);
LockSetFinished();
}
......@@ -25,7 +25,8 @@
#include "Lease.hxx"
#include "thread/Mutex.hxx"
#include "thread/Cond.hxx"
#include "util/Error.hxx"
#include <exception>
class NfsConnection;
......@@ -42,7 +43,7 @@ class BlockingNfsOperation : protected NfsCallback, NfsLease {
bool finished;
Error error;
std::exception_ptr error;
protected:
NfsConnection &connection;
......@@ -51,7 +52,10 @@ public:
BlockingNfsOperation(NfsConnection &_connection)
:finished(false), connection(_connection) {}
bool Run(Error &error);
/**
* Throws std::runtime_error on error.
*/
void Run();
private:
bool LockWaitFinished() {
......@@ -75,15 +79,15 @@ private:
/* virtual methods from NfsLease */
void OnNfsConnectionReady() final;
void OnNfsConnectionFailed(const Error &error) final;
void OnNfsConnectionDisconnected(const Error &error) final;
void OnNfsConnectionFailed(std::exception_ptr e) final;
void OnNfsConnectionDisconnected(std::exception_ptr e) final;
/* virtual methods from NfsCallback */
void OnNfsCallback(unsigned status, void *data) final;
void OnNfsError(Error &&error) final;
void OnNfsError(std::exception_ptr &&e) final;
protected:
virtual bool Start(Error &error) = 0;
virtual void Start() = 0;
virtual void HandleResult(unsigned status, void *data) = 0;
};
......
......@@ -22,12 +22,12 @@
#include "check.h"
class Error;
#include <exception>
class NfsCallback {
public:
virtual void OnNfsCallback(unsigned status, void *data) = 0;
virtual void OnNfsError(Error &&error) = 0;
virtual void OnNfsError(std::exception_ptr &&e) = 0;
};
#endif
......@@ -24,11 +24,11 @@
#include "event/SocketMonitor.hxx"
#include "event/TimeoutMonitor.hxx"
#include "event/DeferredMonitor.hxx"
#include "util/Error.hxx"
#include <string>
#include <list>
#include <forward_list>
#include <exception>
struct nfs_context;
struct nfsdir;
......@@ -65,17 +65,12 @@ class NfsConnection : SocketMonitor, TimeoutMonitor, DeferredMonitor {
connection(_connection),
open(_open), close_fh(nullptr) {}
bool Stat(nfs_context *context, const char *path,
Error &error);
bool OpenDirectory(nfs_context *context, const char *path,
Error &error);
bool Open(nfs_context *context, const char *path, int flags,
Error &error);
bool Stat(nfs_context *context, struct nfsfh *fh,
Error &error);
bool Read(nfs_context *context, struct nfsfh *fh,
uint64_t offset, size_t size,
Error &error);
void Stat(nfs_context *context, const char *path);
void OpenDirectory(nfs_context *context, const char *path);
void Open(nfs_context *context, const char *path, int flags);
void Stat(nfs_context *context, struct nfsfh *fh);
void Read(nfs_context *context, struct nfsfh *fh,
uint64_t offset, size_t size);
/**
* Cancel the operation and schedule a call to
......@@ -115,7 +110,7 @@ class NfsConnection : SocketMonitor, TimeoutMonitor, DeferredMonitor {
*/
std::forward_list<struct nfsfh *> deferred_close;
Error postponed_mount_error;
std::exception_ptr postponed_mount_error;
#ifndef NDEBUG
/**
......@@ -175,25 +170,32 @@ public:
void AddLease(NfsLease &lease);
void RemoveLease(NfsLease &lease);
bool Stat(const char *path, NfsCallback &callback, Error &error);
void Stat(const char *path, NfsCallback &callback);
bool OpenDirectory(const char *path, NfsCallback &callback,
Error &error);
void OpenDirectory(const char *path, NfsCallback &callback);
const struct nfsdirent *ReadDirectory(struct nfsdir *dir);
void CloseDirectory(struct nfsdir *dir);
bool Open(const char *path, int flags, NfsCallback &callback,
Error &error);
bool Stat(struct nfsfh *fh, NfsCallback &callback, Error &error);
bool Read(struct nfsfh *fh, uint64_t offset, size_t size,
NfsCallback &callback, Error &error);
/**
* Throws std::runtime_error on error.
*/
void Open(const char *path, int flags, NfsCallback &callback);
void Stat(struct nfsfh *fh, NfsCallback &callback);
/**
* Throws std::runtime_error on error.
*/
void Read(struct nfsfh *fh, uint64_t offset, size_t size,
NfsCallback &callback);
void Cancel(NfsCallback &callback);
void Close(struct nfsfh *fh);
void CancelAndClose(struct nfsfh *fh, NfsCallback &callback);
protected:
virtual void OnNfsConnectionError(Error &&error) = 0;
virtual void OnNfsConnectionError(std::exception_ptr &&e) = 0;
private:
void DestroyContext();
......@@ -208,10 +210,10 @@ private:
*/
void DeferClose(struct nfsfh *fh);
bool MountInternal(Error &error);
void MountInternal();
void BroadcastMountSuccess();
void BroadcastMountError(Error &&error);
void BroadcastError(Error &&error);
void BroadcastMountError(std::exception_ptr &&e);
void BroadcastError(std::exception_ptr &&e);
static void MountCallback(int status, nfs_context *nfs, void *data,
void *private_data);
......
/*
* Copyright 2003-2016 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.h"
#include "Domain.hxx"
#include "util/Domain.hxx"
const Domain nfs_domain("nfs");
/*
* Copyright 2003-2016 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_NFS_DOMAIN_HXX
#define MPD_NFS_DOMAIN_HXX
class Domain;
extern const Domain nfs_domain;
#endif
......@@ -22,11 +22,9 @@
#include "Glue.hxx"
#include "Base.hxx"
#include "Connection.hxx"
#include "Domain.hxx"
#include "event/Call.hxx"
#include "IOThread.hxx"
#include "util/StringCompare.hxx"
#include "util/Error.hxx"
#include <utility>
......@@ -128,16 +126,13 @@ NfsFileReader::Open(const char *uri)
DeferredMonitor::Schedule();
}
bool
NfsFileReader::Read(uint64_t offset, size_t size, Error &error)
void
NfsFileReader::Read(uint64_t offset, size_t size)
{
assert(state == State::IDLE);
if (!connection->Read(fh, offset, size, *this, error))
return false;
connection->Read(fh, offset, size, *this);
state = State::READ;
return true;
}
void
......@@ -154,9 +149,10 @@ NfsFileReader::OnNfsConnectionReady()
{
assert(state == State::MOUNT);
Error error;
if (!connection->Open(path, O_RDONLY, *this, error)) {
OnNfsFileError(std::move(error));
try {
connection->Open(path, O_RDONLY, *this);
} catch (...) {
OnNfsFileError(std::current_exception());
return;
}
......@@ -164,27 +160,23 @@ NfsFileReader::OnNfsConnectionReady()
}
void
NfsFileReader::OnNfsConnectionFailed(const Error &error)
NfsFileReader::OnNfsConnectionFailed(std::exception_ptr e)
{
assert(state == State::MOUNT);
state = State::INITIAL;
Error copy;
copy.Set(error);
OnNfsFileError(std::move(copy));
OnNfsFileError(std::move(e));
}
void
NfsFileReader::OnNfsConnectionDisconnected(const Error &error)
NfsFileReader::OnNfsConnectionDisconnected(std::exception_ptr e)
{
assert(state > State::MOUNT);
CancelOrClose();
Error copy;
copy.Set(error);
OnNfsFileError(std::move(copy));
OnNfsFileError(std::move(e));
}
inline void
......@@ -196,9 +188,10 @@ NfsFileReader::OpenCallback(nfsfh *_fh)
fh = _fh;
Error error;
if (!connection->Stat(fh, *this, error)) {
OnNfsFileError(std::move(error));
try {
connection->Stat(fh, *this);
} catch (...) {
OnNfsFileError(std::current_exception());
return;
}
......@@ -214,7 +207,7 @@ NfsFileReader::StatCallback(const struct stat *st)
assert(st != nullptr);
if (!S_ISREG(st->st_mode)) {
OnNfsFileError(Error(nfs_domain, "Not a regular file"));
OnNfsFileError(std::make_exception_ptr(std::runtime_error("Not a regular file")));
return;
}
......@@ -250,7 +243,7 @@ NfsFileReader::OnNfsCallback(unsigned status, void *data)
}
void
NfsFileReader::OnNfsError(Error &&error)
NfsFileReader::OnNfsError(std::exception_ptr &&e)
{
switch (state) {
case State::INITIAL:
......@@ -276,7 +269,7 @@ NfsFileReader::OnNfsError(Error &&error)
break;
}
OnNfsFileError(std::move(error));
OnNfsFileError(std::move(e));
}
void
......
......@@ -27,6 +27,7 @@
#include "Compiler.h"
#include <string>
#include <exception>
#include <stdint.h>
#include <stddef.h>
......@@ -66,7 +67,10 @@ public:
*/
void Open(const char *uri);
bool Read(uint64_t offset, size_t size, Error &error);
/**
* Throws std::runtime_error on error.
*/
void Read(uint64_t offset, size_t size);
void CancelRead();
bool IsIdle() const {
......@@ -76,7 +80,7 @@ public:
protected:
virtual void OnNfsFileOpen(uint64_t size) = 0;
virtual void OnNfsFileRead(const void *data, size_t size) = 0;
virtual void OnNfsFileError(Error &&error) = 0;
virtual void OnNfsFileError(std::exception_ptr &&e) = 0;
private:
/**
......@@ -90,12 +94,12 @@ private:
/* virtual methods from NfsLease */
void OnNfsConnectionReady() final;
void OnNfsConnectionFailed(const Error &error) final;
void OnNfsConnectionDisconnected(const Error &error) final;
void OnNfsConnectionFailed(std::exception_ptr e) final;
void OnNfsConnectionDisconnected(std::exception_ptr e) final;
/* virtual methods from NfsCallback */
void OnNfsCallback(unsigned status, void *data) final;
void OnNfsError(Error &&error) final;
void OnNfsError(std::exception_ptr &&e) final;
/* virtual methods from DeferredMonitor */
void RunDeferred() final;
......
......@@ -22,6 +22,8 @@
#include "check.h"
#include <exception>
class Error;
class NfsLease {
......@@ -36,13 +38,13 @@ public:
* The #NfsConnection has failed to mount the server's export.
* This is being called instead of OnNfsConnectionReady().
*/
virtual void OnNfsConnectionFailed(const Error &error) = 0;
virtual void OnNfsConnectionFailed(std::exception_ptr e) = 0;
/**
* The #NfsConnection has failed after OnNfsConnectionReady()
* had been called already.
*/
virtual void OnNfsConnectionDisconnected(const Error &error) = 0;
virtual void OnNfsConnectionDisconnected(std::exception_ptr e) = 0;
};
#endif
......@@ -26,9 +26,9 @@
#include <string.h>
void
NfsManager::ManagedConnection::OnNfsConnectionError(Error &&error)
NfsManager::ManagedConnection::OnNfsConnectionError(std::exception_ptr &&e)
{
FormatError(error, "NFS error on %s:%s", GetServer(), GetExportName());
FormatError(e, "NFS error on %s:%s", GetServer(), GetExportName());
/* defer deletion so the caller
(i.e. NfsConnection::OnSocketReady()) can still use this
......
......@@ -53,7 +53,7 @@ class NfsManager final : IdleMonitor {
protected:
/* virtual methods from NfsConnection */
void OnNfsConnectionError(Error &&error) override;
void OnNfsConnectionError(std::exception_ptr &&e) override;
};
struct Compare {
......
......@@ -24,7 +24,6 @@
#include "storage/FileInfo.hxx"
#include "storage/MemoryDirectoryReader.hxx"
#include "lib/nfs/Blocking.hxx"
#include "lib/nfs/Domain.hxx"
#include "lib/nfs/Base.hxx"
#include "lib/nfs/Lease.hxx"
#include "lib/nfs/Connection.hxx"
......@@ -66,7 +65,7 @@ class NfsStorage final
Mutex mutex;
Cond cond;
State state;
Error last_error;
std::exception_ptr last_exception;
public:
NfsStorage(EventLoop &_loop, const char *_base,
......@@ -102,17 +101,17 @@ public:
SetState(State::READY);
}
void OnNfsConnectionFailed(gcc_unused const Error &error) final {
void OnNfsConnectionFailed(std::exception_ptr e) final {
assert(state == State::CONNECTING);
SetState(State::DELAY, error);
SetState(State::DELAY, std::move(e));
TimeoutMonitor::ScheduleSeconds(60);
}
void OnNfsConnectionDisconnected(gcc_unused const Error &error) final {
void OnNfsConnectionDisconnected(std::exception_ptr e) final {
assert(state == State::READY);
SetState(State::DELAY, error);
SetState(State::DELAY, std::move(e));
TimeoutMonitor::ScheduleSeconds(5);
}
......@@ -142,13 +141,12 @@ private:
cond.broadcast();
}
void SetState(State _state, const Error &error) {
void SetState(State _state, std::exception_ptr &&e) {
assert(GetEventLoop().IsInside());
const ScopeLock protect(mutex);
state = _state;
last_error.Clear();
last_error.Set(error);
last_exception = std::move(e);
cond.broadcast();
}
......@@ -168,7 +166,7 @@ private:
Connect();
}
bool WaitConnected(Error &error) {
void WaitConnected() {
const ScopeLock protect(mutex);
while (true) {
......@@ -184,12 +182,11 @@ private:
case State::CONNECTING:
case State::READY:
return true;
return;
case State::DELAY:
assert(last_error.IsDefined());
error.Set(last_error);
return false;
assert(last_exception);
std::rethrow_exception(last_exception);
}
}
}
......@@ -271,8 +268,8 @@ public:
:BlockingNfsOperation(_connection), path(_path), info(_info) {}
protected:
bool Start(Error &_error) override {
return connection.Stat(path, *this, _error);
void Start() override {
connection.Stat(path, *this);
}
void HandleResult(gcc_unused unsigned status, void *data) override {
......@@ -288,11 +285,11 @@ NfsStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow,
if (path.empty())
return false;
if (!WaitConnected(error))
return false;
WaitConnected();
NfsGetInfoOperation operation(*connection, path.c_str(), info);
return operation.Run(error);
operation.Run();
return true;
}
gcc_pure
......@@ -342,8 +339,8 @@ public:
}
protected:
bool Start(Error &_error) override {
return connection.OpenDirectory(path, *this, _error);
void Start() override {
connection.OpenDirectory(path, *this);
}
void HandleResult(gcc_unused unsigned status, void *data) override {
......@@ -386,19 +383,16 @@ NfsStorage::OpenDirectory(const char *uri_utf8, Error &error)
if (path.empty())
return nullptr;
if (!WaitConnected(error))
return nullptr;
WaitConnected();
NfsListDirectoryOperation operation(*connection, path.c_str());
if (!operation.Run(error))
return nullptr;
operation.Run();
return operation.ToReader();
}
static Storage *
CreateNfsStorageURI(EventLoop &event_loop, const char *base,
Error &error)
CreateNfsStorageURI(EventLoop &event_loop, const char *base, Error &)
{
if (memcmp(base, "nfs://", 6) != 0)
return nullptr;
......@@ -406,10 +400,8 @@ CreateNfsStorageURI(EventLoop &event_loop, const char *base,
const char *p = base + 6;
const char *mount = strchr(p, '/');
if (mount == nullptr) {
error.Set(nfs_domain, "Malformed nfs:// URI");
return nullptr;
}
if (mount == nullptr)
throw std::runtime_error("Malformed nfs:// URI");
const std::string server(p, mount);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment