//////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany /// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// /// @author Jan Steemann //////////////////////////////////////////////////////////////////////////////// #ifndef ARANGOD_WAL_LOGFILE_H #define ARANGOD_WAL_LOGFILE_H 1 #include "Basics/Common.h" #include "Logger/Logger.h" #include "VocBase/datafile.h" #include "VocBase/DatafileHelper.h" #include "VocBase/voc-types.h" #include "Wal/Marker.h" namespace arangodb { namespace wal { class Logfile { public: ////////////////////////////////////////////////////////////////////////////// /// @brief typedef for logfile ids ////////////////////////////////////////////////////////////////////////////// typedef TRI_voc_fid_t IdType; ////////////////////////////////////////////////////////////////////////////// /// @brief logfile status ////////////////////////////////////////////////////////////////////////////// enum class StatusType : uint32_t { UNKNOWN = 0, EMPTY = 1, OPEN = 2, SEAL_REQUESTED = 3, SEALED = 4, COLLECTION_REQUESTED = 5, COLLECTED = 6 }; private: ////////////////////////////////////////////////////////////////////////////// /// @brief Logfile ////////////////////////////////////////////////////////////////////////////// Logfile(Logfile const&) = delete; Logfile& operator=(Logfile const&) = delete; public: ////////////////////////////////////////////////////////////////////////////// /// @brief create a logfile ////////////////////////////////////////////////////////////////////////////// Logfile(Logfile::IdType, TRI_datafile_t*, StatusType); ////////////////////////////////////////////////////////////////////////////// /// @brief destroy a logfile ////////////////////////////////////////////////////////////////////////////// ~Logfile(); ////////////////////////////////////////////////////////////////////////////// /// @brief create a new logfile ////////////////////////////////////////////////////////////////////////////// static Logfile* createNew(std::string const&, Logfile::IdType, uint32_t); ////////////////////////////////////////////////////////////////////////////// /// @brief open an existing logfile ////////////////////////////////////////////////////////////////////////////// static Logfile* openExisting(std::string const&, Logfile::IdType, bool, bool); ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not a logfile is empty ////////////////////////////////////////////////////////////////////////////// static int judge(std::string const&); ////////////////////////////////////////////////////////////////////////////// /// @brief return the filename ////////////////////////////////////////////////////////////////////////////// inline std::string filename() const { if (_df == nullptr) { return ""; } return _df->getName(_df); } ////////////////////////////////////////////////////////////////////////////// /// @brief return the datafile pointer ////////////////////////////////////////////////////////////////////////////// inline TRI_datafile_t* df() const { return _df; } ////////////////////////////////////////////////////////////////////////////// /// @brief return the file descriptor ////////////////////////////////////////////////////////////////////////////// inline int fd() const { return _df->_fd; } ////////////////////////////////////////////////////////////////////////////// /// @brief return the logfile id ////////////////////////////////////////////////////////////////////////////// inline Logfile::IdType id() const { return _id; } ////////////////////////////////////////////////////////////////////////////// /// @brief update the logfile tick status ////////////////////////////////////////////////////////////////////////////// inline void update(TRI_df_marker_t const* marker) { TRI_UpdateTicksDatafile(df(), marker); } ////////////////////////////////////////////////////////////////////////////// /// @brief return the logfile status ////////////////////////////////////////////////////////////////////////////// inline Logfile::StatusType status() const { return _status; } ////////////////////////////////////////////////////////////////////////////// /// @brief return the allocated size of the logfile ////////////////////////////////////////////////////////////////////////////// inline uint64_t allocatedSize() const { return static_cast(_df->_maximalSize); } ////////////////////////////////////////////////////////////////////////////// /// @brief return the size of the free space in the logfile ////////////////////////////////////////////////////////////////////////////// uint64_t freeSize() const { if (isSealed()) { return 0; } return static_cast(allocatedSize() - _df->_currentSize - DatafileHelper::JournalOverhead()); } ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not a marker of the specified size can be written into /// the logfile ////////////////////////////////////////////////////////////////////////////// bool isWriteable(uint32_t size) const { if (isSealed() || freeSize() < static_cast(size)) { return false; } return true; } ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not the logfile is sealed ////////////////////////////////////////////////////////////////////////////// inline bool isSealed() const { return (_status == StatusType::SEAL_REQUESTED || _status == StatusType::SEALED || _status == StatusType::COLLECTION_REQUESTED || _status == StatusType::COLLECTED); } ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not the logfile can be sealed ////////////////////////////////////////////////////////////////////////////// inline bool canBeSealed() const { return (_status == StatusType::SEAL_REQUESTED); } ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not the logfile can be collected ////////////////////////////////////////////////////////////////////////////// inline bool canBeCollected() const { return (_status == StatusType::SEALED || _status == StatusType::COLLECTION_REQUESTED); } ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not the logfile can be removed ////////////////////////////////////////////////////////////////////////////// inline bool canBeRemoved() const { return (_status == StatusType::COLLECTED && _collectQueueSize == 0 && _users == 0); } ////////////////////////////////////////////////////////////////////////////// /// @brief return the logfile status as a string ////////////////////////////////////////////////////////////////////////////// std::string statusText() const { return statusText(status()); } ////////////////////////////////////////////////////////////////////////////// /// @brief return the logfile status as a string ////////////////////////////////////////////////////////////////////////////// static std::string statusText(StatusType status) { switch (status) { case StatusType::EMPTY: return "empty"; case StatusType::OPEN: return "open"; case StatusType::SEAL_REQUESTED: return "seal-requested"; case StatusType::SEALED: return "sealed"; case StatusType::COLLECTION_REQUESTED: return "collection-requested"; case StatusType::COLLECTED: return "collected"; case StatusType::UNKNOWN: default: return "unknown"; } } ////////////////////////////////////////////////////////////////////////////// /// @brief change the logfile status, without assertions ////////////////////////////////////////////////////////////////////////////// void forceStatus(StatusType status) { _status = status; } ////////////////////////////////////////////////////////////////////////////// /// @brief change the logfile status, with assertions ////////////////////////////////////////////////////////////////////////////// void setStatus(StatusType status) { switch (status) { case StatusType::UNKNOWN: case StatusType::EMPTY: TRI_ASSERT(false); break; case StatusType::OPEN: TRI_ASSERT(_status == StatusType::EMPTY); break; case StatusType::SEAL_REQUESTED: TRI_ASSERT(_status == StatusType::OPEN); break; case StatusType::SEALED: TRI_ASSERT(_status == StatusType::SEAL_REQUESTED); break; case StatusType::COLLECTION_REQUESTED: TRI_ASSERT(_status == StatusType::SEALED); break; case StatusType::COLLECTED: TRI_ASSERT(_status == StatusType::COLLECTION_REQUESTED); break; } LOG(TRACE) << "changing logfile status from " << statusText(_status) << " to " << statusText(status) << " for logfile " << id(); _status = status; } ////////////////////////////////////////////////////////////////////////////// /// @brief reserve space and update the current write position ////////////////////////////////////////////////////////////////////////////// char* reserve(size_t); ////////////////////////////////////////////////////////////////////////////// /// @brief increase the number of collect operations waiting ////////////////////////////////////////////////////////////////////////////// inline void increaseCollectQueueSize() { ++_collectQueueSize; } ////////////////////////////////////////////////////////////////////////////// /// @brief decrease the number of collect operations waiting ////////////////////////////////////////////////////////////////////////////// inline void decreaseCollectQueueSize() { --_collectQueueSize; } ////////////////////////////////////////////////////////////////////////////// /// @brief use a logfile - while there are users, the logfile cannot be /// deleted ////////////////////////////////////////////////////////////////////////////// inline void use() { ++_users; } ////////////////////////////////////////////////////////////////////////////// /// @brief release a logfile - while there are users, the logfile cannot be /// deleted ////////////////////////////////////////////////////////////////////////////// inline void release() { TRI_ASSERT(_users > 0); --_users; } ////////////////////////////////////////////////////////////////////////////// /// @brief the logfile id ////////////////////////////////////////////////////////////////////////////// Logfile::IdType const _id; ////////////////////////////////////////////////////////////////////////////// /// @brief the number of logfile users ////////////////////////////////////////////////////////////////////////////// std::atomic _users; ////////////////////////////////////////////////////////////////////////////// /// @brief the datafile entry ////////////////////////////////////////////////////////////////////////////// TRI_datafile_t* _df; ////////////////////////////////////////////////////////////////////////////// /// @brief logfile status ////////////////////////////////////////////////////////////////////////////// StatusType _status; ////////////////////////////////////////////////////////////////////////////// /// @brief number of collect operations waiting ////////////////////////////////////////////////////////////////////////////// std::atomic _collectQueueSize; }; } } #endif