| /* |
| * 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.geode.internal.sequencelog; |
| |
| import org.apache.geode.annotations.Immutable; |
| import org.apache.geode.distributed.internal.InternalDistributedSystem; |
| import org.apache.geode.internal.cache.CachedDeserializable; |
| import org.apache.geode.internal.cache.EntryEventImpl; |
| import org.apache.geode.internal.cache.LocalRegion; |
| import org.apache.geode.internal.cache.PlaceHolderDiskRegion; |
| import org.apache.geode.internal.cache.Token; |
| import org.apache.geode.internal.cache.entries.DiskEntry.RecoveredEntry; |
| import org.apache.geode.internal.cache.persistence.DiskStoreID; |
| import org.apache.geode.internal.offheap.StoredObject; |
| import org.apache.geode.internal.offheap.annotations.Unretained; |
| import org.apache.geode.util.internal.GeodeGlossary; |
| |
| |
| /** |
| * A wrapper around the graph logger that logs entry level events. |
| * |
| * |
| * TODO - I think I need some options to choose to deserialize a key to record states. |
| */ |
| public class EntryLogger { |
| @Immutable |
| private static final SequenceLogger GRAPH_LOGGER = SequenceLoggerImpl.getInstance(); |
| private static final ThreadLocal<String> SOURCE = new ThreadLocal<String>(); |
| private static final ThreadLocal<String> SOURCE_TYPE = new ThreadLocal<String>(); |
| |
| public static final String TRACK_VALUES_PROPERTY = |
| GeodeGlossary.GEMFIRE_PREFIX + "EntryLogger.TRACK_VALUES"; |
| private static final boolean TRACK_VALUES = Boolean.getBoolean(TRACK_VALUES_PROPERTY); |
| |
| public static void clearSource() { |
| if (isEnabled()) { |
| SOURCE.set(null); |
| SOURCE_TYPE.set(null); |
| } |
| } |
| |
| public static void setSource(Object source, String sourceType) { |
| if (isEnabled()) { |
| SOURCE.set(source.toString()); |
| SOURCE_TYPE.set(sourceType); |
| } |
| } |
| |
| public static void logPut(EntryEventImpl event) { |
| if (isEnabled()) { |
| GRAPH_LOGGER.logTransition(GraphType.KEY, getGraphName(event), getEdgeName("put"), |
| processValue(event.getRawNewValue()), getSource(), getDest()); |
| } |
| } |
| |
| private static String getEdgeName(String transition) { |
| String sourceType = SOURCE_TYPE.get(); |
| if (sourceType == null) { |
| sourceType = ""; |
| } else { |
| sourceType = sourceType + " "; |
| } |
| return sourceType + transition; |
| } |
| |
| public static void logInvalidate(EntryEventImpl event) { |
| if (isEnabled()) { |
| final String invalidationType = event.getOperation().isLocal() ? "local_invalid" : "invalid"; |
| GRAPH_LOGGER.logTransition(GraphType.KEY, getGraphName(event), getEdgeName("invalidate"), |
| invalidationType, getSource(), getDest()); |
| } |
| } |
| |
| public static void logDestroy(EntryEventImpl event) { |
| if (isEnabled()) { |
| GRAPH_LOGGER.logTransition(GraphType.KEY, getGraphName(event), getEdgeName("destroy"), |
| "destroyed", getSource(), getDest()); |
| } |
| } |
| |
| public static void logRecovery(Object owner, Object key, RecoveredEntry value) { |
| if (isEnabled()) { |
| GRAPH_LOGGER.logTransition(GraphType.KEY, getGraphNameFromOwner(owner, key), "recovery", |
| processValue(value.getValue()), getSource(), getDest()); |
| } |
| } |
| |
| public static void logPersistPut(String name, Object key, DiskStoreID diskStoreID) { |
| if (isEnabled()) { |
| GRAPH_LOGGER.logTransition(GraphType.KEY, getGraphName(name, key), "persist", "persisted", |
| getDest(), diskStoreID); |
| } |
| } |
| |
| public static void logPersistDestroy(String name, Object key, DiskStoreID diskStoreID) { |
| if (isEnabled()) { |
| GRAPH_LOGGER.logTransition(GraphType.KEY, getGraphName(name, key), "persist_destroy", |
| "destroy", getDest(), diskStoreID); |
| } |
| } |
| |
| public static void logInitialImagePut(Object owner, Object key, Object newValue) { |
| if (isEnabled()) { |
| GRAPH_LOGGER.logTransition(GraphType.KEY, getGraphNameFromOwner(owner, key), "GII", |
| processValue(newValue), getSource(), getDest()); |
| } |
| } |
| |
| public static void logTXDestroy(Object owner, Object key) { |
| if (isEnabled()) { |
| GRAPH_LOGGER.logTransition(GraphType.KEY, getGraphNameFromOwner(owner, key), |
| getEdgeName("txdestroy"), "destroyed", getSource(), getDest()); |
| } |
| } |
| |
| public static void logTXInvalidate(Object owner, Object key) { |
| if (isEnabled()) { |
| GRAPH_LOGGER.logTransition(GraphType.KEY, getGraphNameFromOwner(owner, key), |
| getEdgeName("txinvalidate"), "invalid", getSource(), getDest()); |
| } |
| } |
| |
| public static void logTXPut(Object owner, Object key, Object nv) { |
| if (isEnabled()) { |
| GRAPH_LOGGER.logTransition(GraphType.KEY, getGraphNameFromOwner(owner, key), |
| getEdgeName("txput"), processValue(nv), getSource(), getDest()); |
| } |
| } |
| |
| public static boolean isEnabled() { |
| return GRAPH_LOGGER.isEnabled(GraphType.KEY); |
| } |
| |
| private static Object getDest() { |
| return InternalDistributedSystem.getAnyInstance().getMemberId(); |
| } |
| |
| private static Object getSource() { |
| Object source = SOURCE.get(); |
| if (source == null) { |
| source = InternalDistributedSystem.getAnyInstance().getMemberId(); |
| } |
| return source; |
| } |
| |
| private static Object processValue(@Unretained Object rawNewValue) { |
| if (rawNewValue != null && Token.isInvalid(rawNewValue)) { |
| return "invalid"; |
| } |
| |
| if (!TRACK_VALUES) { |
| return "present"; |
| } |
| if (rawNewValue instanceof StoredObject) { |
| return "off-heap"; |
| } |
| if (rawNewValue instanceof CachedDeserializable) { |
| rawNewValue = ((CachedDeserializable) rawNewValue).getDeserializedForReading(); |
| } |
| if (rawNewValue instanceof byte[]) { |
| return "serialized:" + hash((byte[]) rawNewValue); |
| } |
| |
| return rawNewValue; |
| } |
| |
| private static Object hash(byte[] rawNewValue) { |
| int hash = 17; |
| int length = rawNewValue.length; |
| if (length > 100) { |
| length = 100; |
| } |
| for (int i = 0; i < length; i++) { |
| hash = 31 * hash + rawNewValue[i]; |
| } |
| |
| return Integer.valueOf(hash); |
| } |
| |
| private static String getGraphName(EntryEventImpl event) { |
| return getGraphName(event.getRegion().getFullPath(), event.getKey()); |
| } |
| |
| private static String getGraphNameFromOwner(Object owner, Object key) { |
| String ownerName; |
| if (owner instanceof LocalRegion) { |
| ownerName = ((LocalRegion) owner).getFullPath(); |
| } else if (owner instanceof PlaceHolderDiskRegion) { |
| ownerName = ((PlaceHolderDiskRegion) owner).getName(); |
| } else { |
| ownerName = owner.toString(); |
| } |
| return getGraphName(ownerName, key); |
| } |
| |
| private static String getGraphName(String ownerName, Object key) { |
| return ownerName + ":" + key; |
| } |
| |
| public static void logUpdateEntryVersion(EntryEventImpl event) { |
| if (isEnabled()) { |
| GRAPH_LOGGER.logTransition(GraphType.KEY, getGraphName(event), getEdgeName("update-version"), |
| "version-updated", getSource(), getDest()); |
| } |
| } |
| |
| } |