YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/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
39.6k
std::string GetRootDir(const string& search_for_dir) {
58
39.6k
  char* yb_home = getenv("YB_HOME");
59
39.6k
  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
39.6k
  string executable_path;
70
39.6k
  auto status = Env::Default()->GetExecutablePath(&executable_path);
71
39.6k
  if (!status.ok()) {
72
0
    LOG(WARNING) << "Ignoring status error: " << status.ToString();
73
0
    return "";
74
0
  }
75
76
39.6k
  auto path = executable_path;
77
111k
  while (path != "/") {
78
111k
    path = DirName(path);
79
80
111k
    boost::container::small_vector<string, 2> candidates { path };
81
111k
    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
111k
    for (const auto& candidate_path : candidates) {
89
111k
      auto sub_dir = JoinPathSegments(candidate_path, search_for_dir);
90
111k
      bool is_dir = false;
91
111k
      auto status = Env::Default()->IsDirectory(sub_dir, &is_dir);
92
111k
      if (!status.ok()) {
93
71.4k
        continue;
94
71.4k
      }
95
39.6k
      
if (39.6k
is_dir39.6k
) {
96
39.6k
        return candidate_path;
97
39.6k
      }
98
39.6k
    }
99
111k
  }
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
39.6k
}
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
350k
                         shared_ptr<RandomAccessFile> *file) {
125
350k
  std::unique_ptr<RandomAccessFile> r;
126
350k
  RETURN_NOT_OK(env->NewRandomAccessFile(path, &r));
127
350k
  file->reset(r.release());
128
350k
  return Status::OK();
129
350k
}
130
131
Status OpenFileForSequential(Env *env, const string &path,
132
3.34k
                             shared_ptr<SequentialFile> *file) {
133
3.34k
  std::unique_ptr<SequentialFile> r;
134
3.34k
  RETURN_NOT_OK(env->NewSequentialFile(path, &r));
135
3.34k
  file->reset(r.release());
136
3.34k
  return Status::OK();
137
3.34k
}
138
139
Status ReadFully(RandomAccessFile* file, uint64_t offset, size_t n,
140
3.64M
                 Slice* result, uint8_t* scratch) {
141
142
3.64M
  bool first_read = true;
143
144
3.64M
  size_t rem = n;
145
3.64M
  uint8_t* dst = scratch;
146
3.64M
  while (
rem > 03.63M
) {
147
3.64M
    Slice this_result;
148
3.64M
    RETURN_NOT_OK(file->Read(offset, rem, &this_result, dst));
149
3.64M
    DCHECK_LE(this_result.size(), rem);
150
3.64M
    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
3.64M
    
if (3.64M
first_read3.64M
&& this_result.size() == n) {
157
      // If it's the first read, we can return a zero-copy array.
158
3.64M
      *result = this_result;
159
3.64M
      return Status::OK();
160
3.64M
    }
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
3.64M
}
174
175
2.98M
Status CreateDirIfMissing(Env* env, const string& path, bool* created) {
176
2.98M
  Status s = env->CreateDir(path);
177
2.98M
  if (created != nullptr) {
178
1.26M
    *created = s.ok();
179
1.26M
  }
180
2.98M
  return s.IsAlreadyPresent() ? 
Status::OK()1.50M
:
s1.48M
;
181
2.98M
}
182
183
Status CopyFile(Env* env, const string& source_path, const string& dest_path,
184
166
                WritableFileOptions opts) {
185
166
  std::unique_ptr<SequentialFile> source;
186
166
  RETURN_NOT_OK(env->NewSequentialFile(source_path, &source));
187
166
  uint64_t size = VERIFY_RESULT(env->GetFileSize(source_path));
188
189
0
  std::unique_ptr<WritableFile> dest;
190
166
  RETURN_NOT_OK(env->NewWritableFile(opts, dest_path, &dest));
191
166
  RETURN_NOT_OK(dest->PreAllocate(size));
192
193
166
  const int32_t kBufferSize = 1024 * 1024;
194
166
  std::unique_ptr<uint8_t[]> scratch(new uint8_t[kBufferSize]);
195
196
166
  uint64_t bytes_read = 0;
197
333
  while (bytes_read < size) {
198
167
    uint64_t max_bytes_to_read = std::min<uint64_t>(size - bytes_read, kBufferSize);
199
167
    Slice data;
200
167
    RETURN_NOT_OK(source->Read(max_bytes_to_read, &data, scratch.get()));
201
167
    RETURN_NOT_OK(dest->Append(data));
202
167
    bytes_read += data.size();
203
167
  }
204
166
  return Status::OK();
205
166
}
206
207
ScopedFileDeleter::ScopedFileDeleter(Env* env, std::string path)
208
2.27M
    : env_(DCHECK_NOTNULL(env)), path_(std::move(path)), should_delete_(true) {}
209
210
2.27M
ScopedFileDeleter::~ScopedFileDeleter() {
211
2.27M
  if (should_delete_) {
212
44.0k
    bool is_dir;
213
44.0k
    Status s = env_->IsDirectory(path_, &is_dir);
214
44.0k
    WARN_NOT_OK(s, Substitute(
215
44.0k
        "Failed to determine if path is a directory: $0", path_));
216
44.0k
    if (!s.ok()) {
217
0
      return;
218
0
    }
219
44.0k
    if (is_dir) {
220
0
      WARN_NOT_OK(env_->DeleteDir(path_),
221
0
                  Substitute("Failed to remove directory: $0", path_));
222
44.0k
    } else {
223
44.0k
      WARN_NOT_OK(env_->DeleteFile(path_),
224
44.0k
          Substitute("Failed to remove file: $0", path_));
225
44.0k
    }
226
44.0k
  }
227
2.27M
}
228
229
} // namespace env_util
230
} // namespace yb