1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 #include "precompiled.hpp"
  25 
  26 //#include "logging/log.hpp"
  27 #include "memory/metaspace/chunkTree.hpp"
  28 #include "memory/metaspace/metachunk.hpp"
  29 //#include "utilities/ostream.hpp"
  30 #include "utilities/debug.hpp"
  31 #include "utilities/globalDefinitions.hpp"
  32 
  33 namespace metaspace {
  34 
  35 
  36 #ifdef ASSERT
  37 
  38 void ChunkTree::check_is_valid_ref(ref_t ref) {
  39   const u2 raw_idx = get_raw_index_from_reference(ref);
  40   const u2 info = get_info_from_reference(ref);
  41   switch (info) {
  42     case node_marker:
  43       assert(_nodePool.is_valid_index(raw_idx), "Invalid node ref: %u", (unsigned)ref);
  44       break;
  45     case free_chunk_marker:
  46     case used_chunk_marker:
  47       assert(_chunkPool.is_valid_index(raw_idx), "Invalid chunk ref: %u", (unsigned)ref);
  48       break;
  49     default:
  50       ShouldNotReachHere();
  51   }
  52 }
  53 
  54 void ChunkTree::verify_node(const btnode_t* n) {
  55 
  56   const ref_t node_ref = encode_reference_for_node(n);
  57 
  58   // Check parent.
  59   const ref_t parent_ref = n->parent;
  60 
  61   if (parent_ref == 0) {
  62     assert(node_ref == _root, "This should be the root node");
  63   } else {
  64     btnode_t* parent_node = resolve_reference_to_node(parent_ref);
  65     assert(parent_node->child[0] == node_ref ||
  66            parent_node->child[1] == node_ref, "Incorrect parent backlink.");
  67   }
  68 
  69   // Check children.
  70   for (int i = 0; i < 2; i ++) {
  71     const ref_t child_ref = n->child[i];
  72     assert(child_ref != 0, "child ref null");
  73 
  74     // May be either a chunk or another node.
  75     if (reference_is_chunk(child_ref)) {
  76       Metachunk* c = resolve_reference_to_chunk(child_ref);
  77       assert(c->tree_node_ref() == node_ref, "Incorrect parent backlink.");
  78       if (reference_is_free_chunk(child_ref)) {
  79         assert(c->is_free(), "free info mismatch");
  80       } else {
  81         assert(c->is_in_use(), "free info mismatch");
  82       }
  83     } else {
  84       // This chunk is another node
  85       btnode_t* n = resolve_reference_to_node(child_ref);
  86       assert(n->parent == node_ref, "Incorrect parent backlink.");
  87     }
  88   }
  89 
  90 }
  91 #endif
  92 
  93 
  94 // Initialize: allocate a root node and a root chunk header; return the
  95 // root chunk header. It will be partly initialized.
  96 // Note: this just allocates a memory-less header; memory itself is allocated inside VirtualSpaceNode.
  97 Metachunk* ChunkTree::alloc_root_chunk_header() {
  98 
  99   assert(_root == 0, "already have a root");
 100 
 101   Metachunk* c = _chunkPool.allocate_element();
 102   c->wipe();
 103 
 104   c->set_level(chklvl::ROOT_CHUNK_LEVEL);
 105 
 106   const ref_t root_node_ref = encode_reference_for_chunk(c, true);
 107 
 108   _root = root_node_ref;
 109 
 110   return c;
 111 
 112 }
 113 
 114 // Given a chunk c, split it once.
 115 //
 116 // The original chunk must not be part of a freelist.
 117 //
 118 // Returns pointer to the result chunk; updates the splinters array to return the splintered off chunk.
 119 //
 120 // Returns NULL if chunk cannot be split any further.
 121 Metachunk* ChunkTree::split_once(Metachunk* c, Metachunk* splinters[chklvl::NUM_CHUNK_LEVELS]) {
 122 
 123   assert(c->is_free(), "Can only split free chunks.");
 124 
 125   if (c->level() == chklvl::HIGHEST_CHUNK_LEVEL) {
 126     return NULL;
 127   }
 128 
 129   const ref_t orig_chunk_ref = encode_reference_for_chunk(c, true);
 130 
 131   // Split chunk into two chunks.
 132   Metachunk* leader = c;
 133   Metachunk* follower = allocate_new_chunk();
 134   follower->wipe();
 135 
 136   const chklvl_t new_level = c->level() + 1;
 137   const size_t new_word_size = chklvl::word_size_for_level(new_level);
 138   const size_t old_committed_words = c->committed_words();
 139 
 140   assert(new_word_size == c->word_size() / 2, "Sanity");
 141   assert(old_committed_words <= c->word_size(), "Sanity");
 142 
 143   leader->set_level(new_level);
 144   follower->set_level(new_level);
 145 
 146   follower->set_base(c->base() + new_word_size);
 147 
 148   // Carry over commit boundary to new chunk; this is an optimization
 149   // to avoid too frequent commit requests.
 150   if (old_committed_words >= new_word_size) {
 151     leader->set_committed_words(new_word_size);
 152     follower->set_committed_words(old_committed_words - new_word_size);
 153   } else {
 154     leader->set_committed_words(old_committed_words);
 155     follower->set_committed_words(0);
 156   }
 157 
 158   // Create a new parent node for the two sibling chunks.
 159   btnode_t* const new_parent = allocate_new_node();
 160   const ref_t new_parent_ref = encode_reference_for_node(new_parent);
 161 
 162   // Replace the reference to the original chunk in the parent node with
 163   // the reference to the parent node.
 164   if (_root == orig_chunk_ref) {
 165     assert(new_level == chklvl::ROOT_CHUNK_LEVEL + 1, "Original chunk should have been root chunk.");
 166     assert(c->tree_node_ref() == 0, "Original chunk should not have a parent.");
 167     _root = new_parent_ref;
 168   } else {
 169     const ref_t old_parent_ref = c->tree_node_ref();
 170     btnode_t* const old_parent = resolve_reference_to_node(old_parent_ref);
 171     assert(old_parent != NULL, "Original chunk should have a parent.");
 172     if (old_parent->child[0] == orig_chunk_ref) {
 173       old_parent->child[0] = new_parent_ref;
 174     } else if (old_parent->child[1] == orig_chunk_ref) {
 175       old_parent->child[1] = new_parent_ref;
 176     } else {
 177       ShouldNotReachHere();
 178     }
 179   }
 180 
 181   // Tell the two new chunks who their parent is.
 182   c->set_tree_node_ref(new_parent_ref);
 183   follower->set_tree_node_ref(new_parent_ref);
 184 
 185   // Remember the splintered off chunk in the splinters array
 186   assert(splinters[new_level] == NULL, "Sanity");
 187   splinters[new_level] = follower;
 188 
 189   return c;
 190 
 191 }
 192 
 193 // Given a chunk, attempt to merge it with its sibling if it is free.
 194 // Returns pointer to the result chunk if successful, NULL otherwise.
 195 //
 196 // Returns number of merged chunks, by chunk level, in num_merged array. These numbers
 197 // includes the original chunk.
 198 //
 199 // !!! Please note that if this method returns a non-NULL value, the
 200 // original chunk will be invalid and should not be accessed anymore! !!!
 201 Metachunk* ChunkTree::merge_once(Metachunk* c, int num_merged[chklvl::NUM_CHUNK_LEVELS]) {
 202 
 203   assert(c->is_free(), "Only call for free chunks.");
 204 
 205   const chklvl_t orig_level = c->level();
 206 
 207   // If chunk is already a root chunk, we cannot merge any further.
 208   if (orig_level == chklvl::ROOT_CHUNK_LEVEL) {
 209     return NULL;
 210   }
 211 
 212   const ref_t orig_chunk_ref = encode_reference_for_chunk(c, true);
 213 
 214   // Get parent node and parent ref.
 215   const ref_t parent_ref = c->tree_node_ref();
 216   btnode_t* const parent = resolve_reference_to_node(parent_ref);
 217   assert(parent != NULL, "Chunk should have a parent."); // Since we left for root chunks already
 218 
 219   // Check if sibling are free and not splintered.
 220   if (reference_is_free_chunk(parent->child[0]) == false ||
 221       reference_is_free_chunk(parent->child[1]) == false) {
 222     return NULL;
 223   }
 224 
 225   // Merge chunks.
 226   Metachunk* c1 = resolve_reference_to_chunk(parent->child[0]);
 227   Metachunk* c2 = resolve_reference_to_chunk(parent->child[1]);
 228 
 229   // At this point, both metachunks should be free and not splintered.
 230   assert(c1->is_free() && c2->is_free() && c1->level() == c2->level(), "Sanity");
 231 
 232   // Find out who is leader. Let the leader live on.
 233   Metachunk* leader = c1;
 234   Metachunk* follower = c2;
 235 
 236   if (c1->base() > c2->base()) {
 237     leader = c2; follower = c1;
 238   }
 239 
 240   // Chunk memory should be adjacent to each other.
 241   assert(leader->base() + leader->word_size() == follower->base(), "Wrong geometry");
 242 
 243   leader->set_level(orig_level - 1);
 244 
 245   // Carry over committed words.
 246   size_t new_committed_words = leader->committed_words();
 247   if (leader->is_fully_committed()) {
 248     new_committed_words += follower->committed_words();
 249   }
 250   assert(new_committed_words <= leader->word_size(), "Sanity");
 251   leader->set_committed_words(new_committed_words);
 252 
 253   const ref_t leader_ref = encode_reference_for_chunk(leader, true);
 254 
 255   // Re-hang new merged chunk in tree one level up.
 256   const ref_t grand_parent_ref = parent->parent;
 257   if (grand_parent_ref == 0) {
 258     // Seems old parent node was root. That means we should have a root chunk now.
 259     assert(leader->level() == chklvl::ROOT_CHUNK_LEVEL, "Sanity");
 260     // Which we just hang under _root...
 261     _root = leader_ref;
 262   } else {
 263     btnode_t* grand_parent = resolve_reference_to_node(grand_parent_ref);
 264     if (grand_parent->child[0] == parent_ref) {
 265       grand_parent->child[0] = leader_ref;
 266     } else if (grand_parent->child[1] == parent_ref) {
 267       grand_parent->child[1] = leader_ref;
 268     } else {
 269       ShouldNotReachHere();
 270     }
 271   }
 272 
 273   // Remove the follower from its free list
 274   follower->remove_from_list();
 275 
 276   // Adjust stats
 277   num_merged[orig_level] ++;
 278 
 279   // Release the superfluous chunk header, and the old parent node.
 280   release_chunk(follower);
 281   release_node(parent);
 282 
 283   return leader;
 284 
 285 }
 286 
 287 // Given a chunk c, split it recursively until you get a chunk of the given target_level.
 288 //
 289 // The original chunk must not be part of a freelist.
 290 //
 291 // Returns pointer to the result chunk; returns split off chunks in splinters array.
 292 //
 293 // Returns NULL if chunk cannot be split at least once.
 294 Metachunk* ChunkTree::split(chklvl_t target_level, Metachunk* c, Metachunk* splinters[chklvl::NUM_CHUNK_LEVELS]) {
 295 
 296   DEBUG_ONLY(chklvl::check_valid_level(target_level));
 297   assert(target_level > c->level(), "Wrong target level");
 298 
 299   Metachunk* c_last = split_once(c, splinters);
 300   while (c_last != NULL && c_last->level() < target_level) {
 301     c_last = split_once(c, splinters);
 302   }
 303 
 304   assert(c != NULL, "Sanity");
 305 
 306   return c;
 307 
 308 }
 309 
 310 // Given a chunk, attempt to merge it recursively with its neighboring chunks.
 311 //
 312 // If successful (merged at least once), returns address of
 313 // the merged chunk; NULL otherwise.
 314 //
 315 // The merged chunks are removed from their freelist; the number of merged chunks is
 316 // returned, split by level, in num_merged array. Note that these numbers does not
 317 // include the original chunk.
 318 //
 319 // !!! Please note that if this method returns a non-NULL value, the
 320 // original chunk will be invalid and should not be accessed anymore! !!!
 321 Metachunk* ChunkTree::merge(Metachunk* c, int num_merged[chklvl::NUM_CHUNK_LEVELS]) {
 322 
 323   DEBUG_ONLY(c->verify(false);)
 324   assert(c->is_free(), "Only merge free chunks.");
 325 
 326   assert(c->level() > chklvl::ROOT_CHUNK_LEVEL, "Do not merge root chunks");
 327 
 328   // Original chunk should be outside the chunk manager freelist before attempting to merge.
 329   assert(c->prev() == NULL && c->next() == NULL, "Remove chunk from freelist before merging.");
 330 
 331   Metachunk* c_last = merge_once(c, num_merged);
 332   while (c_last != NULL && c_last->level() > chklvl::ROOT_CHUNK_LEVEL) {
 333     c_last = merge_once(c, num_merged);
 334   }
 335 
 336   return c_last;
 337 }
 338 
 339 
 340 //// tree traversal ////
 341 
 342 bool ChunkTree::iterate_chunks_helper(ref_t ref, ChunkClosure* cc) const {
 343   if (reference_is_chunk(ref)) {
 344     Metachunk* const c = resolve_reference_to_chunk(ref);
 345     return cc->do_chunk(c);
 346   } else {
 347     btnode_t* const n = resolve_reference_to_node(ref);
 348     assert(n->child[0] != 0 && n->child[1] != 0, "nodes have always children");
 349     return iterate_chunks_helper(n->child[0], cc) &&
 350            iterate_chunks_helper(n->child[1], cc);
 351   }
 352 
 353   return true;
 354 }
 355 
 356 // Iterate over all nodes in this tree. Returns true for complete traversal,
 357 // false if traversal was cancelled.
 358 bool ChunkTree::iterate_chunks(ChunkClosure* cc) const {
 359 
 360   if (_root == 0) {
 361     return true;
 362   }
 363 
 364   return iterate_chunks_helper(_root, cc);
 365 }
 366 
 367 
 368 
 369 #ifdef ASSERT
 370 
 371 // Helper for verify()
 372 void ChunkTree::verify_helper(bool slow, ref_t ref, const MetaWord* p, int* num_chunks, int* num_nodes) const {
 373 
 374   if (reference_is_node(ref)) {
 375 
 376     // A node
 377 
 378     const btnode_t* const n = resolve_reference_to_node(ref);
 379 
 380     verify_node(n);
 381 
 382     (*num_nodes) ++;
 383 
 384     // Verify childs recursively.
 385     verify_helper(slow, n->child[0], p, num_chunks, num_nodes);
 386     verify_helper(slow, n->child[1], p, num_chunks, num_nodes);
 387 
 388   } else {
 389 
 390     // A chunk.
 391 
 392     const Metachunk* const c = resolve_reference_to_chunk(ref);
 393 
 394     assert(c->is_free() == reference_is_free_chunk(ref), "free info mismatch");
 395 
 396     // Chunks in the tree should be ordered by base address of the range
 397     // they represent, and there should be no address holes.
 398     if (p == NULL) {
 399       p = c->base() + c->word_size();
 400     } else {
 401       assert(c->base() == p, "Chunk base address mismatch.");
 402     }
 403 
 404     c->verify(slow);
 405 
 406     (*num_chunks) ++;
 407 
 408   }
 409 
 410 }
 411 
 412 void ChunkTree::verify(bool slow, const MetaWord* base) const {
 413 
 414   int num_chunks = 0;
 415   int num_nodes = 0;
 416 
 417   verify_helper(slow, _root, base, &num_chunks, &num_nodes);
 418 
 419   // Number of chunks in the tree should be equal to the number of chunks
 420   // taken from the pool; same for nodes.
 421   assert(num_chunks == _chunkPool.used() - _chunkPool.free(), "chunk count mismatch");
 422   assert(num_nodes == _nodePool.used() - _nodePool.free(), "node count mismatch");
 423 
 424 }
 425 
 426 #endif // ASSERT
 427 
 428 
 429 
 430 
 431 //// ChunkTreeArray /////////////777
 432 
 433 // Create an array of ChunkTree objects, all initialized to NULL, covering
 434 // a given memory range. Memory range must be aligned to size of root chunks.
 435 ChunkTreeArray::ChunkTreeArray(const MetaWord* base, size_t word_size)
 436   : _base(base), _word_size(word_size),
 437     _arr(NULL), _num(0)
 438 {
 439   assert(is_aligned(_word_size, chklvl::MAX_CHUNK_WORD_SIZE), "not aligned");
 440   _num = _word_size / chklvl::MAX_CHUNK_WORD_SIZE;
 441   _arr = NEW_C_HEAP_ARRAY(ChunkTree*, _num, mtInternal);
 442   for (int i = 0; i < _num; i ++) {
 443     _arr[i] = NULL;
 444   }
 445 }
 446 
 447 ChunkTreeArray::~ChunkTreeArray() {
 448   FREE_C_HEAP_ARRAY(ChunkTree*, _arr);
 449 }
 450 
 451 
 452 // Iterate over all nodes in all trees. Returns true for complete traversal,
 453 // false if traversal was cancelled.
 454 bool ChunkTreeArray::iterate_chunks(ChunkClosure* cc) const {
 455   for (int i = 0; i < _num; i ++) {
 456     if (_arr[i] != NULL) {
 457       if (_arr[i]->iterate_chunks(cc) == false) {
 458         return false;
 459       }
 460     }
 461   }
 462 }
 463 
 464 #ifdef ASSERT
 465 void ChunkTreeArray::verify(bool slow) const {
 466   for (int i = 0; i < _num; i ++) {
 467     if (_arr[i] != NULL) {
 468       _arr[i]->verify(slow, _base);
 469     }
 470   }
 471 }
 472 #endif
 473 
 474 
 475 } // namespace metaspace
 476 
 477