#ifndef DISKLIST_H_ #define DISKLIST_H_ #include #include #include #include #include #include #include #include #include #include struct DiskListDoesNotExist : public std::runtime_error { DiskListDoesNotExist(const std::string& file) : runtime_error(file) {} }; template class DiskList; template class DiskListCursor { friend class DiskList; public: bool step() { uint64_t itemLen; { ssize_t readRes = ::pread(fd, &itemLen, sizeof(itemLen), offset); if (readRes == 0) return false; if (readRes < (ssize_t) sizeof(itemLen)) throw std::runtime_error("could not read from disk list file: " + std::string(strerror(errno))); } itemLen = LE_TO_HOST_64(itemLen); std::unique_ptr itemBuf(new char[itemLen]); ssize_t readRes = ::pread(fd, itemBuf.get(), itemLen, offset + sizeof(itemLen)); if (readRes < (ssize_t) itemLen) throw std::runtime_error("could not read from disk list file: " + std::string(strerror(errno))); Deserializer des(itemBuf.get(), itemLen); des % item; if (!des.good()) throw std::runtime_error("could not read from disk list file: " + std::string(strerror(errno))); offset += sizeof(itemLen) + itemLen; return true; } Data* get() { return &item; } private: int fd; size_t offset; Data item; DiskListCursor(int fd): fd(fd), offset(0) { } }; template class DiskList { private: std::string file; int fd; uint64_t itemCount; Mutex mtx; DiskList(const DiskList&); DiskList& operator=(const DiskList&); public: DiskList(const std::string& file, bool allowCreate = true) : file(file), itemCount(0) { fd = ::open(file.c_str(), O_RDWR | (allowCreate ? O_CREAT : 0), 0660); if(fd < 0) { int eno = errno; if(!allowCreate && errno == ENOENT) throw DiskListDoesNotExist(file); else throw std::runtime_error("could not open disk list file " + file + ": " + strerror(eno)); } } ~DiskList() { if(fd >= 0) close(fd); } const std::string filename() const { return file; } void append(const Data& data) { std::lock_guard lock(mtx); boost::scoped_array buffer; ssize_t size = serializeIntoNewBuffer(data, buffer); if (size < 0) throw std::runtime_error("error serializing disk list item"); uint64_t bufSize = HOST_TO_LE_64(size); if (::write(fd, &bufSize, sizeof(bufSize)) < (ssize_t) sizeof(bufSize)) throw std::runtime_error("error writing disk list item: " + std::string(strerror(errno))); if (::write(fd, buffer.get(), size) < size) throw std::runtime_error("error writing disk list item: " + std::string(strerror(errno))); } DiskListCursor cursor() { return DiskListCursor(fd); } void clear() { if (fd >= 0) { if (ftruncate(fd, 0) < 0) throw std::runtime_error("error clearing disk list: " + std::string(strerror(errno))); } } }; #endif