YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/atomic-test.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 <thread>
34
35
#include <gtest/gtest.h>
36
#include "yb/util/random_util.h"
37
#include "yb/util/atomic.h"
38
39
namespace yb {
40
41
using std::numeric_limits;
42
using std::vector;
43
44
// TODO Add some multi-threaded tests; currently AtomicInt is just a
45
// wrapper around 'atomicops.h', but should the underlying
46
// implemention change, it would help to have tests that make sure
47
// invariants are preserved in a multi-threaded environment.
48
49
template<typename T>
50
class AtomicIntTest : public ::testing::Test {
51
 public:
52
53
  AtomicIntTest()
54
      : max_(numeric_limits<T>::max()),
55
16
        min_(numeric_limits<T>::min()) {
56
16
    acquire_release_ = { kMemOrderNoBarrier, kMemOrderAcquire, kMemOrderRelease };
57
16
    barrier_ = { kMemOrderNoBarrier, kMemOrderBarrier };
58
16
  }
_ZN2yb13AtomicIntTestIiEC2Ev
Line
Count
Source
55
4
        min_(numeric_limits<T>::min()) {
56
4
    acquire_release_ = { kMemOrderNoBarrier, kMemOrderAcquire, kMemOrderRelease };
57
4
    barrier_ = { kMemOrderNoBarrier, kMemOrderBarrier };
58
4
  }
_ZN2yb13AtomicIntTestIxEC2Ev
Line
Count
Source
55
4
        min_(numeric_limits<T>::min()) {
56
4
    acquire_release_ = { kMemOrderNoBarrier, kMemOrderAcquire, kMemOrderRelease };
57
4
    barrier_ = { kMemOrderNoBarrier, kMemOrderBarrier };
58
4
  }
_ZN2yb13AtomicIntTestIjEC2Ev
Line
Count
Source
55
4
        min_(numeric_limits<T>::min()) {
56
4
    acquire_release_ = { kMemOrderNoBarrier, kMemOrderAcquire, kMemOrderRelease };
57
4
    barrier_ = { kMemOrderNoBarrier, kMemOrderBarrier };
58
4
  }
_ZN2yb13AtomicIntTestIyEC2Ev
Line
Count
Source
55
4
        min_(numeric_limits<T>::min()) {
56
4
    acquire_release_ = { kMemOrderNoBarrier, kMemOrderAcquire, kMemOrderRelease };
57
4
    barrier_ = { kMemOrderNoBarrier, kMemOrderBarrier };
58
4
  }
59
60
  vector<MemoryOrder> acquire_release_;
61
  vector<MemoryOrder> barrier_;
62
63
  T max_;
64
  T min_;
65
};
66
67
typedef ::testing::Types<int32_t, int64_t, uint32_t, uint64_t> IntTypes;
68
TYPED_TEST_CASE(AtomicIntTest, IntTypes);
69
70
4
TYPED_TEST(AtomicIntTest, LoadStore) {
71
12
  for (const MemoryOrder mem_order : this->acquire_release_) {
72
12
    AtomicInt<TypeParam> i(0);
73
12
    EXPECT_EQ(0, i.Load(mem_order));
74
12
    i.Store(42, mem_order);
75
12
    EXPECT_EQ(42, i.Load(mem_order));
76
12
    i.Store(this->min_, mem_order);
77
12
    EXPECT_EQ(this->min_, i.Load(mem_order));
78
12
    i.Store(this->max_, mem_order);
79
12
    EXPECT_EQ(this->max_, i.Load(mem_order));
80
12
  }
81
4
}
_ZN2yb28AtomicIntTest_LoadStore_TestIiE8TestBodyEv
Line
Count
Source
70
1
TYPED_TEST(AtomicIntTest, LoadStore) {
71
3
  for (const MemoryOrder mem_order : this->acquire_release_) {
72
3
    AtomicInt<TypeParam> i(0);
73
3
    EXPECT_EQ(0, i.Load(mem_order));
74
3
    i.Store(42, mem_order);
75
3
    EXPECT_EQ(42, i.Load(mem_order));
76
3
    i.Store(this->min_, mem_order);
77
3
    EXPECT_EQ(this->min_, i.Load(mem_order));
78
3
    i.Store(this->max_, mem_order);
79
3
    EXPECT_EQ(this->max_, i.Load(mem_order));
80
3
  }
81
1
}
_ZN2yb28AtomicIntTest_LoadStore_TestIxE8TestBodyEv
Line
Count
Source
70
1
TYPED_TEST(AtomicIntTest, LoadStore) {
71
3
  for (const MemoryOrder mem_order : this->acquire_release_) {
72
3
    AtomicInt<TypeParam> i(0);
73
3
    EXPECT_EQ(0, i.Load(mem_order));
74
3
    i.Store(42, mem_order);
75
3
    EXPECT_EQ(42, i.Load(mem_order));
76
3
    i.Store(this->min_, mem_order);
77
3
    EXPECT_EQ(this->min_, i.Load(mem_order));
78
3
    i.Store(this->max_, mem_order);
79
3
    EXPECT_EQ(this->max_, i.Load(mem_order));
80
3
  }
81
1
}
_ZN2yb28AtomicIntTest_LoadStore_TestIjE8TestBodyEv
Line
Count
Source
70
1
TYPED_TEST(AtomicIntTest, LoadStore) {
71
3
  for (const MemoryOrder mem_order : this->acquire_release_) {
72
3
    AtomicInt<TypeParam> i(0);
73
3
    EXPECT_EQ(0, i.Load(mem_order));
74
3
    i.Store(42, mem_order);
75
3
    EXPECT_EQ(42, i.Load(mem_order));
76
3
    i.Store(this->min_, mem_order);
77
3
    EXPECT_EQ(this->min_, i.Load(mem_order));
78
3
    i.Store(this->max_, mem_order);
79
3
    EXPECT_EQ(this->max_, i.Load(mem_order));
80
3
  }
81
1
}
_ZN2yb28AtomicIntTest_LoadStore_TestIyE8TestBodyEv
Line
Count
Source
70
1
TYPED_TEST(AtomicIntTest, LoadStore) {
71
3
  for (const MemoryOrder mem_order : this->acquire_release_) {
72
3
    AtomicInt<TypeParam> i(0);
73
3
    EXPECT_EQ(0, i.Load(mem_order));
74
3
    i.Store(42, mem_order);
75
3
    EXPECT_EQ(42, i.Load(mem_order));
76
3
    i.Store(this->min_, mem_order);
77
3
    EXPECT_EQ(this->min_, i.Load(mem_order));
78
3
    i.Store(this->max_, mem_order);
79
3
    EXPECT_EQ(this->max_, i.Load(mem_order));
80
3
  }
81
1
}
82
83
4
TYPED_TEST(AtomicIntTest, SetSwapExchange) {
84
12
  for (const MemoryOrder mem_order : this->acquire_release_) {
85
12
    AtomicInt<TypeParam> i(0);
86
12
    EXPECT_TRUE(i.CompareAndSet(0, 5, mem_order));
87
12
    EXPECT_EQ(5, i.Load(mem_order));
88
12
    EXPECT_FALSE(i.CompareAndSet(0, 10, mem_order));
89
90
12
    EXPECT_EQ(5, i.CompareAndSwap(5, this->max_, mem_order));
91
12
    EXPECT_EQ(this->max_, i.CompareAndSwap(42, 42, mem_order));
92
12
    EXPECT_EQ(this->max_, i.CompareAndSwap(this->max_, this->min_, mem_order));
93
94
12
    EXPECT_EQ(this->min_, i.Exchange(this->max_, mem_order));
95
12
    EXPECT_EQ(this->max_, i.Load(mem_order));
96
12
  }
97
4
}
_ZN2yb34AtomicIntTest_SetSwapExchange_TestIiE8TestBodyEv
Line
Count
Source
83
1
TYPED_TEST(AtomicIntTest, SetSwapExchange) {
84
3
  for (const MemoryOrder mem_order : this->acquire_release_) {
85
3
    AtomicInt<TypeParam> i(0);
86
3
    EXPECT_TRUE(i.CompareAndSet(0, 5, mem_order));
87
3
    EXPECT_EQ(5, i.Load(mem_order));
88
3
    EXPECT_FALSE(i.CompareAndSet(0, 10, mem_order));
89
90
3
    EXPECT_EQ(5, i.CompareAndSwap(5, this->max_, mem_order));
91
3
    EXPECT_EQ(this->max_, i.CompareAndSwap(42, 42, mem_order));
92
3
    EXPECT_EQ(this->max_, i.CompareAndSwap(this->max_, this->min_, mem_order));
93
94
3
    EXPECT_EQ(this->min_, i.Exchange(this->max_, mem_order));
95
3
    EXPECT_EQ(this->max_, i.Load(mem_order));
96
3
  }
97
1
}
_ZN2yb34AtomicIntTest_SetSwapExchange_TestIxE8TestBodyEv
Line
Count
Source
83
1
TYPED_TEST(AtomicIntTest, SetSwapExchange) {
84
3
  for (const MemoryOrder mem_order : this->acquire_release_) {
85
3
    AtomicInt<TypeParam> i(0);
86
3
    EXPECT_TRUE(i.CompareAndSet(0, 5, mem_order));
87
3
    EXPECT_EQ(5, i.Load(mem_order));
88
3
    EXPECT_FALSE(i.CompareAndSet(0, 10, mem_order));
89
90
3
    EXPECT_EQ(5, i.CompareAndSwap(5, this->max_, mem_order));
91
3
    EXPECT_EQ(this->max_, i.CompareAndSwap(42, 42, mem_order));
92
3
    EXPECT_EQ(this->max_, i.CompareAndSwap(this->max_, this->min_, mem_order));
93
94
3
    EXPECT_EQ(this->min_, i.Exchange(this->max_, mem_order));
95
3
    EXPECT_EQ(this->max_, i.Load(mem_order));
96
3
  }
97
1
}
_ZN2yb34AtomicIntTest_SetSwapExchange_TestIjE8TestBodyEv
Line
Count
Source
83
1
TYPED_TEST(AtomicIntTest, SetSwapExchange) {
84
3
  for (const MemoryOrder mem_order : this->acquire_release_) {
85
3
    AtomicInt<TypeParam> i(0);
86
3
    EXPECT_TRUE(i.CompareAndSet(0, 5, mem_order));
87
3
    EXPECT_EQ(5, i.Load(mem_order));
88
3
    EXPECT_FALSE(i.CompareAndSet(0, 10, mem_order));
89
90
3
    EXPECT_EQ(5, i.CompareAndSwap(5, this->max_, mem_order));
91
3
    EXPECT_EQ(this->max_, i.CompareAndSwap(42, 42, mem_order));
92
3
    EXPECT_EQ(this->max_, i.CompareAndSwap(this->max_, this->min_, mem_order));
93
94
3
    EXPECT_EQ(this->min_, i.Exchange(this->max_, mem_order));
95
3
    EXPECT_EQ(this->max_, i.Load(mem_order));
96
3
  }
97
1
}
_ZN2yb34AtomicIntTest_SetSwapExchange_TestIyE8TestBodyEv
Line
Count
Source
83
1
TYPED_TEST(AtomicIntTest, SetSwapExchange) {
84
3
  for (const MemoryOrder mem_order : this->acquire_release_) {
85
3
    AtomicInt<TypeParam> i(0);
86
3
    EXPECT_TRUE(i.CompareAndSet(0, 5, mem_order));
87
3
    EXPECT_EQ(5, i.Load(mem_order));
88
3
    EXPECT_FALSE(i.CompareAndSet(0, 10, mem_order));
89
90
3
    EXPECT_EQ(5, i.CompareAndSwap(5, this->max_, mem_order));
91
3
    EXPECT_EQ(this->max_, i.CompareAndSwap(42, 42, mem_order));
92
3
    EXPECT_EQ(this->max_, i.CompareAndSwap(this->max_, this->min_, mem_order));
93
94
3
    EXPECT_EQ(this->min_, i.Exchange(this->max_, mem_order));
95
3
    EXPECT_EQ(this->max_, i.Load(mem_order));
96
3
  }
97
1
}
98
99
4
TYPED_TEST(AtomicIntTest, MinMax) {
100
12
  for (const MemoryOrder mem_order : this->acquire_release_) {
101
12
    AtomicInt<TypeParam> i(0);
102
103
12
    i.StoreMax(100, mem_order);
104
12
    EXPECT_EQ(100, i.Load(mem_order));
105
12
    i.StoreMin(50, mem_order);
106
12
    EXPECT_EQ(50, i.Load(mem_order));
107
108
12
    i.StoreMax(25, mem_order);
109
12
    EXPECT_EQ(50, i.Load(mem_order));
110
12
    i.StoreMin(75, mem_order);
111
12
    EXPECT_EQ(50, i.Load(mem_order));
112
113
12
    i.StoreMax(this->max_, mem_order);
114
12
    EXPECT_EQ(this->max_, i.Load(mem_order));
115
12
    i.StoreMin(this->min_, mem_order);
116
12
    EXPECT_EQ(this->min_, i.Load(mem_order));
117
12
  }
118
4
}
_ZN2yb25AtomicIntTest_MinMax_TestIiE8TestBodyEv
Line
Count
Source
99
1
TYPED_TEST(AtomicIntTest, MinMax) {
100
3
  for (const MemoryOrder mem_order : this->acquire_release_) {
101
3
    AtomicInt<TypeParam> i(0);
102
103
3
    i.StoreMax(100, mem_order);
104
3
    EXPECT_EQ(100, i.Load(mem_order));
105
3
    i.StoreMin(50, mem_order);
106
3
    EXPECT_EQ(50, i.Load(mem_order));
107
108
3
    i.StoreMax(25, mem_order);
109
3
    EXPECT_EQ(50, i.Load(mem_order));
110
3
    i.StoreMin(75, mem_order);
111
3
    EXPECT_EQ(50, i.Load(mem_order));
112
113
3
    i.StoreMax(this->max_, mem_order);
114
3
    EXPECT_EQ(this->max_, i.Load(mem_order));
115
3
    i.StoreMin(this->min_, mem_order);
116
3
    EXPECT_EQ(this->min_, i.Load(mem_order));
117
3
  }
118
1
}
_ZN2yb25AtomicIntTest_MinMax_TestIxE8TestBodyEv
Line
Count
Source
99
1
TYPED_TEST(AtomicIntTest, MinMax) {
100
3
  for (const MemoryOrder mem_order : this->acquire_release_) {
101
3
    AtomicInt<TypeParam> i(0);
102
103
3
    i.StoreMax(100, mem_order);
104
3
    EXPECT_EQ(100, i.Load(mem_order));
105
3
    i.StoreMin(50, mem_order);
106
3
    EXPECT_EQ(50, i.Load(mem_order));
107
108
3
    i.StoreMax(25, mem_order);
109
3
    EXPECT_EQ(50, i.Load(mem_order));
110
3
    i.StoreMin(75, mem_order);
111
3
    EXPECT_EQ(50, i.Load(mem_order));
112
113
3
    i.StoreMax(this->max_, mem_order);
114
3
    EXPECT_EQ(this->max_, i.Load(mem_order));
115
3
    i.StoreMin(this->min_, mem_order);
116
3
    EXPECT_EQ(this->min_, i.Load(mem_order));
117
3
  }
118
1
}
_ZN2yb25AtomicIntTest_MinMax_TestIjE8TestBodyEv
Line
Count
Source
99
1
TYPED_TEST(AtomicIntTest, MinMax) {
100
3
  for (const MemoryOrder mem_order : this->acquire_release_) {
101
3
    AtomicInt<TypeParam> i(0);
102
103
3
    i.StoreMax(100, mem_order);
104
3
    EXPECT_EQ(100, i.Load(mem_order));
105
3
    i.StoreMin(50, mem_order);
106
3
    EXPECT_EQ(50, i.Load(mem_order));
107
108
3
    i.StoreMax(25, mem_order);
109
3
    EXPECT_EQ(50, i.Load(mem_order));
110
3
    i.StoreMin(75, mem_order);
111
3
    EXPECT_EQ(50, i.Load(mem_order));
112
113
3
    i.StoreMax(this->max_, mem_order);
114
3
    EXPECT_EQ(this->max_, i.Load(mem_order));
115
3
    i.StoreMin(this->min_, mem_order);
116
3
    EXPECT_EQ(this->min_, i.Load(mem_order));
117
3
  }
118
1
}
_ZN2yb25AtomicIntTest_MinMax_TestIyE8TestBodyEv
Line
Count
Source
99
1
TYPED_TEST(AtomicIntTest, MinMax) {
100
3
  for (const MemoryOrder mem_order : this->acquire_release_) {
101
3
    AtomicInt<TypeParam> i(0);
102
103
3
    i.StoreMax(100, mem_order);
104
3
    EXPECT_EQ(100, i.Load(mem_order));
105
3
    i.StoreMin(50, mem_order);
106
3
    EXPECT_EQ(50, i.Load(mem_order));
107
108
3
    i.StoreMax(25, mem_order);
109
3
    EXPECT_EQ(50, i.Load(mem_order));
110
3
    i.StoreMin(75, mem_order);
111
3
    EXPECT_EQ(50, i.Load(mem_order));
112
113
3
    i.StoreMax(this->max_, mem_order);
114
3
    EXPECT_EQ(this->max_, i.Load(mem_order));
115
3
    i.StoreMin(this->min_, mem_order);
116
3
    EXPECT_EQ(this->min_, i.Load(mem_order));
117
3
  }
118
1
}
119
120
4
TYPED_TEST(AtomicIntTest, Increment) {
121
8
  for (const MemoryOrder mem_order : this->barrier_) {
122
8
    AtomicInt<TypeParam> i(0);
123
8
    EXPECT_EQ(1, i.Increment(mem_order));
124
8
    EXPECT_EQ(3, i.IncrementBy(2, mem_order));
125
8
    EXPECT_EQ(3, i.IncrementBy(0, mem_order));
126
8
  }
127
4
}
_ZN2yb28AtomicIntTest_Increment_TestIiE8TestBodyEv
Line
Count
Source
120
1
TYPED_TEST(AtomicIntTest, Increment) {
121
2
  for (const MemoryOrder mem_order : this->barrier_) {
122
2
    AtomicInt<TypeParam> i(0);
123
2
    EXPECT_EQ(1, i.Increment(mem_order));
124
2
    EXPECT_EQ(3, i.IncrementBy(2, mem_order));
125
2
    EXPECT_EQ(3, i.IncrementBy(0, mem_order));
126
2
  }
127
1
}
_ZN2yb28AtomicIntTest_Increment_TestIxE8TestBodyEv
Line
Count
Source
120
1
TYPED_TEST(AtomicIntTest, Increment) {
121
2
  for (const MemoryOrder mem_order : this->barrier_) {
122
2
    AtomicInt<TypeParam> i(0);
123
2
    EXPECT_EQ(1, i.Increment(mem_order));
124
2
    EXPECT_EQ(3, i.IncrementBy(2, mem_order));
125
2
    EXPECT_EQ(3, i.IncrementBy(0, mem_order));
126
2
  }
127
1
}
_ZN2yb28AtomicIntTest_Increment_TestIjE8TestBodyEv
Line
Count
Source
120
1
TYPED_TEST(AtomicIntTest, Increment) {
121
2
  for (const MemoryOrder mem_order : this->barrier_) {
122
2
    AtomicInt<TypeParam> i(0);
123
2
    EXPECT_EQ(1, i.Increment(mem_order));
124
2
    EXPECT_EQ(3, i.IncrementBy(2, mem_order));
125
2
    EXPECT_EQ(3, i.IncrementBy(0, mem_order));
126
2
  }
127
1
}
_ZN2yb28AtomicIntTest_Increment_TestIyE8TestBodyEv
Line
Count
Source
120
1
TYPED_TEST(AtomicIntTest, Increment) {
121
2
  for (const MemoryOrder mem_order : this->barrier_) {
122
2
    AtomicInt<TypeParam> i(0);
123
2
    EXPECT_EQ(1, i.Increment(mem_order));
124
2
    EXPECT_EQ(3, i.IncrementBy(2, mem_order));
125
2
    EXPECT_EQ(3, i.IncrementBy(0, mem_order));
126
2
  }
127
1
}
128
129
1
TEST(Atomic, AtomicBool) {
130
1
  vector<MemoryOrder> memory_orders = { kMemOrderNoBarrier, kMemOrderRelease, kMemOrderAcquire };
131
3
  for (const MemoryOrder mem_order : memory_orders) {
132
3
    AtomicBool b(false);
133
3
    EXPECT_FALSE(b.Load(mem_order));
134
3
    b.Store(true, mem_order);
135
3
    EXPECT_TRUE(b.Load(mem_order));
136
3
    EXPECT_TRUE(b.CompareAndSet(true, false, mem_order));
137
3
    EXPECT_FALSE(b.Load(mem_order));
138
3
    EXPECT_FALSE(b.CompareAndSet(true, false, mem_order));
139
3
    EXPECT_FALSE(b.CompareAndSwap(false, true, mem_order));
140
3
    EXPECT_TRUE(b.Load(mem_order));
141
3
    EXPECT_TRUE(b.Exchange(false, mem_order));
142
3
    EXPECT_FALSE(b.Load(mem_order));
143
3
  }
144
1
}
145
146
class TestObj {
147
 public:
148
250k
  TestObj(size_t index, std::atomic<size_t>* counter) : index_(index), counter_(counter) {
149
250k
    ++(*counter_);
150
250k
  }
151
326k
  ~TestObj() { --(*counter_); }
152
2.00k
  size_t index() { return index_; }
153
154
 private:
155
  size_t index_;
156
  std::atomic<size_t>* counter_;
157
};
158
159
1
TEST(Atomic, AtomicUniquePtr) {
160
1
  static constexpr size_t kNumObjects = 1000;
161
1
  static constexpr size_t kNumThreads = 32;
162
1
  static constexpr size_t kNumIterations = 50000;
163
164
1
  std::atomic<size_t> counter = { 0 };
165
166
1
  {
167
1
    std::vector<AtomicUniquePtr<TestObj>> ptrs;
168
1
    ptrs.reserve(kNumObjects);
169
170
1.00k
    for (size_t i = 0; i < kNumObjects; ++i) {
171
1.00k
      ptrs.push_back(MakeAtomicUniquePtr<TestObj>(i, &counter));
172
1.00k
    }
173
1
    EXPECT_EQ(kNumObjects, counter.load());
174
1.00k
    for (size_t i = 0; i < kNumObjects; ++i) {
175
1.00k
      ASSERT_EQ(ptrs[i].get()->index(), i);
176
1.00k
    }
177
178
30
    auto task = [&ptrs, &counter]() {
179
30
      std::mt19937 rng;
180
30
      Seed(&rng);
181
30
      std::uniform_int_distribution<size_t> random_op(0, 4);
182
30
      std::uniform_int_distribution<size_t> random_index(0, kNumObjects - 1);
183
184
1.13M
      for (size_t i = 0; i < kNumIterations; ++i) {
185
1.13M
        switch (random_op(rng)) {
186
253k
          case 0: {
187
            // Get.
188
253k
            auto i1 = random_index(rng);
189
253k
            ptrs[i1].get();
190
253k
            break;
191
0
          }
192
254k
          case 1: {
193
            // Release (only half of ptrs, keep the other half to test release on destruction).
194
254k
            auto i1 = random_index(rng);
195
254k
            if (i1 % 2 == 0) {
196
142k
              TestObj *ptr = ptrs[i1].release();
197
142k
              delete ptr;
198
142k
            }
199
254k
            break;
200
0
          }
201
253k
          case 2: {
202
            // Reset.
203
253k
            auto i1 = random_index(rng);
204
253k
            ptrs[i1].reset(new TestObj(i1, &counter));
205
253k
            break;
206
0
          }
207
253k
          case 3: {
208
            // Assign.
209
253k
            auto i1 = random_index(rng);
210
253k
            auto i2 = random_index(rng);
211
253k
            ptrs[i1] = std::move(ptrs[i2]);
212
253k
            break;
213
0
          }
214
254k
          case 4: {
215
            // Move construction.
216
254k
            auto i1 = random_index(rng);
217
254k
            AtomicUniquePtr<TestObj> ptr(std::move(ptrs[i1]));
218
254k
            break;
219
0
          }
220
0
          default:
221
0
            ASSERT_TRUE(false) << "Test internal error, missed case in switch";
222
0
            break;
223
1.13M
        }
224
1.13M
      }
225
30
    };
226
227
1
    std::vector<std::thread> threads;
228
1
    threads.reserve(kNumThreads);
229
33
    for (size_t i = 0; i < kNumThreads; ++i) {
230
32
      threads.push_back(std::thread(task));
231
32
    }
232
32
    for (auto& thread : threads) {
233
32
      thread.join();
234
32
    }
235
1
  }
236
237
1
  EXPECT_EQ(0, counter.load());
238
1
}
239
240
} // namespace yb