xtreemfs/cpp/include/libxtreemfs/file_info.h
2020-09-22 02:25:22 +02:00

349 lines
13 KiB
C++

/*
* Copyright (c) 2011 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#ifndef CPP_INCLUDE_LIBXTREEMFS_FILE_INFO_H_
#define CPP_INCLUDE_LIBXTREEMFS_FILE_INFO_H_
#include <stdint.h>
#include <boost/optional.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <gtest/gtest_prod.h>
#include <list>
#include <map>
#include <string>
#include "libxtreemfs/async_write_handler.h"
#include "libxtreemfs/client_implementation.h"
#include "libxtreemfs/object_cache.h"
#include "libxtreemfs/simple_uuid_iterator.h"
#include "libxtreemfs/uuid_container.h"
#include "xtreemfs/GlobalTypes.pb.h"
namespace xtreemfs {
class FileHandleImplementation;
class VolumeImplementation;
namespace pbrpc {
class Lock;
class Stat;
class UserCredentials;
} // namespace pbrpc
/** Different states regarding osd_write_response_ and its write back. */
enum FilesizeUpdateStatus {
kClean, kDirty, kDirtyAndAsyncPending, kDirtyAndSyncPending
};
class FileInfo {
public:
FileInfo(ClientImplementation* client,
VolumeImplementation* volume,
uint64_t file_id,
const std::string& path,
bool replicate_on_close,
const xtreemfs::pbrpc::XLocSet& xlocset,
const std::string& client_uuid);
~FileInfo();
/** Returns a new FileHandle object to which xcap belongs.
*
* @remark Ownership is transferred to the caller.
*/
FileHandleImplementation* CreateFileHandle(const xtreemfs::pbrpc::XCap& xcap,
bool async_writes_enabled);
/** See CreateFileHandle(xcap). Does not add file_handle to list of open
* file handles if used_for_pending_filesize_update=true.
*
* This function will be used if a FileHandle was solely created to
* asynchronously write back a dirty file size update (osd_write_response_).
*
* @remark Ownership is transferred to the caller.
*/
FileHandleImplementation* CreateFileHandle(
const xtreemfs::pbrpc::XCap& xcap,
bool async_writes_enabled,
bool used_for_pending_filesize_update);
/** Deregisters a closed FileHandle. Called by FileHandle::Close(). */
void CloseFileHandle(FileHandleImplementation* file_handle);
/** Decreases the reference count and returns the current value. */
int DecreaseReferenceCount();
/** Copies osd_write_response_ into response if not NULL. */
void GetOSDWriteResponse(xtreemfs::pbrpc::OSDWriteResponse* response);
/** Writes path_ to path. */
void GetPath(std::string* path);
/** Changes path_ to new_path if path_ == path. */
void RenamePath(const std::string& path, const std::string& new_path);
/** Compares "response" against the current "osd_write_response_". Returns
* true if response is newer and assigns "response" to "osd_write_response_".
*
* If successful, a new file handle will be created and xcap is required to
* send the osd_write_response to the MRC in the background.
*
* @remark Ownership of response is transferred to this object if this
* method returns true. */
bool TryToUpdateOSDWriteResponse(xtreemfs::pbrpc::OSDWriteResponse* response,
const xtreemfs::pbrpc::XCap& xcap);
/** Merge into a possibly outdated Stat object (e.g. from the StatCache) the
* current file size and truncate_epoch from a stored OSDWriteResponse. */
void MergeStatAndOSDWriteResponse(xtreemfs::pbrpc::Stat* stat);
/** Sends pending file size updates to the MRC asynchronously. */
void WriteBackFileSizeAsync(const RPCOptions& options);
/** Renews xcap of all file handles of this file asynchronously. */
void RenewXCapsAsync(const RPCOptions& options);
/** Releases all locks of process_id using file_handle to issue
* ReleaseLock(). */
void ReleaseLockOfProcess(FileHandleImplementation* file_handle,
int process_id);
/** Uses file_handle to release all known local locks. */
void ReleaseAllLocks(FileHandleImplementation* file_handle);
/** Blocks until all asynchronous file size updates are completed. */
void WaitForPendingFileSizeUpdates();
/** Called by the file size update callback of FileHandle. */
void AsyncFileSizeUpdateResponseHandler(
const xtreemfs::pbrpc::OSDWriteResponse& owr,
FileHandleImplementation* file_handle,
bool success);
/** Passes FileHandle::GetAttr() through to Volume. */
void GetAttr(
const xtreemfs::pbrpc::UserCredentials& user_credentials,
xtreemfs::pbrpc::Stat* stat);
/** Compares "lock" against list of active locks.
*
* Sets conflict_found to true and copies the conflicting, active lock into
* "conflicting_lock".
* If no conflict was found, "lock_for_pid_cached" is set to true if there
* exists already a lock for lock.client_pid(). Additionally,
* "cached_lock_for_pid_equal" will be set to true, lock is equal to the lock
* active for this pid. */
void CheckLock(const xtreemfs::pbrpc::Lock& lock,
xtreemfs::pbrpc::Lock* conflicting_lock,
bool* lock_for_pid_cached,
bool* cached_lock_for_pid_equal,
bool* conflict_found);
/** Returns true if a lock for "process_id" is known. */
bool CheckIfProcessHasLocks(int process_id);
/** Add a copy of "lock" to list of active locks. */
void PutLock(const xtreemfs::pbrpc::Lock& lock);
/** Remove locks equal to "lock" from list of active locks. */
void DelLock(const xtreemfs::pbrpc::Lock& lock);
/** Flushes pending async writes and file size updates. */
void Flush(FileHandleImplementation* file_handle);
/** Same as Flush(), takes special actions if called by FileHandle::Close().*/
void Flush(FileHandleImplementation* file_handle, bool close_file);
/** Flushes a pending file size update. */
void FlushPendingFileSizeUpdate(FileHandleImplementation* file_handle);
/** Calls async_write_handler_.Write().
*
* @remark Ownership of write_buffer is transferred to caller.
*/
void AsyncWrite(AsyncWriteBuffer* write_buffer);
/** Calls async_write_handler_.WaitForPendingWrites() (resulting in blocking
* until all pending async writes are finished).
*/
void WaitForPendingAsyncWrites();
/** Returns result of async_write_handler_.WaitForPendingWritesNonBlocking().
*
* @remark Ownership is not transferred to the caller.
*/
bool WaitForPendingAsyncWritesNonBlocking(
boost::condition* condition_variable,
bool* wait_completed,
boost::mutex* wait_completed_mutex);
void UpdateXLocSetAndRest(const xtreemfs::pbrpc::XLocSet& new_xlocset,
bool replicate_on_close);
void UpdateXLocSetAndRest(const xtreemfs::pbrpc::XLocSet& new_xlocset);
/** Copies the XlocSet into new_xlocset. */
void GetXLocSet(xtreemfs::pbrpc::XLocSet* new_xlocset);
/** Copies the XlocSet into new_xlocset
* and returns the corresponding UUIDContainer.
* The UUIDcontainer is just valid for the associated XLocSet.
*/
boost::shared_ptr<UUIDContainer> GetXLocSetAndUUIDContainer(
xtreemfs::pbrpc::XLocSet* new_xlocset);
/** Non-recursive scoped lock which is used to prevent concurrent XLocSet
* renewals from multiple FileHandles associated to the same FileInfo.
*
* @see FileHandleImplementation::RenewXLocSet
*/
class XLocSetRenewalLock {
private:
boost::mutex& m_;
public:
XLocSetRenewalLock(FileInfo* file_info) :
m_(file_info->xlocset_renewal_mutex_) {
m_.lock();
}
~XLocSetRenewalLock() {
m_.unlock();
}
};
private:
/** Same as FlushPendingFileSizeUpdate(), takes special actions if called by Close(). */
void FlushPendingFileSizeUpdate(FileHandleImplementation* file_handle,
bool close_file);
/** See WaitForPendingFileSizeUpdates(). */
void WaitForPendingFileSizeUpdatesHelper(boost::mutex::scoped_lock* lock);
/** Reference to Client which did open this volume. */
ClientImplementation* client_;
/** Volume which did open this file. */
VolumeImplementation* volume_;
/** XtreemFS File ID of this file (does never change). */
uint64_t file_id_;
/** Path of the File, used for debug output and writing back the
* OSDWriteResponse to the MetadataCache. */
std::string path_;
/** Extracted from the FileHandle's XCap: true if an explicit close() has to
* be send to the MRC in order to trigger the on close replication. */
bool replicate_on_close_;
/** Number of file handles which hold a pointer on this object. */
int reference_count_;
/** Use this to protect reference_count_ and path_. */
boost::mutex mutex_;
/** List of corresponding OSDs. */
xtreemfs::pbrpc::XLocSet xlocset_;
/** UUIDIterator which contains the head OSD UUIDs of all replicas.
* It is used for non-striped files. */
SimpleUUIDIterator osd_uuid_iterator_;
/** This UUIDContainer contains all OSD UUIDs for all replicas and is
* constructed from the xlocset_ passed to this class on construction.
* It is used to construct a custom ContainerUUIDIterator on the fly when
* accessing striped files.
* It is managed by a smart pointer, because it has to outlast every
* ContainerUUIDIterator derived from it.
* */
boost::shared_ptr<UUIDContainer> osd_uuid_container_;
/** Use this to protect xlocset_ and replicate_on_close_. */
boost::mutex xlocset_mutex_;
/** Use this to protect xlocset_ renewals. */
boost::mutex xlocset_renewal_mutex_;
/** List of active locks (acts as a cache). The OSD allows only one lock per
* (client UUID, PID) tuple. */
std::map<unsigned int, xtreemfs::pbrpc::Lock*> active_locks_;
/** Use this to protect active_locks_. */
boost::mutex active_locks_mutex_;
/** Random UUID of this client to distinguish them while locking. */
const std::string& client_uuid_;
/** List of open FileHandles for this file. */
std::list<FileHandleImplementation*> open_file_handles_;
/** Use this to protect open_file_handles_. */
boost::mutex open_file_handles_mutex_;
/** List of open FileHandles which solely exist to propagate a pending
* file size update (a OSDWriteResponse object) to the MRC.
*
* This extra list is needed to distinguish between the regular file handles
* (see open_file_handles_) and the ones used for file size updates.
* The intersection of both lists is empty.
*/
std::list<FileHandleImplementation*> pending_filesize_updates_;
/** Pending file size update after a write() operation, may be NULL.
*
* If osd_write_response_ != NULL, the file_size and truncate_epoch of the
* referenced OSDWriteResponse have to be respected, e.g. when answering
* a GetAttr request.
* When all file handles to a file are closed, the information of the
* stored osd_write_response_ will be merged back into the metadata cache.
* This osd_write_response_ also corresponds to the "maximum" of all known
* OSDWriteReponses. The maximum has the highest truncate_epoch, or if equal
* compared to another response, the higher size_in_bytes value.
*/
boost::scoped_ptr<xtreemfs::pbrpc::OSDWriteResponse> osd_write_response_;
/** Denotes the state of the stored osd_write_response_ object. */
FilesizeUpdateStatus osd_write_response_status_;
/** XCap required to send an OSDWriteResponse to the MRC. */
xtreemfs::pbrpc::XCap osd_write_response_xcap_;
/** Always lock to access osd_write_response_, osd_write_response_status_,
* osd_write_response_xcap_ or pending_filesize_updates_. */
boost::mutex osd_write_response_mutex_;
/** Used by NotifyFileSizeUpdateCompletition() to notify waiting threads. */
boost::condition osd_write_response_cond_;
/** Proceeds async writes, handles the callbacks and provides a
* WaitForPendingWrites() method for barrier operations like read. */
AsyncWriteHandler async_write_handler_;
/** A cache for objects of this file. Maybe NULL in which case the
* cache is disabled. */
boost::scoped_ptr<ObjectCache> object_cache_;
FRIEND_TEST(VolumeImplementationTestFastPeriodicFileSizeUpdate,
WorkingPendingFileSizeUpdates);
FRIEND_TEST(VolumeImplementationTest, FileSizeUpdateAfterFlush);
FRIEND_TEST(VolumeImplementationTestFastPeriodicFileSizeUpdate,
FileSizeUpdateAfterFlushWaitsForPendingUpdates);
FRIEND_TEST(VolumeImplementationTest, FilesLockingReleaseNonExistantLock);
FRIEND_TEST(VolumeImplementationTest, FilesLockingReleaseExistantLock);
FRIEND_TEST(VolumeImplementationTest, FilesLockingLastCloseReleasesAllLocks);
FRIEND_TEST(VolumeImplementationTest, FilesLockingReleaseLockOfProcess);
};
} // namespace xtreemfs
#endif // CPP_INCLUDE_LIBXTREEMFS_FILE_INFO_H_