]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/env/env_posix.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / env / env_posix.cc
CommitLineData
7c673cae 1// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
11fdf7f2
TL
2// This source code is licensed under both the GPLv2 (found in the
3// COPYING file in the root directory) and Apache 2.0 License
4// (found in the LICENSE.Apache file in the root directory).
7c673cae
FG
5//
6// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7// Use of this source code is governed by a BSD-style license that can be
8// found in the LICENSE file. See the AUTHORS file for names of contributors
20effc67 9
1e59de90 10#include "port/lang.h"
20effc67
TL
11#if !defined(OS_WIN)
12
7c673cae 13#include <dirent.h>
f67539c2
TL
14#ifndef ROCKSDB_NO_DYNAMIC_EXTENSION
15#include <dlfcn.h>
16#endif
7c673cae
FG
17#include <errno.h>
18#include <fcntl.h>
f67539c2 19
f67539c2
TL
20#if defined(ROCKSDB_IOURING_PRESENT)
21#include <liburing.h>
22#endif
7c673cae
FG
23#include <pthread.h>
24#include <signal.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
7c673cae
FG
28#include <sys/mman.h>
29#include <sys/stat.h>
11fdf7f2 30#if defined(OS_LINUX) || defined(OS_SOLARIS) || defined(OS_ANDROID)
7c673cae 31#include <sys/statfs.h>
7c673cae 32#endif
11fdf7f2 33#include <sys/statvfs.h>
7c673cae
FG
34#include <sys/time.h>
35#include <sys/types.h>
f67539c2
TL
36#if defined(ROCKSDB_IOURING_PRESENT)
37#include <sys/uio.h>
38#endif
7c673cae 39#include <time.h>
1e59de90
TL
40#include <unistd.h>
41
7c673cae
FG
42#include <algorithm>
43// Get nano time includes
20effc67 44#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD)
7c673cae 45#elif defined(__MACH__)
f67539c2 46#include <Availability.h>
7c673cae
FG
47#include <mach/clock.h>
48#include <mach/mach.h>
49#else
50#include <chrono>
51#endif
52#include <deque>
53#include <set>
54#include <vector>
55
f67539c2 56#include "env/composite_env_wrapper.h"
7c673cae 57#include "env/io_posix.h"
7c673cae
FG
58#include "monitoring/iostats_context_imp.h"
59#include "monitoring/thread_status_updater.h"
60#include "port/port.h"
1e59de90
TL
61#include "port/sys_time.h"
62#include "rocksdb/env.h"
7c673cae
FG
63#include "rocksdb/options.h"
64#include "rocksdb/slice.h"
1e59de90 65#include "rocksdb/system_clock.h"
f67539c2 66#include "test_util/sync_point.h"
7c673cae 67#include "util/coding.h"
11fdf7f2 68#include "util/compression_context_cache.h"
7c673cae
FG
69#include "util/random.h"
70#include "util/string_util.h"
7c673cae
FG
71#include "util/thread_local.h"
72#include "util/threadpool_imp.h"
73
74#if !defined(TMPFS_MAGIC)
75#define TMPFS_MAGIC 0x01021994
76#endif
77#if !defined(XFS_SUPER_MAGIC)
78#define XFS_SUPER_MAGIC 0x58465342
79#endif
80#if !defined(EXT4_SUPER_MAGIC)
81#define EXT4_SUPER_MAGIC 0xEF53
82#endif
83
f67539c2
TL
84namespace ROCKSDB_NAMESPACE {
85#if defined(OS_WIN)
86static const std::string kSharedLibExt = ".dll";
87static const char kPathSeparator = ';';
88#else
89static const char kPathSeparator = ':';
90#if defined(OS_MACOSX)
91static const std::string kSharedLibExt = ".dylib";
92#else
93static const std::string kSharedLibExt = ".so";
94#endif
95#endif
7c673cae
FG
96
97namespace {
98
99ThreadStatusUpdater* CreateThreadStatusUpdater() {
100 return new ThreadStatusUpdater();
101}
102
f67539c2
TL
103#ifndef ROCKSDB_NO_DYNAMIC_EXTENSION
104class PosixDynamicLibrary : public DynamicLibrary {
105 public:
106 PosixDynamicLibrary(const std::string& name, void* handle)
107 : name_(name), handle_(handle) {}
108 ~PosixDynamicLibrary() override { dlclose(handle_); }
109
110 Status LoadSymbol(const std::string& sym_name, void** func) override {
111 assert(nullptr != func);
112 dlerror(); // Clear any old error
113 *func = dlsym(handle_, sym_name.c_str());
114 if (*func != nullptr) {
115 return Status::OK();
116 } else {
117 char* err = dlerror();
118 return Status::NotFound("Error finding symbol: " + sym_name, err);
119 }
120 }
11fdf7f2 121
f67539c2 122 const char* Name() const override { return name_.c_str(); }
7c673cae 123
f67539c2
TL
124 private:
125 std::string name_;
126 void* handle_;
7c673cae 127};
f67539c2 128#endif // !ROCKSDB_NO_DYNAMIC_EXTENSION
7c673cae 129
1e59de90
TL
130class PosixClock : public SystemClock {
131 public:
132 static const char* kClassName() { return "PosixClock"; }
133 const char* Name() const override { return kDefaultName(); }
134 const char* NickName() const override { return kClassName(); }
135
136 uint64_t NowMicros() override {
137 port::TimeVal tv;
138 port::GetTimeOfDay(&tv, nullptr);
139 return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
140 }
141
142 uint64_t NowNanos() override {
143#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD) || \
144 defined(OS_AIX)
145 struct timespec ts;
146 clock_gettime(CLOCK_MONOTONIC, &ts);
147 return static_cast<uint64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
148#elif defined(OS_SOLARIS)
149 return gethrtime();
150#elif defined(__MACH__)
151 clock_serv_t cclock;
152 mach_timespec_t ts;
153 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
154 clock_get_time(cclock, &ts);
155 mach_port_deallocate(mach_task_self(), cclock);
156 return static_cast<uint64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
157#else
158 return std::chrono::duration_cast<std::chrono::nanoseconds>(
159 std::chrono::steady_clock::now().time_since_epoch())
160 .count();
161#endif
162 }
163
164 uint64_t CPUMicros() override {
165#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD) || \
166 defined(OS_AIX) || (defined(__MACH__) && defined(__MAC_10_12))
167 struct timespec ts;
168 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
169 return (static_cast<uint64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec) / 1000;
170#endif
171 return 0;
172 }
173
174 uint64_t CPUNanos() override {
175#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD) || \
176 defined(OS_AIX) || (defined(__MACH__) && defined(__MAC_10_12))
177 struct timespec ts;
178 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
179 return static_cast<uint64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
180#endif
181 return 0;
182 }
183
184 void SleepForMicroseconds(int micros) override { usleep(micros); }
185
186 Status GetCurrentTime(int64_t* unix_time) override {
187 time_t ret = time(nullptr);
188 if (ret == (time_t)-1) {
189 return IOError("GetCurrentTime", "", errno);
190 }
191 *unix_time = (int64_t)ret;
192 return Status::OK();
193 }
194
195 std::string TimeToString(uint64_t secondsSince1970) override {
196 const time_t seconds = (time_t)secondsSince1970;
197 struct tm t;
198 int maxsize = 64;
199 std::string dummy;
200 dummy.reserve(maxsize);
201 dummy.resize(maxsize);
202 char* p = &dummy[0];
203 port::LocalTimeR(&seconds, &t);
204 snprintf(p, maxsize, "%04d/%02d/%02d-%02d:%02d:%02d ", t.tm_year + 1900,
205 t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
206 return dummy;
207 }
208};
209
210class PosixEnv : public CompositeEnv {
7c673cae 211 public:
1e59de90
TL
212 static const char* kClassName() { return "PosixEnv"; }
213 const char* Name() const override { return kClassName(); }
214 const char* NickName() const override { return kDefaultName(); }
7c673cae 215
494da23a 216 ~PosixEnv() override {
20effc67
TL
217 if (this == Env::Default()) {
218 for (const auto tid : threads_to_join_) {
219 pthread_join(tid, nullptr);
220 }
221 for (int pool_id = 0; pool_id < Env::Priority::TOTAL; ++pool_id) {
222 thread_pools_[pool_id].JoinAllThreads();
223 }
224 // Do not delete the thread_status_updater_ in order to avoid the
225 // free after use when Env::Default() is destructed while some other
226 // child threads are still trying to update thread status. All
227 // PosixEnv instances use the same thread_status_updater_, so never
228 // explicitly delete it.
7c673cae
FG
229 }
230 }
231
232 void SetFD_CLOEXEC(int fd, const EnvOptions* options) {
233 if ((options == nullptr || options->set_fd_cloexec) && fd > 0) {
234 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
235 }
236 }
237
f67539c2
TL
238#ifndef ROCKSDB_NO_DYNAMIC_EXTENSION
239 // Loads the named library into the result.
240 // If the input name is empty, the current executable is loaded
241 // On *nix systems, a "lib" prefix is added to the name if one is not supplied
242 // Comparably, the appropriate shared library extension is added to the name
243 // if not supplied. If search_path is not specified, the shared library will
244 // be loaded using the default path (LD_LIBRARY_PATH) If search_path is
245 // specified, the shared library will be searched for in the directories
246 // provided by the search path
247 Status LoadLibrary(const std::string& name, const std::string& path,
248 std::shared_ptr<DynamicLibrary>* result) override {
f67539c2
TL
249 assert(result != nullptr);
250 if (name.empty()) {
251 void* hndl = dlopen(NULL, RTLD_NOW);
252 if (hndl != nullptr) {
253 result->reset(new PosixDynamicLibrary(name, hndl));
254 return Status::OK();
7c673cae 255 }
7c673cae 256 } else {
f67539c2
TL
257 std::string library_name = name;
258 if (library_name.find(kSharedLibExt) == std::string::npos) {
259 library_name = library_name + kSharedLibExt;
7c673cae 260 }
f67539c2
TL
261#if !defined(OS_WIN)
262 if (library_name.find('/') == std::string::npos &&
263 library_name.compare(0, 3, "lib") != 0) {
264 library_name = "lib" + library_name;
7c673cae
FG
265 }
266#endif
f67539c2
TL
267 if (path.empty()) {
268 void* hndl = dlopen(library_name.c_str(), RTLD_NOW);
269 if (hndl != nullptr) {
270 result->reset(new PosixDynamicLibrary(library_name, hndl));
271 return Status::OK();
7c673cae 272 }
f67539c2
TL
273 } else {
274 std::string local_path;
275 std::stringstream ss(path);
276 while (getline(ss, local_path, kPathSeparator)) {
277 if (!path.empty()) {
278 std::string full_name = local_path + "/" + library_name;
279 void* hndl = dlopen(full_name.c_str(), RTLD_NOW);
280 if (hndl != nullptr) {
281 result->reset(new PosixDynamicLibrary(full_name, hndl));
282 return Status::OK();
283 }
284 }
11fdf7f2 285 }
7c673cae
FG
286 }
287 }
f67539c2
TL
288 return Status::IOError(
289 IOErrorMsg("Failed to open shared library: xs", name), dlerror());
7c673cae 290 }
f67539c2 291#endif // !ROCKSDB_NO_DYNAMIC_EXTENSION
7c673cae 292
494da23a
TL
293 void Schedule(void (*function)(void* arg1), void* arg, Priority pri = LOW,
294 void* tag = nullptr,
295 void (*unschedFunction)(void* arg) = nullptr) override;
7c673cae 296
494da23a 297 int UnSchedule(void* arg, Priority pri) override;
7c673cae 298
494da23a 299 void StartThread(void (*function)(void* arg), void* arg) override;
7c673cae 300
494da23a 301 void WaitForJoin() override;
7c673cae 302
494da23a 303 unsigned int GetThreadPoolQueueLen(Priority pri = LOW) const override;
7c673cae 304
1e59de90
TL
305 int ReserveThreads(int threads_to_be_reserved, Priority pri) override;
306
307 int ReleaseThreads(int threads_to_be_released, Priority pri) override;
308
494da23a 309 Status GetThreadList(std::vector<ThreadStatus>* thread_list) override {
7c673cae
FG
310 assert(thread_status_updater_);
311 return thread_status_updater_->GetThreadList(thread_list);
312 }
313
1e59de90 314 uint64_t GetThreadID() const override {
7c673cae 315 uint64_t thread_id = 0;
1e59de90
TL
316#if defined(_GNU_SOURCE) && defined(__GLIBC_PREREQ)
317#if __GLIBC_PREREQ(2, 30)
318 thread_id = ::gettid();
319#else // __GLIBC_PREREQ(2, 30)
320 pthread_t tid = pthread_self();
7c673cae 321 memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid)));
1e59de90
TL
322#endif // __GLIBC_PREREQ(2, 30)
323#else // defined(_GNU_SOURCE) && defined(__GLIBC_PREREQ)
7c673cae 324 pthread_t tid = pthread_self();
1e59de90
TL
325 memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid)));
326#endif // defined(_GNU_SOURCE) && defined(__GLIBC_PREREQ)
327 return thread_id;
494da23a
TL
328 }
329
494da23a 330 Status GetHostName(char* name, uint64_t len) override {
7c673cae
FG
331 int ret = gethostname(name, static_cast<size_t>(len));
332 if (ret < 0) {
f67539c2 333 if (errno == EFAULT || errno == EINVAL) {
1e59de90 334 return Status::InvalidArgument(errnoStr(errno).c_str());
f67539c2 335 } else {
11fdf7f2 336 return IOError("GetHostName", name, errno);
f67539c2 337 }
7c673cae
FG
338 }
339 return Status::OK();
340 }
341
f67539c2
TL
342 ThreadStatusUpdater* GetThreadStatusUpdater() const override {
343 return Env::GetThreadStatusUpdater();
7c673cae
FG
344 }
345
f67539c2
TL
346 std::string GenerateUniqueId() override { return Env::GenerateUniqueId(); }
347
7c673cae 348 // Allow increasing the number of worker threads.
494da23a 349 void SetBackgroundThreads(int num, Priority pri) override {
11fdf7f2 350 assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH);
7c673cae
FG
351 thread_pools_[pri].SetBackgroundThreads(num);
352 }
353
494da23a 354 int GetBackgroundThreads(Priority pri) override {
11fdf7f2
TL
355 assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH);
356 return thread_pools_[pri].GetBackgroundThreads();
357 }
358
494da23a 359 Status SetAllowNonOwnerAccess(bool allow_non_owner_access) override {
11fdf7f2
TL
360 allow_non_owner_access_ = allow_non_owner_access;
361 return Status::OK();
362 }
363
7c673cae 364 // Allow increasing the number of worker threads.
494da23a 365 void IncBackgroundThreadsIfNeeded(int num, Priority pri) override {
11fdf7f2 366 assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH);
7c673cae
FG
367 thread_pools_[pri].IncBackgroundThreadsIfNeeded(num);
368 }
369
20effc67 370 void LowerThreadPoolIOPriority(Priority pool) override {
11fdf7f2 371 assert(pool >= Priority::BOTTOM && pool <= Priority::HIGH);
7c673cae
FG
372#ifdef OS_LINUX
373 thread_pools_[pool].LowerIOPriority();
11fdf7f2
TL
374#else
375 (void)pool;
376#endif
377 }
378
20effc67 379 void LowerThreadPoolCPUPriority(Priority pool) override {
11fdf7f2 380 assert(pool >= Priority::BOTTOM && pool <= Priority::HIGH);
20effc67
TL
381 thread_pools_[pool].LowerCPUPriority(CpuPriority::kLow);
382 }
383
384 Status LowerThreadPoolCPUPriority(Priority pool, CpuPriority pri) override {
385 assert(pool >= Priority::BOTTOM && pool <= Priority::HIGH);
386 thread_pools_[pool].LowerCPUPriority(pri);
387 return Status::OK();
7c673cae
FG
388 }
389
7c673cae 390 private:
20effc67
TL
391 friend Env* Env::Default();
392 // Constructs the default Env, a singleton
393 PosixEnv();
394
395 // The below 4 members are only used by the default PosixEnv instance.
396 // Non-default instances simply maintain references to the backing
397 // members in te default instance
398 std::vector<ThreadPoolImpl> thread_pools_storage_;
399 pthread_mutex_t mu_storage_;
400 std::vector<pthread_t> threads_to_join_storage_;
401 bool allow_non_owner_access_storage_;
402
403 std::vector<ThreadPoolImpl>& thread_pools_;
404 pthread_mutex_t& mu_;
405 std::vector<pthread_t>& threads_to_join_;
11fdf7f2
TL
406 // If true, allow non owner read access for db files. Otherwise, non-owner
407 // has no access to db files.
20effc67 408 bool& allow_non_owner_access_;
7c673cae
FG
409};
410
411PosixEnv::PosixEnv()
1e59de90 412 : CompositeEnv(FileSystem::Default(), SystemClock::Default()),
20effc67
TL
413 thread_pools_storage_(Priority::TOTAL),
414 allow_non_owner_access_storage_(true),
415 thread_pools_(thread_pools_storage_),
416 mu_(mu_storage_),
417 threads_to_join_(threads_to_join_storage_),
418 allow_non_owner_access_(allow_non_owner_access_storage_) {
7c673cae
FG
419 ThreadPoolImpl::PthreadCall("mutex_init", pthread_mutex_init(&mu_, nullptr));
420 for (int pool_id = 0; pool_id < Env::Priority::TOTAL; ++pool_id) {
421 thread_pools_[pool_id].SetThreadPriority(
422 static_cast<Env::Priority>(pool_id));
423 // This allows later initializing the thread-local-env of each thread.
424 thread_pools_[pool_id].SetHostEnv(this);
425 }
426 thread_status_updater_ = CreateThreadStatusUpdater();
427}
428
429void PosixEnv::Schedule(void (*function)(void* arg1), void* arg, Priority pri,
430 void* tag, void (*unschedFunction)(void* arg)) {
11fdf7f2 431 assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH);
7c673cae
FG
432 thread_pools_[pri].Schedule(function, arg, tag, unschedFunction);
433}
434
435int PosixEnv::UnSchedule(void* arg, Priority pri) {
436 return thread_pools_[pri].UnSchedule(arg);
437}
438
439unsigned int PosixEnv::GetThreadPoolQueueLen(Priority pri) const {
11fdf7f2 440 assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH);
7c673cae
FG
441 return thread_pools_[pri].GetQueueLen();
442}
443
1e59de90
TL
444int PosixEnv::ReserveThreads(int threads_to_reserved, Priority pri) {
445 assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH);
446 return thread_pools_[pri].ReserveThreads(threads_to_reserved);
447}
448
449int PosixEnv::ReleaseThreads(int threads_to_released, Priority pri) {
450 assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH);
451 return thread_pools_[pri].ReleaseThreads(threads_to_released);
452}
453
7c673cae
FG
454struct StartThreadState {
455 void (*user_function)(void*);
456 void* arg;
457};
458
459static void* StartThreadWrapper(void* arg) {
460 StartThreadState* state = reinterpret_cast<StartThreadState*>(arg);
461 state->user_function(state->arg);
462 delete state;
463 return nullptr;
464}
465
466void PosixEnv::StartThread(void (*function)(void* arg), void* arg) {
467 pthread_t t;
468 StartThreadState* state = new StartThreadState;
469 state->user_function = function;
470 state->arg = arg;
471 ThreadPoolImpl::PthreadCall(
472 "start thread", pthread_create(&t, nullptr, &StartThreadWrapper, state));
473 ThreadPoolImpl::PthreadCall("lock", pthread_mutex_lock(&mu_));
474 threads_to_join_.push_back(t);
475 ThreadPoolImpl::PthreadCall("unlock", pthread_mutex_unlock(&mu_));
476}
477
478void PosixEnv::WaitForJoin() {
479 for (const auto tid : threads_to_join_) {
480 pthread_join(tid, nullptr);
481 }
482 threads_to_join_.clear();
483}
484
485} // namespace
486
7c673cae
FG
487//
488// Default Posix Env
489//
490Env* Env::Default() {
491 // The following function call initializes the singletons of ThreadLocalPtr
492 // right before the static default_env. This guarantees default_env will
493 // always being destructed before the ThreadLocalPtr singletons get
494 // destructed as C++ guarantees that the destructions of static variables
495 // is in the reverse order of their constructions.
496 //
497 // Since static members are destructed in the reverse order
498 // of their construction, having this call here guarantees that
499 // the destructor of static PosixEnv will go first, then the
500 // the singletons of ThreadLocalPtr.
501 ThreadLocalPtr::InitSingletons();
11fdf7f2
TL
502 CompressionContextCache::InitSingleton();
503 INIT_SYNC_POINT_SINGLETONS();
1e59de90
TL
504 // ~PosixEnv must be called on exit
505 //**TODO: Can we make this a STATIC_AVOID_DESTRUCTION?
7c673cae 506 static PosixEnv default_env;
20effc67
TL
507 return &default_env;
508}
509
1e59de90
TL
510//
511// Default Posix SystemClock
512//
513const std::shared_ptr<SystemClock>& SystemClock::Default() {
514 STATIC_AVOID_DESTRUCTION(std::shared_ptr<SystemClock>, instance)
515 (std::make_shared<PosixClock>());
516 return instance;
7c673cae 517}
f67539c2 518} // namespace ROCKSDB_NAMESPACE
20effc67
TL
519
520#endif