59cc7550c67859bf90fe64b09046ac12d88240bf
[controller.git] / opendaylight / md-sal / sal-distributed-eos / src / main / java / org / opendaylight / controller / cluster / entityownership / EntityOwnershipStatistics.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.cluster.entityownership;
9
10 import static org.opendaylight.controller.cluster.entityownership.EntityOwnersModel.entityTypeFromEntityPath;
11
12 import com.google.common.base.Strings;
13 import java.util.Collection;
14 import java.util.HashMap;
15 import java.util.Map;
16 import java.util.Optional;
17 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
18 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
20 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
21 import tech.pantheon.triemap.TrieMap;
22
23 /**
24  * EntityOwnershipStatistics is a utility class that keeps track of ownership statistics for the candidates and
25  * caches it for quick count queries.
26  * <p/>
27  * While the entity ownership model does maintain the information about which entity is owned by which candidate
28  * finding out how many entities of a given type are owned by a given candidate is not an efficient query.
29  */
30 class EntityOwnershipStatistics extends AbstractEntityOwnerChangeListener {
31     private final TrieMap<String, TrieMap<String, Long>> statistics = TrieMap.create();
32
33     EntityOwnershipStatistics() {
34         // Hidden on purpose
35     }
36
37     @Override
38     public void onInitialData() {
39         // No-op
40     }
41
42     @Override
43     public void onDataTreeChanged(final Collection<DataTreeCandidate> changes) {
44         for (DataTreeCandidate change : changes) {
45             DataTreeCandidateNode changeRoot = change.getRootNode();
46             LeafNode<?> ownerLeaf = (LeafNode<?>) changeRoot.getDataAfter().get();
47             String entityType = entityTypeFromEntityPath(change.getRootPath());
48             String newOwner = extractOwner(ownerLeaf);
49             if (!Strings.isNullOrEmpty(newOwner)) {
50                 updateStatistics(entityType, newOwner, 1);
51             }
52
53             Optional<NormalizedNode> dataBefore = changeRoot.getDataBefore();
54             if (dataBefore.isPresent()) {
55                 String origOwner = extractOwner((LeafNode<?>) changeRoot.getDataBefore().get());
56                 if (!Strings.isNullOrEmpty(origOwner)) {
57                     updateStatistics(entityType, origOwner, -1);
58                 }
59             }
60         }
61     }
62
63     Map<String, Map<String, Long>> all() {
64         Map<String, Map<String, Long>> snapshot = new HashMap<>();
65         for (String entityType : statistics.immutableSnapshot().keySet()) {
66             snapshot.put(entityType, byEntityType(entityType));
67         }
68         return snapshot;
69     }
70
71     Map<String, Long> byEntityType(final String entityType) {
72         if (statistics.get(entityType) != null) {
73             return statistics.get(entityType).immutableSnapshot();
74         }
75         return new HashMap<>();
76     }
77
78     private void updateStatistics(final String entityType, final String candidateName, final long count) {
79         TrieMap<String, Long> map = statistics.get(entityType);
80         if (map == null) {
81             map = TrieMap.create();
82             map.put(candidateName, count);
83             statistics.put(entityType, map);
84         } else {
85             map.merge(candidateName, count, (ownedEntities, addedEntities) -> ownedEntities + addedEntities);
86         }
87     }
88 }