/* * 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.catalina.ha.tcp;
/** * <p> * Implementation of a Valve that logs interesting contents from the specified Request (before processing) and the * corresponding Response (after processing). It is especially useful in debugging problems related to headers and * cookies. * </p> * <p> * This Valve may be attached to any Container, depending on the granularity of the logging you wish to perform. * </p> * <p> * primaryIndicator=true, then the request attribute <i>org.apache.catalina.ha.tcp.isPrimarySession.</i> is set true, * when request processing is at sessions primary node. * </p> * * @author Craig R. McClanahan * @author Peter Rossbach
*/ publicclass ReplicationValve extends ValveBase implements ClusterValve {
// --------------------------------------------------------- Public Methods
/** * Register all cross context sessions inside endAccess. Use a list with contains check, that the Portlet API can * include a lot of fragments from same or different applications with session changes. * * @param session cross context session
*/ publicvoid registerReplicationSession(DeltaSession session) {
List<DeltaSession> sessions = crossContextSessions.get(); if (sessions != null) { if (!sessions.contains(session)) { if (log.isDebugEnabled()) {
log.debug(sm.getString("ReplicationValve.crossContext.registerSession", session.getIdInternal(),
session.getManager().getContext().getName()));
}
sessions.add(session);
}
}
}
/** * Log the interesting request parameters, invoke the next Valve in the sequence, and log the interesting response * parameters. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs
*/
@Override publicvoid invoke(Request request, Response response) throws IOException, ServletException { long totalstart = 0;
// this happens before the request if (doStatistics()) {
totalstart = System.currentTimeMillis();
} if (primaryIndicator) {
createPrimaryIndicator(request);
}
Context context = request.getContext(); boolean isCrossContext = context != null && context instanceof StandardContext && context.getCrossContext(); try { if (isCrossContext) { if (log.isDebugEnabled()) {
log.debug(sm.getString("ReplicationValve.crossContext.add"));
} // FIXME add Pool of Arraylists
crossContextSessions.set(new ArrayList<>());
}
getNext().invoke(request, response); if (context != null && cluster != null && context.getManager() instanceof ClusterManager) {
ClusterManager clusterManager = (ClusterManager) context.getManager();
// valve cluster can access manager - other cluster handle replication // at host level - hopefully! if (cluster.getManager(clusterManager.getName()) == null) { return;
} if (cluster.hasMembers()) {
sendReplicationMessage(request, totalstart, isCrossContext, clusterManager);
} else {
resetReplicationRequest(request, isCrossContext);
}
}
} finally { // Array must be remove: Current master request send endAccess at recycle. // Don't register this request session again! if (isCrossContext) { if (log.isDebugEnabled()) {
log.debug(sm.getString("ReplicationValve.crossContext.remove"));
}
crossContextSessions.remove();
}
}
}
/** * reset the active statistics
*/ publicvoid resetStatistics() {
totalRequestTime.reset();
totalSendTime.reset();
lastSendTime.set(0);
nrOfFilterRequests.reset();
nrOfRequests.reset();
nrOfSendRequests.reset();
nrOfCrossContextSendRequests.reset();
}
/** * Start this component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error that prevents this component from being * used
*/
@Override protectedsynchronizedvoid startInternal() throws LifecycleException { if (cluster == null) {
Cluster containerCluster = getContainer().getCluster(); if (containerCluster instanceof CatalinaCluster) {
setCluster((CatalinaCluster) containerCluster);
} else { if (log.isWarnEnabled()) {
log.warn(sm.getString("ReplicationValve.nocluster"));
}
}
} super.startInternal();
}
protectedvoid sendReplicationMessage(Request request, long totalstart, boolean isCrossContext,
ClusterManager clusterManager) { // this happens after the request long start = 0; if (doStatistics()) {
start = System.currentTimeMillis();
} try { // send invalid sessions // DeltaManager returns String[0] if (!(clusterManager instanceof DeltaManager)) {
sendInvalidSessions(clusterManager);
} // send replication
sendSessionReplicationMessage(request, clusterManager); if (isCrossContext) {
sendCrossContextSession();
}
} catch (Exception x) { // FIXME we have a lot of sends, but the trouble with one node stops the correct replication to other nodes!
log.error(sm.getString("ReplicationValve.send.failure"), x);
} finally { if (doStatistics()) {
updateStats(totalstart, start);
}
}
}
/** * Send all changed cross context sessions to backups
*/ protectedvoid sendCrossContextSession() {
List<DeltaSession> sessions = crossContextSessions.get(); if (sessions != null && sessions.size() > 0) { for (DeltaSession session : sessions) { if (log.isDebugEnabled()) {
log.debug(sm.getString("ReplicationValve.crossContext.sendDelta",
session.getManager().getContext().getName()));
}
sendMessage(session, (ClusterManager) session.getManager()); if (doStatistics()) {
nrOfCrossContextSendRequests.increment();
}
}
}
}
/** * Fix memory leak for long sessions with many changes, when no backup member exists! * * @param request current request after response is generated * @param isCrossContext check crosscontext threadlocal
*/ protectedvoid resetReplicationRequest(Request request, boolean isCrossContext) {
Session contextSession = request.getSessionInternal(false); if (contextSession instanceof DeltaSession) {
resetDeltaRequest(contextSession);
((DeltaSession) contextSession).setPrimarySession(true);
} if (isCrossContext) {
List<DeltaSession> sessions = crossContextSessions.get(); if (sessions != null && sessions.size() > 0) {
Iterator<DeltaSession> iter = sessions.iterator(); for (; iter.hasNext();) {
Session session = iter.next();
resetDeltaRequest(session); if (session instanceof DeltaSession) {
((DeltaSession) contextSession).setPrimarySession(true);
}
}
}
}
}
/** * Reset DeltaRequest from session * * @param session HttpSession from current request or cross context session
*/ protectedvoid resetDeltaRequest(Session session) { if (log.isDebugEnabled()) {
log.debug(sm.getString("ReplicationValve.resetDeltaRequest", session.getManager().getContext().getName()));
}
((DeltaSession) session).resetDeltaRequest();
}
/** * Send Cluster Replication Request * * @param request current request * @param manager session manager
*/ protectedvoid sendSessionReplicationMessage(Request request, ClusterManager manager) {
Session session = request.getSessionInternal(false); if (session != null) {
String uri = request.getDecodedRequestURI(); // request without session change if (!isRequestWithoutSessionChange(uri)) { if (log.isDebugEnabled()) {
log.debug(sm.getString("ReplicationValve.invoke.uri", uri));
}
sendMessage(session, manager);
} elseif (doStatistics()) {
nrOfFilterRequests.increment();
}
}
}
/** * Send message delta message from request session * * @param session current session * @param manager session manager
*/ protectedvoid sendMessage(Session session, ClusterManager manager) {
String id = session.getIdInternal(); if (id != null) {
send(manager, id);
}
}
/** * is request without possible session change * * @param uri The request uri * * @return True if no session change
*/ protectedboolean isRequestWithoutSessionChange(String uri) {
Pattern f = filter; return f != null && f.matcher(uri).matches();
}
/** * Protocol cluster replications stats * * @param requestTime Request time * @param clusterTime Cluster time
*/ protectedvoid updateStats(long requestTime, long clusterTime) { // TODO: Async requests may trigger multiple replication requests. How, // if at all, should the stats handle this? long currentTime = System.currentTimeMillis();
lastSendTime.set(currentTime);
totalSendTime.add(currentTime - clusterTime);
totalRequestTime.add(currentTime - requestTime);
nrOfRequests.increment(); if (log.isInfoEnabled()) { if ((nrOfRequests.longValue() % 100) == 0) {
log.info(sm.getString("ReplicationValve.stats", new Object[] { Long.valueOf(totalRequestTime.longValue() / nrOfRequests.longValue()), Long.valueOf(totalSendTime.longValue() / nrOfRequests.longValue()), Long.valueOf(nrOfRequests.longValue()), Long.valueOf(nrOfSendRequests.longValue()), Long.valueOf(nrOfCrossContextSendRequests.longValue()), Long.valueOf(nrOfFilterRequests.longValue()), Long.valueOf(totalRequestTime.longValue()), Long.valueOf(totalSendTime.longValue()) }));
}
}
}
/** * Mark Request that processed at primary node with attribute primaryIndicatorName * * @param request The Servlet request * * @throws IOException IO error finding session
*/ protectedvoid createPrimaryIndicator(Request request) throws IOException {
String id = request.getRequestedSessionId(); if ((id != null) && (id.length() > 0)) {
Manager manager = request.getContext().getManager();
Session session = manager.findSession(id); if (session instanceof ClusterSession) {
ClusterSession cses = (ClusterSession) session; if (log.isDebugEnabled()) {
log.debug(sm.getString("ReplicationValve.session.indicator", request.getContext().getName(), id,
primaryIndicatorName, Boolean.valueOf(cses.isPrimarySession())));
}
request.setAttribute(primaryIndicatorName, cses.isPrimarySession() ? Boolean.TRUE : Boolean.FALSE);
} else { if (log.isDebugEnabled()) { if (session != null) {
log.debug(sm.getString("ReplicationValve.session.found", request.getContext().getName(), id));
} else {
log.debug(sm.getString("ReplicationValve.session.invalid", request.getContext().getName(), id));
}
}
}
}
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.36 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.