/** Start collecting global monitoring information for the replication domain. */ private void initializePendingMonitorData() { // Let's process our directly connected DS // - in the ServerHandler for a given DS1, the stored state contains : // -- the max CSN produced by DS1 // -- the last CSN consumed by DS1 from DS2..n // - in the ReplicationDomainDB/ReplicaDB, the built-in state contains: // -- the max CSN produced by each server // So for a given DS connected we can take the state and the max from // the DS/state. for (ServerHandler ds : domain.getConnectedDSs().values()) { final int serverId = ds.getServerId(); final ServerState dsState = ds.getServerState().duplicate(); CSN maxCSN = dsState.getCSN(serverId); if (maxCSN == null) { // This directly connected LS has never produced any change maxCSN = new CSN(0, 0, serverId); } pendingMonitorData.setMaxCSN(maxCSN); pendingMonitorData.setLDAPServerState(serverId, dsState); pendingMonitorData.setFirstMissingDate(serverId, ds.getApproxFirstMissingDate()); } // Then initialize the max CSN for the LS that produced something // - from our own local db state // - whatever they are directly or indirectly connected final ServerState dbServerState = domain.getLatestServerState(); pendingMonitorData.setRSState(domain.getLocalRSServerId(), dbServerState); for (CSN storedCSN : dbServerState) { pendingMonitorData.setMaxCSN(storedCSN); } }
/** * Processes a Monitor message receives from a remote Replication Server and stores the data * received. * * @param msg The message to be processed. * @param serverId server handler that is receiving the message. */ public void receiveMonitorDataResponse(MonitorMsg msg, int serverId) { synchronized (pendingMonitorDataLock) { if (pendingMonitorData == null) { // This is a response for an earlier request whose computing is // already complete. logger.debug(INFO_IGNORING_REMOTE_MONITOR_DATA, domain.getBaseDN(), msg.getSenderID()); return; } try { // Here is the RS state : list <serverID, lastCSN> // For each LDAP Server, we keep the max CSN across the RSes ServerState replServerState = msg.getReplServerDbState(); pendingMonitorData.setMaxCSNs(replServerState); // store the remote RS states. pendingMonitorData.setRSState(msg.getSenderID(), replServerState); // Store the remote LDAP servers states for (int dsServerId : toIterable(msg.ldapIterator())) { ServerState dsServerState = msg.getLDAPServerState(dsServerId); pendingMonitorData.setMaxCSNs(dsServerState); pendingMonitorData.setLDAPServerState(dsServerId, dsServerState); pendingMonitorData.setFirstMissingDate( dsServerId, msg.getLDAPApproxFirstMissingDate(dsServerId)); } // Process the latency reported by the remote RSi on its connections // to the other RSes for (int rsServerId : toIterable(msg.rsIterator())) { long newFmd = msg.getRSApproxFirstMissingDate(rsServerId); if (rsServerId == domain.getLocalRSServerId()) { // this is the latency of the remote RSi regarding the current RS // let's update the first missing date of my connected LS for (DataServerHandler ds : domain.getConnectedDSs().values()) { int connectedServerId = ds.getServerId(); pendingMonitorData.setFirstMissingDate(connectedServerId, newFmd); } } else { // this is the latency of the remote RSi regarding another RSj // let's update the latency of the LSes connected to RSj ReplicationServerHandler rsjHdr = domain.getConnectedRSs().get(rsServerId); if (rsjHdr != null) { for (int remoteServerId : rsjHdr.getConnectedDirectoryServerIds()) { pendingMonitorData.setFirstMissingDate(remoteServerId, newFmd); } } } } } catch (RuntimeException e) { // FIXME: do we really expect these??? logger.error( ERR_PROCESSING_REMOTE_MONITOR_DATA, e.getMessage() + " " + stackTraceToSingleLineString(e)); } finally { // Decreases the number of expected responses and potentially // wakes up the waiting requester thread. if (pendingMonitorDataServerIDs.remove(serverId)) { pendingMonitorDataLatch.countDown(); } } } }
/** * Recomputes the monitor data for this replication server domain. * * @return The recomputed monitor data for this replication server domain. * @throws InterruptedException If this thread is interrupted while waiting for a response. */ public ReplicationDomainMonitorData recomputeMonitorData() throws InterruptedException { // Only allow monitor recalculation at a time. synchronized (pendingMonitorLock) { if (monitorDataLastBuildDate + monitorDataLifeTime < TimeThread.getTime()) { try { DN baseDN = domain.getBaseDN(); // Prevent out of band monitor responses from updating our pending // table until we are ready. synchronized (pendingMonitorDataLock) { // Clear the pending monitor data. pendingMonitorDataServerIDs.clear(); pendingMonitorData = new ReplicationDomainMonitorData(); initializePendingMonitorData(); // Send the monitor requests to the connected replication servers. for (ServerHandler rs : domain.getConnectedRSs().values()) { final int serverId = rs.getServerId(); MonitorRequestMsg msg = new MonitorRequestMsg(domain.getLocalRSServerId(), serverId); try { rs.send(msg); // Only register this server ID to pending table if we were able // to send the message. pendingMonitorDataServerIDs.add(serverId); } catch (IOException e) { // Log a message and do a best effort from here. logger.error( ERR_SENDING_REMOTE_MONITOR_DATA_REQUEST, baseDN, serverId, e.getMessage()); } } // Create the pending response latch based on the number of expected // monitor responses. pendingMonitorDataLatch = new CountDownLatch(pendingMonitorDataServerIDs.size()); } // Wait for the responses to come back. pendingMonitorDataLatch.await(5, TimeUnit.SECONDS); // Log messages for replication servers that have gone or come back. synchronized (pendingMonitorDataLock) { // Log servers that have come back. for (int serverId : monitorDataLateServers) { // Ensure that we only log once per server: don't fill the // error log with repeated messages. if (!pendingMonitorDataServerIDs.contains(serverId)) { logger.info(NOTE_MONITOR_DATA_RECEIVED, baseDN, serverId); } } // Log servers that have gone away. for (int serverId : pendingMonitorDataServerIDs) { // Ensure that we only log once per server: don't fill the // error log with repeated messages. if (!monitorDataLateServers.contains(serverId)) { logger.warn(WARN_MISSING_REMOTE_MONITOR_DATA, baseDN, serverId); } } // Remember which servers were late this time. monitorDataLateServers.clear(); monitorDataLateServers.addAll(pendingMonitorDataServerIDs); } // Store the new computed data as the reference synchronized (pendingMonitorDataLock) { // Now we have the expected answers or an error occurred pendingMonitorData.completeComputing(); monitorData = pendingMonitorData; monitorDataLastBuildDate = TimeThread.getTime(); } } finally { synchronized (pendingMonitorDataLock) { // Clear pending state. pendingMonitorData = null; pendingMonitorDataLatch = null; pendingMonitorDataServerIDs.clear(); } } } } return monitorData; }