Toggle navigation
Toggle navigation
This project
Loading...
Sign in
홍길동
/
onos
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
alshabib
2014-09-10 17:55:25 -0700
Browse Files
Options
Browse Files
Download
Plain Diff
Commit
f5868c0e4beb2d2adabdbd6a1a4d8640b3a01206
f5868c0e
2 parents
c944fd06
8ccc0bf0
Merge branch 'master' of
ssh://gerrit.onlab.us:29418/onos-next
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
1260 additions
and
103 deletions
core/api/src/main/java/org/onlab/onos/event/AbstractEvent.java
core/api/src/main/java/org/onlab/onos/event/AbstractEventAccumulator.java
core/api/src/main/java/org/onlab/onos/event/EventAccumulator.java
core/api/src/main/java/org/onlab/onos/net/topology/TopologyService.java
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/DefaultTopology.java
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/DefaultTopologyDescription.java
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceManager.java
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleHostManager.java
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleLinkManager.java
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleLinkStore.java
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyManager.java
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyProvider.java
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyStore.java
core/trivial/src/test/java/org/onlab/onos/event/impl/SimpleEventDispatcherTest.java
utils/misc/src/main/java/org/onlab/graph/AdjacencyListsGraph.java
utils/misc/src/main/java/org/onlab/graph/TarjanGraphSearch.java
utils/misc/src/test/java/org/onlab/graph/BellmanFordGraphSearchTest.java
utils/misc/src/test/java/org/onlab/graph/BreadthFirstSearchTest.java
utils/misc/src/test/java/org/onlab/graph/DepthFirstSearchTest.java
utils/misc/src/test/java/org/onlab/graph/DijkstraGraphSearchTest.java
utils/misc/src/test/java/org/onlab/graph/GraphTest.java
utils/misc/src/test/java/org/onlab/graph/TarjanGraphSearchTest.java
core/api/src/main/java/org/onlab/onos/event/AbstractEvent.java
View file @
f5868c0
package
org
.
onlab
.
onos
.
event
;
import
static
com
.
google
.
common
.
base
.
MoreObjects
.
toStringHelper
;
/**
* Base event implementation.
*/
...
...
@@ -48,4 +50,10 @@ public class AbstractEvent<T extends Enum, S extends Object> implements Event<T,
return
subject
;
}
@Override
public
String
toString
()
{
return
toStringHelper
(
this
).
add
(
"time"
,
time
).
add
(
"type"
,
type
())
.
add
(
"subject"
,
subject
()).
toString
();
}
}
...
...
core/api/src/main/java/org/onlab/onos/event/AbstractEventAccumulator.java
0 → 100644
View file @
f5868c0
package
org
.
onlab
.
onos
.
event
;
import
com.google.common.collect.Lists
;
import
java.util.List
;
import
java.util.Timer
;
import
java.util.TimerTask
;
import
static
com
.
google
.
common
.
base
.
Preconditions
.
checkArgument
;
import
static
com
.
google
.
common
.
base
.
Preconditions
.
checkNotNull
;
/**
* Base implementation of an event accumulator. It allows triggering based on
* event inter-arrival time threshold, maximum batch life threshold and maximum
* batch size.
*/
public
abstract
class
AbstractEventAccumulator
implements
EventAccumulator
{
private
final
Timer
timer
;
private
final
int
maxEvents
;
private
final
int
maxBatchMillis
;
private
final
int
maxIdleMillis
;
private
TimerTask
idleTask
=
new
ProcessorTask
();
private
TimerTask
maxTask
=
new
ProcessorTask
();
private
List
<
Event
>
events
=
Lists
.
newArrayList
();
/**
* Creates an event accumulator capable of triggering on the specified
* thresholds.
*
* @param timer timer to use for scheduling check-points
* @param maxEvents maximum number of events to accumulate before
* processing is triggered
* @param maxBatchMillis maximum number of millis allowed since the first
* event before processing is triggered
* @param maxIdleMillis maximum number millis between events before
* processing is triggered
*/
protected
AbstractEventAccumulator
(
Timer
timer
,
int
maxEvents
,
int
maxBatchMillis
,
int
maxIdleMillis
)
{
this
.
timer
=
checkNotNull
(
timer
,
"Timer cannot be null"
);
checkArgument
(
maxEvents
>
1
,
"Maximum number of events must be > 1"
);
checkArgument
(
maxBatchMillis
>
0
,
"Maximum millis must be positive"
);
checkArgument
(
maxIdleMillis
>
0
,
"Maximum idle millis must be positive"
);
this
.
maxEvents
=
maxEvents
;
this
.
maxBatchMillis
=
maxBatchMillis
;
this
.
maxIdleMillis
=
maxIdleMillis
;
}
@Override
public
void
add
(
Event
event
)
{
idleTask
=
cancelIfActive
(
idleTask
);
events
.
add
(
event
);
// Did we hit the max event threshold?
if
(
events
.
size
()
==
maxEvents
)
{
maxTask
=
cancelIfActive
(
maxTask
);
schedule
(
1
);
}
else
{
// Otherwise, schedule idle task and if this is a first event
// also schedule the max batch age task.
idleTask
=
schedule
(
maxIdleMillis
);
if
(
events
.
size
()
==
1
)
{
maxTask
=
schedule
(
maxBatchMillis
);
}
}
}
// Schedules a new processor task given number of millis in the future.
private
TimerTask
schedule
(
int
millis
)
{
TimerTask
task
=
new
ProcessorTask
();
timer
.
schedule
(
task
,
millis
);
return
task
;
}
// Cancels the specified task if it is active.
private
TimerTask
cancelIfActive
(
TimerTask
task
)
{
if
(
task
!=
null
)
{
task
.
cancel
();
}
return
task
;
}
// Task for triggering processing of accumulated events
private
class
ProcessorTask
extends
TimerTask
{
@Override
public
void
run
()
{
idleTask
=
cancelIfActive
(
idleTask
);
maxTask
=
cancelIfActive
(
maxTask
);
processEvents
(
finalizeCurrentBatch
());
}
}
// Demotes and returns the current batch of events and promotes a new one.
private
synchronized
List
<
Event
>
finalizeCurrentBatch
()
{
List
<
Event
>
toBeProcessed
=
events
;
events
=
Lists
.
newArrayList
();
return
toBeProcessed
;
}
/**
* Returns the backing timer.
*
* @return backing timer
*/
public
Timer
timer
()
{
return
timer
;
}
/**
* Returns the maximum number of events allowed to accumulate before
* processing is triggered.
*
* @return max number of events
*/
public
int
maxEvents
()
{
return
maxEvents
;
}
/**
* Returns the maximum number of millis allowed to expire since the first
* event before processing is triggered.
*
* @return max number of millis a batch is allowed to last
*/
public
int
maxBatchMillis
()
{
return
maxBatchMillis
;
}
/**
* Returns the maximum number of millis allowed to expire since the last
* event arrival before processing is triggered.
*
* @return max number of millis since the last event
*/
public
int
maxIdleMillis
()
{
return
maxIdleMillis
;
}
}
core/api/src/main/java/org/onlab/onos/event/EventAccumulator.java
0 → 100644
View file @
f5868c0
package
org
.
onlab
.
onos
.
event
;
import
java.util.List
;
/**
* Abstraction of an accumulator capable of collecting events and at some
* point in time triggers processing of all previously accumulated events.
*/
public
interface
EventAccumulator
{
/**
* Adds an event to the current batch. This operation may, or may not
* trigger processing of the current batch of events.
*
* @param event event to be added to the current batch
*/
void
add
(
Event
event
);
/**
* Processes the specified list of accumulated events.
*
* @param events list of accumulated events
*/
void
processEvents
(
List
<
Event
>
events
);
}
core/api/src/main/java/org/onlab/onos/net/topology/TopologyService.java
View file @
f5868c0
...
...
@@ -20,6 +20,13 @@ public interface TopologyService {
Topology
currentTopology
();
/**
* Indicates whether the specified topology is the latest or not.
* @param topology topology descriptor
* @return true if the topology is the most recent; false otherwise
*/
boolean
isLatest
(
Topology
topology
);
/**
* Returns the set of clusters in the specified topology.
*
* @param topology topology descriptor
...
...
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/DefaultTopology.java
0 → 100644
View file @
f5868c0
package
org
.
onlab
.
onos
.
net
.
trivial
.
impl
;
import
org.onlab.onos.net.AbstractModel
;
import
org.onlab.onos.net.provider.ProviderId
;
import
org.onlab.onos.net.topology.Topology
;
/**
* Default implementation of the topology descriptor. This carries the
* backing topology data.
*/
public
class
DefaultTopology
extends
AbstractModel
implements
Topology
{
private
final
long
time
;
private
final
int
clusterCount
;
private
final
int
deviceCount
;
private
final
int
linkCount
;
private
final
int
pathCount
;
/**
* Creates a topology descriptor attributed to the specified provider.
*
* @param providerId identity of the provider
* @param time creation time in system nanos
* @param clusterCount number of clusters
* @param deviceCount number of devices
* @param linkCount number of links
* @param pathCount number of pre-computed paths
*/
DefaultTopology
(
ProviderId
providerId
,
long
time
,
int
clusterCount
,
int
deviceCount
,
int
linkCount
,
int
pathCount
)
{
super
(
providerId
);
this
.
time
=
time
;
this
.
clusterCount
=
clusterCount
;
this
.
deviceCount
=
deviceCount
;
this
.
linkCount
=
linkCount
;
this
.
pathCount
=
pathCount
;
}
@Override
public
long
time
()
{
return
time
;
}
@Override
public
int
clusterCount
()
{
return
clusterCount
;
}
@Override
public
int
deviceCount
()
{
return
deviceCount
;
}
@Override
public
int
linkCount
()
{
return
linkCount
;
}
@Override
public
int
pathCount
()
{
return
pathCount
;
}
}
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/DefaultTopologyDescription.java
View file @
f5868c0
package
org
.
onlab
.
onos
.
net
.
trivial
.
impl
;
import
com.google.common.collect.ImmutableSet
;
import
com.google.common.collect.Multimap
;
import
com.google.common.collect.Maps
;
import
com.google.common.collect.Sets
;
import
org.onlab.graph.AdjacencyListsGraph
;
import
org.onlab.graph.DijkstraGraphSearch
;
import
org.onlab.graph.Graph
;
import
org.onlab.graph.GraphPathSearch
;
import
org.onlab.onos.net.ConnectPoint
;
import
org.onlab.onos.net.Device
;
import
org.onlab.onos.net.DeviceId
;
import
org.onlab.onos.net.Link
;
import
org.onlab.onos.net.topology.ClusterId
;
import
org.onlab.onos.net.topology.LinkWeight
;
import
org.onlab.onos.net.topology.TopoEdge
;
import
org.onlab.onos.net.topology.TopoVertex
;
import
org.onlab.onos.net.topology.TopologyCluster
;
import
org.onlab.onos.net.topology.TopologyDescription
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.Set
;
import
static
com
.
google
.
common
.
base
.
MoreObjects
.
toStringHelper
;
import
static
org
.
onlab
.
graph
.
GraphPathSearch
.
Result
;
import
static
org
.
onlab
.
onos
.
net
.
Link
.
Type
.
INDIRECT
;
/**
* Default implementation of an immutable topology data carrier.
*/
public
class
DefaultTopologyDescription
implements
TopologyDescription
{
class
DefaultTopologyDescription
implements
TopologyDescription
{
private
static
final
GraphPathSearch
<
TopoVertex
,
TopoEdge
>
DIJKSTRA
=
new
DijkstraGraphSearch
<>();
private
final
long
nanos
;
private
final
Map
<
DeviceId
,
TopoVertex
>
vertexesById
=
Maps
.
newHashMap
();
private
final
Graph
<
TopoVertex
,
TopoEdge
>
graph
;
private
final
Map
<
DeviceId
,
GraphPathSearch
.
Result
<
TopoVertex
,
TopoEdge
>>
results
;
private
final
Map
<
DeviceId
,
Result
<
TopoVertex
,
TopoEdge
>>
results
;
private
final
Map
<
ClusterId
,
TopologyCluster
>
clusters
;
private
final
Multimap
<
ClusterId
,
DeviceId
>
clusterDevices
;
private
final
Multimap
<
ClusterId
,
Link
>
clusterLinks
;
private
final
Map
<
DeviceId
,
TopologyCluster
>
deviceClusters
;
public
DefaultTopologyDescription
(
long
nanos
,
Graph
<
TopoVertex
,
TopoEdge
>
graph
,
Map
<
DeviceId
,
GraphPathSearch
.
Result
<
TopoVertex
,
TopoEdge
>>
results
,
Map
<
ClusterId
,
TopologyCluster
>
clusters
,
Multimap
<
ClusterId
,
DeviceId
>
clusterDevices
,
Multimap
<
ClusterId
,
Link
>
clusterLinks
,
Map
<
DeviceId
,
TopologyCluster
>
deviceClusters
)
{
// private final Multimap<ClusterId, DeviceId> clusterDevices;
// private final Multimap<ClusterId, Link> clusterLinks;
// private final Map<DeviceId, TopologyCluster> deviceClusters;
DefaultTopologyDescription
(
long
nanos
,
Iterable
<
Device
>
devices
,
Iterable
<
Link
>
links
)
{
this
.
nanos
=
nanos
;
this
.
graph
=
graph
;
this
.
results
=
results
;
this
.
clusters
=
clusters
;
this
.
clusterDevices
=
clusterDevices
;
this
.
clusterLinks
=
clusterLinks
;
this
.
deviceClusters
=
deviceClusters
;
this
.
graph
=
buildGraph
(
devices
,
links
);
this
.
results
=
computeDefaultPaths
();
this
.
clusters
=
computeClusters
();
// this.clusterDevices = clusterDevices;
// this.clusterLinks = clusterLinks;
// this.deviceClusters = deviceClusters;
}
// Constructs the topology graph using the supplied devices and links.
private
Graph
<
TopoVertex
,
TopoEdge
>
buildGraph
(
Iterable
<
Device
>
devices
,
Iterable
<
Link
>
links
)
{
Graph
<
TopoVertex
,
TopoEdge
>
graph
=
new
AdjacencyListsGraph
<>(
buildVertexes
(
devices
),
buildEdges
(
links
));
return
graph
;
}
// Builds a set of topology vertexes from the specified list of devices
private
Set
<
TopoVertex
>
buildVertexes
(
Iterable
<
Device
>
devices
)
{
Set
<
TopoVertex
>
vertexes
=
Sets
.
newHashSet
();
for
(
Device
device
:
devices
)
{
TopoVertex
vertex
=
new
TVertex
(
device
.
id
());
vertexesById
.
put
(
vertex
.
deviceId
(),
vertex
);
vertexes
.
add
(
vertex
);
}
return
vertexes
;
}
// Builds a set of topology vertexes from the specified list of links
private
Set
<
TopoEdge
>
buildEdges
(
Iterable
<
Link
>
links
)
{
Set
<
TopoEdge
>
edges
=
Sets
.
newHashSet
();
for
(
Link
link
:
links
)
{
edges
.
add
(
new
TEdge
(
vertexOf
(
link
.
src
()),
vertexOf
(
link
.
dst
()),
link
));
}
return
edges
;
}
// Computes the default shortest paths for all source/dest pairs using
// the multi-path Dijkstra and hop-count as path cost.
private
Map
<
DeviceId
,
Result
<
TopoVertex
,
TopoEdge
>>
computeDefaultPaths
()
{
LinkWeight
weight
=
new
HopCountLinkWeight
(
graph
.
getVertexes
().
size
());
Map
<
DeviceId
,
Result
<
TopoVertex
,
TopoEdge
>>
results
=
Maps
.
newHashMap
();
// Search graph paths for each source to all destinations.
for
(
TopoVertex
src
:
vertexesById
.
values
())
{
results
.
put
(
src
.
deviceId
(),
DIJKSTRA
.
search
(
graph
,
src
,
null
,
weight
));
}
return
results
;
}
// Computes topology SCC clusters using Tarjan algorithm.
private
Map
<
ClusterId
,
TopologyCluster
>
computeClusters
()
{
Map
<
ClusterId
,
TopologyCluster
>
clusters
=
Maps
.
newHashMap
();
return
clusters
;
}
// Fetches a vertex corresponding to the given connection point device.
private
TopoVertex
vertexOf
(
ConnectPoint
connectPoint
)
{
DeviceId
id
=
connectPoint
.
deviceId
();
TopoVertex
vertex
=
vertexesById
.
get
(
id
);
if
(
vertex
==
null
)
{
// If vertex does not exist, create one and register it.
vertex
=
new
TVertex
(
id
);
vertexesById
.
put
(
id
,
vertex
);
}
return
vertex
;
}
@Override
...
...
@@ -54,7 +125,7 @@ public class DefaultTopologyDescription implements TopologyDescription {
}
@Override
public
GraphPathSearch
.
Result
<
TopoVertex
,
TopoEdge
>
pathResults
(
DeviceId
srcDeviceId
)
{
public
Result
<
TopoVertex
,
TopoEdge
>
pathResults
(
DeviceId
srcDeviceId
)
{
return
results
.
get
(
srcDeviceId
);
}
...
...
@@ -75,6 +146,105 @@ public class DefaultTopologyDescription implements TopologyDescription {
@Override
public
TopologyCluster
clusterFor
(
DeviceId
deviceId
)
{
return
deviceClusters
.
get
(
deviceId
);
return
null
;
// deviceClusters.get(deviceId);
}
// Implementation of the topology vertex backed by a device id
private
static
class
TVertex
implements
TopoVertex
{
private
final
DeviceId
deviceId
;
public
TVertex
(
DeviceId
deviceId
)
{
this
.
deviceId
=
deviceId
;
}
@Override
public
DeviceId
deviceId
()
{
return
deviceId
;
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
deviceId
);
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
obj
instanceof
TVertex
)
{
final
TVertex
other
=
(
TVertex
)
obj
;
return
Objects
.
equals
(
this
.
deviceId
,
other
.
deviceId
);
}
return
false
;
}
@Override
public
String
toString
()
{
return
deviceId
.
toString
();
}
}
// Implementation of the topology edge backed by a link
private
class
TEdge
implements
TopoEdge
{
private
final
Link
link
;
private
final
TopoVertex
src
;
private
final
TopoVertex
dst
;
public
TEdge
(
TopoVertex
src
,
TopoVertex
dst
,
Link
link
)
{
this
.
src
=
src
;
this
.
dst
=
dst
;
this
.
link
=
link
;
}
@Override
public
Link
link
()
{
return
link
;
}
@Override
public
TopoVertex
src
()
{
return
src
;
}
@Override
public
TopoVertex
dst
()
{
return
dst
;
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
link
);
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
obj
instanceof
TEdge
)
{
final
TEdge
other
=
(
TEdge
)
obj
;
return
Objects
.
equals
(
this
.
link
,
other
.
link
);
}
return
false
;
}
@Override
public
String
toString
()
{
return
toStringHelper
(
this
).
add
(
"src"
,
src
).
add
(
"dst"
,
dst
).
toString
();
}
}
// Link weight for measuring link cost as hop count with indirect links
// being as expensive as traversing the entire graph to assume the worst.
private
class
HopCountLinkWeight
implements
LinkWeight
{
private
final
int
indirectLinkCost
;
public
HopCountLinkWeight
(
int
indirectLinkCost
)
{
this
.
indirectLinkCost
=
indirectLinkCost
;
}
@Override
public
double
weight
(
TopoEdge
edge
)
{
// To force preference to use direct paths first, make indirect
// links as expensive as the linear vertex traversal.
return
edge
.
link
().
type
()
==
INDIRECT
?
indirectLinkCost
:
1
;
}
}
}
...
...
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceManager.java
View file @
f5868c0
...
...
@@ -150,7 +150,8 @@ public class SimpleDeviceManager
}
// Personalized device provider service issued to the supplied provider.
private
class
InternalDeviceProviderService
extends
AbstractProviderService
<
DeviceProvider
>
private
class
InternalDeviceProviderService
extends
AbstractProviderService
<
DeviceProvider
>
implements
DeviceProviderService
{
InternalDeviceProviderService
(
DeviceProvider
provider
)
{
...
...
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java
View file @
f5868c0
...
...
@@ -28,7 +28,8 @@ import static com.google.common.base.Preconditions.checkArgument;
import
static
org
.
onlab
.
onos
.
net
.
device
.
DeviceEvent
.
Type
.*;
/**
* Manages inventory of infrastructure DEVICES using trivial in-memory
* structures implementation.
*/
class
SimpleDeviceStore
{
...
...
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleHostManager.java
View file @
f5868c0
...
...
@@ -158,7 +158,7 @@ public class SimpleHostManager
// Posts the specified event to the local event dispatcher.
private
void
post
(
HostEvent
event
)
{
if
(
event
!=
null
&&
eventDispatcher
!=
null
)
{
if
(
event
!=
null
)
{
eventDispatcher
.
post
(
event
);
}
}
...
...
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleLinkManager.java
View file @
f5868c0
...
...
@@ -36,8 +36,8 @@ import com.google.common.collect.Sets;
@Component
(
immediate
=
true
)
@Service
public
class
SimpleLinkManager
extends
AbstractProviderRegistry
<
LinkProvider
,
LinkProviderService
>
implements
LinkService
,
LinkAdminService
,
LinkProviderRegistry
{
extends
AbstractProviderRegistry
<
LinkProvider
,
LinkProviderService
>
implements
LinkService
,
LinkAdminService
,
LinkProviderRegistry
{
private
static
final
String
DEVICE_ID_NULL
=
"Device ID cannot be null"
;
private
static
final
String
LINK_DESC_NULL
=
"Link description cannot be null"
;
...
...
@@ -46,7 +46,7 @@ implements LinkService, LinkAdminService, LinkProviderRegistry {
private
final
Logger
log
=
getLogger
(
getClass
());
private
final
AbstractListenerRegistry
<
LinkEvent
,
LinkListener
>
listenerRegistry
=
new
AbstractListenerRegistry
<>();
listenerRegistry
=
new
AbstractListenerRegistry
<>();
private
final
SimpleLinkStore
store
=
new
SimpleLinkStore
();
...
...
@@ -79,7 +79,7 @@ implements LinkService, LinkAdminService, LinkProviderRegistry {
public
Set
<
Link
>
getDeviceLinks
(
DeviceId
deviceId
)
{
checkNotNull
(
deviceId
,
DEVICE_ID_NULL
);
return
Sets
.
union
(
store
.
getDeviceEgressLinks
(
deviceId
),
store
.
getDeviceIngressLinks
(
deviceId
));
store
.
getDeviceIngressLinks
(
deviceId
));
}
@Override
...
...
@@ -98,7 +98,7 @@ implements LinkService, LinkAdminService, LinkProviderRegistry {
public
Set
<
Link
>
getLinks
(
ConnectPoint
connectPoint
)
{
checkNotNull
(
connectPoint
,
CONNECT_POINT_NULL
);
return
Sets
.
union
(
store
.
getEgressLinks
(
connectPoint
),
store
.
getIngressLinks
(
connectPoint
));
store
.
getIngressLinks
(
connectPoint
));
}
@Override
...
...
@@ -146,8 +146,9 @@ implements LinkService, LinkAdminService, LinkProviderRegistry {
}
// Personalized link provider service issued to the supplied provider.
private
class
InternalLinkProviderService
extends
AbstractProviderService
<
LinkProvider
>
implements
LinkProviderService
{
private
class
InternalLinkProviderService
extends
AbstractProviderService
<
LinkProvider
>
implements
LinkProviderService
{
InternalLinkProviderService
(
LinkProvider
provider
)
{
super
(
provider
);
...
...
@@ -157,27 +158,31 @@ implements LinkService, LinkAdminService, LinkProviderRegistry {
public
void
linkDetected
(
LinkDescription
linkDescription
)
{
checkNotNull
(
linkDescription
,
LINK_DESC_NULL
);
checkValidity
();
log
.
debug
(
"Link {} detected"
,
linkDescription
);
LinkEvent
event
=
store
.
createOrUpdateLink
(
provider
().
id
(),
linkDescription
);
post
(
event
);
linkDescription
);
if
(
event
!=
null
)
{
log
.
debug
(
"Link {} detected"
,
linkDescription
);
post
(
event
);
}
}
@Override
public
void
linkVanished
(
LinkDescription
linkDescription
)
{
checkNotNull
(
linkDescription
,
LINK_DESC_NULL
);
checkValidity
();
log
.
info
(
"Link {} vanished"
,
linkDescription
);
LinkEvent
event
=
store
.
removeLink
(
linkDescription
.
src
(),
linkDescription
.
dst
());
post
(
event
);
linkDescription
.
dst
());
if
(
event
!=
null
)
{
log
.
info
(
"Link {} vanished"
,
linkDescription
);
post
(
event
);
}
}
@Override
public
void
linksVanished
(
ConnectPoint
connectPoint
)
{
checkNotNull
(
connectPoint
,
"Connect point cannot be null"
);
checkValidity
();
log
.
info
(
"Link for connection point {} vanished"
,
connectPoint
);
log
.
info
(
"Link
s
for connection point {} vanished"
,
connectPoint
);
removeLinks
(
getLinks
(
connectPoint
));
}
...
...
@@ -185,7 +190,7 @@ implements LinkService, LinkAdminService, LinkProviderRegistry {
public
void
linksVanished
(
DeviceId
deviceId
)
{
checkNotNull
(
deviceId
,
DEVICE_ID_NULL
);
checkValidity
();
log
.
info
(
"Link for device {} vanished"
,
deviceId
);
log
.
info
(
"Link
s
for device {} vanished"
,
deviceId
);
removeLinks
(
getDeviceLinks
(
deviceId
));
}
}
...
...
@@ -200,7 +205,7 @@ implements LinkService, LinkAdminService, LinkProviderRegistry {
// Posts the specified event to the local event dispatcher.
private
void
post
(
LinkEvent
event
)
{
if
(
event
!=
null
&&
eventDispatcher
!=
null
)
{
if
(
event
!=
null
)
{
eventDispatcher
.
post
(
event
);
}
}
...
...
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleLinkStore.java
View file @
f5868c0
...
...
@@ -25,7 +25,7 @@ import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
import
static
org
.
onlab
.
onos
.
net
.
link
.
LinkEvent
.
Type
.
LINK_UPDATED
;
/**
* Manages inventory of infrastructure links using trivial in-memory
link
* Manages inventory of infrastructure links using trivial in-memory
structures
* implementation.
*/
class
SimpleLinkStore
{
...
...
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyManager.java
View file @
f5868c0
...
...
@@ -72,25 +72,26 @@ public class SimpleTopologyManager
}
@Override
p
rotected
TopologyProviderService
createProviderService
(
TopologyProvider
provider
)
{
return
new
InternalTopologyProviderService
(
provider
);
p
ublic
Topology
currentTopology
(
)
{
return
store
.
currentTopology
(
);
}
@Override
public
Topology
currentTopology
()
{
return
null
;
public
boolean
isLatest
(
Topology
topology
)
{
checkNotNull
(
topology
,
TOPOLOGY_NULL
);
return
store
.
isLatest
(
topology
);
}
@Override
public
Set
<
TopologyCluster
>
getClusters
(
Topology
topology
)
{
checkNotNull
(
topology
,
TOPOLOGY_NULL
);
return
null
;
return
store
.
getClusters
(
topology
)
;
}
@Override
public
Graph
<
TopoVertex
,
TopoEdge
>
getGraph
(
Topology
topology
)
{
checkNotNull
(
topology
,
TOPOLOGY_NULL
);
return
null
;
return
store
.
getGraph
(
topology
)
;
}
@Override
...
...
@@ -98,7 +99,7 @@ public class SimpleTopologyManager
checkNotNull
(
topology
,
TOPOLOGY_NULL
);
checkNotNull
(
src
,
DEVICE_ID_NULL
);
checkNotNull
(
dst
,
DEVICE_ID_NULL
);
return
null
;
return
store
.
getPaths
(
topology
,
src
,
dst
)
;
}
@Override
...
...
@@ -107,21 +108,21 @@ public class SimpleTopologyManager
checkNotNull
(
src
,
DEVICE_ID_NULL
);
checkNotNull
(
dst
,
DEVICE_ID_NULL
);
checkNotNull
(
weight
,
"Link weight cannot be null"
);
return
null
;
return
store
.
getPaths
(
topology
,
src
,
dst
,
weight
)
;
}
@Override
public
boolean
isInfrastructure
(
Topology
topology
,
ConnectPoint
connectPoint
)
{
checkNotNull
(
topology
,
TOPOLOGY_NULL
);
checkNotNull
(
connectPoint
,
CONNECTION_POINT_NULL
);
return
false
;
return
store
.
isInfrastructure
(
topology
,
connectPoint
)
;
}
@Override
public
boolean
isInBroadcastTree
(
Topology
topology
,
ConnectPoint
connectPoint
)
{
checkNotNull
(
topology
,
TOPOLOGY_NULL
);
checkNotNull
(
connectPoint
,
CONNECTION_POINT_NULL
);
return
false
;
return
store
.
isInBroadcastTree
(
topology
,
connectPoint
)
;
}
@Override
...
...
@@ -135,6 +136,11 @@ public class SimpleTopologyManager
}
// Personalized host provider service issued to the supplied provider.
@Override
protected
TopologyProviderService
createProviderService
(
TopologyProvider
provider
)
{
return
new
InternalTopologyProviderService
(
provider
);
}
private
class
InternalTopologyProviderService
extends
AbstractProviderService
<
TopologyProvider
>
implements
TopologyProviderService
{
...
...
@@ -147,8 +153,15 @@ public class SimpleTopologyManager
public
void
topologyChanged
(
TopologyDescription
topoDescription
,
List
<
Event
>
reasons
)
{
checkNotNull
(
topoDescription
,
"Topology description cannot be null"
);
log
.
info
(
"Topology changed due to: {}"
,
log
.
info
(
"Topology changed due to: {}"
,
// to be removed soon
reasons
==
null
?
"initial compute"
:
reasons
);
TopologyEvent
event
=
store
.
updateTopology
(
topoDescription
,
reasons
);
if
(
event
!=
null
)
{
log
.
info
(
"Topology changed due to: {}"
,
reasons
==
null
?
"initial compute"
:
reasons
);
eventDispatcher
.
post
(
event
);
}
}
}
...
...
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyProvider.java
0 → 100644
View file @
f5868c0
package
org
.
onlab
.
onos
.
net
.
trivial
.
impl
;
import
org.apache.felix.scr.annotations.Activate
;
import
org.apache.felix.scr.annotations.Component
;
import
org.apache.felix.scr.annotations.Deactivate
;
import
org.apache.felix.scr.annotations.Reference
;
import
org.apache.felix.scr.annotations.ReferenceCardinality
;
import
org.onlab.onos.event.AbstractEventAccumulator
;
import
org.onlab.onos.event.Event
;
import
org.onlab.onos.event.EventAccumulator
;
import
org.onlab.onos.net.device.DeviceEvent
;
import
org.onlab.onos.net.device.DeviceListener
;
import
org.onlab.onos.net.device.DeviceService
;
import
org.onlab.onos.net.link.LinkEvent
;
import
org.onlab.onos.net.link.LinkListener
;
import
org.onlab.onos.net.link.LinkService
;
import
org.onlab.onos.net.provider.AbstractProvider
;
import
org.onlab.onos.net.provider.ProviderId
;
import
org.onlab.onos.net.topology.TopologyDescription
;
import
org.onlab.onos.net.topology.TopologyProvider
;
import
org.onlab.onos.net.topology.TopologyProviderRegistry
;
import
org.onlab.onos.net.topology.TopologyProviderService
;
import
org.slf4j.Logger
;
import
java.util.List
;
import
java.util.Timer
;
import
java.util.concurrent.ExecutorService
;
import
static
java
.
util
.
concurrent
.
Executors
.
newFixedThreadPool
;
import
static
org
.
onlab
.
onos
.
net
.
device
.
DeviceEvent
.
Type
.*;
import
static
org
.
onlab
.
util
.
Tools
.
namedThreads
;
import
static
org
.
slf4j
.
LoggerFactory
.
getLogger
;
/**
* Simple implementation of a network topology provider/computor.
*/
@Component
(
immediate
=
true
)
public
class
SimpleTopologyProvider
extends
AbstractProvider
implements
TopologyProvider
{
// TODO: make these configurable
private
static
final
int
MAX_EVENTS
=
100
;
private
static
final
int
MAX_IDLE_MS
=
50
;
private
static
final
int
MAX_BATCH_MS
=
200
;
private
static
final
int
MAX_THREADS
=
8
;
// FIXME: Replace with a system-wide timer instance
private
static
final
Timer
TIMER
=
new
Timer
();
private
final
Logger
log
=
getLogger
(
getClass
());
@Reference
(
cardinality
=
ReferenceCardinality
.
MANDATORY_UNARY
)
protected
TopologyProviderRegistry
providerRegistry
;
@Reference
(
cardinality
=
ReferenceCardinality
.
MANDATORY_UNARY
)
protected
DeviceService
deviceService
;
@Reference
(
cardinality
=
ReferenceCardinality
.
MANDATORY_UNARY
)
protected
LinkService
linkService
;
private
volatile
boolean
isStarted
=
false
;
private
TopologyProviderService
providerService
;
private
DeviceListener
deviceListener
=
new
InnerDeviceListener
();
private
LinkListener
linkListener
=
new
InnerLinkListener
();
private
EventAccumulator
accumulator
;
private
ExecutorService
executor
;
/**
* Creates a provider with the supplier identifier.
*/
public
SimpleTopologyProvider
()
{
super
(
new
ProviderId
(
"org.onlab.onos.provider.topology"
));
}
@Activate
public
synchronized
void
activate
()
{
executor
=
newFixedThreadPool
(
MAX_THREADS
,
namedThreads
(
"topo-compute-%d"
));
accumulator
=
new
TopologyChangeAccumulator
();
providerService
=
providerRegistry
.
register
(
this
);
deviceService
.
addListener
(
deviceListener
);
linkService
.
addListener
(
linkListener
);
isStarted
=
true
;
triggerTopologyBuild
(
null
);
log
.
info
(
"Started"
);
}
@Deactivate
public
synchronized
void
deactivate
()
{
deviceService
.
removeListener
(
deviceListener
);
linkService
.
removeListener
(
linkListener
);
providerRegistry
.
unregister
(
this
);
providerService
=
null
;
executor
.
shutdownNow
();
executor
=
null
;
isStarted
=
false
;
log
.
info
(
"Stopped"
);
}
/**
* Triggers assembly of topology data citing the specified events as the
* reason.
*
* @param reasons events which triggered the topology change
*/
private
void
triggerTopologyBuild
(
List
<
Event
>
reasons
)
{
executor
.
execute
(
new
TopologyBuilderTask
(
reasons
));
}
// Builds the topology using the latest device and link information
// and citing the specified events as reasons for the change.
private
void
buildTopology
(
List
<
Event
>
reasons
)
{
log
.
info
(
"YO! Computing topology"
);
if
(
isStarted
)
{
TopologyDescription
desc
=
new
DefaultTopologyDescription
(
System
.
nanoTime
(),
deviceService
.
getDevices
(),
linkService
.
getLinks
());
providerService
.
topologyChanged
(
desc
,
reasons
);
}
}
// Callback for device events
private
class
InnerDeviceListener
implements
DeviceListener
{
@Override
public
void
event
(
DeviceEvent
event
)
{
DeviceEvent
.
Type
type
=
event
.
type
();
if
(
type
==
DEVICE_ADDED
||
type
==
DEVICE_REMOVED
||
type
==
DEVICE_AVAILABILITY_CHANGED
)
{
accumulator
.
add
(
event
);
}
}
}
// Callback for link events
private
class
InnerLinkListener
implements
LinkListener
{
@Override
public
void
event
(
LinkEvent
event
)
{
accumulator
.
add
(
event
);
}
}
// Event accumulator for paced triggering of topology assembly.
private
class
TopologyChangeAccumulator
extends
AbstractEventAccumulator
implements
EventAccumulator
{
TopologyChangeAccumulator
()
{
super
(
TIMER
,
MAX_EVENTS
,
MAX_BATCH_MS
,
MAX_IDLE_MS
);
}
@Override
public
void
processEvents
(
List
<
Event
>
events
)
{
triggerTopologyBuild
(
events
);
}
}
// Task for building topology data in a separate thread.
private
class
TopologyBuilderTask
implements
Runnable
{
private
final
List
<
Event
>
reasons
;
public
TopologyBuilderTask
(
List
<
Event
>
reasons
)
{
this
.
reasons
=
reasons
;
}
@Override
public
void
run
()
{
buildTopology
(
reasons
);
}
}
}
core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyStore.java
View file @
f5868c0
package
org
.
onlab
.
onos
.
net
.
trivial
.
impl
;
import
org.onlab.graph.Graph
;
import
org.onlab.onos.event.Event
;
import
org.onlab.onos.net.ConnectPoint
;
import
org.onlab.onos.net.DeviceId
;
import
org.onlab.onos.net.Path
;
import
org.onlab.onos.net.topology.LinkWeight
;
import
org.onlab.onos.net.topology.TopoEdge
;
import
org.onlab.onos.net.topology.TopoVertex
;
import
org.onlab.onos.net.topology.Topology
;
import
org.onlab.onos.net.topology.TopologyCluster
;
import
org.onlab.onos.net.topology.TopologyDescription
;
import
org.onlab.onos.net.topology.TopologyEvent
;
import
java.util.List
;
import
java.util.Set
;
/**
* Manages inventory of topology snapshots using trivial in-memory
* implementation.
*
structures
implementation.
*/
public
class
SimpleTopologyStore
{
class
SimpleTopologyStore
{
private
volatile
DefaultTopology
current
;
/**
* Returns the current topology snapshot.
*
* @return current topology descriptor
*/
Topology
currentTopology
()
{
return
current
;
}
/**
* Indicates whether the topology is the latest.
*
* @param topology topology descriptor
* @return true if topology is the most recent one
*/
boolean
isLatest
(
Topology
topology
)
{
// Topology is current only if it is the same as our current topology
return
topology
==
current
;
}
/**
* Returns the set of topology SCC clusters.
*
* @param topology topology descriptor
* @return set of clusters
*/
Set
<
TopologyCluster
>
getClusters
(
Topology
topology
)
{
return
null
;
}
/**
* Returns the immutable graph view of the current topology.
*
* @param topology topology descriptor
* @return graph view
*/
Graph
<
TopoVertex
,
TopoEdge
>
getGraph
(
Topology
topology
)
{
return
null
;
}
/**
* Returns the set of pre-computed shortest paths between src and dest.
*
* @param topology topology descriptor
* @param src source device
* @param dst destination device
* @return set of shortest paths
*/
Set
<
Path
>
getPaths
(
Topology
topology
,
DeviceId
src
,
DeviceId
dst
)
{
return
null
;
}
/**
* Computes and returns the set of shortest paths between src and dest.
*
* @param topology topology descriptor
* @param src source device
* @param dst destination device
* @param weight link weight function
* @return set of shortest paths
*/
Set
<
Path
>
getPaths
(
Topology
topology
,
DeviceId
src
,
DeviceId
dst
,
LinkWeight
weight
)
{
return
null
;
}
/**
* Indicates whether the given connect point is part of the network fabric.
*
* @param topology topology descriptor
* @param connectPoint connection point
* @return true if infrastructure; false otherwise
*/
boolean
isInfrastructure
(
Topology
topology
,
ConnectPoint
connectPoint
)
{
return
false
;
}
/**
* Indicates whether the given connect point is part of the broadcast tree.
*
* @param topology topology descriptor
* @param connectPoint connection point
* @return true if in broadcast tree; false otherwise
*/
boolean
isInBroadcastTree
(
Topology
topology
,
ConnectPoint
connectPoint
)
{
return
false
;
}
/**
* Generates a new topology snapshot from the specified description.
*
* @param topoDescription topology description
* @param reasons list of events that triggered the update
* @return topology update event or null if the description is old
*/
TopologyEvent
updateTopology
(
TopologyDescription
topoDescription
,
List
<
Event
>
reasons
)
{
return
null
;
}
}
...
...
core/trivial/src/test/java/org/onlab/onos/event/impl/SimpleEventDispatcherTest.java
0 → 100644
View file @
f5868c0
package
org
.
onlab
.
onos
.
event
.
impl
;
import
org.junit.After
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.onlab.onos.event.AbstractEvent
;
import
org.onlab.onos.event.EventSink
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.TimeUnit
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
/**
* Test of the even dispatcher mechanism.
*/
public
class
SimpleEventDispatcherTest
{
private
final
SimpleEventDispatcher
dispatcher
=
new
SimpleEventDispatcher
();
private
final
PrickleSink
prickleSink
=
new
PrickleSink
();
private
final
GooSink
gooSink
=
new
GooSink
();
@Before
public
void
setUp
()
{
dispatcher
.
activate
();
dispatcher
.
addSink
(
Prickle
.
class
,
prickleSink
);
dispatcher
.
addSink
(
Goo
.
class
,
gooSink
);
}
@After
public
void
tearDown
()
{
dispatcher
.
removeSink
(
Goo
.
class
);
dispatcher
.
removeSink
(
Prickle
.
class
);
dispatcher
.
deactivate
();
}
@Test
public
void
post
()
throws
Exception
{
prickleSink
.
latch
=
new
CountDownLatch
(
1
);
dispatcher
.
post
(
new
Prickle
(
"yo"
));
prickleSink
.
latch
.
await
(
100
,
TimeUnit
.
MILLISECONDS
);
validate
(
prickleSink
,
"yo"
);
validate
(
gooSink
);
}
@Test
public
void
postEventWithBadSink
()
throws
Exception
{
gooSink
.
latch
=
new
CountDownLatch
(
1
);
dispatcher
.
post
(
new
Goo
(
"boom"
));
gooSink
.
latch
.
await
(
100
,
TimeUnit
.
MILLISECONDS
);
validate
(
gooSink
,
"boom"
);
validate
(
prickleSink
);
}
@Test
public
void
postEventWithNoSink
()
throws
Exception
{
dispatcher
.
post
(
new
Thing
(
"boom"
));
validate
(
gooSink
);
validate
(
prickleSink
);
}
private
void
validate
(
Sink
sink
,
String
...
strings
)
{
int
i
=
0
;
assertEquals
(
"incorrect event count"
,
strings
.
length
,
sink
.
subjects
.
size
());
for
(
String
string
:
strings
)
{
assertEquals
(
"incorrect event"
,
string
,
sink
.
subjects
.
get
(
i
++));
}
}
private
enum
Type
{
FOO
};
private
static
class
Thing
extends
AbstractEvent
<
Type
,
String
>
{
protected
Thing
(
String
subject
)
{
super
(
Type
.
FOO
,
subject
);
}
}
private
static
class
Prickle
extends
Thing
{
protected
Prickle
(
String
subject
)
{
super
(
subject
);
}
}
private
static
class
Goo
extends
Thing
{
protected
Goo
(
String
subject
)
{
super
(
subject
);
}
}
private
static
class
Sink
{
final
List
<
String
>
subjects
=
new
ArrayList
<>();
CountDownLatch
latch
;
protected
void
process
(
String
subject
)
{
subjects
.
add
(
subject
);
latch
.
countDown
();
}
}
private
static
class
PrickleSink
extends
Sink
implements
EventSink
<
Prickle
>
{
@Override
public
void
process
(
Prickle
event
)
{
process
(
event
.
subject
());
}
}
private
static
class
GooSink
extends
Sink
implements
EventSink
<
Goo
>
{
@Override
public
void
process
(
Goo
event
)
{
process
(
event
.
subject
());
throw
new
IllegalStateException
(
"BOOM!"
);
}
}
}
utils/misc/src/main/java/org/onlab/graph/AdjacencyListsGraph.java
View file @
f5868c0
...
...
@@ -15,7 +15,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
* @param <V> vertex type
* @param <E> edge type
*/
public
class
AdjacencyListsGraph
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
implements
Graph
<
V
,
E
>
{
public
class
AdjacencyListsGraph
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
implements
Graph
<
V
,
E
>
{
private
final
Set
<
V
>
vertexes
;
private
final
Set
<
E
>
edges
;
...
...
utils/misc/src/main/java/org/onlab/graph/TarjanGraphSearch.java
0 → 100644
View file @
f5868c0
package
org
.
onlab
.
graph
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
/**
* Tarjan algorithm for searching a graph and producing results describing
* the graph SCC (strongly-connected components).
*/
public
class
TarjanGraphSearch
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
implements
GraphSearch
<
V
,
E
>
{
/**
* {@inheritDoc}
* <p/>
* This implementation produces results augmented with information on
* SCCs within the graph.
* <p/>
* To prevent traversal of an edge, the {@link EdgeWeight#weight} should
* return a negative value as an edge weight.
*/
@Override
public
SCCResult
<
V
,
E
>
search
(
Graph
<
V
,
E
>
graph
,
EdgeWeight
<
V
,
E
>
weight
)
{
SCCResult
<
V
,
E
>
result
=
new
SCCResult
<>(
graph
);
for
(
V
vertex
:
graph
.
getVertexes
())
{
VertexData
data
=
result
.
data
(
vertex
);
if
(
data
==
null
)
{
connect
(
graph
,
vertex
,
weight
,
result
);
}
}
return
result
.
build
();
}
/**
* Scans the specified graph, using recursion, and produces SCC results.
*
* @param graph graph to search
* @param vertex current vertex to scan and connect
* @param weight optional edge weight
* @param result graph search result
* @return augmentation vertexData for the current vertex
*/
private
VertexData
<
V
>
connect
(
Graph
<
V
,
E
>
graph
,
V
vertex
,
EdgeWeight
<
V
,
E
>
weight
,
SCCResult
<
V
,
E
>
result
)
{
VertexData
<
V
>
data
=
result
.
addData
(
vertex
);
// Scan through all egress edges of the current vertex.
for
(
E
edge
:
graph
.
getEdgesFrom
(
vertex
))
{
V
nextVertex
=
edge
.
dst
();
// If edge weight is negative, skip it.
if
(
weight
!=
null
&&
weight
.
weight
(
edge
)
<
0
)
{
continue
;
}
// Attempt to get the augmentation vertexData for the next vertex.
VertexData
<
V
>
nextData
=
result
.
data
(
nextVertex
);
if
(
nextData
==
null
)
{
// Next vertex has not been visited yet, so do this now.
nextData
=
connect
(
graph
,
nextVertex
,
weight
,
result
);
data
.
lowLink
=
Math
.
min
(
data
.
lowLink
,
nextData
.
lowLink
);
}
else
if
(
result
.
visited
(
nextData
))
{
// Next vertex has been visited, which means it is in the
// same cluster as the current vertex.
data
.
lowLink
=
Math
.
min
(
data
.
lowLink
,
nextData
.
index
);
}
}
if
(
data
.
lowLink
==
data
.
index
)
{
result
.
addCluster
(
data
);
}
return
data
;
}
/**
* Graph search result augmented with SCC vertexData.
*/
public
static
final
class
SCCResult
<
V
extends
Vertex
,
E
extends
Edge
<
V
>>
implements
Result
{
private
final
Graph
<
V
,
E
>
graph
;
private
List
<
Set
<
V
>>
clusterVertexes
=
new
ArrayList
<>();
private
List
<
Set
<
E
>>
clusterEdges
=
new
ArrayList
<>();
private
int
index
=
0
;
private
final
Map
<
V
,
VertexData
<
V
>>
vertexData
=
new
HashMap
<>();
private
final
List
<
VertexData
<
V
>>
visited
=
new
ArrayList
<>();
private
SCCResult
(
Graph
<
V
,
E
>
graph
)
{
this
.
graph
=
graph
;
}
/**
* Returns the number of SCC clusters in the graph.
*
* @return number of clusters
*/
public
int
clusterCount
()
{
return
clusterEdges
.
size
();
}
/**
* Returns the list of strongly connected vertex clusters.
*
* @return list of strongly connected vertex sets
*/
public
List
<
Set
<
V
>>
clusterVertexes
()
{
return
clusterVertexes
;
}
/**
* Returns the list of edges linking strongly connected vertex clusters.
*
* @return list of strongly connected edge sets
*/
public
List
<
Set
<
E
>>
clusterEdges
()
{
return
clusterEdges
;
}
// Gets the augmentation vertexData for the specified vertex
private
VertexData
<
V
>
data
(
V
vertex
)
{
return
vertexData
.
get
(
vertex
);
}
// Adds augmentation vertexData for the specified vertex
private
VertexData
<
V
>
addData
(
V
vertex
)
{
VertexData
<
V
>
d
=
new
VertexData
<>(
vertex
,
index
);
vertexData
.
put
(
vertex
,
d
);
visited
.
add
(
0
,
d
);
index
++;
return
d
;
}
// Indicates whether the given vertex has been visited
private
boolean
visited
(
VertexData
data
)
{
return
visited
.
contains
(
data
);
}
// Adds a new cluster for the specified vertex
private
void
addCluster
(
VertexData
data
)
{
Set
<
V
>
vertexes
=
findClusterVertices
(
data
);
clusterVertexes
.
add
(
vertexes
);
clusterEdges
.
add
(
findClusterEdges
(
vertexes
));
}
private
Set
<
V
>
findClusterVertices
(
VertexData
data
)
{
VertexData
<
V
>
nextVertexData
;
Set
<
V
>
vertexes
=
new
HashSet
<>();
do
{
nextVertexData
=
visited
.
remove
(
0
);
vertexes
.
add
(
nextVertexData
.
vertex
);
}
while
(
data
!=
nextVertexData
);
return
Collections
.
unmodifiableSet
(
vertexes
);
}
private
Set
<
E
>
findClusterEdges
(
Set
<
V
>
vertexes
)
{
Set
<
E
>
edges
=
new
HashSet
<>();
for
(
V
vertex
:
vertexes
)
{
for
(
E
edge
:
graph
.
getEdgesFrom
(
vertex
))
{
if
(
vertexes
.
contains
((
edge
.
dst
())))
{
edges
.
add
(
edge
);
}
}
}
return
Collections
.
unmodifiableSet
(
edges
);
}
public
SCCResult
<
V
,
E
>
build
()
{
clusterVertexes
=
Collections
.
unmodifiableList
(
clusterVertexes
);
clusterEdges
=
Collections
.
unmodifiableList
(
clusterEdges
);
return
this
;
}
}
// Augments the vertex to assist in determining SCC clusters.
private
static
final
class
VertexData
<
V
extends
Vertex
>
{
final
V
vertex
;
int
index
;
int
lowLink
;
private
VertexData
(
V
vertex
,
int
index
)
{
this
.
vertex
=
vertex
;
this
.
index
=
index
;
this
.
lowLink
=
index
;
}
}
}
utils/misc/src/test/java/org/onlab/graph/BellmanFordGraphSearchTest.java
View file @
f5868c0
...
...
@@ -31,17 +31,17 @@ public class BellmanFordGraphSearchTest extends BreadthFirstSearchTest {
@Test
public
void
searchGraphWithNegativeCycles
()
{
Set
<
TestVertex
>
vertexes
=
new
HashSet
<>(
vert
ic
es
());
Set
<
TestVertex
>
vertexes
=
new
HashSet
<>(
vert
ex
es
());
vertexes
.
add
(
Z
);
Set
<
TestEdge
>
edges
=
new
HashSet
<>(
edges
());
edges
.
add
(
new
TestEdge
(
G
,
Z
,
1.0
));
edges
.
add
(
new
TestEdge
(
Z
,
G
,
-
2.0
));
g
=
new
AdjacencyListsGraph
<>(
vertexes
,
edges
);
g
raph
=
new
AdjacencyListsGraph
<>(
vertexes
,
edges
);
GraphPathSearch
<
TestVertex
,
TestEdge
>
search
=
graphSearch
();
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
=
search
.
search
(
g
,
A
,
H
,
weight
).
paths
();
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
=
search
.
search
(
g
raph
,
A
,
H
,
weight
).
paths
();
assertEquals
(
"incorrect paths count"
,
1
,
paths
.
size
());
Path
p
=
paths
.
iterator
().
next
();
...
...
@@ -50,10 +50,10 @@ public class BellmanFordGraphSearchTest extends BreadthFirstSearchTest {
assertEquals
(
"incorrect path length"
,
5
,
p
.
edges
().
size
());
assertEquals
(
"incorrect path cost"
,
5.0
,
p
.
cost
(),
0.1
);
paths
=
search
.
search
(
g
,
A
,
G
,
weight
).
paths
();
paths
=
search
.
search
(
g
raph
,
A
,
G
,
weight
).
paths
();
assertEquals
(
"incorrect paths count"
,
0
,
paths
.
size
());
paths
=
search
.
search
(
g
,
A
,
null
,
weight
).
paths
();
paths
=
search
.
search
(
g
raph
,
A
,
null
,
weight
).
paths
();
printPaths
(
paths
);
assertEquals
(
"incorrect paths count"
,
6
,
paths
.
size
());
}
...
...
utils/misc/src/test/java/org/onlab/graph/BreadthFirstSearchTest.java
View file @
f5868c0
...
...
@@ -29,10 +29,10 @@ public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest {
// Executes the default test
protected
void
executeDefaultTest
(
int
pathCount
,
int
pathLength
,
double
pathCost
)
{
g
=
new
AdjacencyListsGraph
<>(
vertic
es
(),
edges
());
g
raph
=
new
AdjacencyListsGraph
<>(
vertex
es
(),
edges
());
GraphPathSearch
<
TestVertex
,
TestEdge
>
search
=
graphSearch
();
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
=
search
.
search
(
g
,
A
,
H
,
weight
).
paths
();
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
=
search
.
search
(
g
raph
,
A
,
H
,
weight
).
paths
();
assertEquals
(
"incorrect paths count"
,
1
,
paths
.
size
());
Path
p
=
paths
.
iterator
().
next
();
...
...
@@ -41,7 +41,7 @@ public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest {
assertEquals
(
"incorrect path length"
,
pathLength
,
p
.
edges
().
size
());
assertEquals
(
"incorrect path cost"
,
pathCost
,
p
.
cost
(),
0.1
);
paths
=
search
.
search
(
g
,
A
,
null
,
weight
).
paths
();
paths
=
search
.
search
(
g
raph
,
A
,
null
,
weight
).
paths
();
printPaths
(
paths
);
assertEquals
(
"incorrect paths count"
,
pathCount
,
paths
.
size
());
}
...
...
utils/misc/src/test/java/org/onlab/graph/DepthFirstSearchTest.java
View file @
f5868c0
...
...
@@ -33,11 +33,11 @@ public class DepthFirstSearchTest extends AbstractGraphPathSearchTest {
protected
void
executeDefaultTest
(
int
minLength
,
int
maxLength
,
double
minCost
,
double
maxCost
)
{
g
=
new
AdjacencyListsGraph
<>(
vertic
es
(),
edges
());
g
raph
=
new
AdjacencyListsGraph
<>(
vertex
es
(),
edges
());
DepthFirstSearch
<
TestVertex
,
TestEdge
>
search
=
graphSearch
();
DepthFirstSearch
<
TestVertex
,
TestEdge
>.
SpanningTreeResult
result
=
search
.
search
(
g
,
A
,
H
,
weight
);
search
.
search
(
g
raph
,
A
,
H
,
weight
);
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
=
result
.
paths
();
assertEquals
(
"incorrect path count"
,
1
,
paths
.
size
());
...
...
@@ -57,12 +57,12 @@ public class DepthFirstSearchTest extends AbstractGraphPathSearchTest {
}
public
void
executeBroadSearch
()
{
g
=
new
AdjacencyListsGraph
<>(
vertic
es
(),
edges
());
g
raph
=
new
AdjacencyListsGraph
<>(
vertex
es
(),
edges
());
DepthFirstSearch
<
TestVertex
,
TestEdge
>
search
=
graphSearch
();
// Perform narrow path search to a specific destination.
DepthFirstSearch
<
TestVertex
,
TestEdge
>.
SpanningTreeResult
result
=
search
.
search
(
g
,
A
,
null
,
weight
);
search
.
search
(
g
raph
,
A
,
null
,
weight
);
assertEquals
(
"incorrect paths count"
,
7
,
result
.
paths
().
size
());
int
[]
types
=
new
int
[]{
0
,
0
,
0
,
0
};
...
...
utils/misc/src/test/java/org/onlab/graph/DijkstraGraphSearchTest.java
View file @
f5868c0
...
...
@@ -32,22 +32,22 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest {
@Test
public
void
noPath
()
{
g
=
new
AdjacencyListsGraph
<>(
of
(
A
,
B
,
C
,
D
),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
B
,
A
,
1
),
new
TestEdge
(
C
,
D
,
1
),
new
TestEdge
(
D
,
C
,
1
)));
g
raph
=
new
AdjacencyListsGraph
<>(
of
(
A
,
B
,
C
,
D
),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
B
,
A
,
1
),
new
TestEdge
(
C
,
D
,
1
),
new
TestEdge
(
D
,
C
,
1
)));
GraphPathSearch
<
TestVertex
,
TestEdge
>
gs
=
graphSearch
();
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
=
gs
.
search
(
g
,
A
,
B
,
weight
).
paths
();
Set
<
Path
<
TestVertex
,
TestEdge
>>
paths
=
gs
.
search
(
g
raph
,
A
,
B
,
weight
).
paths
();
printPaths
(
paths
);
assertEquals
(
"incorrect paths count"
,
1
,
paths
.
size
());
assertEquals
(
"incorrect path cost"
,
1.0
,
paths
.
iterator
().
next
().
cost
(),
0.1
);
paths
=
gs
.
search
(
g
,
A
,
D
,
weight
).
paths
();
paths
=
gs
.
search
(
g
raph
,
A
,
D
,
weight
).
paths
();
printPaths
(
paths
);
assertEquals
(
"incorrect paths count"
,
0
,
paths
.
size
());
paths
=
gs
.
search
(
g
,
A
,
null
,
weight
).
paths
();
paths
=
gs
.
search
(
g
raph
,
A
,
null
,
weight
).
paths
();
printPaths
(
paths
);
assertEquals
(
"incorrect paths count"
,
1
,
paths
.
size
());
assertEquals
(
"incorrect path cost"
,
1.0
,
paths
.
iterator
().
next
().
cost
(),
0.1
);
...
...
@@ -55,40 +55,40 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest {
@Test
public
void
simpleMultiplePath
()
{
g
=
new
AdjacencyListsGraph
<>(
of
(
A
,
B
,
C
,
D
),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
A
,
C
,
1
),
new
TestEdge
(
B
,
D
,
1
),
new
TestEdge
(
C
,
D
,
1
)));
executeSearch
(
graphSearch
(),
g
,
A
,
D
,
weight
,
2
,
2.0
);
g
raph
=
new
AdjacencyListsGraph
<>(
of
(
A
,
B
,
C
,
D
),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
A
,
C
,
1
),
new
TestEdge
(
B
,
D
,
1
),
new
TestEdge
(
C
,
D
,
1
)));
executeSearch
(
graphSearch
(),
g
raph
,
A
,
D
,
weight
,
2
,
2.0
);
}
@Test
public
void
denseMultiplePath
()
{
g
=
new
AdjacencyListsGraph
<>(
of
(
A
,
B
,
C
,
D
,
E
,
F
,
G
),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
A
,
C
,
1
),
new
TestEdge
(
B
,
D
,
1
),
new
TestEdge
(
C
,
D
,
1
),
new
TestEdge
(
D
,
E
,
1
),
new
TestEdge
(
D
,
F
,
1
),
new
TestEdge
(
E
,
G
,
1
),
new
TestEdge
(
F
,
G
,
1
),
new
TestEdge
(
A
,
G
,
4
)));
executeSearch
(
graphSearch
(),
g
,
A
,
G
,
weight
,
5
,
4.0
);
g
raph
=
new
AdjacencyListsGraph
<>(
of
(
A
,
B
,
C
,
D
,
E
,
F
,
G
),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
A
,
C
,
1
),
new
TestEdge
(
B
,
D
,
1
),
new
TestEdge
(
C
,
D
,
1
),
new
TestEdge
(
D
,
E
,
1
),
new
TestEdge
(
D
,
F
,
1
),
new
TestEdge
(
E
,
G
,
1
),
new
TestEdge
(
F
,
G
,
1
),
new
TestEdge
(
A
,
G
,
4
)));
executeSearch
(
graphSearch
(),
g
raph
,
A
,
G
,
weight
,
5
,
4.0
);
}
@Test
public
void
dualEdgeMultiplePath
()
{
g
=
new
AdjacencyListsGraph
<>(
of
(
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
A
,
C
,
3
),
new
TestEdge
(
B
,
D
,
2
),
new
TestEdge
(
B
,
C
,
1
),
new
TestEdge
(
B
,
E
,
4
),
new
TestEdge
(
C
,
E
,
1
),
new
TestEdge
(
D
,
H
,
5
),
new
TestEdge
(
D
,
E
,
1
),
new
TestEdge
(
E
,
F
,
1
),
new
TestEdge
(
F
,
D
,
1
),
new
TestEdge
(
F
,
G
,
1
),
new
TestEdge
(
F
,
H
,
1
),
new
TestEdge
(
A
,
E
,
3
),
new
TestEdge
(
B
,
D
,
1
)));
executeSearch
(
graphSearch
(),
g
,
A
,
E
,
weight
,
3
,
3.0
);
g
raph
=
new
AdjacencyListsGraph
<>(
of
(
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
A
,
C
,
3
),
new
TestEdge
(
B
,
D
,
2
),
new
TestEdge
(
B
,
C
,
1
),
new
TestEdge
(
B
,
E
,
4
),
new
TestEdge
(
C
,
E
,
1
),
new
TestEdge
(
D
,
H
,
5
),
new
TestEdge
(
D
,
E
,
1
),
new
TestEdge
(
E
,
F
,
1
),
new
TestEdge
(
F
,
D
,
1
),
new
TestEdge
(
F
,
G
,
1
),
new
TestEdge
(
F
,
H
,
1
),
new
TestEdge
(
A
,
E
,
3
),
new
TestEdge
(
B
,
D
,
1
)));
executeSearch
(
graphSearch
(),
g
raph
,
A
,
E
,
weight
,
3
,
3.0
);
}
}
...
...
utils/misc/src/test/java/org/onlab/graph/GraphTest.java
View file @
f5868c0
...
...
@@ -19,7 +19,7 @@ public class GraphTest {
static
final
TestVertex
H
=
new
TestVertex
(
"H"
);
static
final
TestVertex
Z
=
new
TestVertex
(
"Z"
);
protected
Graph
<
TestVertex
,
TestEdge
>
g
;
protected
Graph
<
TestVertex
,
TestEdge
>
g
raph
;
protected
EdgeWeight
<
TestVertex
,
TestEdge
>
weight
=
new
EdgeWeight
<
TestVertex
,
TestEdge
>()
{
...
...
@@ -35,7 +35,7 @@ public class GraphTest {
}
}
protected
Set
<
TestVertex
>
vert
ic
es
()
{
protected
Set
<
TestVertex
>
vert
ex
es
()
{
return
of
(
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
);
}
...
...
utils/misc/src/test/java/org/onlab/graph/TarjanGraphSearchTest.java
0 → 100644
View file @
f5868c0
package
org
.
onlab
.
graph
;
import
org.junit.Test
;
import
static
com
.
google
.
common
.
collect
.
ImmutableSet
.
of
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
onlab
.
graph
.
TarjanGraphSearch
.
SCCResult
;
/**
* Tarjan graph search tests.
*/
public
class
TarjanGraphSearchTest
extends
GraphTest
{
private
void
validate
(
SCCResult
<
TestVertex
,
TestEdge
>
result
,
int
cc
)
{
System
.
out
.
println
(
"Cluster count: "
+
result
.
clusterVertexes
().
size
());
System
.
out
.
println
(
"Clusters: "
+
result
.
clusterVertexes
());
assertEquals
(
"incorrect cluster count"
,
cc
,
result
.
clusterCount
());
}
private
void
validate
(
SCCResult
<
TestVertex
,
TestEdge
>
result
,
int
i
,
int
vc
,
int
ec
)
{
assertEquals
(
"incorrect cluster count"
,
vc
,
result
.
clusterVertexes
().
get
(
i
).
size
());
assertEquals
(
"incorrect edge count"
,
ec
,
result
.
clusterEdges
().
get
(
i
).
size
());
}
@Test
public
void
basic
()
{
graph
=
new
AdjacencyListsGraph
<>(
vertexes
(),
edges
());
TarjanGraphSearch
<
TestVertex
,
TestEdge
>
gs
=
new
TarjanGraphSearch
<>();
SCCResult
<
TestVertex
,
TestEdge
>
result
=
gs
.
search
(
graph
,
null
);
validate
(
result
,
6
);
}
@Test
public
void
singleCluster
()
{
graph
=
new
AdjacencyListsGraph
<>(
vertexes
(),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
B
,
C
,
1
),
new
TestEdge
(
C
,
D
,
1
),
new
TestEdge
(
D
,
E
,
1
),
new
TestEdge
(
E
,
F
,
1
),
new
TestEdge
(
F
,
G
,
1
),
new
TestEdge
(
G
,
H
,
1
),
new
TestEdge
(
H
,
A
,
1
)));
TarjanGraphSearch
<
TestVertex
,
TestEdge
>
gs
=
new
TarjanGraphSearch
<>();
SCCResult
<
TestVertex
,
TestEdge
>
result
=
gs
.
search
(
graph
,
null
);
validate
(
result
,
1
);
validate
(
result
,
0
,
8
,
8
);
}
@Test
public
void
twoUnconnectedCluster
()
{
graph
=
new
AdjacencyListsGraph
<>(
vertexes
(),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
B
,
C
,
1
),
new
TestEdge
(
C
,
D
,
1
),
new
TestEdge
(
D
,
A
,
1
),
new
TestEdge
(
E
,
F
,
1
),
new
TestEdge
(
F
,
G
,
1
),
new
TestEdge
(
G
,
H
,
1
),
new
TestEdge
(
H
,
E
,
1
)));
TarjanGraphSearch
<
TestVertex
,
TestEdge
>
gs
=
new
TarjanGraphSearch
<>();
SCCResult
<
TestVertex
,
TestEdge
>
result
=
gs
.
search
(
graph
,
null
);
validate
(
result
,
2
);
validate
(
result
,
0
,
4
,
4
);
validate
(
result
,
1
,
4
,
4
);
}
@Test
public
void
twoWeaklyConnectedClusters
()
{
graph
=
new
AdjacencyListsGraph
<>(
vertexes
(),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
B
,
C
,
1
),
new
TestEdge
(
C
,
D
,
1
),
new
TestEdge
(
D
,
A
,
1
),
new
TestEdge
(
E
,
F
,
1
),
new
TestEdge
(
F
,
G
,
1
),
new
TestEdge
(
G
,
H
,
1
),
new
TestEdge
(
H
,
E
,
1
),
new
TestEdge
(
B
,
E
,
1
)));
TarjanGraphSearch
<
TestVertex
,
TestEdge
>
gs
=
new
TarjanGraphSearch
<>();
SCCResult
<
TestVertex
,
TestEdge
>
result
=
gs
.
search
(
graph
,
null
);
validate
(
result
,
2
);
validate
(
result
,
0
,
4
,
4
);
validate
(
result
,
1
,
4
,
4
);
}
@Test
public
void
twoClustersConnectedWithIgnoredEdges
()
{
graph
=
new
AdjacencyListsGraph
<>(
vertexes
(),
of
(
new
TestEdge
(
A
,
B
,
1
),
new
TestEdge
(
B
,
C
,
1
),
new
TestEdge
(
C
,
D
,
1
),
new
TestEdge
(
D
,
A
,
1
),
new
TestEdge
(
E
,
F
,
1
),
new
TestEdge
(
F
,
G
,
1
),
new
TestEdge
(
G
,
H
,
1
),
new
TestEdge
(
H
,
E
,
1
),
new
TestEdge
(
B
,
E
,
-
1
),
new
TestEdge
(
E
,
B
,
-
1
)));
TarjanGraphSearch
<
TestVertex
,
TestEdge
>
gs
=
new
TarjanGraphSearch
<>();
SCCResult
<
TestVertex
,
TestEdge
>
result
=
gs
.
search
(
graph
,
weight
);
validate
(
result
,
2
);
validate
(
result
,
0
,
4
,
4
);
validate
(
result
,
1
,
4
,
4
);
}
}
Please
register
or
login
to post a comment