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