1 // mmap_v1_extent_manager.h 2 3 4 /** 5 * Copyright (C) 2018-present MongoDB, Inc. 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the Server Side Public License, version 1, 9 * as published by MongoDB, Inc. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * Server Side Public License for more details. 15 * 16 * You should have received a copy of the Server Side Public License 17 * along with this program. If not, see 18 * <http://www.mongodb.com/licensing/server-side-public-license>. 19 * 20 * As a special exception, the copyright holders give permission to link the 21 * code of portions of this program with the OpenSSL library under certain 22 * conditions as described in each individual source file and distribute 23 * linked combinations including the program with the OpenSSL library. You 24 * must comply with the Server Side Public License in all respects for 25 * all of the code used other than as permitted herein. If you modify file(s) 26 * with this exception, you may extend this exception to your version of the 27 * file(s), but you are not obligated to do so. If you do not wish to do so, 28 * delete this exception statement from your version. If you delete this 29 * exception statement from all source files in the program, then also delete 30 * it in the license file. 31 */ 32 33 #pragma once 34 35 #include <string> 36 37 #include <boost/filesystem/path.hpp> 38 39 #include "mongo/base/status.h" 40 #include "mongo/base/string_data.h" 41 #include "mongo/db/concurrency/lock_manager_defs.h" 42 #include "mongo/db/storage/mmap_v1/diskloc.h" 43 #include "mongo/db/storage/mmap_v1/extent_manager.h" 44 #include "mongo/db/storage/mmap_v1/record_access_tracker.h" 45 #include "mongo/platform/atomic_word.h" 46 #include "mongo/stdx/mutex.h" 47 48 namespace mongo { 49 50 class DataFile; 51 class DataFileVersion; 52 class MmapV1RecordHeader; 53 class OperationContext; 54 55 struct Extent; 56 57 /** 58 * ExtentManager basics 59 * - one per database 60 * - responsible for managing <db>.# files 61 * - NOT responsible for .ns file 62 * - gives out extents 63 * - responsible for figuring out how to get a new extent 64 * - can use any method it wants to do so 65 * - this structure is NOT stored on disk 66 * - this class is thread safe, except as indicated below 67 * 68 * Implementation: 69 * - ExtentManager holds a preallocated list of DataFile 70 * - files will not be removed from the EM, so _files access can be lock-free 71 * - extent size and loc are immutable 72 * - Any non-const public operations on an ExtentManager will acquire an MODE_X lock on its 73 * RESOURCE_MMAPv1_EXTENT_MANAGER resource from the lock-manager, which will extend life 74 * to during WriteUnitOfWorks that might need rollback. Private methods will only 75 * be called from public ones. 76 */ 77 class MmapV1ExtentManager : public ExtentManager { 78 MONGO_DISALLOW_COPYING(MmapV1ExtentManager); 79 80 public: 81 class Factory : public ExtentManager::Factory { 82 virtual std::unique_ptr<ExtentManager> create(StringData dbname, 83 StringData path, 84 bool directoryPerDB) final; 85 }; 86 87 /** 88 * @param freeListDetails this is a reference into the .ns file 89 * while a bit odd, this is not a layer violation as extents 90 * are a peer to the .ns file, without any layering 91 */ 92 MmapV1ExtentManager(StringData dbname, StringData path, bool directoryPerDB); 93 94 /** 95 * Must be called before destruction. 96 */ close(OperationContext * opCtx)97 void close(OperationContext* opCtx) { 98 _files.close(opCtx); 99 } 100 101 /** 102 * opens all current files, not thread safe 103 */ 104 Status init(OperationContext* opCtx); 105 106 int numFiles() const; 107 long long fileSize() const; 108 109 // must call Extent::reuse on the returned extent 110 DiskLoc allocateExtent(OperationContext* opCtx, bool capped, int size, bool enforceQuota); 111 112 /** 113 * firstExt has to be == lastExt or a chain 114 */ 115 void freeExtents(OperationContext* opCtx, DiskLoc firstExt, DiskLoc lastExt); 116 117 /** 118 * frees a single extent 119 * ignores all fields in the Extent except: magic, myLoc, length 120 */ 121 void freeExtent(OperationContext* opCtx, DiskLoc extent); 122 123 124 void freeListStats(OperationContext* opCtx, int* numExtents, int64_t* totalFreeSizeBytes) const; 125 126 /** 127 * @param loc - has to be for a specific MmapV1RecordHeader 128 * Note(erh): this sadly cannot be removed. 129 * A MmapV1RecordHeader DiskLoc has an offset from a file, while a RecordStore really wants an 130 * offset from an extent. This intrinsically links an original record store to the original 131 * extent manager. 132 */ 133 MmapV1RecordHeader* recordForV1(const DiskLoc& loc) const; 134 135 std::unique_ptr<RecordFetcher> recordNeedsFetch(const DiskLoc& loc) const; 136 137 /** 138 * @param loc - has to be for a specific MmapV1RecordHeader (not an Extent) 139 * Note(erh) see comment on recordFor 140 */ 141 Extent* extentForV1(const DiskLoc& loc) const; 142 143 /** 144 * @param loc - has to be for a specific MmapV1RecordHeader (not an Extent) 145 * Note(erh) see comment on recordFor 146 */ 147 DiskLoc extentLocForV1(const DiskLoc& loc) const; 148 149 /** 150 * @param loc - has to be for a specific Extent 151 */ 152 Extent* getExtent(const DiskLoc& loc, bool doSanityCheck = true) const; 153 154 /** 155 * Not thread safe, requires a database exclusive lock 156 */ 157 DataFileVersion getFileFormat(OperationContext* opCtx) const final; 158 void setFileFormat(OperationContext* opCtx, DataFileVersion newVersion) final; 159 getOpenFile(int n)160 const DataFile* getOpenFile(int n) const final { 161 return _getOpenFile(n); 162 } 163 164 virtual int maxSize() const; 165 166 virtual CacheHint* cacheHint(const DiskLoc& extentLoc, const HintType& hint); 167 168 private: 169 /** 170 * will return NULL if nothing suitable in free list 171 */ 172 DiskLoc _allocFromFreeList(OperationContext* opCtx, int approxSize, bool capped); 173 174 /* allocate a new Extent, does not check free list 175 */ 176 DiskLoc _createExtent(OperationContext* opCtx, int approxSize, bool enforceQuota); 177 178 DataFile* _addAFile(OperationContext* opCtx, int sizeNeeded, bool preallocateNextFile); 179 180 181 /** 182 * Shared record retrieval logic used by the public recordForV1() and likelyInPhysicalMem() 183 * above. 184 */ 185 MmapV1RecordHeader* _recordForV1(const DiskLoc& loc) const; 186 187 DiskLoc _getFreeListStart() const; 188 DiskLoc _getFreeListEnd() const; 189 void _setFreeListStart(OperationContext* opCtx, DiskLoc loc); 190 void _setFreeListEnd(OperationContext* opCtx, DiskLoc loc); 191 192 const DataFile* _getOpenFile(int fileId) const; 193 DataFile* _getOpenFile(int fileId); 194 195 DiskLoc _createExtentInFile( 196 OperationContext* opCtx, int fileNo, DataFile* f, int size, bool enforceQuota); 197 198 boost::filesystem::path _fileName(int n) const; 199 200 // ----- 201 202 const std::string _dbname; // i.e. "test" 203 const std::string _path; // i.e. "/data/db" 204 const bool _directoryPerDB; 205 const ResourceId _rid; 206 207 // This reference points into the MMAPv1 engine and is only valid as long as the 208 // engine is valid. Not owned here. 209 RecordAccessTracker* _recordAccessTracker; 210 211 /** 212 * Simple wrapper around an array object to allow append-only modification of the array, 213 * as well as concurrent read-accesses. This class has a minimal interface to keep 214 * implementation simple and easy to modify. 215 */ 216 class FilesArray { 217 public: FilesArray()218 FilesArray() : _size(0) {} 219 ~FilesArray(); 220 221 /** 222 * Must be called before destruction. 223 */ 224 void close(OperationContext* opCtx); 225 226 /** 227 * Returns file at location 'n' in the array, with 'n' less than number of files added. 228 * Will always return the same pointer for a given file. 229 */ 230 DataFile* operator[](int n) const { 231 invariant(n >= 0 && n < size()); 232 return _files[n]; 233 } 234 235 /** 236 * Returns true iff no files were added 237 */ empty()238 bool empty() const { 239 return size() == 0; 240 } 241 242 /** 243 * Returns number of files added to the array 244 */ size()245 int size() const { 246 return _size.load(); 247 } 248 249 // Appends val to the array, taking ownership of its pointer 250 void push_back(DataFile* val); 251 252 private: 253 stdx::mutex _writersMutex; 254 AtomicInt32 _size; // number of files in the array 255 DataFile* _files[DiskLoc::MaxFiles]; 256 }; 257 258 FilesArray _files; 259 }; 260 } 261