1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2/* 3 * Copyright 2013 Couchbase, Inc 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * 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, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18#include "config.h" 19 20#include <signal.h> 21 22#include <algorithm> 23#include <vector> 24 25#include "configuration.h" 26#include "stats.h" 27#include "threadtests.h" 28#include "vbucket.h" 29#include "vbucketmap.h" 30 31static const size_t numThreads = 10; 32static const size_t vbucketsEach = 100; 33 34EPStats global_stats; 35CheckpointConfig checkpoint_config; 36 37extern "C" { 38 static rel_time_t basic_current_time(void) { 39 return 0; 40 } 41 42 rel_time_t (*ep_current_time)() = basic_current_time; 43 44 time_t ep_real_time() { 45 return time(NULL); 46 } 47} 48 49class VBucketGenerator { 50public: 51 VBucketGenerator(EPStats &s, CheckpointConfig &c, int start = 1) 52 : st(s), config(c), i(start) {} 53 VBucket *operator()() { 54 return new VBucket(i++, vbucket_state_active, st, config, NULL); 55 } 56private: 57 EPStats &st; 58 CheckpointConfig &config; 59 int i; 60}; 61 62static void assertVBucket(const VBucketMap& vbm, int id) { 63 RCPtr<VBucket> v = vbm.getBucket(id); 64 cb_assert(v); 65 cb_assert(v->getId() == id); 66} 67 68static void testVBucketLookup() { 69 VBucketGenerator vbgen(global_stats, checkpoint_config); 70 std::vector<VBucket*> bucketList(3); 71 std::generate_n(bucketList.begin(), bucketList.capacity(), vbgen); 72 73 Configuration config; 74 VBucketMap vbm(config); 75 vbm.addBuckets(bucketList); 76 77 cb_assert(!vbm.getBucket(4)); 78 assertVBucket(vbm, 1); 79 assertVBucket(vbm, 2); 80 assertVBucket(vbm, 3); 81} 82 83class AtomicUpdater : public Generator<bool> { 84public: 85 AtomicUpdater(VBucketMap *m) : vbm(m), i(0) {} 86 bool operator()() { 87 for (size_t j = 0; j < vbucketsEach; j++) { 88 int newId = ++i; 89 90 RCPtr<VBucket> v(new VBucket(newId, vbucket_state_active, 91 global_stats, checkpoint_config, NULL)); 92 vbm->addBucket(v); 93 cb_assert(vbm->getBucket(newId) == v); 94 95 if (newId % 2 == 0) { 96 vbm->removeBucket(newId); 97 } 98 } 99 100 return true; 101 } 102private: 103 VBucketMap *vbm; 104 Atomic<int> i; 105}; 106 107static void testConcurrentUpdate(void) { 108 Configuration config; 109 config.setMaxNumShards((size_t)1); 110 VBucketMap vbm(config); 111 AtomicUpdater au(&vbm); 112 getCompletedThreads<bool>(numThreads, &au); 113 114 // We remove half of the buckets in the test 115 std::vector<int> rv; 116 vbm.getBuckets(rv); 117 cb_assert(rv.size() == ((numThreads * vbucketsEach) / 2)); 118} 119 120static void testVBucketFilter() { 121 VBucketFilter empty; 122 123 cb_assert(empty(0)); 124 cb_assert(empty(1)); 125 cb_assert(empty(2)); 126 127 std::vector<uint16_t> v; 128 129 VBucketFilter emptyTwo(v); 130 cb_assert(emptyTwo(0)); 131 cb_assert(emptyTwo(1)); 132 cb_assert(emptyTwo(2)); 133 134 v.push_back(2); 135 136 VBucketFilter hasOne(v); 137 cb_assert(!hasOne(0)); 138 cb_assert(!hasOne(1)); 139 cb_assert(hasOne(2)); 140 141 v.push_back(0); 142 143 VBucketFilter hasTwo(v); 144 cb_assert(hasTwo(0)); 145 cb_assert(!hasTwo(1)); 146 cb_assert(hasTwo(2)); 147 148 v.push_back(1); 149 150 VBucketFilter hasThree(v); 151 cb_assert(hasThree(0)); 152 cb_assert(hasThree(1)); 153 cb_assert(hasThree(2)); 154 cb_assert(!hasThree(3)); 155} 156 157static void assertFilterTxt(const VBucketFilter &filter, const std::string &res) 158{ 159 std::stringstream ss; 160 ss << filter; 161 if (ss.str() != res) { 162 std::cerr << "Filter mismatch: " 163 << ss.str() << " != " << res << std::endl; 164 std::cerr.flush(); 165 abort(); 166 } 167} 168 169static void testVBucketFilterFormatter(void) { 170 std::set<uint16_t> v; 171 172 VBucketFilter filter(v); 173 assertFilterTxt(filter, "{ empty }"); 174 v.insert(1); 175 filter.assign(v); 176 assertFilterTxt(filter, "{ 1 }"); 177 178 for (uint16_t ii = 2; ii < 100; ++ii) { 179 v.insert(ii); 180 } 181 filter.assign(v); 182 assertFilterTxt(filter, "{ [1,99] }"); 183 184 v.insert(101); 185 v.insert(102); 186 filter.assign(v); 187 assertFilterTxt(filter, "{ [1,99], 101, 102 }"); 188 189 v.insert(103); 190 filter.assign(v); 191 assertFilterTxt(filter, "{ [1,99], [101,103] }"); 192 193 v.insert(100); 194 filter.assign(v); 195 assertFilterTxt(filter, "{ [1,103] }"); 196} 197 198static void testGetVBucketsByState(void) { 199 Configuration config; 200 VBucketMap vbm(config); 201 202 int st = vbucket_state_dead; 203 for (int id = 0; id < 4; id++, st--) { 204 RCPtr<VBucket> v(new VBucket(id, (vbucket_state_t)st, global_stats, 205 checkpoint_config, NULL)); 206 vbm.addBucket(v); 207 cb_assert(vbm.getBucket(id) == v); 208 } 209} 210 211int main(int argc, char **argv) { 212 (void)argc; (void)argv; 213 putenv(strdup("ALLOW_NO_STATS_UPDATE=yeah")); 214 215 HashTable::setDefaultNumBuckets(5); 216 HashTable::setDefaultNumLocks(1); 217 218 alarm(60); 219 220 testVBucketLookup(); 221 testConcurrentUpdate(); 222 testVBucketFilter(); 223 testVBucketFilterFormatter(); 224 testGetVBucketsByState(); 225} 226