
com.twitter.cassovary.util.SequentialNodeRenumberer.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2013 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.twitter.cassovary.util
import scala.collection.mutable.{ArrayBuffer,HashMap}
/*
* Renumbers node id values read from source file to internal sequentially increasing id value.
Uses a synchronized map for thread safety when shared by multiple reader threads.
*/
class SequentialNodeRenumberer extends NodeRenumberer {
// See comments in externalToInternal for why HashMap is not Concurrent or Synchronized.
val externalToInternalMap = HashMap[Int,Int]()
var internalToExternalMap = ArrayBuffer[Int]()
/**
* Map external node id to internal node id, where internal nodes sequentially increase
* from 0 for each newly seen external node id. Thread-safe; see body comments for details.
*/
def externalToInternal(externalNodeId: Int): Int =
/**
* We don't use Concurrent or Synchronized HashMap alone because of potential race:
* Thread1 | Thread2
* --------------------------------+------------------------
* externalToInternalMap.size |
* | externalToInternalMap.size
* externalToInternalMap.getOr... |
* | externalToInternalMap.getOr...
*
* To guard against this we use a synchronized block to make a thread's calls
* to both .size and subsequently .getOrElseUpdate atomic.
*/
this.synchronized {
val internalNodeId = externalToInternalMap.getOrElseUpdate(externalNodeId, externalToInternalMap.size)
// Note: Assertions are consistency checks which can be uncommented for testing.
// When loaded correctly we should not be seeing internal ids beyond length of externalToInternalMap.
//assert(externalToInternalMap.size > internalNodeId)
// InternalNodeId should be no larger than internalToExternalMap.
//assert(internalToExternalMap.size >= internalNodeId)
if (internalToExternalMap.size == internalNodeId) {
internalToExternalMap += externalNodeId
}
// The internal id should be assigned to the correct external id.
//assert(internalToExternalMap(internalNodeId) == externalNodeId)
internalNodeId
}
def internalToExternal(internalNodeId: Int): Int = {
internalToExternalMap(internalNodeId)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy