{input,storage}/nfs: use C++ exceptions instead of class Error
This commit is contained in:
parent
553365b942
commit
539c0ed171
@ -671,8 +671,7 @@ NFS_SOURCES = \
|
|||||||
src/lib/nfs/Glue.cxx src/lib/nfs/Glue.hxx \
|
src/lib/nfs/Glue.cxx src/lib/nfs/Glue.hxx \
|
||||||
src/lib/nfs/Base.cxx src/lib/nfs/Base.hxx \
|
src/lib/nfs/Base.cxx src/lib/nfs/Base.hxx \
|
||||||
src/lib/nfs/FileReader.cxx src/lib/nfs/FileReader.hxx \
|
src/lib/nfs/FileReader.cxx src/lib/nfs/FileReader.hxx \
|
||||||
src/lib/nfs/Blocking.cxx src/lib/nfs/Blocking.hxx \
|
src/lib/nfs/Blocking.cxx src/lib/nfs/Blocking.hxx
|
||||||
src/lib/nfs/Domain.cxx src/lib/nfs/Domain.hxx
|
|
||||||
|
|
||||||
if ENABLE_DATABASE
|
if ENABLE_DATABASE
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "NfsInputPlugin.hxx"
|
#include "NfsInputPlugin.hxx"
|
||||||
#include "../AsyncInputStream.hxx"
|
#include "../AsyncInputStream.hxx"
|
||||||
#include "../InputPlugin.hxx"
|
#include "../InputPlugin.hxx"
|
||||||
#include "lib/nfs/Domain.hxx"
|
|
||||||
#include "lib/nfs/Glue.hxx"
|
#include "lib/nfs/Glue.hxx"
|
||||||
#include "lib/nfs/FileReader.hxx"
|
#include "lib/nfs/FileReader.hxx"
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
@ -64,7 +63,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool DoRead();
|
void DoRead();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* virtual methods from AsyncInputStream */
|
/* virtual methods from AsyncInputStream */
|
||||||
@ -75,41 +74,34 @@ private:
|
|||||||
/* virtual methods from NfsFileReader */
|
/* virtual methods from NfsFileReader */
|
||||||
void OnNfsFileOpen(uint64_t size) override;
|
void OnNfsFileOpen(uint64_t size) override;
|
||||||
void OnNfsFileRead(const void *data, size_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()
|
NfsInputStream::DoRead()
|
||||||
{
|
{
|
||||||
assert(NfsFileReader::IsIdle());
|
assert(NfsFileReader::IsIdle());
|
||||||
|
|
||||||
int64_t remaining = size - next_offset;
|
int64_t remaining = size - next_offset;
|
||||||
if (remaining <= 0)
|
if (remaining <= 0)
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
const size_t buffer_space = GetBufferSpace();
|
const size_t buffer_space = GetBufferSpace();
|
||||||
if (buffer_space == 0) {
|
if (buffer_space == 0) {
|
||||||
Pause();
|
Pause();
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t nbytes = std::min<size_t>(std::min<uint64_t>(remaining, 32768),
|
size_t nbytes = std::min<size_t>(std::min<uint64_t>(remaining, 32768),
|
||||||
buffer_space);
|
buffer_space);
|
||||||
|
|
||||||
Error error;
|
try {
|
||||||
bool success;
|
|
||||||
|
|
||||||
{
|
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
success = NfsFileReader::Read(next_offset, nbytes, error);
|
NfsFileReader::Read(next_offset, nbytes);
|
||||||
|
} catch (...) {
|
||||||
|
postponed_exception = std::current_exception();
|
||||||
|
cond.broadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
PostponeError(std::move(error));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -182,7 +174,7 @@ NfsInputStream::OnNfsFileRead(const void *data, size_t data_size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NfsInputStream::OnNfsFileError(Error &&error)
|
NfsInputStream::OnNfsFileError(std::exception_ptr &&e)
|
||||||
{
|
{
|
||||||
const ScopeLock protect(mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
|
||||||
@ -197,7 +189,7 @@ NfsInputStream::OnNfsFileError(Error &&error)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
postponed_error = std::move(error);
|
postponed_exception = std::move(e);
|
||||||
|
|
||||||
if (IsSeekPending())
|
if (IsSeekPending())
|
||||||
SeekDone();
|
SeekDone();
|
||||||
|
@ -20,12 +20,10 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "Blocking.hxx"
|
#include "Blocking.hxx"
|
||||||
#include "Connection.hxx"
|
#include "Connection.hxx"
|
||||||
#include "Domain.hxx"
|
|
||||||
#include "event/Call.hxx"
|
#include "event/Call.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
|
|
||||||
bool
|
void
|
||||||
BlockingNfsOperation::Run(Error &_error)
|
BlockingNfsOperation::Run()
|
||||||
{
|
{
|
||||||
/* subscribe to the connection, which will invoke either
|
/* subscribe to the connection, which will invoke either
|
||||||
OnNfsConnectionReady() or OnNfsConnectionFailed() */
|
OnNfsConnectionReady() or OnNfsConnectionFailed() */
|
||||||
@ -33,40 +31,37 @@ BlockingNfsOperation::Run(Error &_error)
|
|||||||
[this](){ connection.AddLease(*this); });
|
[this](){ connection.AddLease(*this); });
|
||||||
|
|
||||||
/* wait for completion */
|
/* wait for completion */
|
||||||
if (!LockWaitFinished()) {
|
if (!LockWaitFinished())
|
||||||
_error.Set(nfs_domain, 0, "Timeout");
|
throw std::runtime_error("Timeout");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check for error */
|
/* check for error */
|
||||||
if (error.IsDefined()) {
|
if (error)
|
||||||
_error = std::move(error);
|
std::rethrow_exception(std::move(error));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BlockingNfsOperation::OnNfsConnectionReady()
|
BlockingNfsOperation::OnNfsConnectionReady()
|
||||||
{
|
{
|
||||||
if (!Start(error)) {
|
try {
|
||||||
|
Start();
|
||||||
|
} catch (...) {
|
||||||
|
error = std::current_exception();
|
||||||
connection.RemoveLease(*this);
|
connection.RemoveLease(*this);
|
||||||
LockSetFinished();
|
LockSetFinished();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BlockingNfsOperation::OnNfsConnectionFailed(const Error &_error)
|
BlockingNfsOperation::OnNfsConnectionFailed(std::exception_ptr e)
|
||||||
{
|
{
|
||||||
error.Set(_error);
|
error = std::move(e);
|
||||||
LockSetFinished();
|
LockSetFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BlockingNfsOperation::OnNfsConnectionDisconnected(const Error &_error)
|
BlockingNfsOperation::OnNfsConnectionDisconnected(std::exception_ptr e)
|
||||||
{
|
{
|
||||||
error.Set(_error);
|
error = std::move(e);
|
||||||
LockSetFinished();
|
LockSetFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,10 +75,10 @@ BlockingNfsOperation::OnNfsCallback(unsigned status, void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BlockingNfsOperation::OnNfsError(Error &&_error)
|
BlockingNfsOperation::OnNfsError(std::exception_ptr &&e)
|
||||||
{
|
{
|
||||||
connection.RemoveLease(*this);
|
connection.RemoveLease(*this);
|
||||||
|
|
||||||
error = std::move(_error);
|
error = std::move(e);
|
||||||
LockSetFinished();
|
LockSetFinished();
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,8 @@
|
|||||||
#include "Lease.hxx"
|
#include "Lease.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
class NfsConnection;
|
class NfsConnection;
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ class BlockingNfsOperation : protected NfsCallback, NfsLease {
|
|||||||
|
|
||||||
bool finished;
|
bool finished;
|
||||||
|
|
||||||
Error error;
|
std::exception_ptr error;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NfsConnection &connection;
|
NfsConnection &connection;
|
||||||
@ -51,7 +52,10 @@ public:
|
|||||||
BlockingNfsOperation(NfsConnection &_connection)
|
BlockingNfsOperation(NfsConnection &_connection)
|
||||||
:finished(false), connection(_connection) {}
|
:finished(false), connection(_connection) {}
|
||||||
|
|
||||||
bool Run(Error &error);
|
/**
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
|
*/
|
||||||
|
void Run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool LockWaitFinished() {
|
bool LockWaitFinished() {
|
||||||
@ -75,15 +79,15 @@ private:
|
|||||||
|
|
||||||
/* virtual methods from NfsLease */
|
/* virtual methods from NfsLease */
|
||||||
void OnNfsConnectionReady() final;
|
void OnNfsConnectionReady() final;
|
||||||
void OnNfsConnectionFailed(const Error &error) final;
|
void OnNfsConnectionFailed(std::exception_ptr e) final;
|
||||||
void OnNfsConnectionDisconnected(const Error &error) final;
|
void OnNfsConnectionDisconnected(std::exception_ptr e) final;
|
||||||
|
|
||||||
/* virtual methods from NfsCallback */
|
/* virtual methods from NfsCallback */
|
||||||
void OnNfsCallback(unsigned status, void *data) final;
|
void OnNfsCallback(unsigned status, void *data) final;
|
||||||
void OnNfsError(Error &&error) final;
|
void OnNfsError(std::exception_ptr &&e) final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool Start(Error &error) = 0;
|
virtual void Start() = 0;
|
||||||
virtual void HandleResult(unsigned status, void *data) = 0;
|
virtual void HandleResult(unsigned status, void *data) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,12 +22,12 @@
|
|||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
|
|
||||||
class Error;
|
#include <exception>
|
||||||
|
|
||||||
class NfsCallback {
|
class NfsCallback {
|
||||||
public:
|
public:
|
||||||
virtual void OnNfsCallback(unsigned status, void *data) = 0;
|
virtual void OnNfsCallback(unsigned status, void *data) = 0;
|
||||||
virtual void OnNfsError(Error &&error) = 0;
|
virtual void OnNfsError(std::exception_ptr &&e) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,11 +20,10 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "Connection.hxx"
|
#include "Connection.hxx"
|
||||||
#include "Lease.hxx"
|
#include "Lease.hxx"
|
||||||
#include "Domain.hxx"
|
|
||||||
#include "Callback.hxx"
|
#include "Callback.hxx"
|
||||||
#include "event/Loop.hxx"
|
#include "event/Loop.hxx"
|
||||||
#include "system/fd_util.h"
|
#include "system/fd_util.h"
|
||||||
#include "util/Error.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <nfsc/libnfs.h>
|
#include <nfsc/libnfs.h>
|
||||||
@ -36,90 +35,65 @@ extern "C" {
|
|||||||
|
|
||||||
static constexpr unsigned NFS_MOUNT_TIMEOUT = 60;
|
static constexpr unsigned NFS_MOUNT_TIMEOUT = 60;
|
||||||
|
|
||||||
inline bool
|
inline void
|
||||||
NfsConnection::CancellableCallback::Stat(nfs_context *ctx,
|
NfsConnection::CancellableCallback::Stat(nfs_context *ctx,
|
||||||
const char *path,
|
const char *path)
|
||||||
Error &error)
|
|
||||||
{
|
{
|
||||||
assert(connection.GetEventLoop().IsInside());
|
assert(connection.GetEventLoop().IsInside());
|
||||||
|
|
||||||
int result = nfs_stat_async(ctx, path, Callback, this);
|
int result = nfs_stat_async(ctx, path, Callback, this);
|
||||||
if (result < 0) {
|
if (result < 0)
|
||||||
error.Format(nfs_domain, "nfs_stat_async() failed: %s",
|
throw FormatRuntimeError("nfs_stat_async() failed: %s",
|
||||||
nfs_get_error(ctx));
|
nfs_get_error(ctx));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline void
|
||||||
NfsConnection::CancellableCallback::OpenDirectory(nfs_context *ctx,
|
NfsConnection::CancellableCallback::OpenDirectory(nfs_context *ctx,
|
||||||
const char *path,
|
const char *path)
|
||||||
Error &error)
|
|
||||||
{
|
{
|
||||||
assert(connection.GetEventLoop().IsInside());
|
assert(connection.GetEventLoop().IsInside());
|
||||||
|
|
||||||
int result = nfs_opendir_async(ctx, path, Callback, this);
|
int result = nfs_opendir_async(ctx, path, Callback, this);
|
||||||
if (result < 0) {
|
if (result < 0)
|
||||||
error.Format(nfs_domain, "nfs_opendir_async() failed: %s",
|
throw FormatRuntimeError("nfs_opendir_async() failed: %s",
|
||||||
nfs_get_error(ctx));
|
nfs_get_error(ctx));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline void
|
||||||
NfsConnection::CancellableCallback::Open(nfs_context *ctx,
|
NfsConnection::CancellableCallback::Open(nfs_context *ctx,
|
||||||
const char *path, int flags,
|
const char *path, int flags)
|
||||||
Error &error)
|
|
||||||
{
|
{
|
||||||
assert(connection.GetEventLoop().IsInside());
|
assert(connection.GetEventLoop().IsInside());
|
||||||
|
|
||||||
int result = nfs_open_async(ctx, path, flags,
|
int result = nfs_open_async(ctx, path, flags,
|
||||||
Callback, this);
|
Callback, this);
|
||||||
if (result < 0) {
|
if (result < 0)
|
||||||
error.Format(nfs_domain, "nfs_open_async() failed: %s",
|
throw FormatRuntimeError("nfs_open_async() failed: %s",
|
||||||
nfs_get_error(ctx));
|
nfs_get_error(ctx));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline void
|
||||||
NfsConnection::CancellableCallback::Stat(nfs_context *ctx,
|
NfsConnection::CancellableCallback::Stat(nfs_context *ctx,
|
||||||
struct nfsfh *fh,
|
struct nfsfh *fh)
|
||||||
Error &error)
|
|
||||||
{
|
{
|
||||||
assert(connection.GetEventLoop().IsInside());
|
assert(connection.GetEventLoop().IsInside());
|
||||||
|
|
||||||
int result = nfs_fstat_async(ctx, fh, Callback, this);
|
int result = nfs_fstat_async(ctx, fh, Callback, this);
|
||||||
if (result < 0) {
|
if (result < 0)
|
||||||
error.Format(nfs_domain, "nfs_fstat_async() failed: %s",
|
throw FormatRuntimeError("nfs_fstat_async() failed: %s",
|
||||||
nfs_get_error(ctx));
|
nfs_get_error(ctx));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline void
|
||||||
NfsConnection::CancellableCallback::Read(nfs_context *ctx, struct nfsfh *fh,
|
NfsConnection::CancellableCallback::Read(nfs_context *ctx, struct nfsfh *fh,
|
||||||
uint64_t offset, size_t size,
|
uint64_t offset, size_t size)
|
||||||
Error &error)
|
|
||||||
{
|
{
|
||||||
assert(connection.GetEventLoop().IsInside());
|
assert(connection.GetEventLoop().IsInside());
|
||||||
|
|
||||||
int result = nfs_pread_async(ctx, fh, offset, size, Callback, this);
|
int result = nfs_pread_async(ctx, fh, offset, size, Callback, this);
|
||||||
if (result < 0) {
|
if (result < 0)
|
||||||
error.Format(nfs_domain, "nfs_pread_async() failed: %s",
|
throw FormatRuntimeError("nfs_pread_async() failed: %s",
|
||||||
nfs_get_error(ctx));
|
nfs_get_error(ctx));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
@ -160,8 +134,7 @@ NfsConnection::CancellableCallback::Callback(int err, void *data)
|
|||||||
if (err >= 0)
|
if (err >= 0)
|
||||||
cb.OnNfsCallback((unsigned)err, data);
|
cb.OnNfsCallback((unsigned)err, data);
|
||||||
else
|
else
|
||||||
cb.OnNfsError(Error(nfs_domain, err,
|
cb.OnNfsError(std::make_exception_ptr(std::runtime_error((const char *)data)));
|
||||||
(const char *)data));
|
|
||||||
} else {
|
} else {
|
||||||
if (open) {
|
if (open) {
|
||||||
/* a nfs_open_async() call was cancelled - to
|
/* a nfs_open_async() call was cancelled - to
|
||||||
@ -234,37 +207,38 @@ NfsConnection::RemoveLease(NfsLease &lease)
|
|||||||
active_leases.remove(&lease);
|
active_leases.remove(&lease);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
NfsConnection::Stat(const char *path, NfsCallback &callback, Error &error)
|
NfsConnection::Stat(const char *path, NfsCallback &callback)
|
||||||
{
|
{
|
||||||
assert(GetEventLoop().IsInside());
|
assert(GetEventLoop().IsInside());
|
||||||
assert(!callbacks.Contains(callback));
|
assert(!callbacks.Contains(callback));
|
||||||
|
|
||||||
auto &c = callbacks.Add(callback, *this, false);
|
auto &c = callbacks.Add(callback, *this, false);
|
||||||
if (!c.Stat(context, path, error)) {
|
try {
|
||||||
|
c.Stat(context, path);
|
||||||
|
} catch (...) {
|
||||||
callbacks.Remove(c);
|
callbacks.Remove(c);
|
||||||
return false;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleSocket();
|
ScheduleSocket();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
NfsConnection::OpenDirectory(const char *path, NfsCallback &callback,
|
NfsConnection::OpenDirectory(const char *path, NfsCallback &callback)
|
||||||
Error &error)
|
|
||||||
{
|
{
|
||||||
assert(GetEventLoop().IsInside());
|
assert(GetEventLoop().IsInside());
|
||||||
assert(!callbacks.Contains(callback));
|
assert(!callbacks.Contains(callback));
|
||||||
|
|
||||||
auto &c = callbacks.Add(callback, *this, true);
|
auto &c = callbacks.Add(callback, *this, true);
|
||||||
if (!c.OpenDirectory(context, path, error)) {
|
try {
|
||||||
|
c.OpenDirectory(context, path);
|
||||||
|
} catch (...) {
|
||||||
callbacks.Remove(c);
|
callbacks.Remove(c);
|
||||||
return false;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleSocket();
|
ScheduleSocket();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct nfsdirent *
|
const struct nfsdirent *
|
||||||
@ -283,54 +257,56 @@ NfsConnection::CloseDirectory(struct nfsdir *dir)
|
|||||||
return nfs_closedir(context, dir);
|
return nfs_closedir(context, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
NfsConnection::Open(const char *path, int flags, NfsCallback &callback,
|
NfsConnection::Open(const char *path, int flags, NfsCallback &callback)
|
||||||
Error &error)
|
|
||||||
{
|
{
|
||||||
assert(GetEventLoop().IsInside());
|
assert(GetEventLoop().IsInside());
|
||||||
assert(!callbacks.Contains(callback));
|
assert(!callbacks.Contains(callback));
|
||||||
|
|
||||||
auto &c = callbacks.Add(callback, *this, true);
|
auto &c = callbacks.Add(callback, *this, true);
|
||||||
if (!c.Open(context, path, flags, error)) {
|
try {
|
||||||
|
c.Open(context, path, flags);
|
||||||
|
} catch (...) {
|
||||||
callbacks.Remove(c);
|
callbacks.Remove(c);
|
||||||
return false;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleSocket();
|
ScheduleSocket();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
NfsConnection::Stat(struct nfsfh *fh, NfsCallback &callback, Error &error)
|
NfsConnection::Stat(struct nfsfh *fh, NfsCallback &callback)
|
||||||
{
|
{
|
||||||
assert(GetEventLoop().IsInside());
|
assert(GetEventLoop().IsInside());
|
||||||
assert(!callbacks.Contains(callback));
|
assert(!callbacks.Contains(callback));
|
||||||
|
|
||||||
auto &c = callbacks.Add(callback, *this, false);
|
auto &c = callbacks.Add(callback, *this, false);
|
||||||
if (!c.Stat(context, fh, error)) {
|
try {
|
||||||
|
c.Stat(context, fh);
|
||||||
|
} catch (...) {
|
||||||
callbacks.Remove(c);
|
callbacks.Remove(c);
|
||||||
return false;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleSocket();
|
ScheduleSocket();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
NfsConnection::Read(struct nfsfh *fh, uint64_t offset, size_t size,
|
NfsConnection::Read(struct nfsfh *fh, uint64_t offset, size_t size,
|
||||||
NfsCallback &callback, Error &error)
|
NfsCallback &callback)
|
||||||
{
|
{
|
||||||
assert(GetEventLoop().IsInside());
|
assert(GetEventLoop().IsInside());
|
||||||
assert(!callbacks.Contains(callback));
|
assert(!callbacks.Contains(callback));
|
||||||
|
|
||||||
auto &c = callbacks.Add(callback, *this, false);
|
auto &c = callbacks.Add(callback, *this, false);
|
||||||
if (!c.Read(context, fh, offset, size, error)) {
|
try {
|
||||||
|
c.Read(context, fh, offset, size);
|
||||||
|
} catch (...) {
|
||||||
callbacks.Remove(c);
|
callbacks.Remove(c);
|
||||||
return false;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleSocket();
|
ScheduleSocket();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -479,7 +455,7 @@ NfsConnection::OnSocketReady(unsigned flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!was_mounted && mount_finished) {
|
if (!was_mounted && mount_finished) {
|
||||||
if (postponed_mount_error.IsDefined()) {
|
if (postponed_mount_error) {
|
||||||
DestroyContext();
|
DestroyContext();
|
||||||
closed = true;
|
closed = true;
|
||||||
BroadcastMountError(std::move(postponed_mount_error));
|
BroadcastMountError(std::move(postponed_mount_error));
|
||||||
@ -487,11 +463,10 @@ NfsConnection::OnSocketReady(unsigned flags)
|
|||||||
BroadcastMountSuccess();
|
BroadcastMountSuccess();
|
||||||
} else if (result < 0) {
|
} else if (result < 0) {
|
||||||
/* the connection has failed */
|
/* the connection has failed */
|
||||||
Error error;
|
|
||||||
error.Format(nfs_domain, "NFS connection has failed: %s",
|
|
||||||
nfs_get_error(context));
|
|
||||||
|
|
||||||
BroadcastError(std::move(error));
|
auto e = FormatRuntimeError("NFS connection has failed: %s",
|
||||||
|
nfs_get_error(context));
|
||||||
|
BroadcastError(std::make_exception_ptr(e));
|
||||||
|
|
||||||
DestroyContext();
|
DestroyContext();
|
||||||
closed = true;
|
closed = true;
|
||||||
@ -499,15 +474,13 @@ NfsConnection::OnSocketReady(unsigned flags)
|
|||||||
/* this happens when rpc_reconnect_requeue() is called
|
/* this happens when rpc_reconnect_requeue() is called
|
||||||
after the connection broke, but autoreconnect was
|
after the connection broke, but autoreconnect was
|
||||||
disabled - nfs_service() returns 0 */
|
disabled - nfs_service() returns 0 */
|
||||||
Error error;
|
|
||||||
const char *msg = nfs_get_error(context);
|
const char *msg = nfs_get_error(context);
|
||||||
if (msg == nullptr)
|
if (msg == nullptr)
|
||||||
error.Set(nfs_domain, "NFS socket disappeared");
|
msg = "<unknown>";
|
||||||
else
|
auto e = FormatRuntimeError("NFS socket disappeared: %s", msg);
|
||||||
error.Format(nfs_domain,
|
|
||||||
"NFS socket disappeared: %s", msg);
|
|
||||||
|
|
||||||
BroadcastError(std::move(error));
|
BroadcastError(std::make_exception_ptr(e));
|
||||||
|
|
||||||
DestroyContext();
|
DestroyContext();
|
||||||
closed = true;
|
closed = true;
|
||||||
@ -539,9 +512,9 @@ NfsConnection::MountCallback(int status, gcc_unused nfs_context *nfs,
|
|||||||
TimeoutMonitor::Cancel();
|
TimeoutMonitor::Cancel();
|
||||||
|
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
postponed_mount_error.Format(nfs_domain, status,
|
auto e = FormatRuntimeError("nfs_mount_async() failed: %s",
|
||||||
"nfs_mount_async() failed: %s",
|
nfs_get_error(context));
|
||||||
nfs_get_error(context));
|
postponed_mount_error = std::make_exception_ptr(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -555,19 +528,17 @@ NfsConnection::MountCallback(int status, nfs_context *nfs, void *data,
|
|||||||
c->MountCallback(status, nfs, data);
|
c->MountCallback(status, nfs, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline void
|
||||||
NfsConnection::MountInternal(Error &error)
|
NfsConnection::MountInternal()
|
||||||
{
|
{
|
||||||
assert(GetEventLoop().IsInside());
|
assert(GetEventLoop().IsInside());
|
||||||
assert(context == nullptr);
|
assert(context == nullptr);
|
||||||
|
|
||||||
context = nfs_init_context();
|
context = nfs_init_context();
|
||||||
if (context == nullptr) {
|
if (context == nullptr)
|
||||||
error.Set(nfs_domain, "nfs_init_context() failed");
|
throw std::runtime_error("nfs_init_context() failed");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
postponed_mount_error.Clear();
|
postponed_mount_error = std::exception_ptr();
|
||||||
mount_finished = false;
|
mount_finished = false;
|
||||||
|
|
||||||
TimeoutMonitor::ScheduleSeconds(NFS_MOUNT_TIMEOUT);
|
TimeoutMonitor::ScheduleSeconds(NFS_MOUNT_TIMEOUT);
|
||||||
@ -580,16 +551,14 @@ NfsConnection::MountInternal(Error &error)
|
|||||||
|
|
||||||
if (nfs_mount_async(context, server.c_str(), export_name.c_str(),
|
if (nfs_mount_async(context, server.c_str(), export_name.c_str(),
|
||||||
MountCallback, this) != 0) {
|
MountCallback, this) != 0) {
|
||||||
error.Format(nfs_domain,
|
auto e = FormatRuntimeError("nfs_mount_async() failed: %s",
|
||||||
"nfs_mount_async() failed: %s",
|
nfs_get_error(context));
|
||||||
nfs_get_error(context));
|
|
||||||
nfs_destroy_context(context);
|
nfs_destroy_context(context);
|
||||||
context = nullptr;
|
context = nullptr;
|
||||||
return false;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleSocket();
|
ScheduleSocket();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -605,31 +574,31 @@ NfsConnection::BroadcastMountSuccess()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NfsConnection::BroadcastMountError(Error &&error)
|
NfsConnection::BroadcastMountError(std::exception_ptr &&e)
|
||||||
{
|
{
|
||||||
assert(GetEventLoop().IsInside());
|
assert(GetEventLoop().IsInside());
|
||||||
|
|
||||||
while (!new_leases.empty()) {
|
while (!new_leases.empty()) {
|
||||||
auto l = new_leases.front();
|
auto l = new_leases.front();
|
||||||
new_leases.pop_front();
|
new_leases.pop_front();
|
||||||
l->OnNfsConnectionFailed(error);
|
l->OnNfsConnectionFailed(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnNfsConnectionError(std::move(error));
|
OnNfsConnectionError(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NfsConnection::BroadcastError(Error &&error)
|
NfsConnection::BroadcastError(std::exception_ptr &&e)
|
||||||
{
|
{
|
||||||
assert(GetEventLoop().IsInside());
|
assert(GetEventLoop().IsInside());
|
||||||
|
|
||||||
while (!active_leases.empty()) {
|
while (!active_leases.empty()) {
|
||||||
auto l = active_leases.front();
|
auto l = active_leases.front();
|
||||||
active_leases.pop_front();
|
active_leases.pop_front();
|
||||||
l->OnNfsConnectionDisconnected(error);
|
l->OnNfsConnectionDisconnected(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
BroadcastMountError(std::move(error));
|
BroadcastMountError(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -641,7 +610,7 @@ NfsConnection::OnTimeout()
|
|||||||
mount_finished = true;
|
mount_finished = true;
|
||||||
DestroyContext();
|
DestroyContext();
|
||||||
|
|
||||||
BroadcastMountError(Error(nfs_domain, "Mount timeout"));
|
BroadcastMountError(std::make_exception_ptr(std::runtime_error("Mount timeout")));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -650,9 +619,10 @@ NfsConnection::RunDeferred()
|
|||||||
assert(GetEventLoop().IsInside());
|
assert(GetEventLoop().IsInside());
|
||||||
|
|
||||||
if (context == nullptr) {
|
if (context == nullptr) {
|
||||||
Error error;
|
try {
|
||||||
if (!MountInternal(error)) {
|
MountInternal();
|
||||||
BroadcastMountError(std::move(error));
|
} catch (...) {
|
||||||
|
BroadcastMountError(std::current_exception());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,11 @@
|
|||||||
#include "event/SocketMonitor.hxx"
|
#include "event/SocketMonitor.hxx"
|
||||||
#include "event/TimeoutMonitor.hxx"
|
#include "event/TimeoutMonitor.hxx"
|
||||||
#include "event/DeferredMonitor.hxx"
|
#include "event/DeferredMonitor.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <forward_list>
|
#include <forward_list>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
struct nfs_context;
|
struct nfs_context;
|
||||||
struct nfsdir;
|
struct nfsdir;
|
||||||
@ -65,17 +65,12 @@ class NfsConnection : SocketMonitor, TimeoutMonitor, DeferredMonitor {
|
|||||||
connection(_connection),
|
connection(_connection),
|
||||||
open(_open), close_fh(nullptr) {}
|
open(_open), close_fh(nullptr) {}
|
||||||
|
|
||||||
bool Stat(nfs_context *context, const char *path,
|
void Stat(nfs_context *context, const char *path);
|
||||||
Error &error);
|
void OpenDirectory(nfs_context *context, const char *path);
|
||||||
bool OpenDirectory(nfs_context *context, const char *path,
|
void Open(nfs_context *context, const char *path, int flags);
|
||||||
Error &error);
|
void Stat(nfs_context *context, struct nfsfh *fh);
|
||||||
bool Open(nfs_context *context, const char *path, int flags,
|
void Read(nfs_context *context, struct nfsfh *fh,
|
||||||
Error &error);
|
uint64_t offset, size_t size);
|
||||||
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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel the operation and schedule a call to
|
* Cancel the operation and schedule a call to
|
||||||
@ -115,7 +110,7 @@ class NfsConnection : SocketMonitor, TimeoutMonitor, DeferredMonitor {
|
|||||||
*/
|
*/
|
||||||
std::forward_list<struct nfsfh *> deferred_close;
|
std::forward_list<struct nfsfh *> deferred_close;
|
||||||
|
|
||||||
Error postponed_mount_error;
|
std::exception_ptr postponed_mount_error;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
/**
|
/**
|
||||||
@ -175,25 +170,32 @@ public:
|
|||||||
void AddLease(NfsLease &lease);
|
void AddLease(NfsLease &lease);
|
||||||
void RemoveLease(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,
|
void OpenDirectory(const char *path, NfsCallback &callback);
|
||||||
Error &error);
|
|
||||||
const struct nfsdirent *ReadDirectory(struct nfsdir *dir);
|
const struct nfsdirent *ReadDirectory(struct nfsdir *dir);
|
||||||
void CloseDirectory(struct nfsdir *dir);
|
void CloseDirectory(struct nfsdir *dir);
|
||||||
|
|
||||||
bool Open(const char *path, int flags, NfsCallback &callback,
|
/**
|
||||||
Error &error);
|
* Throws std::runtime_error on error.
|
||||||
bool Stat(struct nfsfh *fh, NfsCallback &callback, Error &error);
|
*/
|
||||||
bool Read(struct nfsfh *fh, uint64_t offset, size_t size,
|
void Open(const char *path, int flags, NfsCallback &callback);
|
||||||
NfsCallback &callback, Error &error);
|
|
||||||
|
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 Cancel(NfsCallback &callback);
|
||||||
|
|
||||||
void Close(struct nfsfh *fh);
|
void Close(struct nfsfh *fh);
|
||||||
void CancelAndClose(struct nfsfh *fh, NfsCallback &callback);
|
void CancelAndClose(struct nfsfh *fh, NfsCallback &callback);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void OnNfsConnectionError(Error &&error) = 0;
|
virtual void OnNfsConnectionError(std::exception_ptr &&e) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DestroyContext();
|
void DestroyContext();
|
||||||
@ -208,10 +210,10 @@ private:
|
|||||||
*/
|
*/
|
||||||
void DeferClose(struct nfsfh *fh);
|
void DeferClose(struct nfsfh *fh);
|
||||||
|
|
||||||
bool MountInternal(Error &error);
|
void MountInternal();
|
||||||
void BroadcastMountSuccess();
|
void BroadcastMountSuccess();
|
||||||
void BroadcastMountError(Error &&error);
|
void BroadcastMountError(std::exception_ptr &&e);
|
||||||
void BroadcastError(Error &&error);
|
void BroadcastError(std::exception_ptr &&e);
|
||||||
|
|
||||||
static void MountCallback(int status, nfs_context *nfs, void *data,
|
static void MountCallback(int status, nfs_context *nfs, void *data,
|
||||||
void *private_data);
|
void *private_data);
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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");
|
|
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "Glue.hxx"
|
||||||
#include "Base.hxx"
|
#include "Base.hxx"
|
||||||
#include "Connection.hxx"
|
#include "Connection.hxx"
|
||||||
#include "Domain.hxx"
|
|
||||||
#include "event/Call.hxx"
|
#include "event/Call.hxx"
|
||||||
#include "IOThread.hxx"
|
#include "IOThread.hxx"
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@ -128,16 +126,13 @@ NfsFileReader::Open(const char *uri)
|
|||||||
DeferredMonitor::Schedule();
|
DeferredMonitor::Schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
NfsFileReader::Read(uint64_t offset, size_t size, Error &error)
|
NfsFileReader::Read(uint64_t offset, size_t size)
|
||||||
{
|
{
|
||||||
assert(state == State::IDLE);
|
assert(state == State::IDLE);
|
||||||
|
|
||||||
if (!connection->Read(fh, offset, size, *this, error))
|
connection->Read(fh, offset, size, *this);
|
||||||
return false;
|
|
||||||
|
|
||||||
state = State::READ;
|
state = State::READ;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -154,9 +149,10 @@ NfsFileReader::OnNfsConnectionReady()
|
|||||||
{
|
{
|
||||||
assert(state == State::MOUNT);
|
assert(state == State::MOUNT);
|
||||||
|
|
||||||
Error error;
|
try {
|
||||||
if (!connection->Open(path, O_RDONLY, *this, error)) {
|
connection->Open(path, O_RDONLY, *this);
|
||||||
OnNfsFileError(std::move(error));
|
} catch (...) {
|
||||||
|
OnNfsFileError(std::current_exception());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,27 +160,23 @@ NfsFileReader::OnNfsConnectionReady()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NfsFileReader::OnNfsConnectionFailed(const Error &error)
|
NfsFileReader::OnNfsConnectionFailed(std::exception_ptr e)
|
||||||
{
|
{
|
||||||
assert(state == State::MOUNT);
|
assert(state == State::MOUNT);
|
||||||
|
|
||||||
state = State::INITIAL;
|
state = State::INITIAL;
|
||||||
|
|
||||||
Error copy;
|
OnNfsFileError(std::move(e));
|
||||||
copy.Set(error);
|
|
||||||
OnNfsFileError(std::move(copy));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NfsFileReader::OnNfsConnectionDisconnected(const Error &error)
|
NfsFileReader::OnNfsConnectionDisconnected(std::exception_ptr e)
|
||||||
{
|
{
|
||||||
assert(state > State::MOUNT);
|
assert(state > State::MOUNT);
|
||||||
|
|
||||||
CancelOrClose();
|
CancelOrClose();
|
||||||
|
|
||||||
Error copy;
|
OnNfsFileError(std::move(e));
|
||||||
copy.Set(error);
|
|
||||||
OnNfsFileError(std::move(copy));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
@ -196,9 +188,10 @@ NfsFileReader::OpenCallback(nfsfh *_fh)
|
|||||||
|
|
||||||
fh = _fh;
|
fh = _fh;
|
||||||
|
|
||||||
Error error;
|
try {
|
||||||
if (!connection->Stat(fh, *this, error)) {
|
connection->Stat(fh, *this);
|
||||||
OnNfsFileError(std::move(error));
|
} catch (...) {
|
||||||
|
OnNfsFileError(std::current_exception());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +207,7 @@ NfsFileReader::StatCallback(const struct stat *st)
|
|||||||
assert(st != nullptr);
|
assert(st != nullptr);
|
||||||
|
|
||||||
if (!S_ISREG(st->st_mode)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +243,7 @@ NfsFileReader::OnNfsCallback(unsigned status, void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NfsFileReader::OnNfsError(Error &&error)
|
NfsFileReader::OnNfsError(std::exception_ptr &&e)
|
||||||
{
|
{
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case State::INITIAL:
|
case State::INITIAL:
|
||||||
@ -276,7 +269,7 @@ NfsFileReader::OnNfsError(Error &&error)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnNfsFileError(std::move(error));
|
OnNfsFileError(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@ -66,7 +67,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
void Open(const char *uri);
|
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();
|
void CancelRead();
|
||||||
|
|
||||||
bool IsIdle() const {
|
bool IsIdle() const {
|
||||||
@ -76,7 +80,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
virtual void OnNfsFileOpen(uint64_t size) = 0;
|
virtual void OnNfsFileOpen(uint64_t size) = 0;
|
||||||
virtual void OnNfsFileRead(const void *data, size_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:
|
private:
|
||||||
/**
|
/**
|
||||||
@ -90,12 +94,12 @@ private:
|
|||||||
|
|
||||||
/* virtual methods from NfsLease */
|
/* virtual methods from NfsLease */
|
||||||
void OnNfsConnectionReady() final;
|
void OnNfsConnectionReady() final;
|
||||||
void OnNfsConnectionFailed(const Error &error) final;
|
void OnNfsConnectionFailed(std::exception_ptr e) final;
|
||||||
void OnNfsConnectionDisconnected(const Error &error) final;
|
void OnNfsConnectionDisconnected(std::exception_ptr e) final;
|
||||||
|
|
||||||
/* virtual methods from NfsCallback */
|
/* virtual methods from NfsCallback */
|
||||||
void OnNfsCallback(unsigned status, void *data) final;
|
void OnNfsCallback(unsigned status, void *data) final;
|
||||||
void OnNfsError(Error &&error) final;
|
void OnNfsError(std::exception_ptr &&e) final;
|
||||||
|
|
||||||
/* virtual methods from DeferredMonitor */
|
/* virtual methods from DeferredMonitor */
|
||||||
void RunDeferred() final;
|
void RunDeferred() final;
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
class Error;
|
class Error;
|
||||||
|
|
||||||
class NfsLease {
|
class NfsLease {
|
||||||
@ -36,13 +38,13 @@ public:
|
|||||||
* The #NfsConnection has failed to mount the server's export.
|
* The #NfsConnection has failed to mount the server's export.
|
||||||
* This is being called instead of OnNfsConnectionReady().
|
* 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()
|
* The #NfsConnection has failed after OnNfsConnectionReady()
|
||||||
* had been called already.
|
* had been called already.
|
||||||
*/
|
*/
|
||||||
virtual void OnNfsConnectionDisconnected(const Error &error) = 0;
|
virtual void OnNfsConnectionDisconnected(std::exception_ptr e) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,9 +26,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
void
|
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
|
/* defer deletion so the caller
|
||||||
(i.e. NfsConnection::OnSocketReady()) can still use this
|
(i.e. NfsConnection::OnSocketReady()) can still use this
|
||||||
|
@ -53,7 +53,7 @@ class NfsManager final : IdleMonitor {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* virtual methods from NfsConnection */
|
/* virtual methods from NfsConnection */
|
||||||
void OnNfsConnectionError(Error &&error) override;
|
void OnNfsConnectionError(std::exception_ptr &&e) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Compare {
|
struct Compare {
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include "storage/FileInfo.hxx"
|
#include "storage/FileInfo.hxx"
|
||||||
#include "storage/MemoryDirectoryReader.hxx"
|
#include "storage/MemoryDirectoryReader.hxx"
|
||||||
#include "lib/nfs/Blocking.hxx"
|
#include "lib/nfs/Blocking.hxx"
|
||||||
#include "lib/nfs/Domain.hxx"
|
|
||||||
#include "lib/nfs/Base.hxx"
|
#include "lib/nfs/Base.hxx"
|
||||||
#include "lib/nfs/Lease.hxx"
|
#include "lib/nfs/Lease.hxx"
|
||||||
#include "lib/nfs/Connection.hxx"
|
#include "lib/nfs/Connection.hxx"
|
||||||
@ -66,7 +65,7 @@ class NfsStorage final
|
|||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Cond cond;
|
Cond cond;
|
||||||
State state;
|
State state;
|
||||||
Error last_error;
|
std::exception_ptr last_exception;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NfsStorage(EventLoop &_loop, const char *_base,
|
NfsStorage(EventLoop &_loop, const char *_base,
|
||||||
@ -102,17 +101,17 @@ public:
|
|||||||
SetState(State::READY);
|
SetState(State::READY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnNfsConnectionFailed(gcc_unused const Error &error) final {
|
void OnNfsConnectionFailed(std::exception_ptr e) final {
|
||||||
assert(state == State::CONNECTING);
|
assert(state == State::CONNECTING);
|
||||||
|
|
||||||
SetState(State::DELAY, error);
|
SetState(State::DELAY, std::move(e));
|
||||||
TimeoutMonitor::ScheduleSeconds(60);
|
TimeoutMonitor::ScheduleSeconds(60);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnNfsConnectionDisconnected(gcc_unused const Error &error) final {
|
void OnNfsConnectionDisconnected(std::exception_ptr e) final {
|
||||||
assert(state == State::READY);
|
assert(state == State::READY);
|
||||||
|
|
||||||
SetState(State::DELAY, error);
|
SetState(State::DELAY, std::move(e));
|
||||||
TimeoutMonitor::ScheduleSeconds(5);
|
TimeoutMonitor::ScheduleSeconds(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,13 +141,12 @@ private:
|
|||||||
cond.broadcast();
|
cond.broadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetState(State _state, const Error &error) {
|
void SetState(State _state, std::exception_ptr &&e) {
|
||||||
assert(GetEventLoop().IsInside());
|
assert(GetEventLoop().IsInside());
|
||||||
|
|
||||||
const ScopeLock protect(mutex);
|
const ScopeLock protect(mutex);
|
||||||
state = _state;
|
state = _state;
|
||||||
last_error.Clear();
|
last_exception = std::move(e);
|
||||||
last_error.Set(error);
|
|
||||||
cond.broadcast();
|
cond.broadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +166,7 @@ private:
|
|||||||
Connect();
|
Connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WaitConnected(Error &error) {
|
void WaitConnected() {
|
||||||
const ScopeLock protect(mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -184,12 +182,11 @@ private:
|
|||||||
|
|
||||||
case State::CONNECTING:
|
case State::CONNECTING:
|
||||||
case State::READY:
|
case State::READY:
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
case State::DELAY:
|
case State::DELAY:
|
||||||
assert(last_error.IsDefined());
|
assert(last_exception);
|
||||||
error.Set(last_error);
|
std::rethrow_exception(last_exception);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -271,8 +268,8 @@ public:
|
|||||||
:BlockingNfsOperation(_connection), path(_path), info(_info) {}
|
:BlockingNfsOperation(_connection), path(_path), info(_info) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool Start(Error &_error) override {
|
void Start() override {
|
||||||
return connection.Stat(path, *this, _error);
|
connection.Stat(path, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleResult(gcc_unused unsigned status, void *data) override {
|
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())
|
if (path.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!WaitConnected(error))
|
WaitConnected();
|
||||||
return false;
|
|
||||||
|
|
||||||
NfsGetInfoOperation operation(*connection, path.c_str(), info);
|
NfsGetInfoOperation operation(*connection, path.c_str(), info);
|
||||||
return operation.Run(error);
|
operation.Run();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
@ -342,8 +339,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool Start(Error &_error) override {
|
void Start() override {
|
||||||
return connection.OpenDirectory(path, *this, _error);
|
connection.OpenDirectory(path, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleResult(gcc_unused unsigned status, void *data) override {
|
void HandleResult(gcc_unused unsigned status, void *data) override {
|
||||||
@ -386,19 +383,16 @@ NfsStorage::OpenDirectory(const char *uri_utf8, Error &error)
|
|||||||
if (path.empty())
|
if (path.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (!WaitConnected(error))
|
WaitConnected();
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
NfsListDirectoryOperation operation(*connection, path.c_str());
|
NfsListDirectoryOperation operation(*connection, path.c_str());
|
||||||
if (!operation.Run(error))
|
operation.Run();
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return operation.ToReader();
|
return operation.ToReader();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Storage *
|
static Storage *
|
||||||
CreateNfsStorageURI(EventLoop &event_loop, const char *base,
|
CreateNfsStorageURI(EventLoop &event_loop, const char *base, Error &)
|
||||||
Error &error)
|
|
||||||
{
|
{
|
||||||
if (memcmp(base, "nfs://", 6) != 0)
|
if (memcmp(base, "nfs://", 6) != 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -406,10 +400,8 @@ CreateNfsStorageURI(EventLoop &event_loop, const char *base,
|
|||||||
const char *p = base + 6;
|
const char *p = base + 6;
|
||||||
|
|
||||||
const char *mount = strchr(p, '/');
|
const char *mount = strchr(p, '/');
|
||||||
if (mount == nullptr) {
|
if (mount == nullptr)
|
||||||
error.Set(nfs_domain, "Malformed nfs:// URI");
|
throw std::runtime_error("Malformed nfs:// URI");
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string server(p, mount);
|
const std::string server(p, mount);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user