#ifndef BLOCK_CACHE_IO_ENGINE_H #define BLOCK_CACHE_IO_ENGINE_H #include "base/types.h" #include "base/unique_handle.h" #include <boost/optional.hpp> #include <ctype.h> #include <set> #include <string> #include <libaio.h> #include <vector> #include <limits.h> #ifndef PAGE_SIZE #define PAGE_SIZE sysconf(_SC_PAGE_SIZE) #endif //---------------------------------------------------------------- namespace bcache { using base::sector_t; using base::SECTOR_SHIFT; // Virtual base class to aid unit testing class io_engine { public: enum mode { M_READ_ONLY, M_READ_WRITE }; enum dir { D_READ, D_WRITE }; enum sharing { EXCLUSIVE, SHARED }; io_engine() {} virtual ~io_engine() {} using handle = unsigned; virtual handle open_file(std::string const &path, mode m, sharing s = EXCLUSIVE) = 0; virtual void close_file(handle h) = 0; // returns false if there are insufficient resources to // queue the IO virtual bool issue_io(handle h, dir d, sector_t b, sector_t e, void *data, unsigned context) = 0; // returns (success, context) using wait_result = std::pair<bool, unsigned>; virtual boost::optional<wait_result> wait() = 0; virtual boost::optional<wait_result> wait(unsigned µsec) = 0; private: io_engine(io_engine const &) = delete; io_engine &operator =(io_engine const &) = delete; }; //-------------------------------- class control_block_set { public: control_block_set(unsigned nr); iocb *alloc(unsigned context); void free(iocb *); unsigned context(iocb *) const; private: struct cblock { unsigned context; struct iocb cb; }; std::set<unsigned> free_cbs_; std::vector<cblock> cbs_; }; //---------------- class aio_engine : public io_engine { public: // max_io is the maximum nr of concurrent ios expected aio_engine(unsigned max_io); ~aio_engine(); using handle = unsigned; virtual handle open_file(std::string const &path, mode m, sharing s = EXCLUSIVE); virtual void close_file(handle h); // Returns false if queueing the io failed virtual bool issue_io(handle h, dir d, sector_t b, sector_t e, void *data, unsigned context); virtual boost::optional<wait_result> wait(); virtual boost::optional<wait_result> wait(unsigned µsec); private: static struct timespec micro_to_ts(unsigned micro); static unsigned ts_to_micro(timespec const &ts); boost::optional<io_engine::wait_result> wait_(timespec *ts); std::list<base::unique_fd> descriptors_; io_context_t aio_context_; control_block_set cbs_; aio_engine(io_engine const &) = delete; aio_engine &operator =(io_engine const &) = delete; }; } //---------------------------------------------------------------- #endif