/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.accumulo.monitor.servlets; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.accumulo.core.client.Connector; import org.apache.accumulo.core.client.admin.TableOperations; import org.apache.accumulo.core.master.thrift.MasterMonitorInfo; import org.apache.accumulo.core.replication.ReplicationConstants; import org.apache.accumulo.core.replication.ReplicationTable; import org.apache.accumulo.core.replication.ReplicationTarget; import org.apache.accumulo.core.zookeeper.ZooUtil; import org.apache.accumulo.monitor.Monitor; import org.apache.accumulo.monitor.util.Table; import org.apache.accumulo.monitor.util.celltypes.NumberType; import org.apache.accumulo.server.replication.DistributedWorkQueueWorkAssignerHelper; import org.apache.accumulo.server.replication.ReplicationUtil; import org.apache.accumulo.server.zookeeper.DistributedWorkQueue; import org.apache.zookeeper.KeeperException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * */ public class ReplicationServlet extends BasicServlet { private static final Logger log = LoggerFactory.getLogger(ReplicationServlet.class); private static final long serialVersionUID = 1L; // transient because it's not serializable and servlets are serializable private transient volatile ReplicationUtil replicationUtil = null; private synchronized ReplicationUtil getReplicationUtil() { // make transient replicationUtil available as needed if (replicationUtil == null) { replicationUtil = new ReplicationUtil(Monitor.getContext()); } return replicationUtil; } @Override protected String getTitle(HttpServletRequest req) { return "Replication Overview"; } @Override protected void pageBody(HttpServletRequest req, HttpServletResponse response, StringBuilder sb) throws Exception { final Connector conn = Monitor.getContext().getConnector(); final MasterMonitorInfo mmi = Monitor.getMmi(); // The total number of "slots" we have to replicate data int totalWorkQueueSize = getReplicationUtil().getMaxReplicationThreads(mmi); TableOperations tops = conn.tableOperations(); if (!ReplicationTable.isOnline(conn)) { banner(sb, "", "Replication table is offline"); return; } Table replicationStats = new Table("replicationStats", "Replication Status"); replicationStats.addSortableColumn("Table"); replicationStats.addSortableColumn("Peer"); replicationStats.addSortableColumn("Remote Identifier"); replicationStats.addSortableColumn("ReplicaSystem Type"); replicationStats.addSortableColumn("Files needing replication", new NumberType<Long>(), null); Map<String,String> peers = getReplicationUtil().getPeers(); // The total set of configured targets Set<ReplicationTarget> allConfiguredTargets = getReplicationUtil().getReplicationTargets(); // Number of files per target we have to replicate Map<ReplicationTarget,Long> targetCounts = getReplicationUtil().getPendingReplications(); Map<String,String> tableNameToId = tops.tableIdMap(); Map<String,String> tableIdToName = getReplicationUtil().invert(tableNameToId); long filesPendingOverAllTargets = 0l; for (ReplicationTarget configuredTarget : allConfiguredTargets) { String tableName = tableIdToName.get(configuredTarget.getSourceTableId()); if (null == tableName) { log.trace("Could not determine table name from id {}", configuredTarget.getSourceTableId()); continue; } String replicaSystemClass = peers.get(configuredTarget.getPeerName()); if (null == replicaSystemClass) { log.trace("Could not determine configured ReplicaSystem for {}", configuredTarget.getPeerName()); continue; } Long numFiles = targetCounts.get(configuredTarget); if (null == numFiles) { replicationStats.addRow(tableName, configuredTarget.getPeerName(), configuredTarget.getRemoteIdentifier(), replicaSystemClass, 0); } else { replicationStats.addRow(tableName, configuredTarget.getPeerName(), configuredTarget.getRemoteIdentifier(), replicaSystemClass, numFiles); filesPendingOverAllTargets += numFiles; } } // Up to 2x the number of slots for replication available, WARN // More than 2x the number of slots for replication available, ERROR NumberType<Long> filesPendingFormat = new NumberType<>(Long.valueOf(0), Long.valueOf(2 * totalWorkQueueSize), Long.valueOf(0), Long.valueOf(4 * totalWorkQueueSize)); String utilization = filesPendingFormat.format(filesPendingOverAllTargets); sb.append("<div><center><br /><span class=\"table-caption\">Total files pending replication: ").append(utilization).append("</span></center></div>"); replicationStats.generate(req, sb); // Make a table for the replication data in progress Table replicationInProgress = new Table("replicationInProgress", "In-Progress Replication"); replicationInProgress.addSortableColumn("File"); replicationInProgress.addSortableColumn("Peer"); replicationInProgress.addSortableColumn("Source Table ID"); replicationInProgress.addSortableColumn("Peer Identifier"); replicationInProgress.addUnsortableColumn("Status"); // Read the files from the workqueue in zk String zkRoot = ZooUtil.getRoot(Monitor.getContext().getInstance()); final String workQueuePath = zkRoot + ReplicationConstants.ZOO_WORK_QUEUE; DistributedWorkQueue workQueue = new DistributedWorkQueue(workQueuePath, Monitor.getContext().getConfiguration()); try { for (String queueKey : workQueue.getWorkQueued()) { Entry<String,ReplicationTarget> queueKeyPair = DistributedWorkQueueWorkAssignerHelper.fromQueueKey(queueKey); String filename = queueKeyPair.getKey(); ReplicationTarget target = queueKeyPair.getValue(); String path = getReplicationUtil().getAbsolutePath(conn, workQueuePath, queueKey); String progress = getReplicationUtil().getProgress(conn, path, target); // Add a row in the table replicationInProgress.addRow(null == path ? ".../" + filename : path, target.getPeerName(), target.getSourceTableId(), target.getRemoteIdentifier(), progress); } } catch (KeeperException | InterruptedException e) { log.warn("Could not calculate replication in progress", e); } replicationInProgress.generate(req, sb); } }