YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/util/rwc_lock.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
33
#include "yb/util/rwc_lock.h"
34
35
#include <glog/logging.h>
36
37
#ifndef NDEBUG
38
#include <utility>
39
#endif // NDEBUG
40
41
#ifndef NDEBUG
42
#include "yb/gutil/walltime.h"
43
#include "yb/util/debug-util.h"
44
#include "yb/util/env.h"
45
#include "yb/util/thread.h"
46
#endif // NDEBUG
47
48
namespace yb {
49
50
namespace {
51
52
const auto kFirstWait = MonoDelta::FromSeconds(1);
53
const auto kSecondWait = MonoDelta::FromSeconds(180);
54
55
} // namespace
56
57
RWCLock::RWCLock()
58
  : no_mutators_(&lock_),
59
    no_readers_(&lock_),
60
    reader_count_(0),
61
#ifdef NDEBUG
62
    write_locked_(false) {
63
#else
64
    write_locked_(false),
65
    last_writer_tid_(0),
66
635k
    last_writelock_acquire_time_(0) {
67
635k
#endif // NDEBUG
68
635k
}
69
70
12.1k
RWCLock::~RWCLock() {
71
12.1k
  CHECK_EQ(reader_count_, 0);
72
12.1k
}
73
74
1.11G
void RWCLock::ReadLock() {
75
1.11G
  MutexLock l(lock_);
76
1.11G
  reader_count_++;
77
1.11G
#ifndef NDEBUG
78
1.11G
  if (VLOG_IS_ON(1)) {
79
0
    const int64_t tid = Thread::CurrentThreadId();
80
0
    if (reader_stacks_.find(tid) == reader_stacks_.end()) {
81
0
      StackTrace stack_trace = StackTrace();
82
0
      stack_trace.Collect();
83
0
      reader_stacks_[tid] = {
84
0
        .count = 1,
85
0
        .stack = std::move(stack_trace),
86
0
      };
87
0
    } else {
88
0
      reader_stacks_[tid].count++;
89
0
    }
90
0
  }
91
1.11G
#endif // NDEBUG
92
1.11G
}
93
94
1.11G
void RWCLock::ReadUnlock() {
95
1.11G
  MutexLock l(lock_);
96
1.11G
  DCHECK_GT(reader_count_, 0);
97
1.11G
  reader_count_--;
98
1.11G
#ifndef NDEBUG
99
1.11G
  if (VLOG_IS_ON(1)) {
100
0
    const int64_t tid = Thread::CurrentThreadId();
101
0
    if (--reader_stacks_[tid].count == 0) {
102
0
      reader_stacks_.erase(tid);
103
0
    }
104
0
  }
105
1.11G
#endif // NDEBUG
106
1.11G
  if (reader_count_ == 0) {
107
1.00G
    no_readers_.Signal();
108
1.00G
  }
109
1.11G
}
110
111
864M
bool RWCLock::HasReaders() const {
112
864M
  MutexLock l(lock_);
113
864M
  return reader_count_ > 0;
114
864M
}
115
116
2.32M
bool RWCLock::HasWriteLock() const {
117
2.32M
  MutexLock l(lock_);
118
2.32M
#ifndef NDEBUG
119
2.32M
  return last_writer_tid_ == Thread::CurrentThreadId();
120
#else
121
  return write_locked_;
122
#endif
123
2.32M
}
124
125
2.19M
void RWCLock::WriteLock() {
126
2.19M
  MutexLock l(lock_);
127
  // Wait for any other mutations to finish.
128
2.19M
#ifndef NDEBUG
129
2.19M
  bool first_wait = true;
130
2.33M
  while (write_locked_) {
131
138k
    if (!no_mutators_.TimedWait(first_wait ? 
kFirstWait128k
:
kSecondWait9.74k
)) {
132
21
      std::ostringstream ss;
133
21
      ss << "Too long write lock wait, last writer stack: " << last_writer_stacktrace_.Symbolize();
134
21
      if (VLOG_IS_ON(1) || !first_wait) {
135
1
        ss << "current thread stack: " << GetStackTrace();
136
1
      }
137
21
      (first_wait ? LOG(WARNING) : LOG(FATAL)) << ss.str();
138
21
    }
139
138k
    first_wait = false;
140
138k
  }
141
#else
142
  while (write_locked_) {
143
    no_mutators_.Wait();
144
  }
145
#endif
146
2.19M
#ifndef NDEBUG
147
2.19M
  last_writelock_acquire_time_ = GetCurrentTimeMicros();
148
2.19M
  last_writer_tid_ = Thread::CurrentThreadId();
149
2.19M
  last_writer_stacktrace_.Collect();
150
2.19M
#endif // NDEBUG
151
2.19M
  write_locked_ = true;
152
2.19M
}
153
154
882k
void RWCLock::WriteUnlock() {
155
882k
  MutexLock l(lock_);
156
882k
  DCHECK(write_locked_);
157
882k
  write_locked_ = false;
158
882k
#ifndef NDEBUG
159
882k
  last_writer_stacktrace_.Reset();
160
882k
#endif // NDEBUG
161
882k
  no_mutators_.Signal();
162
882k
}
163
164
1.31M
void RWCLock::UpgradeToCommitLock() {
165
1.31M
  lock_.lock();
166
1.31M
  DCHECK(write_locked_);
167
1.31M
#ifndef NDEBUG
168
1.31M
  bool first_wait = true;
169
1.31M
  while (reader_count_ > 0) {
170
2.53k
    if (!no_readers_.TimedWait(first_wait ? 
kFirstWait458
:
kSecondWait2.08k
)) {
171
0
      std::ostringstream ss;
172
0
      ss << "Too long commit lock wait, num readers: " << reader_count_
173
0
         << ", current thread stack: " << GetStackTrace();
174
0
      if (VLOG_IS_ON(1)) {
175
0
        for (const auto& entry : reader_stacks_) {
176
0
          ss << "reader thread " << entry.first;
177
0
          if (entry.second.count > 1) {
178
0
            ss << " (holding " << entry.second.count << " locks) first";
179
0
          }
180
0
          ss << " stack: " << entry.second.stack.Symbolize();
181
0
        }
182
0
      }
183
0
      (first_wait ? LOG(WARNING) : LOG(FATAL)) << ss.str();
184
0
    }
185
2.53k
    first_wait = false;
186
2.53k
  }
187
#else
188
  while (reader_count_ > 0) {
189
    no_readers_.Wait();
190
  }
191
#endif
192
1.31M
  DCHECK(write_locked_);
193
194
  // Leaves the lock held, which prevents any new readers
195
  // or writers.
196
1.31M
}
197
198
1.31M
void RWCLock::CommitUnlock() {
199
1.31M
  DCHECK_EQ(0, reader_count_);
200
1.31M
  write_locked_ = false;
201
1.31M
#ifndef NDEBUG
202
1.31M
  last_writer_stacktrace_.Reset();
203
1.31M
#endif // NDEBUG
204
1.31M
  no_mutators_.Broadcast();
205
1.31M
  lock_.unlock();
206
1.31M
}
207
208
} // namespace yb