YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/docdb/transaction_dump.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#include "yb/docdb/transaction_dump.h"
15
16
#include <condition_variable>
17
#include <mutex>
18
19
#include <glog/logging.h>
20
21
#include "yb/util/env.h"
22
#include "yb/util/lockfree.h"
23
#include "yb/util/path_util.h"
24
#include "yb/util/result.h"
25
#include "yb/util/status_log.h"
26
27
DEFINE_bool(dump_transactions, false, "Dump transactions data in debug binary format");
28
// The output dir is tried in the following order (first existing and non empty is taken):
29
// Symlink $HOME/logs/latest_test
30
// Flag log_dir
31
// /tmp
32
33
namespace yb {
34
namespace docdb {
35
36
namespace {
37
38
struct DumpEntry {
39
  DumpEntry* next = nullptr;
40
  size_t size;
41
  char data[0];
42
};
43
44
0
void SetNext(DumpEntry* entry, DumpEntry* next) {
45
0
  entry->next = next;
46
0
}
47
48
0
DumpEntry* GetNext(DumpEntry* entry) {
49
0
  return entry->next;
50
0
}
51
52
class Dumper {
53
 public:
54
0
  Dumper() {
55
0
    writer_ = std::thread([this] {
56
0
      this->Execute();
57
0
    });
58
0
  }
59
60
0
  ~Dumper() {
61
0
    {
62
0
      std::unique_lock<std::mutex> lock(mutex_);
63
0
      stop_.store(true, std::memory_order_release);
64
0
    }
65
0
    cond_.notify_one();
66
0
    writer_.join();
67
0
    while (auto* entry = queue_.Pop()) {
68
0
      free(entry);
69
0
    }
70
0
  }
71
72
0
  void Dump(const SliceParts& parts) {
73
0
    size_t size = parts.SumSizes();
74
0
    auto* entry = static_cast<DumpEntry*>(malloc(offsetof(DumpEntry, data) + size));
75
0
    entry->size = size;
76
0
    parts.CopyAllTo(entry->data);
77
0
    queue_.Push(entry);
78
0
    cond_.notify_one();
79
0
  }
80
81
 private:
82
0
  void Execute() {
83
0
    Open();
84
0
    DumpEntry* entry = nullptr;
85
0
    for (;;) {
86
0
      while (entry) {
87
0
        CHECK_OK(file_->Append(Slice(entry->data, entry->size)));
88
0
        free(entry);
89
0
        entry = queue_.Pop();
90
0
      }
91
0
      {
92
0
        std::unique_lock<std::mutex> lock(mutex_);
93
0
        if (stop_.load(std::memory_order_acquire)) {
94
0
          break;
95
0
        }
96
0
        entry = queue_.Pop();
97
0
        if (!entry) {
98
0
          cond_.wait(lock);
99
0
        }
100
0
      }
101
0
    }
102
0
  }
103
104
0
  void Open() {
105
0
    std::string dir = OutDir();
106
107
0
    auto now = std::time(/* arg= */ nullptr);
108
0
    auto* tm = std::localtime(&now);
109
0
    char buffer[32];
110
0
    buffer[strftime(buffer, sizeof(buffer), "%Y%m%d-%H%M%S", tm)] = 0;
111
0
    auto fname = JoinPathSegments(dir, Format("DUMP.$0.$1", buffer, getpid()));
112
0
    LOG(INFO) << "Dump transactions to " << fname;
113
0
    CHECK_OK(Env::Default()->NewWritableFile(fname, &file_));
114
0
  }
115
116
0
  std::string OutDir() {
117
0
    std::string result;
118
0
    auto* home = getenv("HOME");
119
0
    if (home && home[0]) {
120
0
      auto latest_logs = JoinPathSegments(home, "logs/latest_test");
121
0
      auto result_dir = Env::Default()->ReadLink(latest_logs);
122
0
      if (result_dir.ok()) {
123
0
        result = *result_dir;
124
0
      } else {
125
0
        LOG(WARNING) << "Failed to read link " << latest_logs << ": " << result_dir.status();
126
0
      }
127
0
    }
128
0
    if (result.empty()) {
129
0
      result = FLAGS_log_dir;
130
0
    }
131
0
    if (result.empty()) {
132
0
      result = "/tmp";
133
0
    }
134
0
    return result;
135
0
  }
136
137
  std::unique_ptr<WritableFile> file_;
138
  std::thread writer_;
139
  std::atomic<bool> stop_{false};
140
  MPSCQueue<DumpEntry> queue_;
141
  std::mutex mutex_;
142
  std::condition_variable cond_;
143
};
144
145
} // namespace
146
147
0
void TransactionDump(const SliceParts& parts) {
148
0
  static Dumper dumper;
149
0
  dumper.Dump(parts);
150
0
}
151
152
}  // namespace docdb
153
}  // namespace yb