/*
* DBeaver - Universal Database Manager
* Copyright (C) 2017 Andrew Khitrin (ahitrin@gmail.com)
*
* 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.jkiss.dbeaver.ext.ui.locks.manage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jkiss.dbeaver.ext.ui.locks.graph.LockGraph;
import org.jkiss.dbeaver.ext.ui.locks.graph.LockGraphEdge;
import org.jkiss.dbeaver.ext.ui.locks.graph.LockGraphNode;
import org.jkiss.dbeaver.model.admin.locks.DBAServerLock;
public abstract class LockGraphManager<LOCK_TYPE extends DBAServerLock<?>, ID_TYPE> {
private Map<ID_TYPE,LockGraphNode> nodes = new HashMap<ID_TYPE,LockGraphNode>();
private Map<ID_TYPE,LockGraph> graphIndex = new HashMap<ID_TYPE,LockGraph>();
public LockGraph getGraph(DBAServerLock<?> curLock) {
LockGraphNode selection = nodes.get(curLock.getId());
LockGraph graph = graphIndex.get(curLock.getId());
if (graph != null && selection != null) {
graph.setSelection(selection);
}
return graph;
}
@SuppressWarnings("unchecked")
private LockGraph createGraph(LOCK_TYPE root) {
LockGraph graph = new LockGraph(root);
int maxWidth = 1;
int level = 1;
LockGraphNode nodeRoot = nodes.get(root.getId());
nodeRoot.setLevel(0);
nodeRoot.setSpan(1);
graph.getNodes().add(nodeRoot);
graphIndex.put((ID_TYPE) root.getId(), graph);
List<LOCK_TYPE> current = new ArrayList<LOCK_TYPE>();
Set<DBAServerLock<ID_TYPE>> touched = new HashSet<>(); //Prevent Cycle
current.add(root);
touched.add((DBAServerLock<ID_TYPE>) root);
Map<ID_TYPE,DBAServerLock<ID_TYPE>> childs = new HashMap<ID_TYPE,DBAServerLock<ID_TYPE>>();
while(current.size() > 0) {
if (maxWidth < current.size()) {
maxWidth = current.size();
}
for(int index = 0; index < current.size(); index++) {
DBAServerLock<ID_TYPE> l = (DBAServerLock<ID_TYPE>) current.get(index);
LockGraphNode node = nodes.get(l.getId());
if (index == 0) {
node.setLevelPosition(LockGraphNode.LevelPosition.LEFT);
} else if (index == current.size() - 1) {
node.setLevelPosition(LockGraphNode.LevelPosition.RIGHT);
} else {
node.setLevelPosition(LockGraphNode.LevelPosition.CENTER);
}
node.setSpan(current.size());
for(DBAServerLock<ID_TYPE> c : l.waitThis()) {
if (touched.contains(c)) continue;
touched.add(c);
childs.put(c.getId(), c);
graphIndex.put(c.getId(), graph);
LockGraphNode nodeChild = nodes.get(c.getId());
graph.getNodes().add(nodeChild);
nodeChild.setLevel(level);
LockGraphEdge edge = new LockGraphEdge();
edge.setSource(node);
edge.setTarget(nodeChild);
}
}
level++;
current = new ArrayList<LOCK_TYPE>((Collection<? extends LOCK_TYPE>) childs.values());
childs.clear();
}
graph.setMaxWidth(maxWidth);
return graph;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public void buildGraphs(Map<ID_TYPE,LOCK_TYPE> locks) {
Set<LOCK_TYPE> roots = new HashSet<LOCK_TYPE>();
this.nodes.clear();
this.graphIndex.clear();
for(LOCK_TYPE l: locks.values()) {
if (locks.containsKey(l.getHoldID()) && (!l.getHoldID().equals(l.getId()))) {
LOCK_TYPE holder = locks.get(l.getHoldID());
l.setHoldBy(holder);
holder.waitThis().add((DBAServerLock) l);
} else {
roots.add(l);
}
nodes.put((ID_TYPE) l.getId(), new LockGraphNode(l));
}
for(LOCK_TYPE root : roots) {
if (root.waitThis().size() >= 0)
createGraph(root);
}
}
}