xref: /aosp_15_r20/external/leveldb/db/skiplist_test.cc (revision 9507f98c5f32dee4b5f9e4a38cd499f3ff5c4490)
1*9507f98cSAndroid Build Coastguard Worker // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2*9507f98cSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*9507f98cSAndroid Build Coastguard Worker // found in the LICENSE file. See the AUTHORS file for names of contributors.
4*9507f98cSAndroid Build Coastguard Worker 
5*9507f98cSAndroid Build Coastguard Worker #include "db/skiplist.h"
6*9507f98cSAndroid Build Coastguard Worker 
7*9507f98cSAndroid Build Coastguard Worker #include <atomic>
8*9507f98cSAndroid Build Coastguard Worker #include <set>
9*9507f98cSAndroid Build Coastguard Worker 
10*9507f98cSAndroid Build Coastguard Worker #include "gtest/gtest.h"
11*9507f98cSAndroid Build Coastguard Worker #include "leveldb/env.h"
12*9507f98cSAndroid Build Coastguard Worker #include "port/port.h"
13*9507f98cSAndroid Build Coastguard Worker #include "port/thread_annotations.h"
14*9507f98cSAndroid Build Coastguard Worker #include "util/arena.h"
15*9507f98cSAndroid Build Coastguard Worker #include "util/hash.h"
16*9507f98cSAndroid Build Coastguard Worker #include "util/random.h"
17*9507f98cSAndroid Build Coastguard Worker #include "util/testutil.h"
18*9507f98cSAndroid Build Coastguard Worker 
19*9507f98cSAndroid Build Coastguard Worker namespace leveldb {
20*9507f98cSAndroid Build Coastguard Worker 
21*9507f98cSAndroid Build Coastguard Worker typedef uint64_t Key;
22*9507f98cSAndroid Build Coastguard Worker 
23*9507f98cSAndroid Build Coastguard Worker struct Comparator {
operator ()leveldb::Comparator24*9507f98cSAndroid Build Coastguard Worker   int operator()(const Key& a, const Key& b) const {
25*9507f98cSAndroid Build Coastguard Worker     if (a < b) {
26*9507f98cSAndroid Build Coastguard Worker       return -1;
27*9507f98cSAndroid Build Coastguard Worker     } else if (a > b) {
28*9507f98cSAndroid Build Coastguard Worker       return +1;
29*9507f98cSAndroid Build Coastguard Worker     } else {
30*9507f98cSAndroid Build Coastguard Worker       return 0;
31*9507f98cSAndroid Build Coastguard Worker     }
32*9507f98cSAndroid Build Coastguard Worker   }
33*9507f98cSAndroid Build Coastguard Worker };
34*9507f98cSAndroid Build Coastguard Worker 
TEST(SkipTest,Empty)35*9507f98cSAndroid Build Coastguard Worker TEST(SkipTest, Empty) {
36*9507f98cSAndroid Build Coastguard Worker   Arena arena;
37*9507f98cSAndroid Build Coastguard Worker   Comparator cmp;
38*9507f98cSAndroid Build Coastguard Worker   SkipList<Key, Comparator> list(cmp, &arena);
39*9507f98cSAndroid Build Coastguard Worker   ASSERT_TRUE(!list.Contains(10));
40*9507f98cSAndroid Build Coastguard Worker 
41*9507f98cSAndroid Build Coastguard Worker   SkipList<Key, Comparator>::Iterator iter(&list);
42*9507f98cSAndroid Build Coastguard Worker   ASSERT_TRUE(!iter.Valid());
43*9507f98cSAndroid Build Coastguard Worker   iter.SeekToFirst();
44*9507f98cSAndroid Build Coastguard Worker   ASSERT_TRUE(!iter.Valid());
45*9507f98cSAndroid Build Coastguard Worker   iter.Seek(100);
46*9507f98cSAndroid Build Coastguard Worker   ASSERT_TRUE(!iter.Valid());
47*9507f98cSAndroid Build Coastguard Worker   iter.SeekToLast();
48*9507f98cSAndroid Build Coastguard Worker   ASSERT_TRUE(!iter.Valid());
49*9507f98cSAndroid Build Coastguard Worker }
50*9507f98cSAndroid Build Coastguard Worker 
TEST(SkipTest,InsertAndLookup)51*9507f98cSAndroid Build Coastguard Worker TEST(SkipTest, InsertAndLookup) {
52*9507f98cSAndroid Build Coastguard Worker   const int N = 2000;
53*9507f98cSAndroid Build Coastguard Worker   const int R = 5000;
54*9507f98cSAndroid Build Coastguard Worker   Random rnd(1000);
55*9507f98cSAndroid Build Coastguard Worker   std::set<Key> keys;
56*9507f98cSAndroid Build Coastguard Worker   Arena arena;
57*9507f98cSAndroid Build Coastguard Worker   Comparator cmp;
58*9507f98cSAndroid Build Coastguard Worker   SkipList<Key, Comparator> list(cmp, &arena);
59*9507f98cSAndroid Build Coastguard Worker   for (int i = 0; i < N; i++) {
60*9507f98cSAndroid Build Coastguard Worker     Key key = rnd.Next() % R;
61*9507f98cSAndroid Build Coastguard Worker     if (keys.insert(key).second) {
62*9507f98cSAndroid Build Coastguard Worker       list.Insert(key);
63*9507f98cSAndroid Build Coastguard Worker     }
64*9507f98cSAndroid Build Coastguard Worker   }
65*9507f98cSAndroid Build Coastguard Worker 
66*9507f98cSAndroid Build Coastguard Worker   for (int i = 0; i < R; i++) {
67*9507f98cSAndroid Build Coastguard Worker     if (list.Contains(i)) {
68*9507f98cSAndroid Build Coastguard Worker       ASSERT_EQ(keys.count(i), 1);
69*9507f98cSAndroid Build Coastguard Worker     } else {
70*9507f98cSAndroid Build Coastguard Worker       ASSERT_EQ(keys.count(i), 0);
71*9507f98cSAndroid Build Coastguard Worker     }
72*9507f98cSAndroid Build Coastguard Worker   }
73*9507f98cSAndroid Build Coastguard Worker 
74*9507f98cSAndroid Build Coastguard Worker   // Simple iterator tests
75*9507f98cSAndroid Build Coastguard Worker   {
76*9507f98cSAndroid Build Coastguard Worker     SkipList<Key, Comparator>::Iterator iter(&list);
77*9507f98cSAndroid Build Coastguard Worker     ASSERT_TRUE(!iter.Valid());
78*9507f98cSAndroid Build Coastguard Worker 
79*9507f98cSAndroid Build Coastguard Worker     iter.Seek(0);
80*9507f98cSAndroid Build Coastguard Worker     ASSERT_TRUE(iter.Valid());
81*9507f98cSAndroid Build Coastguard Worker     ASSERT_EQ(*(keys.begin()), iter.key());
82*9507f98cSAndroid Build Coastguard Worker 
83*9507f98cSAndroid Build Coastguard Worker     iter.SeekToFirst();
84*9507f98cSAndroid Build Coastguard Worker     ASSERT_TRUE(iter.Valid());
85*9507f98cSAndroid Build Coastguard Worker     ASSERT_EQ(*(keys.begin()), iter.key());
86*9507f98cSAndroid Build Coastguard Worker 
87*9507f98cSAndroid Build Coastguard Worker     iter.SeekToLast();
88*9507f98cSAndroid Build Coastguard Worker     ASSERT_TRUE(iter.Valid());
89*9507f98cSAndroid Build Coastguard Worker     ASSERT_EQ(*(keys.rbegin()), iter.key());
90*9507f98cSAndroid Build Coastguard Worker   }
91*9507f98cSAndroid Build Coastguard Worker 
92*9507f98cSAndroid Build Coastguard Worker   // Forward iteration test
93*9507f98cSAndroid Build Coastguard Worker   for (int i = 0; i < R; i++) {
94*9507f98cSAndroid Build Coastguard Worker     SkipList<Key, Comparator>::Iterator iter(&list);
95*9507f98cSAndroid Build Coastguard Worker     iter.Seek(i);
96*9507f98cSAndroid Build Coastguard Worker 
97*9507f98cSAndroid Build Coastguard Worker     // Compare against model iterator
98*9507f98cSAndroid Build Coastguard Worker     std::set<Key>::iterator model_iter = keys.lower_bound(i);
99*9507f98cSAndroid Build Coastguard Worker     for (int j = 0; j < 3; j++) {
100*9507f98cSAndroid Build Coastguard Worker       if (model_iter == keys.end()) {
101*9507f98cSAndroid Build Coastguard Worker         ASSERT_TRUE(!iter.Valid());
102*9507f98cSAndroid Build Coastguard Worker         break;
103*9507f98cSAndroid Build Coastguard Worker       } else {
104*9507f98cSAndroid Build Coastguard Worker         ASSERT_TRUE(iter.Valid());
105*9507f98cSAndroid Build Coastguard Worker         ASSERT_EQ(*model_iter, iter.key());
106*9507f98cSAndroid Build Coastguard Worker         ++model_iter;
107*9507f98cSAndroid Build Coastguard Worker         iter.Next();
108*9507f98cSAndroid Build Coastguard Worker       }
109*9507f98cSAndroid Build Coastguard Worker     }
110*9507f98cSAndroid Build Coastguard Worker   }
111*9507f98cSAndroid Build Coastguard Worker 
112*9507f98cSAndroid Build Coastguard Worker   // Backward iteration test
113*9507f98cSAndroid Build Coastguard Worker   {
114*9507f98cSAndroid Build Coastguard Worker     SkipList<Key, Comparator>::Iterator iter(&list);
115*9507f98cSAndroid Build Coastguard Worker     iter.SeekToLast();
116*9507f98cSAndroid Build Coastguard Worker 
117*9507f98cSAndroid Build Coastguard Worker     // Compare against model iterator
118*9507f98cSAndroid Build Coastguard Worker     for (std::set<Key>::reverse_iterator model_iter = keys.rbegin();
119*9507f98cSAndroid Build Coastguard Worker          model_iter != keys.rend(); ++model_iter) {
120*9507f98cSAndroid Build Coastguard Worker       ASSERT_TRUE(iter.Valid());
121*9507f98cSAndroid Build Coastguard Worker       ASSERT_EQ(*model_iter, iter.key());
122*9507f98cSAndroid Build Coastguard Worker       iter.Prev();
123*9507f98cSAndroid Build Coastguard Worker     }
124*9507f98cSAndroid Build Coastguard Worker     ASSERT_TRUE(!iter.Valid());
125*9507f98cSAndroid Build Coastguard Worker   }
126*9507f98cSAndroid Build Coastguard Worker }
127*9507f98cSAndroid Build Coastguard Worker 
128*9507f98cSAndroid Build Coastguard Worker // We want to make sure that with a single writer and multiple
129*9507f98cSAndroid Build Coastguard Worker // concurrent readers (with no synchronization other than when a
130*9507f98cSAndroid Build Coastguard Worker // reader's iterator is created), the reader always observes all the
131*9507f98cSAndroid Build Coastguard Worker // data that was present in the skip list when the iterator was
132*9507f98cSAndroid Build Coastguard Worker // constructed.  Because insertions are happening concurrently, we may
133*9507f98cSAndroid Build Coastguard Worker // also observe new values that were inserted since the iterator was
134*9507f98cSAndroid Build Coastguard Worker // constructed, but we should never miss any values that were present
135*9507f98cSAndroid Build Coastguard Worker // at iterator construction time.
136*9507f98cSAndroid Build Coastguard Worker //
137*9507f98cSAndroid Build Coastguard Worker // We generate multi-part keys:
138*9507f98cSAndroid Build Coastguard Worker //     <key,gen,hash>
139*9507f98cSAndroid Build Coastguard Worker // where:
140*9507f98cSAndroid Build Coastguard Worker //     key is in range [0..K-1]
141*9507f98cSAndroid Build Coastguard Worker //     gen is a generation number for key
142*9507f98cSAndroid Build Coastguard Worker //     hash is hash(key,gen)
143*9507f98cSAndroid Build Coastguard Worker //
144*9507f98cSAndroid Build Coastguard Worker // The insertion code picks a random key, sets gen to be 1 + the last
145*9507f98cSAndroid Build Coastguard Worker // generation number inserted for that key, and sets hash to Hash(key,gen).
146*9507f98cSAndroid Build Coastguard Worker //
147*9507f98cSAndroid Build Coastguard Worker // At the beginning of a read, we snapshot the last inserted
148*9507f98cSAndroid Build Coastguard Worker // generation number for each key.  We then iterate, including random
149*9507f98cSAndroid Build Coastguard Worker // calls to Next() and Seek().  For every key we encounter, we
150*9507f98cSAndroid Build Coastguard Worker // check that it is either expected given the initial snapshot or has
151*9507f98cSAndroid Build Coastguard Worker // been concurrently added since the iterator started.
152*9507f98cSAndroid Build Coastguard Worker class ConcurrentTest {
153*9507f98cSAndroid Build Coastguard Worker  private:
154*9507f98cSAndroid Build Coastguard Worker   static constexpr uint32_t K = 4;
155*9507f98cSAndroid Build Coastguard Worker 
key(Key key)156*9507f98cSAndroid Build Coastguard Worker   static uint64_t key(Key key) { return (key >> 40); }
gen(Key key)157*9507f98cSAndroid Build Coastguard Worker   static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; }
hash(Key key)158*9507f98cSAndroid Build Coastguard Worker   static uint64_t hash(Key key) { return key & 0xff; }
159*9507f98cSAndroid Build Coastguard Worker 
HashNumbers(uint64_t k,uint64_t g)160*9507f98cSAndroid Build Coastguard Worker   static uint64_t HashNumbers(uint64_t k, uint64_t g) {
161*9507f98cSAndroid Build Coastguard Worker     uint64_t data[2] = {k, g};
162*9507f98cSAndroid Build Coastguard Worker     return Hash(reinterpret_cast<char*>(data), sizeof(data), 0);
163*9507f98cSAndroid Build Coastguard Worker   }
164*9507f98cSAndroid Build Coastguard Worker 
MakeKey(uint64_t k,uint64_t g)165*9507f98cSAndroid Build Coastguard Worker   static Key MakeKey(uint64_t k, uint64_t g) {
166*9507f98cSAndroid Build Coastguard Worker     static_assert(sizeof(Key) == sizeof(uint64_t), "");
167*9507f98cSAndroid Build Coastguard Worker     assert(k <= K);  // We sometimes pass K to seek to the end of the skiplist
168*9507f98cSAndroid Build Coastguard Worker     assert(g <= 0xffffffffu);
169*9507f98cSAndroid Build Coastguard Worker     return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff));
170*9507f98cSAndroid Build Coastguard Worker   }
171*9507f98cSAndroid Build Coastguard Worker 
IsValidKey(Key k)172*9507f98cSAndroid Build Coastguard Worker   static bool IsValidKey(Key k) {
173*9507f98cSAndroid Build Coastguard Worker     return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff);
174*9507f98cSAndroid Build Coastguard Worker   }
175*9507f98cSAndroid Build Coastguard Worker 
RandomTarget(Random * rnd)176*9507f98cSAndroid Build Coastguard Worker   static Key RandomTarget(Random* rnd) {
177*9507f98cSAndroid Build Coastguard Worker     switch (rnd->Next() % 10) {
178*9507f98cSAndroid Build Coastguard Worker       case 0:
179*9507f98cSAndroid Build Coastguard Worker         // Seek to beginning
180*9507f98cSAndroid Build Coastguard Worker         return MakeKey(0, 0);
181*9507f98cSAndroid Build Coastguard Worker       case 1:
182*9507f98cSAndroid Build Coastguard Worker         // Seek to end
183*9507f98cSAndroid Build Coastguard Worker         return MakeKey(K, 0);
184*9507f98cSAndroid Build Coastguard Worker       default:
185*9507f98cSAndroid Build Coastguard Worker         // Seek to middle
186*9507f98cSAndroid Build Coastguard Worker         return MakeKey(rnd->Next() % K, 0);
187*9507f98cSAndroid Build Coastguard Worker     }
188*9507f98cSAndroid Build Coastguard Worker   }
189*9507f98cSAndroid Build Coastguard Worker 
190*9507f98cSAndroid Build Coastguard Worker   // Per-key generation
191*9507f98cSAndroid Build Coastguard Worker   struct State {
192*9507f98cSAndroid Build Coastguard Worker     std::atomic<int> generation[K];
Setleveldb::ConcurrentTest::State193*9507f98cSAndroid Build Coastguard Worker     void Set(int k, int v) {
194*9507f98cSAndroid Build Coastguard Worker       generation[k].store(v, std::memory_order_release);
195*9507f98cSAndroid Build Coastguard Worker     }
Getleveldb::ConcurrentTest::State196*9507f98cSAndroid Build Coastguard Worker     int Get(int k) { return generation[k].load(std::memory_order_acquire); }
197*9507f98cSAndroid Build Coastguard Worker 
Stateleveldb::ConcurrentTest::State198*9507f98cSAndroid Build Coastguard Worker     State() {
199*9507f98cSAndroid Build Coastguard Worker       for (int k = 0; k < K; k++) {
200*9507f98cSAndroid Build Coastguard Worker         Set(k, 0);
201*9507f98cSAndroid Build Coastguard Worker       }
202*9507f98cSAndroid Build Coastguard Worker     }
203*9507f98cSAndroid Build Coastguard Worker   };
204*9507f98cSAndroid Build Coastguard Worker 
205*9507f98cSAndroid Build Coastguard Worker   // Current state of the test
206*9507f98cSAndroid Build Coastguard Worker   State current_;
207*9507f98cSAndroid Build Coastguard Worker 
208*9507f98cSAndroid Build Coastguard Worker   Arena arena_;
209*9507f98cSAndroid Build Coastguard Worker 
210*9507f98cSAndroid Build Coastguard Worker   // SkipList is not protected by mu_.  We just use a single writer
211*9507f98cSAndroid Build Coastguard Worker   // thread to modify it.
212*9507f98cSAndroid Build Coastguard Worker   SkipList<Key, Comparator> list_;
213*9507f98cSAndroid Build Coastguard Worker 
214*9507f98cSAndroid Build Coastguard Worker  public:
ConcurrentTest()215*9507f98cSAndroid Build Coastguard Worker   ConcurrentTest() : list_(Comparator(), &arena_) {}
216*9507f98cSAndroid Build Coastguard Worker 
217*9507f98cSAndroid Build Coastguard Worker   // REQUIRES: External synchronization
WriteStep(Random * rnd)218*9507f98cSAndroid Build Coastguard Worker   void WriteStep(Random* rnd) {
219*9507f98cSAndroid Build Coastguard Worker     const uint32_t k = rnd->Next() % K;
220*9507f98cSAndroid Build Coastguard Worker     const intptr_t g = current_.Get(k) + 1;
221*9507f98cSAndroid Build Coastguard Worker     const Key key = MakeKey(k, g);
222*9507f98cSAndroid Build Coastguard Worker     list_.Insert(key);
223*9507f98cSAndroid Build Coastguard Worker     current_.Set(k, g);
224*9507f98cSAndroid Build Coastguard Worker   }
225*9507f98cSAndroid Build Coastguard Worker 
ReadStep(Random * rnd)226*9507f98cSAndroid Build Coastguard Worker   void ReadStep(Random* rnd) {
227*9507f98cSAndroid Build Coastguard Worker     // Remember the initial committed state of the skiplist.
228*9507f98cSAndroid Build Coastguard Worker     State initial_state;
229*9507f98cSAndroid Build Coastguard Worker     for (int k = 0; k < K; k++) {
230*9507f98cSAndroid Build Coastguard Worker       initial_state.Set(k, current_.Get(k));
231*9507f98cSAndroid Build Coastguard Worker     }
232*9507f98cSAndroid Build Coastguard Worker 
233*9507f98cSAndroid Build Coastguard Worker     Key pos = RandomTarget(rnd);
234*9507f98cSAndroid Build Coastguard Worker     SkipList<Key, Comparator>::Iterator iter(&list_);
235*9507f98cSAndroid Build Coastguard Worker     iter.Seek(pos);
236*9507f98cSAndroid Build Coastguard Worker     while (true) {
237*9507f98cSAndroid Build Coastguard Worker       Key current;
238*9507f98cSAndroid Build Coastguard Worker       if (!iter.Valid()) {
239*9507f98cSAndroid Build Coastguard Worker         current = MakeKey(K, 0);
240*9507f98cSAndroid Build Coastguard Worker       } else {
241*9507f98cSAndroid Build Coastguard Worker         current = iter.key();
242*9507f98cSAndroid Build Coastguard Worker         ASSERT_TRUE(IsValidKey(current)) << current;
243*9507f98cSAndroid Build Coastguard Worker       }
244*9507f98cSAndroid Build Coastguard Worker       ASSERT_LE(pos, current) << "should not go backwards";
245*9507f98cSAndroid Build Coastguard Worker 
246*9507f98cSAndroid Build Coastguard Worker       // Verify that everything in [pos,current) was not present in
247*9507f98cSAndroid Build Coastguard Worker       // initial_state.
248*9507f98cSAndroid Build Coastguard Worker       while (pos < current) {
249*9507f98cSAndroid Build Coastguard Worker         ASSERT_LT(key(pos), K) << pos;
250*9507f98cSAndroid Build Coastguard Worker 
251*9507f98cSAndroid Build Coastguard Worker         // Note that generation 0 is never inserted, so it is ok if
252*9507f98cSAndroid Build Coastguard Worker         // <*,0,*> is missing.
253*9507f98cSAndroid Build Coastguard Worker         ASSERT_TRUE((gen(pos) == 0) ||
254*9507f98cSAndroid Build Coastguard Worker                     (gen(pos) > static_cast<Key>(initial_state.Get(key(pos)))))
255*9507f98cSAndroid Build Coastguard Worker             << "key: " << key(pos) << "; gen: " << gen(pos)
256*9507f98cSAndroid Build Coastguard Worker             << "; initgen: " << initial_state.Get(key(pos));
257*9507f98cSAndroid Build Coastguard Worker 
258*9507f98cSAndroid Build Coastguard Worker         // Advance to next key in the valid key space
259*9507f98cSAndroid Build Coastguard Worker         if (key(pos) < key(current)) {
260*9507f98cSAndroid Build Coastguard Worker           pos = MakeKey(key(pos) + 1, 0);
261*9507f98cSAndroid Build Coastguard Worker         } else {
262*9507f98cSAndroid Build Coastguard Worker           pos = MakeKey(key(pos), gen(pos) + 1);
263*9507f98cSAndroid Build Coastguard Worker         }
264*9507f98cSAndroid Build Coastguard Worker       }
265*9507f98cSAndroid Build Coastguard Worker 
266*9507f98cSAndroid Build Coastguard Worker       if (!iter.Valid()) {
267*9507f98cSAndroid Build Coastguard Worker         break;
268*9507f98cSAndroid Build Coastguard Worker       }
269*9507f98cSAndroid Build Coastguard Worker 
270*9507f98cSAndroid Build Coastguard Worker       if (rnd->Next() % 2) {
271*9507f98cSAndroid Build Coastguard Worker         iter.Next();
272*9507f98cSAndroid Build Coastguard Worker         pos = MakeKey(key(pos), gen(pos) + 1);
273*9507f98cSAndroid Build Coastguard Worker       } else {
274*9507f98cSAndroid Build Coastguard Worker         Key new_target = RandomTarget(rnd);
275*9507f98cSAndroid Build Coastguard Worker         if (new_target > pos) {
276*9507f98cSAndroid Build Coastguard Worker           pos = new_target;
277*9507f98cSAndroid Build Coastguard Worker           iter.Seek(new_target);
278*9507f98cSAndroid Build Coastguard Worker         }
279*9507f98cSAndroid Build Coastguard Worker       }
280*9507f98cSAndroid Build Coastguard Worker     }
281*9507f98cSAndroid Build Coastguard Worker   }
282*9507f98cSAndroid Build Coastguard Worker };
283*9507f98cSAndroid Build Coastguard Worker 
284*9507f98cSAndroid Build Coastguard Worker // Needed when building in C++11 mode.
285*9507f98cSAndroid Build Coastguard Worker constexpr uint32_t ConcurrentTest::K;
286*9507f98cSAndroid Build Coastguard Worker 
287*9507f98cSAndroid Build Coastguard Worker // Simple test that does single-threaded testing of the ConcurrentTest
288*9507f98cSAndroid Build Coastguard Worker // scaffolding.
TEST(SkipTest,ConcurrentWithoutThreads)289*9507f98cSAndroid Build Coastguard Worker TEST(SkipTest, ConcurrentWithoutThreads) {
290*9507f98cSAndroid Build Coastguard Worker   ConcurrentTest test;
291*9507f98cSAndroid Build Coastguard Worker   Random rnd(test::RandomSeed());
292*9507f98cSAndroid Build Coastguard Worker   for (int i = 0; i < 10000; i++) {
293*9507f98cSAndroid Build Coastguard Worker     test.ReadStep(&rnd);
294*9507f98cSAndroid Build Coastguard Worker     test.WriteStep(&rnd);
295*9507f98cSAndroid Build Coastguard Worker   }
296*9507f98cSAndroid Build Coastguard Worker }
297*9507f98cSAndroid Build Coastguard Worker 
298*9507f98cSAndroid Build Coastguard Worker class TestState {
299*9507f98cSAndroid Build Coastguard Worker  public:
300*9507f98cSAndroid Build Coastguard Worker   ConcurrentTest t_;
301*9507f98cSAndroid Build Coastguard Worker   int seed_;
302*9507f98cSAndroid Build Coastguard Worker   std::atomic<bool> quit_flag_;
303*9507f98cSAndroid Build Coastguard Worker 
304*9507f98cSAndroid Build Coastguard Worker   enum ReaderState { STARTING, RUNNING, DONE };
305*9507f98cSAndroid Build Coastguard Worker 
TestState(int s)306*9507f98cSAndroid Build Coastguard Worker   explicit TestState(int s)
307*9507f98cSAndroid Build Coastguard Worker       : seed_(s), quit_flag_(false), state_(STARTING), state_cv_(&mu_) {}
308*9507f98cSAndroid Build Coastguard Worker 
Wait(ReaderState s)309*9507f98cSAndroid Build Coastguard Worker   void Wait(ReaderState s) LOCKS_EXCLUDED(mu_) {
310*9507f98cSAndroid Build Coastguard Worker     mu_.Lock();
311*9507f98cSAndroid Build Coastguard Worker     while (state_ != s) {
312*9507f98cSAndroid Build Coastguard Worker       state_cv_.Wait();
313*9507f98cSAndroid Build Coastguard Worker     }
314*9507f98cSAndroid Build Coastguard Worker     mu_.Unlock();
315*9507f98cSAndroid Build Coastguard Worker   }
316*9507f98cSAndroid Build Coastguard Worker 
Change(ReaderState s)317*9507f98cSAndroid Build Coastguard Worker   void Change(ReaderState s) LOCKS_EXCLUDED(mu_) {
318*9507f98cSAndroid Build Coastguard Worker     mu_.Lock();
319*9507f98cSAndroid Build Coastguard Worker     state_ = s;
320*9507f98cSAndroid Build Coastguard Worker     state_cv_.Signal();
321*9507f98cSAndroid Build Coastguard Worker     mu_.Unlock();
322*9507f98cSAndroid Build Coastguard Worker   }
323*9507f98cSAndroid Build Coastguard Worker 
324*9507f98cSAndroid Build Coastguard Worker  private:
325*9507f98cSAndroid Build Coastguard Worker   port::Mutex mu_;
326*9507f98cSAndroid Build Coastguard Worker   ReaderState state_ GUARDED_BY(mu_);
327*9507f98cSAndroid Build Coastguard Worker   port::CondVar state_cv_ GUARDED_BY(mu_);
328*9507f98cSAndroid Build Coastguard Worker };
329*9507f98cSAndroid Build Coastguard Worker 
ConcurrentReader(void * arg)330*9507f98cSAndroid Build Coastguard Worker static void ConcurrentReader(void* arg) {
331*9507f98cSAndroid Build Coastguard Worker   TestState* state = reinterpret_cast<TestState*>(arg);
332*9507f98cSAndroid Build Coastguard Worker   Random rnd(state->seed_);
333*9507f98cSAndroid Build Coastguard Worker   int64_t reads = 0;
334*9507f98cSAndroid Build Coastguard Worker   state->Change(TestState::RUNNING);
335*9507f98cSAndroid Build Coastguard Worker   while (!state->quit_flag_.load(std::memory_order_acquire)) {
336*9507f98cSAndroid Build Coastguard Worker     state->t_.ReadStep(&rnd);
337*9507f98cSAndroid Build Coastguard Worker     ++reads;
338*9507f98cSAndroid Build Coastguard Worker   }
339*9507f98cSAndroid Build Coastguard Worker   state->Change(TestState::DONE);
340*9507f98cSAndroid Build Coastguard Worker }
341*9507f98cSAndroid Build Coastguard Worker 
RunConcurrent(int run)342*9507f98cSAndroid Build Coastguard Worker static void RunConcurrent(int run) {
343*9507f98cSAndroid Build Coastguard Worker   const int seed = test::RandomSeed() + (run * 100);
344*9507f98cSAndroid Build Coastguard Worker   Random rnd(seed);
345*9507f98cSAndroid Build Coastguard Worker   const int N = 1000;
346*9507f98cSAndroid Build Coastguard Worker   const int kSize = 1000;
347*9507f98cSAndroid Build Coastguard Worker   for (int i = 0; i < N; i++) {
348*9507f98cSAndroid Build Coastguard Worker     if ((i % 100) == 0) {
349*9507f98cSAndroid Build Coastguard Worker       std::fprintf(stderr, "Run %d of %d\n", i, N);
350*9507f98cSAndroid Build Coastguard Worker     }
351*9507f98cSAndroid Build Coastguard Worker     TestState state(seed + 1);
352*9507f98cSAndroid Build Coastguard Worker     Env::Default()->Schedule(ConcurrentReader, &state);
353*9507f98cSAndroid Build Coastguard Worker     state.Wait(TestState::RUNNING);
354*9507f98cSAndroid Build Coastguard Worker     for (int i = 0; i < kSize; i++) {
355*9507f98cSAndroid Build Coastguard Worker       state.t_.WriteStep(&rnd);
356*9507f98cSAndroid Build Coastguard Worker     }
357*9507f98cSAndroid Build Coastguard Worker     state.quit_flag_.store(true, std::memory_order_release);
358*9507f98cSAndroid Build Coastguard Worker     state.Wait(TestState::DONE);
359*9507f98cSAndroid Build Coastguard Worker   }
360*9507f98cSAndroid Build Coastguard Worker }
361*9507f98cSAndroid Build Coastguard Worker 
TEST(SkipTest,Concurrent1)362*9507f98cSAndroid Build Coastguard Worker TEST(SkipTest, Concurrent1) { RunConcurrent(1); }
TEST(SkipTest,Concurrent2)363*9507f98cSAndroid Build Coastguard Worker TEST(SkipTest, Concurrent2) { RunConcurrent(2); }
TEST(SkipTest,Concurrent3)364*9507f98cSAndroid Build Coastguard Worker TEST(SkipTest, Concurrent3) { RunConcurrent(3); }
TEST(SkipTest,Concurrent4)365*9507f98cSAndroid Build Coastguard Worker TEST(SkipTest, Concurrent4) { RunConcurrent(4); }
TEST(SkipTest,Concurrent5)366*9507f98cSAndroid Build Coastguard Worker TEST(SkipTest, Concurrent5) { RunConcurrent(5); }
367*9507f98cSAndroid Build Coastguard Worker 
368*9507f98cSAndroid Build Coastguard Worker }  // namespace leveldb
369*9507f98cSAndroid Build Coastguard Worker 
370