1 /** @file 2 3 A brief file description 4 5 @section license License 6 7 Licensed to the Apache Software Foundation (ASF) under one 8 or more contributor license agreements. See the NOTICE file 9 distributed with this work for additional information 10 regarding copyright ownership. The ASF licenses this file 11 to you under the Apache License, Version 2.0 (the 12 "License"); you may not use this file except in compliance 13 with the License. You may obtain a copy of the License at 14 15 http://www.apache.org/licenses/LICENSE-2.0 16 17 Unless required by applicable law or agreed to in writing, software 18 distributed under the License is distributed on an "AS IS" BASIS, 19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 See the License for the specific language governing permissions and 21 limitations under the License. 22 */ 23 24 /**************************************************************************** 25 26 Store.h 27 28 29 ****************************************************************************/ 30 31 #pragma once 32 33 #include "tscore/ink_platform.h" 34 #include "tscore/Result.h" 35 36 #define STORE_BLOCK_SIZE 8192 37 #define STORE_BLOCK_SHIFT 13 38 #define DEFAULT_HW_SECTOR_SIZE 512 39 40 enum span_error_t { 41 SPAN_ERROR_OK, 42 SPAN_ERROR_UNKNOWN, 43 SPAN_ERROR_NOT_FOUND, 44 SPAN_ERROR_NO_ACCESS, 45 SPAN_ERROR_MISSING_SIZE, 46 SPAN_ERROR_UNSUPPORTED_DEVTYPE, 47 SPAN_ERROR_MEDIA_PROBE, 48 }; 49 50 struct span_diskid_t { 51 int64_t id[2]; 52 53 bool 54 operator<(const span_diskid_t &rhs) const 55 { 56 return id[0] < rhs.id[0] && id[1] < rhs.id[1]; 57 } 58 59 bool 60 operator==(const span_diskid_t &rhs) const 61 { 62 return id[0] == rhs.id[0] && id[1] == rhs.id[1]; 63 } 64 65 int64_t & 66 operator[](unsigned i) 67 { 68 return id[i]; 69 } 70 }; 71 72 // 73 // A Store is a place to store data. 74 // Those on the same disk should be in a linked list. 75 // 76 struct Span { 77 int64_t blocks = 0; // in STORE_BLOCK_SIZE blocks 78 int64_t offset = 0; // used only if (file == true); in bytes 79 unsigned hw_sector_size = DEFAULT_HW_SECTOR_SIZE; 80 unsigned alignment = 0; 81 span_diskid_t disk_id; 82 int forced_volume_num = -1; ///< Force span in to specific volume. 83 private: 84 bool is_mmapable_internal = false; 85 86 public: 87 bool file_pathname = false; // the pathname is a file 88 // v- used as a magic location for copy constructor. 89 // we memcpy everything before this member and do explicit assignment for the rest. 90 ats_scoped_str pathname; 91 ats_scoped_str hash_base_string; ///< Used to seed the stripe assignment hash. 92 SLINK(Span, link); 93 94 bool is_mmapableSpan95 is_mmapable() const 96 { 97 return is_mmapable_internal; 98 } 99 void set_mmapableSpan100 set_mmapable(bool s) 101 { 102 is_mmapable_internal = s; 103 } 104 int64_t sizeSpan105 size() const 106 { 107 return blocks * STORE_BLOCK_SIZE; 108 } 109 110 int64_t total_blocksSpan111 total_blocks() const 112 { 113 if (link.next) { 114 return blocks + link.next->total_blocks(); 115 } else { 116 return blocks; 117 } 118 } 119 120 Span * nthSpan121 nth(unsigned i) 122 { 123 Span *x = this; 124 while (x && i--) { 125 x = x->link.next; 126 } 127 return x; 128 } 129 130 unsigned pathsSpan131 paths() const 132 { 133 int i = 0; 134 for (const Span *x = this; x; i++, x = x->link.next) { 135 ; 136 } 137 138 return i; 139 } 140 141 int write(int fd) const; 142 int read(int fd); 143 144 /// Duplicate this span and all chained spans. 145 Span *dup(); 146 int64_t endSpan147 end() const 148 { 149 return offset + blocks; 150 } 151 152 const char *init(const char *n, int64_t size); 153 154 // 0 on success -1 on failure 155 int path(char *filename, // for non-file, the filename in the director 156 int64_t *offset, // for file, start offset (unsupported) 157 char *buf, int buflen); // where to store the path 158 159 /// Set the hash seed string. 160 void hash_base_string_set(const char *s); 161 /// Set the volume number. 162 void volume_number_set(int n); 163 SpanSpan164 Span() { disk_id[0] = disk_id[1] = 0; } 165 166 /// Copy constructor. 167 /// @internal Prior to this implementation handling the char* pointers was done manually 168 /// at every call site. We also need this because we have @c ats_scoped_str members and need 169 /// to make copies. SpanSpan170 Span(Span const &that) 171 { 172 /* I looked at simplifying this by changing the @c ats_scoped_str instances to @c std::string 173 * but that actually makes it worse. The copy constructor @b must be overridden to get the 174 * internal link (@a link.next) correct. Given that, changing to @c std::string means doing 175 * explicit assignment for every member, which has its own problems. 176 */ 177 memcpy(static_cast<void *>(this), &that, reinterpret_cast<intptr_t>(&(static_cast<Span *>(nullptr)->pathname))); 178 if (that.pathname) { 179 pathname = ats_strdup(that.pathname); 180 } 181 if (that.hash_base_string) { 182 hash_base_string = ats_strdup(that.hash_base_string); 183 } 184 link.next = nullptr; 185 } 186 187 ~Span(); 188 189 static const char *errorstr(span_error_t serr); 190 }; 191 192 struct Store { 193 // 194 // Public Interface 195 // Thread-safe operations 196 // 197 198 // spread evenly on all disks 199 void spread_alloc(Store &s, unsigned int blocks, bool mmapable = true); 200 void alloc(Store &s, unsigned int blocks, bool only_one = false, bool mmapable = true); 201 202 Span * alloc_oneStore203 alloc_one(unsigned int blocks, bool mmapable) 204 { 205 Store s; 206 alloc(s, blocks, true, mmapable); 207 if (s.n_disks) { 208 Span *t = s.disk[0]; 209 s.disk[0] = nullptr; 210 return t; 211 } 212 213 return nullptr; 214 } 215 // try to allocate, return (s == gotten, diff == not gotten) 216 void try_realloc(Store &s, Store &diff); 217 218 // free back the contents of a store. 219 // must have been JUST allocated (no intervening allocs/frees) 220 void free(Store &s); 221 void add(Span *s); 222 void add(Store &s); 223 void dup(Store &s); 224 void sort(); 225 void extendStore226 extend(unsigned i) 227 { 228 if (i > n_disks) { 229 disk = (Span **)ats_realloc(disk, i * sizeof(Span *)); 230 for (unsigned j = n_disks; j < i; j++) { 231 disk[j] = nullptr; 232 } 233 n_disks = i; 234 } 235 } 236 237 // Non Thread-safe operations 238 unsigned int 239 total_blocks(unsigned after = 0) const 240 { 241 int64_t t = 0; 242 for (unsigned i = after; i < n_disks; i++) { 243 if (disk[i]) { 244 t += disk[i]->total_blocks(); 245 } 246 } 247 return (unsigned int)t; 248 } 249 // 0 on success -1 on failure 250 // these operations are NOT thread-safe 251 // 252 int write(int fd, const char *name) const; 253 int read(int fd, char *name); 254 int clear(char *filename, bool clear_dirs = true); 255 void normalize(); 256 void delete_all(); 257 int remove(char *pathname); 258 Store(); 259 ~Store(); 260 261 // The number of disks/paths defined in storage.config 262 unsigned n_disks_in_config = 0; 263 // The number of disks/paths we could actually read and parse. 264 unsigned n_disks = 0; 265 Span **disk = nullptr; 266 267 Result read_config(); 268 269 int write_config_data(int fd) const; 270 271 /// Additional configuration key values. 272 static const char VOLUME_KEY[]; 273 static const char HASH_BASE_STRING_KEY[]; 274 }; 275 276 // store either free or in the cache, can be stolen for reconfiguration 277 void stealStore(Store &s, int blocks); 278