LogCabin
|
00001 /* Copyright (c) 2013 Stanford University 00002 * Copyright (c) 2015 Diego Ongaro 00003 * 00004 * Permission to use, copy, modify, and distribute this software for any 00005 * purpose with or without fee is hereby granted, provided that the above 00006 * copyright notice and this permission notice appear in all copies. 00007 * 00008 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES 00009 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 00010 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR 00011 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00012 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 00013 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 00014 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00015 */ 00016 00017 #include <google/protobuf/message.h> 00018 #include <memory> 00019 #include <stdexcept> 00020 #include <string> 00021 00022 #include "Core/CompatAtomic.h" 00023 #include "Core/ProtoBuf.h" 00024 #include "Storage/FilesystemUtil.h" 00025 00026 #ifndef LOGCABIN_STORAGE_SNAPSHOTFILE_H 00027 #define LOGCABIN_STORAGE_SNAPSHOTFILE_H 00028 00029 namespace LogCabin { 00030 namespace Storage { 00031 00032 class Layout; // forward declaration 00033 00034 namespace SnapshotFile { 00035 00036 /** 00037 * Remove any partial snapshots found on disk. This is normally called when the 00038 * server boots up. 00039 */ 00040 void discardPartialSnapshots(const Storage::Layout& storageLayout); 00041 00042 /** 00043 * Assists in reading snapshot files from the local filesystem. 00044 */ 00045 class Reader : public Core::ProtoBuf::InputStream { 00046 public: 00047 /** 00048 * Constructor. 00049 * \param storageLayout 00050 * The directories in which to find the snapshot (in a file called 00051 * "snapshot" in the snapshotDir). 00052 * \throw std::runtime_error 00053 * If the file can't be found. 00054 */ 00055 explicit Reader(const Storage::Layout& storageLayout); 00056 /// Destructor. 00057 ~Reader(); 00058 /// Return the size in bytes for the file. 00059 uint64_t getSizeBytes(); 00060 // See Core::ProtoBuf::InputStream. 00061 uint64_t getBytesRead() const; 00062 // See Core::ProtoBuf::InputStream. 00063 std::string readMessage(google::protobuf::Message& message); 00064 // See Core::ProtoBuf::InputStream. 00065 uint64_t readRaw(void* data, uint64_t length); 00066 private: 00067 /// Wraps the raw file descriptor; in charge of closing it when done. 00068 Storage::FilesystemUtil::File file; 00069 /// Maps the file into memory for reading. 00070 std::unique_ptr<Storage::FilesystemUtil::FileContents> contents; 00071 /// The number of bytes read from the file. 00072 uint64_t bytesRead; 00073 }; 00074 00075 /** 00076 * Assists in writing snapshot files to the local filesystem. 00077 */ 00078 class Writer : public Core::ProtoBuf::OutputStream { 00079 public: 00080 /** 00081 * Allocates an object that is shared across processes. Uses a shared, 00082 * anonymous mmap region internally. 00083 */ 00084 template<typename T> 00085 struct SharedMMap { 00086 SharedMMap(); 00087 ~SharedMMap(); 00088 T* value; // pointer does not change after construction 00089 // SharedMMap is not copyable 00090 SharedMMap(const SharedMMap& other) = delete; 00091 SharedMMap& operator=(const SharedMMap& other) = delete; 00092 }; 00093 00094 /** 00095 * Constructor. 00096 * \param storageLayout 00097 * The directories in which to create the snapshot (in a file called 00098 * "snapshot" in the snapshotDir). 00099 * TODO(ongaro): what if it can't be written? 00100 */ 00101 explicit Writer(const Storage::Layout& storageLayout); 00102 /** 00103 * Destructor. 00104 * If the file hasn't been explicitly saved or discarded, prints a warning 00105 * and discards the file. 00106 */ 00107 ~Writer(); 00108 /** 00109 * Throw away the file. 00110 * If you call this after the file has been closed, it will PANIC. 00111 */ 00112 void discard(); 00113 /** 00114 * Flush changes just down to the operating system's buffer cache. 00115 * Leave the file open for additional writes. 00116 * 00117 * This is useful when forking child processes to write to the file. 00118 * The correct procedure for that is: 00119 * 0. write stuff 00120 * 1. call flushToOS() 00121 * 2. fork 00122 * 3. child process: write stuff 00123 * 4. child process: call flushToOS() 00124 * 5. child process: call _exit() 00125 * 6. parent process: call seekToEnd() 00126 * 7. parent process: write stuff 00127 * 8. parent process: call save() 00128 */ 00129 void flushToOS(); 00130 /** 00131 * Seek to the end of the file, in case another process has written to it. 00132 * Subsequent calls to getBytesWritten() will include data written by other 00133 * processes. 00134 */ 00135 void seekToEnd(); 00136 /** 00137 * Flush changes all the way down to the disk and close the file. 00138 * If you call this after the file has been closed, it will PANIC. 00139 * \return 00140 * Size in bytes of the file 00141 */ 00142 uint64_t save(); 00143 // See Core::ProtoBuf::OutputStream. 00144 uint64_t getBytesWritten() const; 00145 // See Core::ProtoBuf::OutputStream. 00146 void writeMessage(const google::protobuf::Message& message); 00147 // See Core::ProtoBuf::OutputStream. 00148 void writeRaw(const void* data, uint64_t length); 00149 00150 private: 00151 /// A handle to the directory containing the snapshot. Used for renameat on 00152 /// close. 00153 Storage::FilesystemUtil::File parentDir; 00154 /// The temporary name of 'file' before it is closed. 00155 std::string stagingName; 00156 /// Wraps the raw file descriptor; in charge of closing it when done. 00157 Storage::FilesystemUtil::File file; 00158 /// The number of bytes accumulated in the file so far. 00159 uint64_t bytesWritten; 00160 public: 00161 /** 00162 * This value is incremented every time bytes are written to the Writer 00163 * from any process holding this Writer. Used by Server/StateMachine to 00164 * implement a watchdog that checks progress of a snapshotting process. 00165 */ 00166 SharedMMap<std::atomic<uint64_t>> sharedBytesWritten; 00167 00168 }; 00169 00170 } // namespace LogCabin::Storage::SnapshotFile 00171 } // namespace LogCabin::Storage 00172 } // namespace LogCabin 00173 00174 #endif /* LOGCABIN_STORAGE_SNAPSHOTFILE_H */