| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library index.page_node_manager; | 5 library index.page_node_manager; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 import 'dart:typed_data'; | 8 import 'dart:typed_data'; |
| 9 | 9 |
| 10 import 'package:analysis_server/src/index/lru_cache.dart'; |
| 11 |
| 10 import 'b_plus_tree.dart'; | 12 import 'b_plus_tree.dart'; |
| 11 | 13 |
| 12 | 14 |
| 13 /** | 15 /** |
| 16 * A [NodeManager] that caches a specified number of index and leaf nodes. |
| 17 */ |
| 18 class CachingNodeManager<K, V, N> implements NodeManager<K, V, N> { |
| 19 final NodeManager<K, V, N> _delegate; |
| 20 LRUCache<N, IndexNodeData<K, N>> _indexCache; |
| 21 LRUCache<N, LeafNodeData<K, V>> _leafCache; |
| 22 |
| 23 CachingNodeManager(this._delegate, int indexNodeCacheSize, |
| 24 int leafNodeCacheSize) { |
| 25 // TODO(scheglov) method pointers don't work with mocks |
| 26 // _indexCache = new LRUCache<N, IndexNodeData<K, N>>(indexNodeCacheSize, |
| 27 // _delegate.writeIndex); |
| 28 // _leafCache = new LRUCache<N, LeafNodeData<K, V>>(leafNodeCacheSize, |
| 29 // _delegate.writeLeaf); |
| 30 _indexCache = new LRUCache<N, IndexNodeData<K, N>>(indexNodeCacheSize, |
| 31 (N key, IndexNodeData<K, N> value) { |
| 32 _delegate.writeIndex(key, value); |
| 33 }); |
| 34 _leafCache = new LRUCache<N, LeafNodeData<K, V>>(leafNodeCacheSize, (N key, |
| 35 LeafNodeData<K, V> value) { |
| 36 _delegate.writeLeaf(key, value); |
| 37 }); |
| 38 } |
| 39 |
| 40 @override |
| 41 int get maxIndexKeys => _delegate.maxIndexKeys; |
| 42 |
| 43 @override |
| 44 int get maxLeafKeys => _delegate.maxLeafKeys; |
| 45 |
| 46 @override |
| 47 N createIndex() { |
| 48 return _delegate.createIndex(); |
| 49 } |
| 50 |
| 51 @override |
| 52 N createLeaf() { |
| 53 return _delegate.createLeaf(); |
| 54 } |
| 55 |
| 56 @override |
| 57 void delete(N id) { |
| 58 _indexCache.remove(id); |
| 59 _leafCache.remove(id); |
| 60 _delegate.delete(id); |
| 61 } |
| 62 |
| 63 @override |
| 64 bool isIndex(N id) { |
| 65 return _delegate.isIndex(id); |
| 66 } |
| 67 |
| 68 @override |
| 69 IndexNodeData<K, N> readIndex(N id) { |
| 70 IndexNodeData<K, N> data = _indexCache.get(id); |
| 71 if (data != null) { |
| 72 return data; |
| 73 } |
| 74 return _delegate.readIndex(id); |
| 75 } |
| 76 |
| 77 @override |
| 78 LeafNodeData<K, V> readLeaf(N id) { |
| 79 LeafNodeData<K, V> data = _leafCache.get(id); |
| 80 if (data != null) { |
| 81 return data; |
| 82 } |
| 83 return _delegate.readLeaf(id); |
| 84 } |
| 85 |
| 86 @override |
| 87 void writeIndex(N id, IndexNodeData<K, N> data) { |
| 88 _indexCache.put(id, data); |
| 89 } |
| 90 |
| 91 @override |
| 92 void writeLeaf(N id, LeafNodeData<K, V> data) { |
| 93 _leafCache.put(id, data); |
| 94 } |
| 95 } |
| 96 |
| 97 |
| 98 /** |
| 14 * A [Codec] encodes and decodes data. | 99 * A [Codec] encodes and decodes data. |
| 15 */ | 100 */ |
| 16 abstract class Codec<E> { | 101 abstract class Codec<E> { |
| 17 /** | 102 /** |
| 18 * The size of the value in bytes. | 103 * The size of the value in bytes. |
| 19 */ | 104 */ |
| 20 int get sizeInBytes; | 105 int get sizeInBytes; |
| 21 | 106 |
| 22 /** | 107 /** |
| 23 * Returns the value decoded from [buffer]. | 108 * Returns the value decoded from [buffer]. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 | 145 |
| 61 @override | 146 @override |
| 62 void encode(ByteData buffer, String value) { | 147 void encode(ByteData buffer, String value) { |
| 63 int length = value.length; | 148 int length = value.length; |
| 64 if (length > maxLength) { | 149 if (length > maxLength) { |
| 65 throw new ArgumentError( | 150 throw new ArgumentError( |
| 66 'String $value length=$length is greater than allowed $maxLength'); | 151 'String $value length=$length is greater than allowed $maxLength'); |
| 67 } | 152 } |
| 68 buffer.setUint16(0, length); | 153 buffer.setUint16(0, length); |
| 69 int offset = 2; | 154 int offset = 2; |
| 70 for (int codeUnit in value.codeUnits) { | 155 List<int> codeUnits = value.codeUnits; |
| 71 buffer.setUint16(offset, codeUnit); | 156 for (int i = 0; i < length; i++) { |
| 157 buffer.setUint16(offset, codeUnits[i]); |
| 72 offset += 2; | 158 offset += 2; |
| 73 } | 159 } |
| 74 } | 160 } |
| 75 } | 161 } |
| 76 | 162 |
| 77 | 163 |
| 78 /** | 164 /** |
| 79 * A [PageManager] that keeps all [Uint8List] pages in memory. | 165 * A [PageManager] that keeps all [Uint8List] pages in memory. |
| 80 */ | 166 */ |
| 81 class MemoryPageManager implements PageManager { | 167 class MemoryPageManager implements PageManager { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 | 239 |
| 154 /** | 240 /** |
| 155 * A [NodeManager] that keeps nodes in [PageManager]. | 241 * A [NodeManager] that keeps nodes in [PageManager]. |
| 156 */ | 242 */ |
| 157 class PageNodeManager<K, V> implements NodeManager<K, V, int> { | 243 class PageNodeManager<K, V> implements NodeManager<K, V, int> { |
| 158 static const int INDEX_OFFSET_DATA = 4; | 244 static const int INDEX_OFFSET_DATA = 4; |
| 159 static const int INDEX_OFFSET_KEY_COUNT = 0; | 245 static const int INDEX_OFFSET_KEY_COUNT = 0; |
| 160 static const int LEAF_OFFSET_DATA = 4; | 246 static const int LEAF_OFFSET_DATA = 4; |
| 161 static const int LEAF_OFFSET_KEY_COUNT = 0; | 247 static const int LEAF_OFFSET_KEY_COUNT = 0; |
| 162 | 248 |
| 163 final Set<int> indexPages = new HashSet<int>(); | 249 final Set<int> _indexPages = new HashSet<int>(); |
| 164 Codec<K> keyCodec; | 250 Codec<K> _keyCodec; |
| 165 final Set<int> leafPages = new HashSet<int>(); | 251 final Set<int> _leafPages = new HashSet<int>(); |
| 166 PageManager pageManager; | 252 PageManager _pageManager; |
| 167 Codec<V> valueCodec; | 253 Codec<V> _valueCodec; |
| 168 | 254 |
| 169 PageNodeManager(this.pageManager, this.keyCodec, this.valueCodec); | 255 PageNodeManager(this._pageManager, this._keyCodec, this._valueCodec); |
| 170 | 256 |
| 171 @override | 257 @override |
| 172 int get maxIndexKeys { | 258 int get maxIndexKeys { |
| 173 int keySize = keyCodec.sizeInBytes; | 259 int keySize = _keyCodec.sizeInBytes; |
| 174 int childSize = 4; | 260 int childSize = 4; |
| 175 int dataSize = pageManager.pageSizeInBytes - INDEX_OFFSET_DATA; | 261 int dataSize = _pageManager.pageSizeInBytes - INDEX_OFFSET_DATA; |
| 176 return (dataSize - childSize) ~/ (keySize + childSize); | 262 return (dataSize - childSize) ~/ (keySize + childSize); |
| 177 } | 263 } |
| 178 | 264 |
| 179 @override | 265 @override |
| 180 int get maxLeafKeys { | 266 int get maxLeafKeys { |
| 181 int keySize = keyCodec.sizeInBytes; | 267 int keySize = _keyCodec.sizeInBytes; |
| 182 int valueSize = valueCodec.sizeInBytes; | 268 int valueSize = _valueCodec.sizeInBytes; |
| 183 int dataSize = pageManager.pageSizeInBytes - INDEX_OFFSET_DATA; | 269 int dataSize = _pageManager.pageSizeInBytes - INDEX_OFFSET_DATA; |
| 184 return dataSize ~/ (keySize + valueSize); | 270 return dataSize ~/ (keySize + valueSize); |
| 185 } | 271 } |
| 186 | 272 |
| 187 @override | 273 @override |
| 188 int createIndex() { | 274 int createIndex() { |
| 189 int id = pageManager.alloc(); | 275 int id = _pageManager.alloc(); |
| 190 indexPages.add(id); | 276 _indexPages.add(id); |
| 191 return id; | 277 return id; |
| 192 } | 278 } |
| 193 | 279 |
| 194 @override | 280 @override |
| 195 int createLeaf() { | 281 int createLeaf() { |
| 196 int id = pageManager.alloc(); | 282 int id = _pageManager.alloc(); |
| 197 leafPages.add(id); | 283 _leafPages.add(id); |
| 198 return id; | 284 return id; |
| 199 } | 285 } |
| 200 | 286 |
| 201 @override | 287 @override |
| 202 void delete(int id) { | 288 void delete(int id) { |
| 203 pageManager.free(id); | 289 _pageManager.free(id); |
| 204 indexPages.remove(id); | 290 _indexPages.remove(id); |
| 205 leafPages.remove(id); | 291 _leafPages.remove(id); |
| 206 } | 292 } |
| 207 | 293 |
| 208 @override | 294 @override |
| 209 bool isIndex(int id) { | 295 bool isIndex(int id) { |
| 210 return indexPages.contains(id); | 296 return _indexPages.contains(id); |
| 211 } | 297 } |
| 212 | 298 |
| 213 @override | 299 @override |
| 214 IndexNodeData<K, int> readIndex(int id) { | 300 IndexNodeData<K, int> readIndex(int id) { |
| 215 Uint8List page = pageManager.read(id); | 301 Uint8List page = _pageManager.read(id); |
| 216 // read header | 302 // read header |
| 217 int keyCount; | 303 int keyCount; |
| 218 { | 304 { |
| 219 ByteData data = new ByteData.view(page.buffer); | 305 ByteData data = new ByteData.view(page.buffer); |
| 220 keyCount = data.getInt32(INDEX_OFFSET_KEY_COUNT); | 306 keyCount = data.getInt32(INDEX_OFFSET_KEY_COUNT); |
| 221 } | 307 } |
| 222 // read keys/children | 308 // read keys/children |
| 223 List<K> keys = new List<K>(); | 309 List<K> keys = new List<K>(); |
| 224 List<int> children = new List<int>(); | 310 List<int> children = new List<int>(); |
| 225 int keySize = keyCodec.sizeInBytes; | 311 int keySize = _keyCodec.sizeInBytes; |
| 226 int offset = INDEX_OFFSET_DATA; | 312 int offset = INDEX_OFFSET_DATA; |
| 227 for (int i = 0; i < keyCount; i++) { | 313 for (int i = 0; i < keyCount; i++) { |
| 228 // read child | 314 // read child |
| 229 { | 315 { |
| 230 ByteData byteData = new ByteData.view(page.buffer, offset); | 316 ByteData byteData = new ByteData.view(page.buffer, offset); |
| 231 int childPage = byteData.getUint32(0); | 317 int childPage = byteData.getUint32(0); |
| 232 children.add(childPage); | 318 children.add(childPage); |
| 233 offset += 4; | 319 offset += 4; |
| 234 } | 320 } |
| 235 // read key | 321 // read key |
| 236 { | 322 { |
| 237 ByteData byteData = new ByteData.view(page.buffer, offset, keySize); | 323 ByteData byteData = new ByteData.view(page.buffer, offset, keySize); |
| 238 K key = keyCodec.decode(byteData); | 324 K key = _keyCodec.decode(byteData); |
| 239 keys.add(key); | 325 keys.add(key); |
| 240 offset += keySize; | 326 offset += keySize; |
| 241 } | 327 } |
| 242 } | 328 } |
| 243 // read last child | 329 // read last child |
| 244 { | 330 { |
| 245 ByteData byteData = new ByteData.view(page.buffer, offset); | 331 ByteData byteData = new ByteData.view(page.buffer, offset); |
| 246 int childPage = byteData.getUint32(0); | 332 int childPage = byteData.getUint32(0); |
| 247 children.add(childPage); | 333 children.add(childPage); |
| 248 } | 334 } |
| 249 // done | 335 // done |
| 250 return new IndexNodeData<K, int>(keys, children); | 336 return new IndexNodeData<K, int>(keys, children); |
| 251 } | 337 } |
| 252 | 338 |
| 253 @override | 339 @override |
| 254 LeafNodeData<K, V> readLeaf(int id) { | 340 LeafNodeData<K, V> readLeaf(int id) { |
| 255 Uint8List page = pageManager.read(id); | 341 Uint8List page = _pageManager.read(id); |
| 256 // read header | 342 // read header |
| 257 int keyCount; | 343 int keyCount; |
| 258 { | 344 { |
| 259 ByteData data = new ByteData.view(page.buffer); | 345 ByteData data = new ByteData.view(page.buffer); |
| 260 keyCount = data.getInt32(LEAF_OFFSET_KEY_COUNT); | 346 keyCount = data.getInt32(LEAF_OFFSET_KEY_COUNT); |
| 261 } | 347 } |
| 262 // read keys/children | 348 // read keys/children |
| 263 List<K> keys = new List<K>(); | 349 List<K> keys = new List<K>(); |
| 264 List<V> values = new List<V>(); | 350 List<V> values = new List<V>(); |
| 265 int keySize = keyCodec.sizeInBytes; | 351 int keySize = _keyCodec.sizeInBytes; |
| 266 int valueSize = valueCodec.sizeInBytes; | 352 int valueSize = _valueCodec.sizeInBytes; |
| 267 int offset = LEAF_OFFSET_DATA; | 353 int offset = LEAF_OFFSET_DATA; |
| 268 for (int i = 0; i < keyCount; i++) { | 354 for (int i = 0; i < keyCount; i++) { |
| 269 // read key | 355 // read key |
| 270 { | 356 { |
| 271 ByteData byteData = new ByteData.view(page.buffer, offset, keySize); | 357 ByteData byteData = new ByteData.view(page.buffer, offset, keySize); |
| 272 K key = keyCodec.decode(byteData); | 358 K key = _keyCodec.decode(byteData); |
| 273 keys.add(key); | 359 keys.add(key); |
| 274 offset += keySize; | 360 offset += keySize; |
| 275 } | 361 } |
| 276 // read value | 362 // read value |
| 277 { | 363 { |
| 278 ByteData byteData = new ByteData.view(page.buffer, offset); | 364 ByteData byteData = new ByteData.view(page.buffer, offset); |
| 279 V value = valueCodec.decode(byteData); | 365 V value = _valueCodec.decode(byteData); |
| 280 values.add(value); | 366 values.add(value); |
| 281 offset += valueSize; | 367 offset += valueSize; |
| 282 } | 368 } |
| 283 } | 369 } |
| 284 // done | 370 // done |
| 285 return new LeafNodeData<K, V>(keys, values); | 371 return new LeafNodeData<K, V>(keys, values); |
| 286 } | 372 } |
| 287 | 373 |
| 288 @override | 374 @override |
| 289 void writeIndex(int id, IndexNodeData<K, int> data) { | 375 void writeIndex(int id, IndexNodeData<K, int> data) { |
| 290 Uint8List page = new Uint8List(pageManager.pageSizeInBytes); | 376 Uint8List page = new Uint8List(_pageManager.pageSizeInBytes); |
| 291 // write header | 377 // write header |
| 292 int keyCount = data.keys.length; | 378 int keyCount = data.keys.length; |
| 293 { | 379 { |
| 294 ByteData byteData = new ByteData.view(page.buffer); | 380 ByteData byteData = new ByteData.view(page.buffer); |
| 295 byteData.setUint32(INDEX_OFFSET_KEY_COUNT, keyCount); | 381 byteData.setUint32(PageNodeManager.INDEX_OFFSET_KEY_COUNT, keyCount); |
| 296 } | 382 } |
| 297 // write keys/children | 383 // write keys/children |
| 298 int keySize = keyCodec.sizeInBytes; | 384 int keySize = _keyCodec.sizeInBytes; |
| 299 int offset = INDEX_OFFSET_DATA; | 385 int offset = PageNodeManager.INDEX_OFFSET_DATA; |
| 300 for (int i = 0; i < keyCount; i++) { | 386 for (int i = 0; i < keyCount; i++) { |
| 301 // write child | 387 // write child |
| 302 { | 388 { |
| 303 ByteData byteData = new ByteData.view(page.buffer, offset); | 389 ByteData byteData = new ByteData.view(page.buffer, offset); |
| 304 byteData.setUint32(0, data.children[i]); | 390 byteData.setUint32(0, data.children[i]); |
| 305 offset += 4; | 391 offset += 4; |
| 306 } | 392 } |
| 307 // write key | 393 // write key |
| 308 { | 394 { |
| 309 ByteData byteData = new ByteData.view(page.buffer, offset, keySize); | 395 ByteData byteData = new ByteData.view(page.buffer, offset, keySize); |
| 310 keyCodec.encode(byteData, data.keys[i]); | 396 _keyCodec.encode(byteData, data.keys[i]); |
| 311 offset += keySize; | 397 offset += keySize; |
| 312 } | 398 } |
| 313 } | 399 } |
| 314 // write last child | 400 // write last child |
| 315 { | 401 { |
| 316 ByteData byteData = new ByteData.view(page.buffer, offset); | 402 ByteData byteData = new ByteData.view(page.buffer, offset); |
| 317 byteData.setUint32(0, data.children.last); | 403 byteData.setUint32(0, data.children.last); |
| 318 } | 404 } |
| 319 // write page | 405 // write page |
| 320 pageManager.write(id, page); | 406 _pageManager.write(id, page); |
| 321 } | 407 } |
| 322 | 408 |
| 323 @override | 409 @override |
| 324 void writeLeaf(int id, LeafNodeData<K, V> data) { | 410 void writeLeaf(int id, LeafNodeData<K, V> data) { |
| 325 Uint8List page = new Uint8List(pageManager.pageSizeInBytes); | 411 Uint8List page = new Uint8List(_pageManager.pageSizeInBytes); |
| 326 // write header | 412 // write header |
| 327 int keyCount = data.keys.length; | 413 int keyCount = data.keys.length; |
| 328 { | 414 { |
| 329 ByteData byteData = new ByteData.view(page.buffer); | 415 ByteData byteData = new ByteData.view(page.buffer); |
| 330 byteData.setUint32(LEAF_OFFSET_KEY_COUNT, keyCount); | 416 byteData.setUint32(PageNodeManager.LEAF_OFFSET_KEY_COUNT, keyCount); |
| 331 } | 417 } |
| 332 // write keys/values | 418 // write keys/values |
| 333 int keySize = keyCodec.sizeInBytes; | 419 int keySize = _keyCodec.sizeInBytes; |
| 334 int valueSize = valueCodec.sizeInBytes; | 420 int valueSize = _valueCodec.sizeInBytes; |
| 335 int offset = LEAF_OFFSET_DATA; | 421 int offset = PageNodeManager.LEAF_OFFSET_DATA; |
| 336 for (int i = 0; i < keyCount; i++) { | 422 for (int i = 0; i < keyCount; i++) { |
| 337 // write key | 423 // write key |
| 338 { | 424 { |
| 339 ByteData byteData = new ByteData.view(page.buffer, offset, keySize); | 425 ByteData byteData = new ByteData.view(page.buffer, offset, keySize); |
| 340 keyCodec.encode(byteData, data.keys[i]); | 426 _keyCodec.encode(byteData, data.keys[i]); |
| 341 offset += keySize; | 427 offset += keySize; |
| 342 } | 428 } |
| 343 // write value | 429 // write value |
| 344 { | 430 { |
| 345 ByteData byteData = new ByteData.view(page.buffer, offset); | 431 ByteData byteData = new ByteData.view(page.buffer, offset); |
| 346 valueCodec.encode(byteData, data.values[i]); | 432 _valueCodec.encode(byteData, data.values[i]); |
| 347 offset += valueSize; | 433 offset += valueSize; |
| 348 } | 434 } |
| 349 } | 435 } |
| 350 // write page | 436 // write page |
| 351 pageManager.write(id, page); | 437 _pageManager.write(id, page); |
| 352 } | 438 } |
| 353 } | 439 } |
| 354 | 440 |
| 355 | 441 |
| 356 /** | 442 /** |
| 357 * A [Codec] for unsigned 32-bit integers. | 443 * A [Codec] for unsigned 32-bit integers. |
| 358 */ | 444 */ |
| 359 class Uint32Codec implements Codec<int> { | 445 class Uint32Codec implements Codec<int> { |
| 360 static const Uint32Codec INSTANCE = const Uint32Codec._(); | 446 static const Uint32Codec INSTANCE = const Uint32Codec._(); |
| 361 | 447 |
| 362 const Uint32Codec._(); | 448 const Uint32Codec._(); |
| 363 | 449 |
| 364 @override | 450 @override |
| 365 int get sizeInBytes => 4; | 451 int get sizeInBytes => 4; |
| 366 | 452 |
| 367 @override | 453 @override |
| 368 int decode(ByteData buffer) { | 454 int decode(ByteData buffer) { |
| 369 return buffer.getUint32(0); | 455 return buffer.getUint32(0); |
| 370 } | 456 } |
| 371 | 457 |
| 372 @override | 458 @override |
| 373 void encode(ByteData buffer, int element) { | 459 void encode(ByteData buffer, int element) { |
| 374 buffer.setUint32(0, element); | 460 buffer.setUint32(0, element); |
| 375 } | 461 } |
| 376 } | 462 } |
| OLD | NEW |