mirror of
https://github.com/uroni/urbackup_backend.git
synced 2025-10-26 11:36:50 +00:00
(cherry picked from commit 989e60f639e7add19c0a72667efa4fa9219f0b6a) # Conflicts: # Interface/BackupFileSystem.h # btrfs/btrfsplugin/BackupFileSystem.h # clouddrive/CloudFile.cpp # clouddrive/KvStoreBackendAzure.cpp # clouddrive/KvStoreBackendAzure.h # clouddrive/KvStoreBackendLocal.cpp # clouddrive/KvStoreBackendLocal.h # clouddrive/KvStoreBackendS3.cpp # clouddrive/KvStoreBackendS3.h # clouddrive/KvStoreFrontend.cpp # clouddrive/OnlineKvStore.cpp # clouddrive/OnlineKvStore.h # clouddrive/PassThroughFileSystem.cpp # clouddrive/dllmain.cpp
797 lines
20 KiB
C++
797 lines
20 KiB
C++
#pragma once
|
|
#include "../Interface/File.h"
|
|
#include "../Interface/Thread.h"
|
|
#include "IOnlineKvStore.h"
|
|
#include "../Interface/Mutex.h"
|
|
#include "../Interface/SharedMutex.h"
|
|
#include "../Interface/ThreadPool.h"
|
|
#include "ICompressEncrypt.h"
|
|
#include "../common/data.h"
|
|
#include "TransactionalKvStore.h"
|
|
#ifdef HAS_MOUNT_SERVICE
|
|
#include "btrfs_chunks.h"
|
|
#endif
|
|
#include "KvStoreFrontend.h"
|
|
#ifdef HAS_ASYNC
|
|
#include "fuse_io_context.h"
|
|
#endif
|
|
#include <atomic>
|
|
#include <queue>
|
|
|
|
class IBackupFileSystem;
|
|
|
|
namespace
|
|
{
|
|
class FileBitmap;
|
|
class SparseFileBitmap;
|
|
class UpdateMissingChunksThread;
|
|
class ShareWithUpdater;
|
|
}
|
|
|
|
void task_set_less_throttle();
|
|
void task_unset_less_throttle();
|
|
bool flush_dev(std::string dev_fn);
|
|
void setMountStatus(const std::string& data);
|
|
void setMountStatusErr(const std::string& err);
|
|
|
|
class CloudFile : public IFile, public IThread, public TransactionalKvStore::INumSecondChancesCallback, IOnlineKvStore::IHasKeyCallback
|
|
{
|
|
public:
|
|
CloudFile(const std::string& cache_path,
|
|
IBackupFileSystem* cachefs,
|
|
int64 cloudfile_size,
|
|
int64 max_cloudfile_size,
|
|
IOnlineKvStore* online_kv_store,
|
|
const std::string& encryption_key,
|
|
ICompressEncryptFactory* compress_encrypt_factory,
|
|
bool verify_cache, float cpu_multiplier,
|
|
bool background_compress,
|
|
size_t no_compress_mult,
|
|
int64 reserved_cache_device_space,
|
|
int64 min_metadata_cache_free,
|
|
bool with_prev_link,
|
|
bool allow_evict,
|
|
bool with_submitted_files,
|
|
float resubmit_compressed_ratio,
|
|
int64 max_memfile_size,
|
|
std::string memcache_path,
|
|
float memory_usage_factor,
|
|
bool only_memfiles,
|
|
std::string mount_path,
|
|
std::string share_with_mount_paths,
|
|
unsigned int background_comp_method,
|
|
const std::string& slog_path,
|
|
int64 slog_max_size,
|
|
bool is_async,
|
|
unsigned int cache_comp, unsigned int meta_cache_comp);
|
|
|
|
~CloudFile();
|
|
|
|
CloudFile(CloudFile const&) = delete;
|
|
CloudFile(CloudFile&& other) = delete;
|
|
CloudFile& operator=(CloudFile&&) = delete;
|
|
CloudFile& operator=(CloudFile const&) = delete;
|
|
|
|
virtual std::string Read( _u32 tr, bool* has_error=NULL);
|
|
|
|
virtual std::string Read( int64 pos, _u32 tr, bool* has_error = NULL);
|
|
|
|
_u32 Read(int64 pos, char* buffer, _u32 bsize, bool* has_error = NULL);
|
|
|
|
virtual _u32 Read( char* buffer, _u32 bsize, bool* has_error = NULL);
|
|
|
|
virtual _u32 Write( const std::string &tw, bool* has_error = NULL);
|
|
|
|
virtual _u32 Write(int64 pos, const std::string &tw, bool* has_error = NULL);
|
|
|
|
virtual _u32 Write( const char* buffer, _u32 bsize, bool* has_error = NULL);
|
|
|
|
virtual _u32 Write( int64 pos, const char* buffer, _u32 bsize, bool* has_error = NULL);
|
|
|
|
_u32 WriteNonBlocking( int64 pos, const char* buffer, _u32 bsize, bool* has_error = NULL);
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<int> ReadAsync(fuse_io_context& io, fuse_io_context::FuseIo& fuse_io,
|
|
int64 pos, _u32 bsize, unsigned int flags, bool ext_lock);
|
|
|
|
fuse_io_context::io_uring_task<int> WriteAsync(fuse_io_context& io, fuse_io_context::FuseIo& fuse_io,
|
|
int64 pos, _u32 bsize, bool new_block, bool ext_lock, bool can_block);
|
|
#endif
|
|
|
|
virtual bool Seek( _i64 spos );
|
|
|
|
virtual _i64 Size( void );
|
|
|
|
#ifdef HAS_ASYNC
|
|
virtual fuse_io_context::io_uring_task<_i64> SizeAsync(void);
|
|
#endif
|
|
|
|
virtual _i64 RealSize(void);
|
|
|
|
virtual bool Resize(int64 nsize);
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<bool> ResizeAsync(fuse_io_context& io, int64 nsize);
|
|
#endif
|
|
|
|
virtual bool PunchHole( _i64 spos, _i64 size );
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<int> PunchHoleAsync(fuse_io_context& io, _i64 spos, _i64 size);
|
|
#endif
|
|
|
|
virtual std::string getFilename( void );
|
|
|
|
virtual bool Sync();
|
|
|
|
bool Flush();
|
|
|
|
bool Flush(bool do_submit, bool for_slog=false);
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<bool> FlushAsync(fuse_io_context& io, bool do_submit);
|
|
#endif
|
|
|
|
bool close_bitmaps();
|
|
|
|
void Reset();
|
|
|
|
int64 getDirtyBytes();
|
|
|
|
int64 getSubmittedBytes();
|
|
|
|
int64 getTotalSubmittedBytes();
|
|
|
|
int64 getUsedBytes();
|
|
|
|
std::string getNumDirtyItems();
|
|
|
|
std::string getNumMemfileItems();
|
|
|
|
int64 getCacheSize();
|
|
|
|
std::string getStats();
|
|
|
|
int64 getCompBytes();
|
|
|
|
void setDevNames(std::string bdev, std::string ldev);
|
|
|
|
static std::string block_key(int64 blocknum);
|
|
|
|
static int64 block_key_rev(const std::string& data);
|
|
|
|
static std::string big_block_key(int64 blocknum);
|
|
|
|
static std::string small_block_key(int64 blocknum);
|
|
|
|
static std::string hex_big_block_key(int64 bytenum);
|
|
|
|
static std::string hex_small_block_key(int64 bytenum);
|
|
|
|
int Congested();
|
|
|
|
int CongestedAsync();
|
|
|
|
std::string get_raid_groups();
|
|
|
|
std::string scrub_stats();
|
|
|
|
void start_scrub(ScrubAction action);
|
|
|
|
void stop_scrub();
|
|
|
|
bool add_disk(const std::string& path);
|
|
|
|
bool remove_disk(const std::string& path, bool completely);
|
|
|
|
std::string disk_error_info();
|
|
|
|
int64 current_total_size();
|
|
|
|
int64 current_free_space();
|
|
|
|
bool set_target_failure_probability(double t);
|
|
|
|
bool set_target_overhead(double t);
|
|
|
|
std::string get_scrub_position();
|
|
|
|
int64 get_memfile_bytes();
|
|
|
|
int64 get_submitted_memfile_bytes();
|
|
|
|
virtual void operator()();
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task_discard<int> run_async(fuse_io_context& io);
|
|
#endif
|
|
|
|
void run_cd_fracture();
|
|
|
|
bool start_raid_defrag(const std::string& settings);
|
|
|
|
bool is_background_worker_enabled();
|
|
|
|
bool is_background_worker_running();
|
|
|
|
void enable_background_worker(bool b);
|
|
|
|
bool start_background_worker();
|
|
|
|
void set_background_worker_result_fn(const std::string& result_fn);
|
|
|
|
bool has_background_task();
|
|
|
|
void preload(int64 start, int64 stop, size_t n_threads);
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<int> preload_async(fuse_io_context& io, int64 start, int64 stop, size_t n_threads);
|
|
#endif
|
|
|
|
void cmd(const std::string& c);
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<int> cmd_async(fuse_io_context& io, const std::string& c);
|
|
#endif
|
|
|
|
static int64 key_offset_hex(const std::string& key);
|
|
|
|
static int64 key_offset(const std::string& key, bool& big_block);
|
|
|
|
static int64 key_offset(const std::string& key);
|
|
|
|
std::string meminfo();
|
|
|
|
void shrink_mem();
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<int> shrink_mem_async(fuse_io_context& io);
|
|
#endif
|
|
|
|
int64 get_total_hits();
|
|
|
|
int64 get_total_hits_async();
|
|
|
|
int64 get_total_memory_hits();
|
|
|
|
int64 get_total_memory_hits_async();
|
|
|
|
int64 get_total_cache_miss_backend();
|
|
|
|
int64 get_total_cache_miss_decompress();
|
|
|
|
int64 get_total_dirty_ops();
|
|
|
|
int64 get_total_balance_ops();
|
|
|
|
int64 get_total_del_ops();
|
|
|
|
int64 get_total_put_ops();
|
|
|
|
int64 get_total_compress_ops();
|
|
|
|
bool has_preload_item(int64 offset_start, int64 offset_end);
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<bool> has_preload_item_async(fuse_io_context& io, int64 offset_start, int64 offset_end);
|
|
#endif
|
|
|
|
int64 min_block_size();
|
|
|
|
void set_is_mounted(const std::string& p_mount_path, IBackupFileSystem* fs);
|
|
|
|
bool is_metadata(int64 offset, const std::string& key);
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<bool> is_metadata_async(fuse_io_context& io, int64 offset, const std::string& key);
|
|
#endif
|
|
|
|
virtual unsigned int get_num_second_chances(const std::string& key);
|
|
|
|
virtual bool is_metadata(const std::string& key);
|
|
|
|
bool update_missing_fs_chunks();
|
|
|
|
bool migrate(std::vector<char>& buf, int64 offset, int64 len);
|
|
|
|
bool migrate(const std::string& conf_fn, bool continue_migration);
|
|
|
|
std::string migration_info();
|
|
|
|
void preload_key(const std::string& key, int64 offset, int64 len, int tag, bool disable_memfiles, bool load_only);
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<int> preload_key_async(fuse_io_context& io, const std::string& key, int64 offset, int64 len, int tag, bool disable_memfiles, bool load_only);
|
|
#endif
|
|
|
|
int64 get_uploaded_bytes();
|
|
|
|
int64 get_downloaded_bytes();
|
|
|
|
int64 get_written_bytes();
|
|
|
|
int64 get_read_bytes();
|
|
|
|
std::string get_raid_io_stats();
|
|
|
|
bool replay_slog();
|
|
|
|
std::string get_mirror_stats();
|
|
|
|
std::string get_raid_freespace_stats();
|
|
|
|
virtual bool hasKey(const std::string& key) override;
|
|
|
|
int64 get_transid();
|
|
private:
|
|
|
|
void preload_items(const std::string& fn, size_t n_threads, int tag, bool disable_memfiles, bool load_only);
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<int> preload_items_async(fuse_io_context& io, const std::string& fn,
|
|
size_t n_threads, int tag, bool disable_memfiles, bool load_only);
|
|
#endif
|
|
|
|
_u32 WriteInt(int64 pos, const char* buffer, _u32 bsize, bool new_block, IScopedLock* ext_lock, bool can_block, bool* has_error);
|
|
|
|
_u32 ReadInt(int64 pos, char* buffer, _u32 bsize, IScopedLock* ext_lock, unsigned int flags, bool* has_error);
|
|
|
|
_u32 ReadAligned(IFile* block, int64 pos, char* buffer, _u32 toread, bool* has_read_error);
|
|
|
|
_u32 WriteAligned(IFile* block, int64 pos, const char* buffer, _u32 towrite);
|
|
|
|
void perform_deletes();
|
|
|
|
void open_bitmaps();
|
|
|
|
bool bitmap_has_big_block(int64 blocknum);
|
|
bool bitmap_has_small_block(int64 blocknum);
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<bool> bitmap_has_big_block_async(fuse_io_context& io, int64 blocknum);
|
|
fuse_io_context::io_uring_task<bool> bitmap_has_small_block_async(fuse_io_context& io, int64 blocknum);
|
|
#endif
|
|
|
|
void lock_extent(IScopedLock& lock, int64 start, int64 length, bool exclusive);
|
|
void unlock_extent(IScopedLock& lock, int64 start, int64 length, bool exclusive);
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<size_t> lock_extent_async(int64 start, int64 length, bool exclusive);
|
|
#endif
|
|
void unlock_extent_async(int64 start, int64 length, bool exclusive, size_t lock_idx);
|
|
|
|
void add_fracture_big_block(int64 b);
|
|
|
|
void update_fs_chunks(bool update_time, IScopedWriteLock& lock);
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<void> update_fs_chunks_async(fuse_io_context& io, bool update_time);
|
|
#endif
|
|
|
|
bool migrate(const std::string& conf_fn, ISettingsReader* settings);
|
|
|
|
bool update_migration_settings();
|
|
|
|
IOnlineKvStore* create_migration_endpoint(const std::string& conf_fn, ISettingsReader* settings,
|
|
IBackupFileSystem* migrate_cachefs);
|
|
|
|
bool slog_write(int64 pos, const char* buffer, _u32 bsize, bool& needs_reset);
|
|
|
|
bool slog_open();
|
|
|
|
void purge_jemalloc();
|
|
|
|
void set_jemalloc_dirty_decay(int64 timems);
|
|
|
|
/*_u32 prepare_zero_n_sqes(_u32 towrite);
|
|
|
|
std::vector<io_uring_sqe*> prepare_zeros(fuse_io_context& io, fuse_io_context::FuseIo& fuse_io, _u32 towrite, _u32 peek_add);*/
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task<int> empty_pipe(fuse_io_context& io, fuse_io_context::FuseIo& fuse_io);
|
|
|
|
fuse_io_context::io_uring_task<bool> verify_pipe_empty(fuse_io_context& io, fuse_io_context::FuseIo& fuse_io);
|
|
|
|
struct AwaiterCoList
|
|
{
|
|
AwaiterCoList* next;
|
|
std::coroutine_handle<> awaiter;
|
|
};
|
|
|
|
fuse_io_context::io_uring_task_discard<int> preload_async_read(fuse_io_context& io, std::vector<std::unique_ptr<fuse_io_context::FuseIo> >& ios, AwaiterCoList*& ios_waiters_head, int64 start, _u32 size);
|
|
|
|
fuse_io_context::io_uring_task_discard<int> preload_items_single_async(fuse_io_context& io, size_t& available_workers, AwaiterCoList*& worker_waiters_head,
|
|
std::string key, int64 offset, _u32 len, int tag, bool disable_memfiles, bool load_only);
|
|
|
|
struct ReadTask
|
|
{
|
|
ReadTask(int fd, IFsFile* file, std::string key, uint64_t off, _u32 size)
|
|
: fd(fd), file(file), key(std::move(key)), off(off), size(size), flush_mem(false) {}
|
|
int fd;
|
|
IFsFile* file;
|
|
std::string key;
|
|
int64 off;
|
|
_u32 size;
|
|
bool flush_mem;
|
|
};
|
|
|
|
fuse_io_context::io_uring_task<int> complete_read_tasks(fuse_io_context& io, fuse_io_context::FuseIo& fuse_io,
|
|
const std::vector<ReadTask>& read_tasks, const size_t flush_mem_n_tasks, const int64 orig_pos, const _u32 bsize,
|
|
const unsigned int flags);
|
|
#endif
|
|
|
|
|
|
struct SExtent
|
|
{
|
|
int64 start;
|
|
int64 length;
|
|
ICondition* cond;
|
|
int refcount;
|
|
bool alive;
|
|
};
|
|
|
|
std::vector<SExtent> locked_extents;
|
|
|
|
#ifdef HAS_ASYNC
|
|
struct SExtentAsync
|
|
{
|
|
int64 start;
|
|
int64 length;
|
|
bool exclusive;
|
|
AwaiterCoList* awaiters;
|
|
int refcount;
|
|
};
|
|
|
|
std::vector<SExtentAsync> async_locked_extents;
|
|
#endif
|
|
|
|
|
|
size_t locked_extents_max_alive;
|
|
size_t wait_for_exclusive;
|
|
|
|
std::unique_ptr<IOnlineKvStore> online_kv_store;
|
|
TransactionalKvStore kv_store;
|
|
|
|
IFsFile* big_blocks_bitmap_file;
|
|
IFsFile* bitmap_file;
|
|
IFsFile* new_big_blocks_bitmap_file;
|
|
IFsFile* old_big_blocks_bitmap_file;
|
|
|
|
std::unique_ptr<FileBitmap> old_big_blocks_bitmap;
|
|
std::unique_ptr<FileBitmap> new_big_blocks_bitmap;
|
|
|
|
std::unique_ptr<SparseFileBitmap> big_blocks_bitmap;
|
|
std::unique_ptr<SparseFileBitmap> bitmap;
|
|
|
|
int64 cf_pos;
|
|
int64 active_big_block;
|
|
|
|
int64 used_bytes;
|
|
|
|
int64 last_stat_update_time;
|
|
int64 last_flush_check;
|
|
|
|
int64 cloudfile_size;
|
|
|
|
std::unique_ptr<IMutex> mutex;
|
|
|
|
std::string bdev_name;
|
|
std::string ldev_name;
|
|
size_t writeback_count;
|
|
std::string bcache_writeback_percent;
|
|
|
|
unsigned int io_alignment;
|
|
|
|
std::map<int64, int64> fracture_big_blogs;
|
|
std::unique_ptr<ICondition> thread_cond;
|
|
bool exit_thread;
|
|
THREADPOOL_TICKET fracture_big_blogs_ticket;
|
|
|
|
float memory_usage_factor;
|
|
|
|
int64 bitmaps_file_size;
|
|
|
|
size_t flush_enabled;
|
|
|
|
std::string cache_path;
|
|
|
|
std::string mount_path;
|
|
|
|
std::unique_ptr<ISharedMutex> chunks_mutex;
|
|
std::vector<IBackupFileSystem::SChunk> fs_chunks;
|
|
int64 last_fs_chunks_update;
|
|
std::vector<std::pair<std::string, int64> > missing_chunk_keys;
|
|
bool updating_fs_chunks;
|
|
std::unique_ptr<UpdateMissingChunksThread> update_missing_chunks_thread;
|
|
THREADPOOL_TICKET update_missing_chunks_thread_ticket;
|
|
|
|
std::unique_ptr<CloudFile> migrate_to_cf;
|
|
std::unique_ptr<IThreadPool> migration_thread_pool;
|
|
std::atomic<bool> migration_has_error;
|
|
std::atomic<int64> migration_copy_max;
|
|
std::atomic<int64> migration_copy_done;
|
|
int64 migration_copy_done_lag;
|
|
std::string migration_conf_fn;
|
|
THREADPOOL_TICKET migration_ticket;
|
|
|
|
std::set<std::string> in_write_retrieval;
|
|
std::unique_ptr<ICondition> in_write_retrieval_cond;
|
|
|
|
THREADPOOL_TICKET share_with_updater_ticket;
|
|
std::unique_ptr<ShareWithUpdater> share_with_updater;
|
|
|
|
int64 written_bytes;
|
|
int64 read_bytes;
|
|
|
|
std::atomic<int64> slog_size;
|
|
std::atomic<int64> slog_last_sync;
|
|
std::unique_ptr<IFsFile> slog;
|
|
std::string slog_path;
|
|
int64 slog_max_size;
|
|
|
|
bool enable_raid_freespace_stats;
|
|
|
|
bool is_flushing;
|
|
|
|
int zero_memfd;
|
|
_u32 zero_memfd_size;
|
|
|
|
#ifdef HAS_ASYNC
|
|
AwaiterCoList* exclusive_awaiter_head = nullptr;
|
|
|
|
struct ExclusiveAwaiter
|
|
{
|
|
ExclusiveAwaiter(CloudFile& cd)
|
|
: cd(cd) {}
|
|
ExclusiveAwaiter(ExclusiveAwaiter const&) = delete;
|
|
ExclusiveAwaiter(ExclusiveAwaiter&& other) = delete;
|
|
ExclusiveAwaiter& operator=(ExclusiveAwaiter&&) = delete;
|
|
ExclusiveAwaiter& operator=(ExclusiveAwaiter const&) = delete;
|
|
|
|
bool await_ready() const noexcept
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void await_suspend(std::coroutine_handle<> p_awaiter) noexcept
|
|
{
|
|
awaiter.awaiter = p_awaiter;
|
|
awaiter.next = cd.exclusive_awaiter_head;
|
|
cd.exclusive_awaiter_head = &awaiter;
|
|
}
|
|
|
|
void await_resume() const noexcept
|
|
{
|
|
}
|
|
|
|
private:
|
|
AwaiterCoList awaiter;
|
|
CloudFile& cd;
|
|
};
|
|
|
|
void resume_awaiters(AwaiterCoList*& head)
|
|
{
|
|
AwaiterCoList* curr = head;
|
|
head = nullptr;
|
|
|
|
while (curr != nullptr)
|
|
{
|
|
AwaiterCoList* next = curr->next;
|
|
curr->awaiter.resume();
|
|
curr = next;
|
|
}
|
|
}
|
|
|
|
void resume_exclusive_awaiters()
|
|
{
|
|
resume_awaiters(exclusive_awaiter_head);
|
|
}
|
|
|
|
AwaiterCoList* write_retrieval_head = nullptr;
|
|
|
|
struct WriteRetrievalAwaiter
|
|
{
|
|
WriteRetrievalAwaiter(CloudFile& cd)
|
|
: cd(cd) {}
|
|
WriteRetrievalAwaiter(WriteRetrievalAwaiter const&) = delete;
|
|
WriteRetrievalAwaiter(WriteRetrievalAwaiter&& other) = delete;
|
|
WriteRetrievalAwaiter& operator=(WriteRetrievalAwaiter&&) = delete;
|
|
WriteRetrievalAwaiter& operator=(WriteRetrievalAwaiter const&) = delete;
|
|
|
|
bool await_ready() const noexcept
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void await_suspend(std::coroutine_handle<> p_awaiter) noexcept
|
|
{
|
|
awaiter.awaiter = p_awaiter;
|
|
awaiter.next = cd.write_retrieval_head;
|
|
cd.write_retrieval_head = &awaiter;
|
|
}
|
|
|
|
void await_resume() const noexcept
|
|
{
|
|
}
|
|
|
|
private:
|
|
AwaiterCoList awaiter;
|
|
CloudFile& cd;
|
|
};
|
|
|
|
void resume_write_retrieval_awaiters()
|
|
{
|
|
resume_awaiters(write_retrieval_head);
|
|
}
|
|
|
|
struct ExtentAwaiter
|
|
{
|
|
ExtentAwaiter(SExtentAsync& extent)
|
|
: extent(extent) {}
|
|
ExtentAwaiter(ExtentAwaiter const&) = delete;
|
|
ExtentAwaiter(ExtentAwaiter&& other) = delete;
|
|
ExtentAwaiter& operator=(ExtentAwaiter&&) = delete;
|
|
ExtentAwaiter& operator=(ExtentAwaiter const&) = delete;
|
|
|
|
bool await_ready() const noexcept
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void await_suspend(std::coroutine_handle<> p_awaiter) noexcept
|
|
{
|
|
awaiter.awaiter = p_awaiter;
|
|
awaiter.next = extent.awaiters;
|
|
extent.awaiters = &awaiter;
|
|
}
|
|
|
|
void await_resume() const noexcept
|
|
{
|
|
}
|
|
|
|
private:
|
|
AwaiterCoList awaiter;
|
|
SExtentAsync& extent;
|
|
};
|
|
|
|
struct IosAwaiter
|
|
{
|
|
IosAwaiter(std::vector<std::unique_ptr<fuse_io_context::FuseIo> >& ios, AwaiterCoList*& ios_awaiter_head)
|
|
: ios(ios), ios_awaiter_head(ios_awaiter_head) {}
|
|
IosAwaiter(IosAwaiter const&) = delete;
|
|
IosAwaiter(IosAwaiter&& other) = delete;
|
|
IosAwaiter& operator=(IosAwaiter&&) = delete;
|
|
IosAwaiter& operator=(IosAwaiter const&) = delete;
|
|
|
|
bool await_ready() const noexcept
|
|
{
|
|
return !ios.empty();
|
|
}
|
|
|
|
void await_suspend(std::coroutine_handle<> p_awaiter) noexcept
|
|
{
|
|
awaiter.awaiter = p_awaiter;
|
|
awaiter.next = ios_awaiter_head;
|
|
ios_awaiter_head = &awaiter;
|
|
}
|
|
|
|
std::unique_ptr<fuse_io_context::FuseIo> await_resume() noexcept
|
|
{
|
|
std::unique_ptr<fuse_io_context::FuseIo> ret = std::move(ios.back());
|
|
ios.pop_back();
|
|
return std::move(ret);
|
|
}
|
|
|
|
private:
|
|
AwaiterCoList awaiter;
|
|
std::vector<std::unique_ptr<fuse_io_context::FuseIo> >& ios;
|
|
AwaiterCoList*& ios_awaiter_head;
|
|
};
|
|
|
|
void iosWaitersResume(std::vector<std::unique_ptr<fuse_io_context::FuseIo> >& ios,
|
|
AwaiterCoList*& ios_waiters_head)
|
|
{
|
|
AwaiterCoList* curr = ios_waiters_head;
|
|
ios_waiters_head = nullptr;
|
|
|
|
while (curr != nullptr
|
|
&& !ios.empty())
|
|
{
|
|
AwaiterCoList* next = curr->next;
|
|
curr->awaiter.resume();
|
|
curr = next;
|
|
}
|
|
|
|
if (curr != nullptr)
|
|
{
|
|
curr->next = ios_waiters_head;
|
|
ios_waiters_head = curr;
|
|
}
|
|
}
|
|
|
|
struct WorkerAwaiter
|
|
{
|
|
WorkerAwaiter(size_t& available_workers, AwaiterCoList*& worker_awaiter_head)
|
|
: available_workers(available_workers), worker_awaiter_head(worker_awaiter_head) {}
|
|
WorkerAwaiter(WorkerAwaiter const&) = delete;
|
|
WorkerAwaiter(WorkerAwaiter&& other) = delete;
|
|
WorkerAwaiter& operator=(WorkerAwaiter&&) = delete;
|
|
WorkerAwaiter& operator=(WorkerAwaiter const&) = delete;
|
|
|
|
bool await_ready() const noexcept
|
|
{
|
|
return available_workers > 0;
|
|
}
|
|
|
|
void await_suspend(std::coroutine_handle<> p_awaiter) noexcept
|
|
{
|
|
awaiter.awaiter = p_awaiter;
|
|
awaiter.next = worker_awaiter_head;
|
|
worker_awaiter_head = &awaiter;
|
|
}
|
|
|
|
void await_resume() noexcept
|
|
{
|
|
assert(available_workers > 0);
|
|
--available_workers;
|
|
}
|
|
|
|
private:
|
|
AwaiterCoList awaiter;
|
|
size_t& available_workers;
|
|
AwaiterCoList*& worker_awaiter_head;
|
|
};
|
|
|
|
void workerWaitersResume(size_t& available_workers,
|
|
AwaiterCoList*& ios_waiters_head)
|
|
{
|
|
AwaiterCoList* curr = ios_waiters_head;
|
|
ios_waiters_head = nullptr;
|
|
|
|
while (curr != nullptr
|
|
&& available_workers>0)
|
|
{
|
|
AwaiterCoList* next = curr->next;
|
|
curr->awaiter.resume();
|
|
curr = next;
|
|
}
|
|
|
|
if (curr != nullptr)
|
|
{
|
|
curr->next = ios_waiters_head;
|
|
ios_waiters_head = curr;
|
|
}
|
|
}
|
|
#endif //HAS_ASYNC
|
|
|
|
std::unique_ptr<IFsFile> null_file;
|
|
std::unique_ptr<IFsFile> zero_file;
|
|
|
|
bool is_async;
|
|
|
|
#ifdef HAS_ASYNC
|
|
fuse_io_context::io_uring_task_discard<int> run_async_queue(fuse_io_context& io);
|
|
|
|
bool get_async_msg(CWData& msg, CRData& resp);
|
|
#endif
|
|
|
|
int queue_in_eventfd;
|
|
|
|
int update_fs_chunks_eventfd;
|
|
|
|
std::unique_ptr<IMutex> msg_queue_mutex;
|
|
std::unique_ptr<ICondition> msg_queue_cond;
|
|
int64 msg_queue_id;
|
|
std::queue<std::vector<char> > msg_queue;
|
|
std::map<size_t, std::vector<char> > msg_queue_responses;
|
|
|
|
std::set<int64> consider_big_blocks;
|
|
std::set<int64> curr_consider_big_blocks;
|
|
|
|
bool fallocate_block_file = true;
|
|
|
|
IBackupFileSystem* cachefs;
|
|
|
|
IBackupFileSystem* topfs = nullptr;
|
|
};
|