| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library test.index.page_node_manager; | |
| 6 | |
| 7 import 'dart:math'; | |
| 8 import 'dart:typed_data'; | |
| 9 | |
| 10 import 'package:analysis_server/src/index/b_plus_tree.dart'; | |
| 11 import 'package:analysis_server/src/index/page_node_manager.dart'; | |
| 12 import 'package:typed_mock/typed_mock.dart'; | |
| 13 import 'package:unittest/unittest.dart'; | |
| 14 | |
| 15 import '../reflective_tests.dart'; | |
| 16 | |
| 17 | |
| 18 main() { | |
| 19 groupSep = ' | '; | |
| 20 group('_CachingNodeManagerTest', () { | |
| 21 runReflectiveTests(_CachingNodeManagerTest); | |
| 22 }); | |
| 23 group('FixedStringCodecTest', () { | |
| 24 runReflectiveTests(_FixedStringCodecTest); | |
| 25 }); | |
| 26 group('MemoryPageManager', () { | |
| 27 runReflectiveTests(_MemoryPageManagerTest); | |
| 28 }); | |
| 29 group('PageNodeManager', () { | |
| 30 runReflectiveTests(_PageNodeManagerTest); | |
| 31 }); | |
| 32 group('Uint32CodecTest', () { | |
| 33 runReflectiveTests(_Uint32CodecTest); | |
| 34 }); | |
| 35 test('B+ tree with PageNodeManager', _treeWithPageNodeManager); | |
| 36 } | |
| 37 | |
| 38 | |
| 39 int _intComparator(int a, int b) => a - b; | |
| 40 | |
| 41 | |
| 42 /** | |
| 43 * A stress test for [BPlusTree] using [PageNodeManager]. | |
| 44 */ | |
| 45 _treeWithPageNodeManager() { | |
| 46 int pageSize = 256; | |
| 47 MemoryPageManager pageManager = new MemoryPageManager(pageSize); | |
| 48 NodeManager<int, String, int> nodeManager = new PageNodeManager<int, String>( | |
| 49 pageManager, Uint32Codec.INSTANCE, new FixedStringCodec(7)); | |
| 50 // NodeManager<int, String, int> nodeManager = new MemoryNodeManager(); | |
| 51 BPlusTree<int, String, int> tree = new BPlusTree(_intComparator, nodeManager); | |
| 52 int maxKey = 1000000; | |
| 53 int tryCount = 1000; | |
| 54 Set<int> keys = new Set<int>(); | |
| 55 { | |
| 56 Random random = new Random(37); | |
| 57 for (int i = 0; i < tryCount; i++) { | |
| 58 int key = random.nextInt(maxKey); | |
| 59 keys.add(key); | |
| 60 tree.insert(key, 'V$key'); | |
| 61 } | |
| 62 } | |
| 63 // find every | |
| 64 for (int key in keys) { | |
| 65 expect(tree.find(key), 'V$key'); | |
| 66 } | |
| 67 // remove random keys | |
| 68 { | |
| 69 Random random = new Random(37); | |
| 70 for (int key in new Set<int>.from(keys)) { | |
| 71 if (random.nextBool()) { | |
| 72 keys.remove(key); | |
| 73 expect(tree.remove(key), 'V$key'); | |
| 74 } | |
| 75 } | |
| 76 } | |
| 77 // find every remaining key | |
| 78 for (int key in keys) { | |
| 79 expect(tree.find(key), 'V$key'); | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 | |
| 84 @ReflectiveTestCase() | |
| 85 class _CachingNodeManagerTest { | |
| 86 _NodeManagerMock<int, String, int> delegate = new _NodeManagerMock<int, | |
| 87 String, int>(); | |
| 88 NodeManager<int, String, int> manager; | |
| 89 | |
| 90 void setUp() { | |
| 91 when(delegate.writeIndex).thenReturn((key, value) { | |
| 92 delegate.writeIndex(key, value); | |
| 93 }); | |
| 94 when(delegate.writeLeaf).thenReturn((key, value) { | |
| 95 delegate.writeLeaf(key, value); | |
| 96 }); | |
| 97 manager = new CachingNodeManager<int, String, int>(delegate, 4, 4); | |
| 98 resetInteractions(delegate); | |
| 99 } | |
| 100 | |
| 101 void test_createIndex() { | |
| 102 when(delegate.createIndex()).thenReturn(77); | |
| 103 expect(manager.createIndex(), 77); | |
| 104 } | |
| 105 | |
| 106 void test_createLeaf() { | |
| 107 when(delegate.createLeaf()).thenReturn(99); | |
| 108 expect(manager.createLeaf(), 99); | |
| 109 } | |
| 110 | |
| 111 void test_delete() { | |
| 112 manager.delete(42); | |
| 113 verify(delegate.delete(42)).once(); | |
| 114 } | |
| 115 | |
| 116 void test_isIndex() { | |
| 117 when(delegate.isIndex(1)).thenReturn(true); | |
| 118 when(delegate.isIndex(2)).thenReturn(false); | |
| 119 expect(manager.isIndex(1), isTrue); | |
| 120 expect(manager.isIndex(2), isFalse); | |
| 121 } | |
| 122 | |
| 123 void test_maxIndexKeys() { | |
| 124 when(delegate.maxIndexKeys).thenReturn(42); | |
| 125 expect(manager.maxIndexKeys, 42); | |
| 126 } | |
| 127 | |
| 128 void test_maxLeafKeys() { | |
| 129 when(delegate.maxLeafKeys).thenReturn(42); | |
| 130 expect(manager.maxLeafKeys, 42); | |
| 131 } | |
| 132 | |
| 133 void test_readIndex_cache_whenRead() { | |
| 134 var data = new IndexNodeData<int, int>([1, 2], [10, 20, 30]); | |
| 135 when(delegate.readIndex(2)).thenReturn(data); | |
| 136 expect(manager.readIndex(2), data); | |
| 137 verify(delegate.readIndex(2)).once(); | |
| 138 resetInteractions(delegate); | |
| 139 // we just read "2", so it should be cached | |
| 140 manager.readIndex(2); | |
| 141 verify(delegate.readIndex(2)).never(); | |
| 142 } | |
| 143 | |
| 144 void test_readIndex_cache_whenWrite() { | |
| 145 var data = new IndexNodeData<int, int>([1, 2], [10, 20, 30]); | |
| 146 manager.writeIndex(2, data); | |
| 147 expect(manager.readIndex(2), data); | |
| 148 verify(delegate.readLeaf(2)).never(); | |
| 149 // delete, forces request to the delegate | |
| 150 manager.delete(2); | |
| 151 manager.readIndex(2); | |
| 152 verify(delegate.readIndex(2)).once(); | |
| 153 } | |
| 154 | |
| 155 void test_readIndex_delegate() { | |
| 156 var data = new IndexNodeData<int, int>([1, 2], [10, 20, 30]); | |
| 157 when(delegate.readIndex(2)).thenReturn(data); | |
| 158 expect(manager.readIndex(2), data); | |
| 159 } | |
| 160 | |
| 161 void test_readLeaf_cache_whenRead() { | |
| 162 var data = new LeafNodeData<int, String>([1, 2, 3], ['A', 'B', 'C']); | |
| 163 when(delegate.readLeaf(2)).thenReturn(data); | |
| 164 expect(manager.readLeaf(2), data); | |
| 165 verify(delegate.readLeaf(2)).once(); | |
| 166 resetInteractions(delegate); | |
| 167 // we just read "2", so it should be cached | |
| 168 manager.readLeaf(2); | |
| 169 verify(delegate.readLeaf(2)).never(); | |
| 170 } | |
| 171 | |
| 172 void test_readLeaf_cache_whenWrite() { | |
| 173 var data = new LeafNodeData<int, String>([1, 2, 3], ['A', 'B', 'C']); | |
| 174 manager.writeLeaf(2, data); | |
| 175 expect(manager.readLeaf(2), data); | |
| 176 verify(delegate.readLeaf(2)).never(); | |
| 177 // delete, forces request to the delegate | |
| 178 manager.delete(2); | |
| 179 manager.readLeaf(2); | |
| 180 verify(delegate.readLeaf(2)).once(); | |
| 181 } | |
| 182 | |
| 183 void test_readLeaf_delegate() { | |
| 184 var data = new LeafNodeData<int, String>([1, 2, 3], ['A', 'B', 'C']); | |
| 185 when(delegate.readLeaf(2)).thenReturn(data); | |
| 186 expect(manager.readLeaf(2), data); | |
| 187 } | |
| 188 | |
| 189 void test_writeIndex() { | |
| 190 var data = new IndexNodeData<int, int>([1], [10, 20]); | |
| 191 manager.writeIndex(1, data); | |
| 192 manager.writeIndex(2, data); | |
| 193 manager.writeIndex(3, data); | |
| 194 manager.writeIndex(4, data); | |
| 195 manager.writeIndex(1, data); | |
| 196 verifyZeroInteractions(delegate); | |
| 197 // only 4 nodes can be cached, 5-th one cause write to the delegate | |
| 198 manager.writeIndex(5, data); | |
| 199 verify(delegate.writeIndex(2, data)).once(); | |
| 200 } | |
| 201 | |
| 202 void test_writeLeaf() { | |
| 203 var data = new LeafNodeData<int, String>([1, 2], ['A', 'B']); | |
| 204 manager.writeLeaf(1, data); | |
| 205 manager.writeLeaf(2, data); | |
| 206 manager.writeLeaf(3, data); | |
| 207 manager.writeLeaf(4, data); | |
| 208 manager.writeLeaf(1, data); | |
| 209 verifyZeroInteractions(delegate); | |
| 210 // only 4 nodes can be cached, 5-th one cause write to the delegate | |
| 211 manager.writeLeaf(5, data); | |
| 212 verify(delegate.writeLeaf(2, data)).once(); | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 | |
| 217 @ReflectiveTestCase() | |
| 218 class _FixedStringCodecTest { | |
| 219 ByteData buffer; | |
| 220 Uint8List bytes = new Uint8List(2 + 2 * 4); | |
| 221 FixedStringCodec codec = new FixedStringCodec(4); | |
| 222 | |
| 223 void setUp() { | |
| 224 buffer = new ByteData.view(bytes.buffer); | |
| 225 } | |
| 226 | |
| 227 test_empty() { | |
| 228 // encode | |
| 229 codec.encode(buffer, ''); | |
| 230 expect(bytes, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); | |
| 231 // decode | |
| 232 expect(codec.decode(buffer), ''); | |
| 233 } | |
| 234 | |
| 235 test_fourChars() { | |
| 236 // encode | |
| 237 codec.encode(buffer, 'ABCD'); | |
| 238 expect(bytes, [0, 4, 0, 65, 0, 66, 0, 67, 0, 68]); | |
| 239 // decode | |
| 240 expect(codec.decode(buffer), 'ABCD'); | |
| 241 } | |
| 242 | |
| 243 test_russian() { | |
| 244 // encode | |
| 245 codec.encode(buffer, 'ЩУКА'); | |
| 246 expect(bytes, [0, 4, 4, 41, 4, 35, 4, 26, 4, 16]); | |
| 247 // decode | |
| 248 expect(codec.decode(buffer), 'ЩУКА'); | |
| 249 } | |
| 250 | |
| 251 test_tooManyChars() { | |
| 252 expect(() { | |
| 253 codec.encode(buffer, 'ABCDE'); | |
| 254 }, throws); | |
| 255 } | |
| 256 | |
| 257 test_twoChars() { | |
| 258 // encode | |
| 259 codec.encode(buffer, 'AB'); | |
| 260 expect(bytes, [0, 2, 0, 65, 0, 66, 0, 0, 0, 0]); | |
| 261 // decode | |
| 262 expect(codec.decode(buffer), 'AB'); | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 | |
| 267 @ReflectiveTestCase() | |
| 268 class _MemoryPageManagerTest { | |
| 269 static const PAGE_SIZE = 8; | |
| 270 MemoryPageManager manager = new MemoryPageManager(PAGE_SIZE); | |
| 271 | |
| 272 test_alloc() { | |
| 273 int idA = manager.alloc(); | |
| 274 int idB = manager.alloc(); | |
| 275 expect(idB, isNot(idA)); | |
| 276 } | |
| 277 | |
| 278 test_free() { | |
| 279 int id = manager.alloc(); | |
| 280 manager.free(id); | |
| 281 // double free | |
| 282 expect(() { | |
| 283 manager.free(id); | |
| 284 }, throws); | |
| 285 } | |
| 286 | |
| 287 test_read() { | |
| 288 int id = manager.alloc(); | |
| 289 Uint8List page = manager.read(id); | |
| 290 expect(page.length, PAGE_SIZE); | |
| 291 } | |
| 292 | |
| 293 test_read_doesNotExist() { | |
| 294 expect(() { | |
| 295 manager.read(0); | |
| 296 }, throws); | |
| 297 } | |
| 298 | |
| 299 test_write() { | |
| 300 int id = manager.alloc(); | |
| 301 // do write | |
| 302 { | |
| 303 Uint8List page = new Uint8List(PAGE_SIZE); | |
| 304 page[3] = 42; | |
| 305 manager.write(id, page); | |
| 306 } | |
| 307 // now read | |
| 308 { | |
| 309 Uint8List page = manager.read(id); | |
| 310 expect(page.length, PAGE_SIZE); | |
| 311 expect(page[3], 42); | |
| 312 } | |
| 313 } | |
| 314 | |
| 315 test_write_doesNotExist() { | |
| 316 expect(() { | |
| 317 Uint8List page = new Uint8List(PAGE_SIZE); | |
| 318 manager.write(42, page); | |
| 319 }, throws); | |
| 320 } | |
| 321 | |
| 322 test_write_invalidLength() { | |
| 323 int id = manager.alloc(); | |
| 324 Uint8List page = new Uint8List(0); | |
| 325 expect(() { | |
| 326 manager.write(id, page); | |
| 327 }, throws); | |
| 328 } | |
| 329 } | |
| 330 | |
| 331 | |
| 332 | |
| 333 class _NodeManagerMock<K, V, N> extends TypedMock implements NodeManager<K, V, | |
| 334 N> { | |
| 335 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); | |
| 336 } | |
| 337 | |
| 338 | |
| 339 | |
| 340 @ReflectiveTestCase() | |
| 341 class _PageNodeManagerTest { | |
| 342 static const Codec KEY_CODEC = Uint32Codec.INSTANCE; | |
| 343 static const int PAGE_SIZE = 128; | |
| 344 static const Codec VALUE_CODEC = const FixedStringCodec(4); | |
| 345 | |
| 346 PageNodeManager<int, String> nodeManager; | |
| 347 MemoryPageManager pageManager = new MemoryPageManager(PAGE_SIZE); | |
| 348 | |
| 349 setUp() { | |
| 350 nodeManager = new PageNodeManager<int, String>(pageManager, KEY_CODEC, | |
| 351 VALUE_CODEC); | |
| 352 } | |
| 353 | |
| 354 test_index_createDelete() { | |
| 355 int id = nodeManager.createIndex(); | |
| 356 expect(nodeManager.isIndex(id), isTrue); | |
| 357 // do delete | |
| 358 nodeManager.delete(id); | |
| 359 expect(nodeManager.isIndex(id), isFalse); | |
| 360 } | |
| 361 | |
| 362 test_index_readWrite() { | |
| 363 int id = nodeManager.createIndex(); | |
| 364 expect(nodeManager.isIndex(id), isTrue); | |
| 365 // write | |
| 366 { | |
| 367 var keys = [1, 2]; | |
| 368 var children = [10, 20, 30]; | |
| 369 nodeManager.writeIndex(id, new IndexNodeData<int, int>(keys, children)); | |
| 370 } | |
| 371 // check the page | |
| 372 { | |
| 373 Uint8List page = pageManager.read(id); | |
| 374 expect(page, [0, 0, 0, 2, 0, 0, 0, 10, 0, 0, 0, 1, 0, 0, 0, 20, 0, 0, 0, | |
| 375 2, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, | |
| 376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, | |
| 377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, | |
| 378 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, | |
| 379 0, 0]); | |
| 380 } | |
| 381 // read | |
| 382 { | |
| 383 IndexNodeData<int, int> data = nodeManager.readIndex(id); | |
| 384 expect(data.keys, [1, 2]); | |
| 385 expect(data.children, [10, 20, 30]); | |
| 386 } | |
| 387 } | |
| 388 | |
| 389 test_leaf_readWrite() { | |
| 390 int id = nodeManager.createLeaf(); | |
| 391 expect(nodeManager.isIndex(id), isFalse); | |
| 392 // write | |
| 393 { | |
| 394 var keys = [1, 2, 3]; | |
| 395 var children = ['A', 'BB', 'CCC']; | |
| 396 nodeManager.writeLeaf(id, new LeafNodeData<int, String>(keys, children)); | |
| 397 } | |
| 398 // check the page | |
| 399 { | |
| 400 Uint8List page = pageManager.read(id); | |
| 401 expect(page, [0, 0, 0, 3, 0, 0, 0, 1, 0, 1, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 402 0, 2, 0, 2, 0, 66, 0, 66, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 67, 0, 67,
0, 67, 0, | |
| 403 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, | |
| 404 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, | |
| 405 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, | |
| 406 0, 0]); | |
| 407 } | |
| 408 // read | |
| 409 { | |
| 410 LeafNodeData<int, String> data = nodeManager.readLeaf(id); | |
| 411 expect(data.keys, [1, 2, 3]); | |
| 412 expect(data.values, ['A', 'BB', 'CCC']); | |
| 413 } | |
| 414 } | |
| 415 } | |
| 416 | |
| 417 @ReflectiveTestCase() | |
| 418 class _Uint32CodecTest { | |
| 419 ByteData buffer; | |
| 420 Uint8List bytes = new Uint8List(4); | |
| 421 Uint32Codec codec = Uint32Codec.INSTANCE; | |
| 422 | |
| 423 void setUp() { | |
| 424 buffer = new ByteData.view(bytes.buffer); | |
| 425 } | |
| 426 | |
| 427 test_all() { | |
| 428 // encode | |
| 429 codec.encode(buffer, 42); | |
| 430 expect(bytes, [0, 0, 0, 42]); | |
| 431 // decode | |
| 432 expect(codec.decode(buffer), 42); | |
| 433 } | |
| 434 } | |
| OLD | NEW |