YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/env_util.cc
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
#include "yb/util/env_util.h"
33
34
#include <memory>
35
#include <string>
36
37
#include <boost/container/small_vector.hpp>
38
39
#include "yb/gutil/strings/util.h"
40
#include "yb/util/env.h"
41
#include "yb/util/path_util.h"
42
#include "yb/util/result.h"
43
#include "yb/util/status_log.h"
44
45
using strings::Substitute;
46
using std::shared_ptr;
47
using std::string;
48
49
namespace yb {
50
namespace env_util {
51
52
// We use this suffix in the "external build directory" mode, i.e. the source could be in
53
// ~/code/yugabyte the build directories for different configurations will all be in
54
// ~/code/yugabyte__build. This will prevent IDEs from trying to parse build artifacts.
55
const string kExternalBuildDirSuffix = "__build";
56
57
21.7k
std::string GetRootDir(const string& search_for_dir) {
58
21.7k
  char* yb_home = getenv("YB_HOME");
59
21.7k
  if (yb_home) {
60
0
    return yb_home;
61
0
  }
62
63
  // If YB_HOME is not set, we use the path where the binary is located
64
  // (e.g., /opt/yugabyte/tserver/bin/yb-tserver) to determine the doc root.
65
  // To find "www"'s location, we search whether "www" exists at each directory, starting with
66
  // the directory where the current binary (yb-tserver, or yb-master) is located.
67
  // During each iteration, we keep going up one directory and do the search again.
68
  // If we can't find a directory that contains "www", we return a default value for now.
69
21.7k
  string executable_path;
70
21.7k
  auto status = Env::Default()->GetExecutablePath(&executable_path);
71
21.7k
  if (!status.ok()) {
72
0
    LOG(WARNING) << "Ignoring status error: " << status.ToString();
73
0
    return "";
74
0
  }
75
76
21.7k
  auto path = executable_path;
77
56.3k
  while (path != "/") {
78
56.3k
    path = DirName(path);
79
80
56.3k
    boost::container::small_vector<string, 2> candidates { path };
81
56.3k
    if (HasSuffixString(path, kExternalBuildDirSuffix)) {
82
0
      candidates.push_back(std::string(path.begin(), path.end() - kExternalBuildDirSuffix.size()));
83
0
      if (candidates.back().back() == '/') {
84
        // path was of the ".../__build" form instead of ".../<some_name>__build", ignore it.
85
0
        candidates.pop_back();
86
0
      }
87
0
    }
88
56.3k
    for (const auto& candidate_path : candidates) {
89
56.3k
      auto sub_dir = JoinPathSegments(candidate_path, search_for_dir);
90
56.3k
      bool is_dir = false;
91
56.3k
      auto status = Env::Default()->IsDirectory(sub_dir, &is_dir);
92
56.3k
      if (!status.ok()) {
93
34.5k
        continue;
94
34.5k
      }
95
21.7k
      if (is_dir) {
96
21.7k
        return candidate_path;
97
21.7k
      }
98
21.7k
    }
99
56.3k
  }
100
101
0
  LOG(ERROR) << "Unable to find '" << search_for_dir
102
0
             << "' directory by starting the search at path " << DirName(executable_path)
103
0
             << " and walking up the directory structure";
104
105
  // Return a path.
106
0
  return DirName(DirName(executable_path));
107
21.7k
}
108
109
Status OpenFileForWrite(Env* env, const string& path,
110
9
                        shared_ptr<WritableFile>* file) {
111
9
  return OpenFileForWrite(WritableFileOptions(), env, path, file);
112
9
}
113
114
Status OpenFileForWrite(const WritableFileOptions& opts,
115
                        Env *env, const string &path,
116
17
                        shared_ptr<WritableFile> *file) {
117
17
  std::unique_ptr<WritableFile> w;
118
17
  RETURN_NOT_OK(env->NewWritableFile(opts, path, &w));
119
15
  file->reset(w.release());
120
15
  return Status::OK();
121
17
}
122
123
Status OpenFileForRandom(Env *env, const string &path,
124
226k
                         shared_ptr<RandomAccessFile> *file) {
125
226k
  std::unique_ptr<RandomAccessFile> r;
126
226k
  RETURN_NOT_OK(env->NewRandomAccessFile(path, &r));
127
226k
  file->reset(r.release());
128
226k
  return Status::OK();
129
226k
}
130
131
Status OpenFileForSequential(Env *env, const string &path,
132
1.80k
                             shared_ptr<SequentialFile> *file) {
133
1.80k
  std::unique_ptr<SequentialFile> r;
134
1.80k
  RETURN_NOT_OK(env->NewSequentialFile(path, &r));
135
1.80k
  file->reset(r.release());
136
1.80k
  return Status::OK();
137
1.80k
}
138
139
Status ReadFully(RandomAccessFile* file, uint64_t offset, size_t n,
140
2.41M
                 Slice* result, uint8_t* scratch) {
141
142
2.41M
  bool first_read = true;
143
144
2.41M
  size_t rem = n;
145
2.41M
  uint8_t* dst = scratch;
146
2.41M
  while (rem > 0) {
147
2.41M
    Slice this_result;
148
2.41M
    RETURN_NOT_OK(file->Read(offset, rem, &this_result, dst));
149
2.41M
    DCHECK_LE(this_result.size(), rem);
150
2.41M
    if (this_result.size() == 0) {
151
      // EOF
152
1
      return STATUS(IOError, Substitute("EOF trying to read $0 bytes at offset $1",
153
1
                                        n, offset));
154
1
    }
155
156
2.41M
    if (first_read && this_result.size() == n) {
157
      // If it's the first read, we can return a zero-copy array.
158
2.41M
      *result = this_result;
159
2.41M
      return Status::OK();
160
2.41M
    }
161
18.4E
    first_read = false;
162
163
    // Otherwise, we're going to have to do more reads and stitch
164
    // each read together.
165
18.4E
    this_result.relocate(dst);
166
18.4E
    dst += this_result.size();
167
18.4E
    rem -= this_result.size();
168
18.4E
    offset += this_result.size();
169
18.4E
  }
170
18.4E
  DCHECK_EQ(0, rem);
171
18.4E
  *result = Slice(scratch, n);
172
18.4E
  return Status::OK();
173
2.41M
}
174
175
1.65M
Status CreateDirIfMissing(Env* env, const string& path, bool* created) {
176
1.65M
  Status s = env->CreateDir(path);
177
1.65M
  if (created != nullptr) {
178
409k
    *created = s.ok();
179
409k
  }
180
1.01M
  return s.IsAlreadyPresent() ? Status::OK() : s;
181
1.65M
}
182
183
Status CopyFile(Env* env, const string& source_path, const string& dest_path,
184
118
                WritableFileOptions opts) {
185
118
  std::unique_ptr<SequentialFile> source;
186
118
  RETURN_NOT_OK(env->NewSequentialFile(source_path, &source));
187
118
  uint64_t size = VERIFY_RESULT(env->GetFileSize(source_path));
188
189
118
  std::unique_ptr<WritableFile> dest;
190
118
  RETURN_NOT_OK(env->NewWritableFile(opts, dest_path, &dest));
191
118
  RETURN_NOT_OK(dest->PreAllocate(size));
192
193
118
  const int32_t kBufferSize = 1024 * 1024;
194
118
  std::unique_ptr<uint8_t[]> scratch(new uint8_t[kBufferSize]);
195
196
118
  uint64_t bytes_read = 0;
197
237
  while (bytes_read < size) {
198
119
    uint64_t max_bytes_to_read = std::min<uint64_t>(size - bytes_read, kBufferSize);
199
119
    Slice data;
200
119
    RETURN_NOT_OK(source->Read(max_bytes_to_read, &data, scratch.get()));
201
119
    RETURN_NOT_OK(dest->Append(data));
202
119
    bytes_read += data.size();
203
119
  }
204
118
  return Status::OK();
205
118
}
206
207
ScopedFileDeleter::ScopedFileDeleter(Env* env, std::string path)
208
1.21M
    : env_(DCHECK_NOTNULL(env)), path_(std::move(path)), should_delete_(true) {}
209
210
1.21M
ScopedFileDeleter::~ScopedFileDeleter() {
211
1.21M
  if (should_delete_) {
212
0
    bool is_dir;
213
0
    Status s = env_->IsDirectory(path_, &is_dir);
214
0
    WARN_NOT_OK(s, Substitute(
215
0
        "Failed to determine if path is a directory: $0", path_));
216
0
    if (!s.ok()) {
217
0
      return;
218
0
    }
219
0
    if (is_dir) {
220
0
      WARN_NOT_OK(env_->DeleteDir(path_),
221
0
                  Substitute("Failed to remove directory: $0", path_));
222
0
    } else {
223
0
      WARN_NOT_OK(env_->DeleteFile(path_),
224
0
          Substitute("Failed to remove file: $0", path_));
225
0
    }
226
0
  }
227
1.21M
}
228
229
} // namespace env_util
230
} // namespace yb