void ChunkLoaderJob::Execute( void* param /*= 0 */ )
    {
        while( Thread::self()->getCurrentState() != TERMINATED )
        {
            ChunkData to_load( -1, 0, 0 );
            int to_load_priority = -1;
            {
                MutexLock lock( m_Octree->m_OctreeHandleMutex );

                if( m_Octree->m_ChunksToLoad.size() > 0 )
                {
                    to_load = m_Octree->m_ChunksToLoad[ 0 ].m_Data;
                    to_load_priority = m_Octree->m_ChunksToLoad[ 0 ].priority;
                    m_Octree->m_CurrentlyLoadingChunkID = to_load.m_ChunkID;
                    m_Octree->m_ChunksToLoad.erase( m_Octree->m_ChunksToLoad.begin() );
                }
            }

            if( to_load.m_ChunkID > 0 )
            {
                int id = to_load.m_ChunkID;
                size_t loc = to_load.m_ChunkFilePosition;
                int size = (int)to_load.m_ChunkSize;
                m_FileHandle.seekg( loc );

                char* chunk_data = reinterpret_cast< char* >( malloc( size ) );

                if( chunk_data )
                {
                    m_FileHandle.read( chunk_data, size );
                    {
                        MutexLock lock( m_Octree->m_OctreeHandleMutex );

                        m_Octree->m_CPU_Allocations += size;
                        m_Octree->m_RawChunkData[ id ] = chunk_data;
                        m_Octree->m_UncheckedDataFromDisk.push_back( ChunkDataPriority( to_load, to_load_priority ) ); 
                        m_Octree->m_CurrentlyLoadingChunkID = -1;
                    }
                }
                else
                {
                    MutexLock lock( m_Octree->m_OctreeHandleMutex );

                    m_Octree->m_ChunksToLoad.push_back( ChunkDataPriority( to_load, to_load_priority ) );

                    m_Octree->m_NeedsToFreeUnusedChunksFromCPU = true;

                    Sleep( 1 );
                }
            }

            Sleep( 0 );
        }
    }
void restrictive_coarsening::prepare_data_to_send(
    int n_local_hyperedges, int n_local_pins,
    dynamic_array<int> local_hyperedge_weights,
    dynamic_array<int> local_hyperedge_offsets,
    dynamic_array<int> local_pins, MPI_Comm comm) {

  ds::dynamic_array<int> processors(processors_);
  for (int i = 0; i < processors_; ++i) {
    processors[i] = i;
  }

  ds::dynamic_array<int> min_local_indices(processors_);
  ds::dynamic_array<int> max_local_indices(processors_);

  // Prepare data structures
  MPI_Allgather(&minimum_vertex_index_, 1, MPI_INT, min_local_indices.data(), 1,
                MPI_INT, comm);
  MPI_Allgather(&maximum_vertex_index_, 1, MPI_INT, max_local_indices.data(), 1,
                MPI_INT, comm);

  ds::complete_binary_tree<int> vertex_to_processor(processors.data(),
                                                    min_local_indices.data(),
                                                    processors_);

  ds::dynamic_array<int> vertices_per_processor(processors_);
  utility::set_to_zero<int>(vertices_per_processor.data(), processors_);
  utility::set_to_zero<int>(send_lens_.data(), processors_);

  ds::bit_field to_load(n_local_hyperedges);
  if (percentile_ == 100) {
    to_load.set();
  } else {
    compute_hyperedges_to_load(to_load, n_local_hyperedges,
                               n_local_pins, local_hyperedge_weights,
                               local_hyperedge_offsets, comm);
  }

  ds::dynamic_array<bool> sent_to_processor(processors_, false);
  utility::set_to_zero<int>(send_lens_.data(), processors_);

  for (int i = 0; i < n_local_hyperedges; ++i) {
    if (to_load.test(i)) {
      int start_offset = local_hyperedge_offsets[i];
      int end_offset = local_hyperedge_offsets[i + 1];
      for (int j = start_offset; j < end_offset; ++j) {
        int proc = vertex_to_processor.root_value(local_pins[j]);
        ++vertices_per_processor[proc];
      }

      for (int j = 0; j < processors_; ++j) {
        if (vertices_per_processor[j] > 1) {
          if (j == rank_) {
            hyperedge_weights_[number_of_hyperedges_] = local_hyperedge_weights[i];
            hyperedge_offsets_[number_of_hyperedges_] = number_of_local_pins_;
            ++number_of_hyperedges_;

            for (int l = start_offset; l < end_offset; ++l) {
              int local_vertex = local_pins[l] - minimum_vertex_index_;
              if (0 <= local_vertex &&
                  local_vertex < number_of_local_vertices_) {
                local_pin_list_[number_of_local_pins_++] = local_vertex;
                ++vertex_to_hyperedges_offset_[local_vertex];
              }
            }
          } else {
            data_out_sets_[j][send_lens_[j]++] = vertices_per_processor[j] + 2;
            data_out_sets_[j][send_lens_[j]++] = local_hyperedge_weights[i];
            for (int l = start_offset; l < end_offset; ++l) {
              if (min_local_indices[j] <= local_pins[l] &&
                  local_pins[l] < max_local_indices[j]) {
                data_out_sets_[j][send_lens_[j]++] =
                    local_pins[l] - min_local_indices[j];
              }
            }
          }
          vertices_per_processor[j] = 0;
        }
        if (vertices_per_processor[j] == 1) {
          vertices_per_processor[j] = 0;
        }
      }
    }
  }
}