org.bboxdb.distribution.region.DistributionRegionIdMapper Maven / Gradle / Ivy
/*******************************************************************************
*
* Copyright (C) 2015-2018 the BBoxDB project
*
* 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 org.bboxdb.distribution.region;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.bboxdb.commons.math.Hyperrectangle;
import org.bboxdb.misc.Const;
import org.bboxdb.storage.entity.TupleStoreName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Stopwatch;
public class DistributionRegionIdMapper {
/**
* The mappings
*/
private final Map regions;
/**
* The distribution group name
*/
private final String distributionGroup;
/**
* The mutex for synchronization
*/
private final Object MUTEX;
/**
* The Logger
*/
private final static Logger logger = LoggerFactory.getLogger(DistributionRegionIdMapper.class);
public DistributionRegionIdMapper(final String distributionGroup) {
this.distributionGroup = distributionGroup;
this.regions = new ConcurrentHashMap<>();
this.MUTEX = new Object();
}
/**
* Search the region ids that are overlapped by the bounding box
*/
public Set getRegionIdsForRegion(final Hyperrectangle region) {
return regions.entrySet()
.stream()
.filter(e -> e.getValue().intersects(region))
.map(e -> e.getKey())
.collect(Collectors.toSet());
}
/**
* Get all region ids
* @return
*/
public Set getAllRegionIds() {
return new HashSet<>(regions.keySet());
}
/**
* Get the SSTables that are responsible for a given bounding box
* @param region
* @param ssTableName
* @return
*/
public List getLocalTablesForRegion(final Hyperrectangle region,
final TupleStoreName ssTableName) {
Collection namprefixes = null;
for(int execution = 0; execution < Const.OPERATION_RETRY; execution++) {
namprefixes = getRegionIdsForRegion(region);
if(! namprefixes.isEmpty()) {
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
if(namprefixes.isEmpty() && logger.isDebugEnabled()) {
logger.debug("Got an empty result list by query region: {} in {}", region, distributionGroup);
}
return convertRegionIdToTableNames(ssTableName, namprefixes);
}
/**
* Get all SSTables that are stored local
* @param ssTableName
* @return
*/
public List getAllLocalTables(final TupleStoreName ssTableName) {
final Collection namprefixes = getAllRegionIds();
if(namprefixes.isEmpty() && logger.isWarnEnabled()) {
logger.warn("Got an empty result list by query all regions in {}", distributionGroup);
}
return convertRegionIdToTableNames(ssTableName, namprefixes);
}
/**
* Prefix all entries of the given list with the name of the sstable
* @param ssTableName
* @param regionIds
* @return
*/
public List convertRegionIdToTableNames(final TupleStoreName ssTableName,
final Collection regionIds) {
return regionIds
.stream()
.map(i -> ssTableName.cloneWithDifferntRegionId(i))
.collect(Collectors.toList());
}
/**
* Add a new mapping
* @param tablename
* @param boundingBox
*/
public boolean addMapping(final long regionId, final Hyperrectangle boundingBox) {
if(regions.containsKey(regionId)) {
logger.debug("Mapping for region {} / {} already exists, ignoring",
regionId, distributionGroup);
return false;
}
logger.info("Add local mapping for: {} / {}", regionId, distributionGroup);
regions.put(regionId, boundingBox);
synchronized (MUTEX) {
MUTEX.notifyAll();
}
return true;
}
/**
* Remove a mapping
* @return
*/
public boolean removeMapping(final long regionId) {
final boolean removed = regions.containsKey(regionId);
regions.remove(regionId);
if(removed) {
logger.info("Mapping for region id {} / {} removed", regionId, distributionGroup);
}
synchronized (MUTEX) {
MUTEX.notifyAll();
}
return removed;
}
/**
* Remove all mappings
*/
public void clear() {
logger.info("Clear all local mappings in {}", distributionGroup);
regions.clear();
synchronized (MUTEX) {
MUTEX.notifyAll();
}
}
/**
* Wait until mapping appears
* @param regionId
* @throws InterruptedException
* @throws TimeoutException
*/
public void waitUntilMappingAppears(final long regionId) throws TimeoutException, InterruptedException {
waitUntilMappingAppears(regionId, 30, TimeUnit.SECONDS);
}
/**
* Wait until mapping appears
* @param regionId
* @throws TimeoutException
* @throws InterruptedException
*/
public void waitUntilMappingAppears(final long regionId, final int maxWaitTime,
final TimeUnit timeUnit) throws TimeoutException, InterruptedException {
final Predicate> mappingAppearsPredicate = (l) -> (l.contains(regionId));
waitUntilChangeHappens(regionId, maxWaitTime, timeUnit, mappingAppearsPredicate);
}
/**
* Wait until a mapping disappears
* @param regionId
* @throws InterruptedException
* @throws TimeoutException
*/
public void waitUntilMappingDisappears(final long regionId) throws TimeoutException, InterruptedException {
waitUntilMappingDisappears(regionId, 30, TimeUnit.SECONDS);
}
/**
* Wait until a mapping disappears
* @param regionId
* @throws InterruptedException
* @throws TimeoutException
*/
public void waitUntilMappingDisappears(final long regionId, final int maxWaitTime,
final TimeUnit timeUnit) throws TimeoutException, InterruptedException {
final Predicate> mappingAppearsPredicate = (l) -> (! l.contains(regionId));
waitUntilChangeHappens(regionId, maxWaitTime, timeUnit, mappingAppearsPredicate);
}
/**
* Test until a change happens
* @param regionId
* @param maxWaitTime
* @param timeUnit
* @param predicate
* @throws TimeoutException
* @throws InterruptedException
*/
private void waitUntilChangeHappens(final long regionId, final int maxWaitTime,
final TimeUnit timeUnit, final Predicate> predicate)
throws TimeoutException, InterruptedException {
final Stopwatch stopwatch = Stopwatch.createStarted();
final long waitTimeInMilis = timeUnit.toMillis(maxWaitTime);
while(! predicate.test(getAllRegionIds())) {
synchronized (MUTEX) {
final long timeToWait = waitTimeInMilis - stopwatch.elapsed(TimeUnit.MILLISECONDS);
MUTEX.wait(timeToWait);
final long passedTime = stopwatch.elapsed(TimeUnit.MILLISECONDS);
if(passedTime >= waitTimeInMilis) {
throw new TimeoutException("Timeout after waiting " + passedTime + " ms");
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy