All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bboxdb.distribution.region.DistributionRegion 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.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import org.bboxdb.commons.math.Hyperrectangle;
import org.bboxdb.distribution.membership.BBoxDBInstance;
import org.bboxdb.distribution.partitioner.DistributionRegionState;
import org.bboxdb.storage.entity.DistributionGroupHelper;

public class DistributionRegion {

	/**
	 * The name of the distribution group
	 */
	private final String distributionGroupName;

	/**
	 * The left child
	 */
	private final Map children;
		
	/**
	 * The parent of this node
	 */
	private final DistributionRegion parent;

	/**
	 * The area that is covered
	 */
	private final Hyperrectangle converingBox;
	
	/**
	 * The state of the region
	 */
	private DistributionRegionState state = DistributionRegionState.CREATING;
	
	/**
	 * The systems
	 */
	private Collection systems;
	
	/**
	 * The id of the region
	 */
	private final long regionid;
	
	/**
	 * The root pointer of the root element of the tree
	 */
	public final static DistributionRegion ROOT_NODE_ROOT_POINTER = null;

	public DistributionRegion(final String name, final Hyperrectangle boundingBox) {
		this(name, ROOT_NODE_ROOT_POINTER, boundingBox, 0);
	}
	
	/**
	 * @param name
	 * @param boundingBox 
	 * @param level
	 */
	public DistributionRegion(final String name, final DistributionRegion parent,
			final Hyperrectangle boundingBox, final long regionid) {
		
		if(! DistributionGroupHelper.validateDistributionGroupName(name)) {
			throw new IllegalArgumentException("Invalid distribution group specified");
		}
		
		this.distributionGroupName = name;
		this.converingBox = boundingBox;
		this.parent = parent;
		this.regionid = regionid;
		this.systems = new ArrayList<>();
		this.children = new ConcurrentHashMap<>();
	}

	/**
	 * Get the parent of the node
	 * @return
	 */
	public DistributionRegion getParent() {
		return parent;
	}

	/**
	 * Get the children of the region
	 * @return
	 */
	public List getDirectChildren() {
		return new ArrayList<>(children.values());
	}
	
	/**
	 * Get all the children of the region
	 * @return
	 */
	public List getAllChildren() {
		final List result = new ArrayList<>();
		
		for(final DistributionRegion child : children.values()) {
			result.add(child);
			result.addAll(child.getAllChildren());
		}
		
		return result;
	}
	
	/**
	 * Get all distribution regions
	 * @return
	 */
	public List getThisAndChildRegions() {
		final List result = new ArrayList<>();
		result.add(this);
		result.addAll(getAllChildren());
		return result;
	}
	
	/**
	 * Set the childs to state active
	 */
	public void makeChildsActive() {
		for(final DistributionRegion child : children.values()) {
			child.setState(DistributionRegionState.ACTIVE);
		}
	}

	/**
	 * Merge the distribution group
	 */
	public void merge() {
		children.clear();
	}
	
	/**
	 * Get the state of the node
	 * @return
	 */
	public DistributionRegionState getState() {
		return state;
	}

	/**
	 * Set the state of the node
	 * @param state
	 */
	public void setState(final DistributionRegionState state) {
		this.state = state;
	}

	/**
	 * Get the level of the region
	 * @return
	 */
	public int getLevel() {
		int levelCounter = 0;
		
		DistributionRegion parent = this.getParent();
		
		while(parent != null) {
			parent = parent.getParent();
			levelCounter++;
		}
		
		return levelCounter;
	}
	
	/**
	 * Get the number of levels in this tree
	 * @return
	 */
	public int getTotalLevel() {		
		return getRootRegion().getAllChildren()
				.stream()
				.mapToInt(d -> d.getLevel())
				.max()
				.orElse(0) + 1;
	}
	
	/**
	 * Get the highest child number
	 */
	public long getHighestChildNumber() {
		return children.keySet().stream().mapToLong(l -> l).max().orElse(0);
	}

	@Override
	public String toString() {
		return "DistributionRegion [distributionGroupName=" + distributionGroupName
				+ ", converingBox=" + converingBox.toCompactString() + ", state=" + state
				+ ", systems=" + systems + ", nameprefix=" + regionid + "]";
	}

	/**
	 * Get the root element of the region
	 */
	public DistributionRegion getRootRegion() {
		DistributionRegion currentElement = this;
		
		// Follow the links to the root element
		while(currentElement.parent != ROOT_NODE_ROOT_POINTER) {
			currentElement = currentElement.parent;
		}
		
		return currentElement;
	}
	
	/**
	 * Is this a leaf region node?
	 * @return
	 */
	public boolean isLeafRegion() {
		return getDirectChildren().isEmpty();
	}
	
	/**
	 * Add a new child
	 * @param newChild
	 */
	public void addChildren(final long childNumber, final DistributionRegion newChild) {
		
		if(newChild.getParent() != this) {
			throw new IllegalArgumentException("Parent of child " + newChild + " is not this " + this);
		}
		
		if(children.containsKey(childNumber)) {
			throw new IllegalArgumentException("Child with id " + childNumber + " already exists");
		}
		
		children.put(childNumber, newChild);
	}
	
	/**
	 * Get the child with the given number
	 * @param childNumber
	 * @return
	 */
	public DistributionRegion getChildNumber(final long childNumber) {
		return children.get(childNumber);
	}
	
	/**
	 * Get all known children numbers
	 * @return
	 */
	public List getAllChildrenNumbers() {
		return new ArrayList<>(children.keySet());
	}
	
	/**
	 * Has this node childs?
	 * @return
	 */
	public boolean hasChilds() {
		return ! children.isEmpty();
	}
	
	/**
	 * Remove the children
	 */
	public void removeAllChildren() {
		children.clear();
	}
	
	/**
	 * Remove the children
	 * @return 
	 */
	public DistributionRegion removeChildren(final long childrenNumber) {
		return children.remove(childrenNumber);
	}

	/**
	 * Is this the root element?
	 */
	public boolean isRootElement() {
		return (parent == ROOT_NODE_ROOT_POINTER);
	}
	
	/**
	 * Get the child number
	 * @return
	 */
	public long getChildNumberOfParent() {
		
		// This is the root element
		if(isRootElement()) {
			return 0;
		}
		
		return getParent().children.entrySet()
			.stream()
			.filter(e -> e.getValue() == this)
			.map(e -> e.getKey())
			.findAny()
			.orElseThrow(() -> new RuntimeException("Unable to find child number for: " + this));
	}

	/**
	 * Get the covering bounding box
	 * @return
	 */
	public Hyperrectangle getConveringBox() {
		return converingBox;
	}

	/**
	 * Returns get the distribution group name
	 * @return
	 */
	public String getDistributionGroupName() {
		return distributionGroupName;
	}
	
	/**
	 * Get a unique identifier for this region
	 * @return
	 */
	public String getIdentifier() {
		return distributionGroupName + "_" + regionid;
	}
	
	/**
	 * Get all systems that are responsible for this DistributionRegion
	 * @return
	 */
	public List getSystems() {
		return new ArrayList<>(systems);
	}
	
	/**
	 * Add a system to this DistributionRegion
	 * @param system
	 */
	public void addSystem(final BBoxDBInstance system) {
		systems.add(system);
	}
	
	/**
	 * Set the systems for this DistributionRegion
	 * @param newSystems
	 */
	public void setSystems(final Collection newSystems) {
		
		if(newSystems == null || newSystems.isEmpty()) {
			systems.clear();
			return;
		}
		
		final List newSystemsList = new ArrayList<>(newSystems.size());
		newSystemsList.addAll(newSystems);
		
		// Replace systems atomically
		this.systems = newSystemsList;
	}
	
	/**
	 * Get the DistributionRegions for a given bounding box 
	 * @param boundingBox
	 * @return
	 */
	public List getDistributionRegionsForBoundingBox(final Hyperrectangle boundingBox) {
		return getThisAndChildRegions().stream()
			.filter(r -> r.getConveringBox().overlaps(boundingBox))
			.collect(Collectors.toList());
	}
	
	/**
	 * Get the region id of the node
	 * @return
	 */
	public long getRegionId() {
		return regionid;
	}
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy