Search in sources :

Example 1 with ClusterNodeInfo

use of org.jivesoftware.openfire.cluster.ClusterNodeInfo in project Openfire by igniterealtime.

the class ClusteredCacheFactory method getClusterNodeInfo.

public ClusterNodeInfo getClusterNodeInfo(byte[] nodeID) {
    if (cluster == null) {
        return null;
    }
    ClusterNodeInfo result = null;
    Member member = getMember(nodeID);
    if (member != null) {
        result = new HazelcastClusterNodeInfo(member, cluster.getClusterTime());
    }
    return result;
}
Also used : HazelcastClusterNodeInfo(org.jivesoftware.openfire.plugin.util.cluster.HazelcastClusterNodeInfo) ClusterNodeInfo(org.jivesoftware.openfire.cluster.ClusterNodeInfo) Member(com.hazelcast.core.Member) HazelcastClusterNodeInfo(org.jivesoftware.openfire.plugin.util.cluster.HazelcastClusterNodeInfo)

Example 2 with ClusterNodeInfo

use of org.jivesoftware.openfire.cluster.ClusterNodeInfo in project Openfire by igniterealtime.

the class RemoteSession method doSynchronousClusterTask.

/**
     * Invokes a task on the remote cluster member synchronously and returns the result of
     * the remote operation.
     *
     * @param task        the ClusterTask object to be invoked on a given cluster member.
     * @return result of remote operation.
     */
protected Object doSynchronousClusterTask(ClusterTask task) {
    ClusterNodeInfo info = CacheFactory.getClusterNodeInfo(nodeID);
    Object result = null;
    if (info == null && task instanceof RemoteSessionTask) {
        // clean up invalid session
        Session remoteSession = ((RemoteSessionTask) task).getSession();
        if (remoteSession instanceof ClientSession) {
            SessionManager.getInstance().removeSession(null, remoteSession.getAddress(), false, false);
        }
    } else {
        result = (info == null) ? null : CacheFactory.doSynchronousClusterTask(task, nodeID);
    }
    return result;
}
Also used : ClientSession(org.jivesoftware.openfire.session.ClientSession) ClusterNodeInfo(org.jivesoftware.openfire.cluster.ClusterNodeInfo) ClientSession(org.jivesoftware.openfire.session.ClientSession) Session(org.jivesoftware.openfire.session.Session)

Example 3 with ClusterNodeInfo

use of org.jivesoftware.openfire.cluster.ClusterNodeInfo in project Openfire by igniterealtime.

the class ConsistencyChecks method generateReportForUserSessions.

public static Multimap<String, String> generateReportForUserSessions(@Nonnull final Cache<String, HashSet<String>> usersSessionsCache, @Nonnull final Cache<String, ClientRoute> usersCache, @Nonnull final Cache<String, ClientRoute> anonymousUsersCache) {
    final Set<NodeID> clusterNodeIDs = ClusterManager.getNodesInfo().stream().map(ClusterNodeInfo::getNodeID).collect(Collectors.toSet());
    // Take snapshots of all data structures at as much the same time as possible.
    final ConcurrentMap<String, HashSet<String>> cache = new ConcurrentHashMap<>(usersSessionsCache);
    final Set<String> usersCacheKeys = usersCache.keySet();
    final Set<String> anonymousUsersCacheKeys = anonymousUsersCache.keySet();
    final Set<String> userCacheKeysNotInSessionsCache = usersCacheKeys.stream().filter(fullJid -> {
        HashSet<String> fullJids = cache.get(new JID(fullJid).toBareJID());
        return fullJids == null || !fullJids.contains(fullJid);
    }).collect(Collectors.toSet());
    final Set<String> anonymousUserCacheKeysNotInSessionsCache = anonymousUsersCacheKeys.stream().filter(fullJid -> {
        HashSet<String> fullJids = cache.get(new JID(fullJid).toBareJID());
        return fullJids == null || !fullJids.contains(fullJid);
    }).collect(Collectors.toSet());
    final Set<String> sessionCacheItemsNotInUserCaches = cache.values().stream().flatMap(HashSet::stream).filter(fullJid -> !usersCacheKeys.contains(fullJid) && !anonymousUsersCacheKeys.contains(fullJid)).collect(Collectors.toSet());
    final Set<String> duplicatesBetweenAnonAndNonAnonUsers = CollectionUtils.findDuplicates(usersCacheKeys, anonymousUsersCacheKeys);
    // Generate report
    final Multimap<String, String> result = HashMultimap.create();
    result.put("info", String.format("The cache named %s is used to share data in the cluster, which contains %d session infos.", usersSessionsCache.getName(), cache.size()));
    result.put("data", String.format("%s contains these entries (these are shared in the cluster):\n%s", usersSessionsCache.getName(), cache.entrySet().stream().map(e -> e.getKey() + " -> " + e.getValue()).sorted().collect(Collectors.joining("\n"))));
    result.put("data", String.format("%s contains these entries (these are shared in the cluster):\n%s", usersCache.getName(), usersCacheKeys.stream().sorted().collect(Collectors.joining("\n"))));
    result.put("data", String.format("%s contains these entries (these are shared in the cluster):\n%s", anonymousUsersCache.getName(), anonymousUsersCacheKeys.stream().sorted().collect(Collectors.joining("\n"))));
    if (userCacheKeysNotInSessionsCache.isEmpty()) {
        result.put("pass", "All user cache entries exist in the user sessions cache.");
    } else {
        result.put("fail", String.format("User sessions cache is missing entries that are present in the user cache. These %d entries are missing: %s", userCacheKeysNotInSessionsCache.size(), String.join(", ", userCacheKeysNotInSessionsCache)));
    }
    if (anonymousUserCacheKeysNotInSessionsCache.isEmpty()) {
        result.put("pass", "All anonymous user cache entries exist in the user sessions cache.");
    } else {
        result.put("fail", String.format("User sessions cache is missing entries that are present in the anonymous user cache. These %d entries are missing: %s", anonymousUserCacheKeysNotInSessionsCache.size(), String.join(", ", anonymousUserCacheKeysNotInSessionsCache)));
    }
    if (sessionCacheItemsNotInUserCaches.isEmpty()) {
        result.put("pass", "All user sessions cache entries exist in either the user cache or the anonymous user cache.");
    } else {
        result.put("fail", String.format("User cache and/or anonymous user cache is missing entries that are present in the user sessions cache. These %d entries are missing: %s", sessionCacheItemsNotInUserCaches.size(), String.join(", ", sessionCacheItemsNotInUserCaches)));
    }
    if (duplicatesBetweenAnonAndNonAnonUsers.isEmpty()) {
        result.put("pass", "There are no duplicates between non-anonymous users cache and anonymous users cache.");
    } else {
        result.put("fail", String.format("There are users both present in non-anonymous users cache and anonymous users cache. These %d entries are duplicates: %s", duplicatesBetweenAnonAndNonAnonUsers.size(), String.join(", ", duplicatesBetweenAnonAndNonAnonUsers)));
    }
    return result;
}
Also used : java.util(java.util) ClusterManager(org.jivesoftware.openfire.cluster.ClusterManager) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) MUCRoom(org.jivesoftware.openfire.muc.MUCRoom) Multimap(com.google.common.collect.Multimap) StreamID(org.jivesoftware.openfire.StreamID) JID(org.xmpp.packet.JID) Collectors(java.util.stream.Collectors) org.jivesoftware.openfire.session(org.jivesoftware.openfire.session) ClientRoute(org.jivesoftware.openfire.spi.ClientRoute) ConcurrentMap(java.util.concurrent.ConcurrentMap) OccupantManager(org.jivesoftware.openfire.muc.spi.OccupantManager) ClusterNodeInfo(org.jivesoftware.openfire.cluster.ClusterNodeInfo) MUCRole(org.jivesoftware.openfire.muc.MUCRole) HashMultimap(com.google.common.collect.HashMultimap) NodeID(org.jivesoftware.openfire.cluster.NodeID) XMPPServer(org.jivesoftware.openfire.XMPPServer) RoutableChannelHandler(org.jivesoftware.openfire.RoutableChannelHandler) Nonnull(javax.annotation.Nonnull) CollectionUtils(org.jivesoftware.util.CollectionUtils) JID(org.xmpp.packet.JID) NodeID(org.jivesoftware.openfire.cluster.NodeID) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 4 with ClusterNodeInfo

use of org.jivesoftware.openfire.cluster.ClusterNodeInfo in project Openfire by igniterealtime.

the class ConsistencyChecks method generateReportForSessionManagerIncomingServerSessions.

/**
 * Verifies that #incomingServerSessionsCache, #localIncomingServerSessions and #incomingServerSessionsByClusterNode
 * of {@link org.jivesoftware.openfire.SessionManager} are in a consistent state.
 * <p>
 * Note that this operation can be costly in terms of resource usage. Use with caution in large / busy systems.
 * <p>
 * The returned multi-map can contain up to four keys: info, fail, pass, data. All entry values are a human readable
 * description of a checked characteristic. When the state is consistent, no 'fail' entries will be returned.
 *
 * @param incomingServerSessionsCache         The cache that is used to share data across cluster nodes
 * @param localIncomingServerSessions         The data structure that keeps track of what data was added to the cache by the local cluster node.
 * @param incomingServerSessionsByClusterNode The data structure that keeps track of what data was added to the cache by the remote cluster nodes.
 * @return A consistency state report.
 */
public static Multimap<String, String> generateReportForSessionManagerIncomingServerSessions(@Nonnull final Cache<StreamID, IncomingServerSessionInfo> incomingServerSessionsCache, @Nonnull final Collection<LocalIncomingServerSession> localIncomingServerSessions, @Nonnull final Map<NodeID, Set<StreamID>> incomingServerSessionsByClusterNode) {
    final Set<NodeID> clusterNodeIDs = ClusterManager.getNodesInfo().stream().map(ClusterNodeInfo::getNodeID).collect(Collectors.toSet());
    // Take snapshots of all data structures at as much the same time as possible.
    final ConcurrentMap<StreamID, IncomingServerSessionInfo> cache = new ConcurrentHashMap<>(incomingServerSessionsCache);
    final List<StreamID> localIncomingServerSessionsStreamIDs = localIncomingServerSessions.stream().map(LocalIncomingServerSession::getStreamID).collect(Collectors.toList());
    final List<StreamID> remoteIncomingServerSessions = incomingServerSessionsByClusterNode.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
    final List<String> remoteIncomingServerSessionsWithNodeId = new ArrayList<>();
    for (Map.Entry<NodeID, Set<StreamID>> entry : incomingServerSessionsByClusterNode.entrySet()) {
        for (StreamID item : entry.getValue()) {
            remoteIncomingServerSessionsWithNodeId.add(item + " (" + entry.getKey() + ")");
        }
    }
    // Duplicates detection
    final Set<StreamID> localIncomingServerSessionsDuplicates = CollectionUtils.findDuplicates(localIncomingServerSessionsStreamIDs);
    final Set<StreamID> remoteIncomingServerSessionsDuplicates = CollectionUtils.findDuplicates(remoteIncomingServerSessions);
    final Set<StreamID> incomingServerSessionsBothLocalAndRemote = CollectionUtils.findDuplicates(localIncomingServerSessionsStreamIDs, remoteIncomingServerSessions);
    // Detection of other inconsistencies
    final Set<StreamID> nonLocallyStoredCachedIncomingServerSessions = cache.keySet().stream().filter(v -> !localIncomingServerSessionsStreamIDs.contains(v)).filter(v -> !remoteIncomingServerSessions.contains(v)).collect(Collectors.toSet());
    final Set<StreamID> nonCachedLocalIncomingServerSessions = localIncomingServerSessionsStreamIDs.stream().filter(v -> !cache.containsKey(v)).collect(Collectors.toSet());
    final Set<StreamID> nonCachedRemoteIncomingServerSessions = remoteIncomingServerSessions.stream().filter(v -> !cache.containsKey(v)).collect(Collectors.toSet());
    // Generate report
    final Multimap<String, String> result = HashMultimap.create();
    result.put("info", String.format("The cache named %s is used to share data in the cluster, which contains %d incoming server sessions.", incomingServerSessionsCache.getName(), cache.size()));
    result.put("info", String.format("SessionManager's TODO response is used to track 'local' data to be restored after a cache switch-over. It tracks %d incoming server sessions.", localIncomingServerSessionsStreamIDs.size()));
    result.put("info", String.format("The field incomingServerSessionsByClusterNode is used to track data in the cache from every other cluster node. It contains %d routes for %d cluster nodes.", incomingServerSessionsByClusterNode.values().stream().reduce(0, (subtotal, values) -> subtotal + values.size(), Integer::sum), incomingServerSessionsByClusterNode.size()));
    result.put("data", String.format("%s contains these entries (these are shared in the cluster):\n%s", incomingServerSessionsCache.getName(), cache.keySet().stream().map(StreamID::getID).collect(Collectors.joining("\n"))));
    result.put("data", String.format("SessionManager's localSessionManager contains these entries (these represent 'local' data):\n%s", localIncomingServerSessionsStreamIDs.stream().map(StreamID::getID).collect(Collectors.joining("\n"))));
    result.put("data", String.format("incomingServerSessionsByClusterNode contains these entries (these represent 'remote' data):\n%s", String.join("\n", remoteIncomingServerSessionsWithNodeId)));
    if (!incomingServerSessionsByClusterNode.containsKey(XMPPServer.getInstance().getNodeID())) {
        result.put("pass", "incomingServerSessionsByClusterNode does not track data for the local cluster node.");
    } else {
        result.put("fail", "incomingServerSessionsByClusterNode tracks data for the local cluster node.");
    }
    if (clusterNodeIDs.containsAll(incomingServerSessionsByClusterNode.keySet())) {
        result.put("pass", "incomingServerSessionsByClusterNode tracks data for cluster nodes that are recognized in the cluster.");
    } else {
        result.put("fail", String.format("incomingServerSessionsByClusterNode tracks data for cluster nodes that are not recognized. All cluster nodeIDs as recognized: %s All cluster nodeIDs for which data is tracked: %s.", clusterNodeIDs.stream().map(NodeID::toString).collect(Collectors.joining(", ")), incomingServerSessionsByClusterNode.keySet().stream().map(NodeID::toString).collect(Collectors.joining(", "))));
    }
    if (localIncomingServerSessionsDuplicates.isEmpty()) {
        result.put("pass", "There is no overlap in local incoming server sessions (they are all unique values).");
    } else {
        result.put("fail", String.format("There is overlap in local incoming server sessions (they are not all unique values). These %d values are duplicated: %s", localIncomingServerSessionsDuplicates.size(), localIncomingServerSessionsDuplicates.stream().map(StreamID::getID).collect(Collectors.joining(", "))));
    }
    if (remoteIncomingServerSessionsDuplicates.isEmpty()) {
        result.put("pass", "There is no overlap in incomingServerSessionsByClusterNode (they are all unique values).");
    } else {
        result.put("fail", String.format("There is overlap in incomingServerSessionsByClusterNode (they are not all unique values). These %d values are duplicated: %s", remoteIncomingServerSessionsDuplicates.size(), remoteIncomingServerSessionsDuplicates.stream().map(StreamID::getID).collect(Collectors.joining(", "))));
    }
    if (incomingServerSessionsBothLocalAndRemote.isEmpty()) {
        result.put("pass", "There are no elements that are both 'remote' (in incomingServerSessionsByClusterNode) as well as 'local' (in SessionManager's localSessionManager).");
    } else {
        result.put("fail", String.format("There are %d elements that are both 'remote' (in incomingServerSessionsByClusterNode) as well as 'local' (in SessionManager's localSessionManager): %s", incomingServerSessionsBothLocalAndRemote.size(), incomingServerSessionsBothLocalAndRemote.stream().map(StreamID::getID).collect(Collectors.joining(", "))));
    }
    if (nonCachedLocalIncomingServerSessions.isEmpty()) {
        result.put("pass", String.format("All elements in SessionManager's localSessionManager exist in %s.", incomingServerSessionsCache.getName()));
    } else {
        result.put("fail", String.format("Not all elements in SessionManager's localSessionManager exist in %s. These %d entries do not: %s", incomingServerSessionsCache.getName(), nonCachedLocalIncomingServerSessions.size(), nonCachedLocalIncomingServerSessions.stream().map(StreamID::getID).collect(Collectors.joining(", "))));
    }
    if (nonCachedRemoteIncomingServerSessions.isEmpty()) {
        result.put("pass", String.format("All elements inincomingServerSessionsByClusterNode exist in %s.", incomingServerSessionsCache.getName()));
    } else {
        result.put("fail", String.format("Not all elements in incomingServerSessionsByClusterNode exist in %s. These %d entries do not: %s", incomingServerSessionsCache.getName(), nonCachedRemoteIncomingServerSessions.size(), nonCachedRemoteIncomingServerSessions.stream().map(StreamID::getID).collect(Collectors.joining(", "))));
    }
    if (nonLocallyStoredCachedIncomingServerSessions.isEmpty()) {
        result.put("pass", String.format("All cache entries of %s exist in incomingServerSessionsByClusterNode and/or SessionManager's localSessionManager.", incomingServerSessionsCache.getName()));
    } else {
        result.put("fail", String.format("Not all cache entries of %s exist in incomingServerSessionsByClusterNode and/or SessionManager's localSessionManager. These %d entries do not: %s", incomingServerSessionsCache.getName(), nonLocallyStoredCachedIncomingServerSessions.size(), nonLocallyStoredCachedIncomingServerSessions.stream().map(StreamID::getID).collect(Collectors.joining(", "))));
    }
    return result;
}
Also used : java.util(java.util) ClusterManager(org.jivesoftware.openfire.cluster.ClusterManager) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) MUCRoom(org.jivesoftware.openfire.muc.MUCRoom) Multimap(com.google.common.collect.Multimap) StreamID(org.jivesoftware.openfire.StreamID) JID(org.xmpp.packet.JID) Collectors(java.util.stream.Collectors) org.jivesoftware.openfire.session(org.jivesoftware.openfire.session) ClientRoute(org.jivesoftware.openfire.spi.ClientRoute) ConcurrentMap(java.util.concurrent.ConcurrentMap) OccupantManager(org.jivesoftware.openfire.muc.spi.OccupantManager) ClusterNodeInfo(org.jivesoftware.openfire.cluster.ClusterNodeInfo) MUCRole(org.jivesoftware.openfire.muc.MUCRole) HashMultimap(com.google.common.collect.HashMultimap) NodeID(org.jivesoftware.openfire.cluster.NodeID) XMPPServer(org.jivesoftware.openfire.XMPPServer) RoutableChannelHandler(org.jivesoftware.openfire.RoutableChannelHandler) Nonnull(javax.annotation.Nonnull) CollectionUtils(org.jivesoftware.util.CollectionUtils) StreamID(org.jivesoftware.openfire.StreamID) NodeID(org.jivesoftware.openfire.cluster.NodeID) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap)

Example 5 with ClusterNodeInfo

use of org.jivesoftware.openfire.cluster.ClusterNodeInfo in project Openfire by igniterealtime.

the class RemoteSession method doSynchronousClusterTask.

/**
 * Invokes a task on the remote cluster member synchronously and returns the result of
 * the remote operation.
 *
 * @param task        the ClusterTask object to be invoked on a given cluster member.
 * @return result of remote operation.
 */
protected Object doSynchronousClusterTask(ClusterTask<Object> task) {
    ClusterNodeInfo info = CacheFactory.getClusterNodeInfo(nodeID);
    Object result = null;
    if (info == null && task instanceof RemoteSessionTask) {
        // clean up invalid session
        Session remoteSession = ((RemoteSessionTask) task).getSession();
        if (remoteSession instanceof ClientSession) {
            SessionManager.getInstance().removeSession(null, remoteSession.getAddress(), false, false);
        }
    } else {
        result = (info == null) ? null : CacheFactory.doSynchronousClusterTask(task, nodeID);
    }
    return result;
}
Also used : ClusterNodeInfo(org.jivesoftware.openfire.cluster.ClusterNodeInfo)

Aggregations

ClusterNodeInfo (org.jivesoftware.openfire.cluster.ClusterNodeInfo)7 HashMultimap (com.google.common.collect.HashMultimap)3 Multimap (com.google.common.collect.Multimap)3 java.util (java.util)3 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)3 ConcurrentMap (java.util.concurrent.ConcurrentMap)3 Collectors (java.util.stream.Collectors)3 Nonnull (javax.annotation.Nonnull)3 RoutableChannelHandler (org.jivesoftware.openfire.RoutableChannelHandler)3 StreamID (org.jivesoftware.openfire.StreamID)3 XMPPServer (org.jivesoftware.openfire.XMPPServer)3 ClusterManager (org.jivesoftware.openfire.cluster.ClusterManager)3 NodeID (org.jivesoftware.openfire.cluster.NodeID)3 MUCRole (org.jivesoftware.openfire.muc.MUCRole)3 MUCRoom (org.jivesoftware.openfire.muc.MUCRoom)3 OccupantManager (org.jivesoftware.openfire.muc.spi.OccupantManager)3 org.jivesoftware.openfire.session (org.jivesoftware.openfire.session)3 ClientRoute (org.jivesoftware.openfire.spi.ClientRoute)3 CollectionUtils (org.jivesoftware.util.CollectionUtils)3 JID (org.xmpp.packet.JID)3