1 /* Copyright (C) 2019 MariaDB Corporation
2
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public License
5 as published by the Free Software Foundation; version 2 of
6 the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16 MA 02110-1301, USA. */
17
18
19
20 #include <boost/filesystem.hpp>
21 #include <iostream>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <time.h>
26 #include "LocalStorage.h"
27 #include "Config.h"
28
29 using namespace std;
30 namespace bf = boost::filesystem;
31
32 namespace storagemanager
33 {
34
LocalStorage()35 LocalStorage::LocalStorage()
36 {
37 prefix = Config::get()->getValue("LocalStorage", "path");
38 //cout << "LS: got prefix " << prefix << endl;
39 if (!bf::is_directory(prefix))
40 {
41 try
42 {
43 bf::create_directories(prefix);
44 }
45 catch (exception &e)
46 {
47 logger->log(LOG_CRIT, "Failed to create %s, got: %s", prefix.string().c_str(), e.what());
48 throw e;
49 }
50 }
51 string stmp = Config::get()->getValue("LocalStorage", "fake_latency");
52 if (!stmp.empty() && (stmp[0] == 'Y' || stmp[0] == 'y'))
53 {
54 fakeLatency = true;
55 stmp = Config::get()->getValue("LocalStorage", "max_latency");
56 usecLatencyCap = strtoull(stmp.c_str(), NULL, 10);
57 if (usecLatencyCap == 0)
58 {
59 logger->log(LOG_CRIT, "LocalStorage: bad value for max_latency");
60 throw runtime_error("LocalStorage: bad value for max_latency");
61 }
62 r_seed = (uint) ::time(NULL);
63 logger->log(LOG_DEBUG, "LocalStorage: Will simulate cloud latency of max %llu us", usecLatencyCap);
64 }
65 else
66 fakeLatency = false;
67
68 bytesRead = bytesWritten = 0;
69 }
70
~LocalStorage()71 LocalStorage::~LocalStorage()
72 {
73 }
74
printKPIs() const75 void LocalStorage::printKPIs() const
76 {
77 cout << "LocalStorage" << endl;
78 cout << "\tbytesRead = " << bytesRead << endl;
79 cout << "\tbytesWritten = " << bytesWritten << endl;
80 CloudStorage::printKPIs();
81 }
82
getPrefix() const83 const bf::path & LocalStorage::getPrefix() const
84 {
85 return prefix;
86 }
87
addLatency()88 inline void LocalStorage::addLatency()
89 {
90 if (fakeLatency)
91 {
92 uint64_t usec_delay = ((double) rand_r(&r_seed) / (double) RAND_MAX) * usecLatencyCap;
93 ::usleep(usec_delay);
94 }
95 }
96
copy(const bf::path & source,const bf::path & dest)97 int LocalStorage::copy(const bf::path &source, const bf::path &dest)
98 {
99 boost::system::error_code err;
100 bf::copy_file(source, dest, bf::copy_option::fail_if_exists, err);
101 if (err)
102 {
103 errno = err.value();
104 ::unlink(dest.string().c_str());
105 return -1;
106 }
107 return 0;
108 }
109
operator +(const bf::path & p1,const bf::path & p2)110 bf::path operator+(const bf::path &p1, const bf::path &p2)
111 {
112 bf::path ret(p1);
113 ret /= p2;
114 return ret;
115 }
116
getObject(const string & source,const string & dest,size_t * size)117 int LocalStorage::getObject(const string &source, const string &dest, size_t *size)
118 {
119 addLatency();
120
121 int ret = copy(prefix / source, dest);
122 if (ret)
123 return ret;
124 size_t _size = bf::file_size(dest);
125 if (size)
126 *size = _size;
127 bytesRead += _size;
128 bytesWritten += _size;
129 ++objectsGotten;
130 return ret;
131 }
132
getObject(const std::string & sourceKey,boost::shared_array<uint8_t> * data,size_t * size)133 int LocalStorage::getObject(const std::string &sourceKey, boost::shared_array<uint8_t> *data, size_t *size)
134 {
135 addLatency();
136
137 bf::path source = prefix / sourceKey;
138 const char *c_source = source.string().c_str();
139 //char buf[80];
140 int l_errno;
141
142 int fd = ::open(c_source, O_RDONLY);
143 if (fd < 0)
144 {
145 l_errno = errno;
146 //logger->log(LOG_WARNING, "LocalStorage::getObject() failed to open %s, got '%s'", c_source, strerror_r(errno, buf, 80));
147 errno = l_errno;
148 return fd;
149 }
150
151 size_t l_size = bf::file_size(source);
152 data->reset(new uint8_t[l_size]);
153 size_t count = 0;
154 while (count < l_size)
155 {
156 int err = ::read(fd, &(*data)[count], l_size - count);
157 if (err < 0)
158 {
159 l_errno = errno;
160 //logger->log(LOG_WARNING, "LocalStorage::getObject() failed to read %s, got '%s'", c_source, strerror_r(errno, buf, 80));
161 close(fd);
162 bytesRead += count;
163 errno = l_errno;
164 return err;
165 }
166 count += err;
167 }
168 if (size)
169 *size = l_size;
170 close(fd);
171 bytesRead += l_size;
172 ++objectsGotten;
173 return 0;
174 }
175
putObject(const string & source,const string & dest)176 int LocalStorage::putObject(const string &source, const string &dest)
177 {
178 addLatency();
179
180 int ret = copy(source, prefix / dest);
181
182 if (ret == 0)
183 {
184 size_t _size = bf::file_size(source);
185 bytesRead += _size;
186 bytesWritten += _size;
187 ++objectsPut;
188 }
189 return ret;
190 }
191
putObject(boost::shared_array<uint8_t> data,size_t len,const string & dest)192 int LocalStorage::putObject(boost::shared_array<uint8_t> data, size_t len, const string &dest)
193 {
194 addLatency();
195
196 bf::path destPath = prefix / dest;
197 const char *c_dest = destPath.string().c_str();
198 //char buf[80];
199 int l_errno;
200
201 int fd = ::open(c_dest, O_WRONLY | O_CREAT | O_TRUNC, 0600);
202 if (fd < 0)
203 {
204 l_errno = errno;
205 //logger->log(LOG_CRIT, "LocalStorage::putObject(): Failed to open %s, got '%s'", c_dest, strerror_r(errno, buf, 80));
206 errno = l_errno;
207 return fd;
208 }
209
210 size_t count = 0;
211 int err;
212 while (count < len)
213 {
214 err = ::write(fd, &data[count], len - count);
215 if (err < 0)
216 {
217 l_errno = errno;
218 //logger->log(LOG_CRIT, "LocalStorage::putObject(): Failed to write to %s, got '%s'", c_dest, strerror_r(errno, buf, 80));
219 close(fd);
220 ::unlink(c_dest);
221 errno = l_errno;
222 bytesWritten += count;
223 return err;
224 }
225 count += err;
226 }
227 close(fd);
228 bytesWritten += count;
229 ++objectsPut;
230 return 0;
231 }
232
copyObject(const string & source,const string & dest)233 int LocalStorage::copyObject(const string &source, const string &dest)
234 {
235 addLatency();
236
237 int ret = copy(prefix / source, prefix / dest);
238
239 if (ret == 0)
240 {
241 ++objectsCopied;
242 size_t _size = bf::file_size(prefix/source);
243 bytesRead += _size;
244 bytesWritten += _size;
245 }
246 return ret;
247 }
248
deleteObject(const string & key)249 int LocalStorage::deleteObject(const string &key)
250 {
251 addLatency();
252
253 ++objectsDeleted;
254 boost::system::error_code err;
255 bf::remove(prefix / key, err);
256 return 0;
257 }
258
exists(const std::string & key,bool * out)259 int LocalStorage::exists(const std::string &key, bool *out)
260 {
261 addLatency();
262
263 ++existenceChecks;
264 *out = bf::exists(prefix / key);
265 return 0;
266 }
267
268 }
269