/* * Copyright 2008-2009 LinkedIn, Inc * * Licensed 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 voldemort.store.stats; import java.util.List; import java.util.Map; import voldemort.VoldemortException; import voldemort.store.CompositeVoldemortRequest; import voldemort.store.DelegatingStore; import voldemort.store.Store; import voldemort.store.StoreCapabilityType; import voldemort.utils.ByteArray; import voldemort.versioning.ObsoleteVersionException; import voldemort.versioning.Version; import voldemort.versioning.Versioned; /** * A store wrapper that tracks basic usage statistics * * */ public class StatTrackingStore extends DelegatingStore<ByteArray, byte[], byte[]> { private final StoreStats stats; private StoreStats getOrCreateStoreStats(Map<String, StoreStats> cachedStats, StoreStats parentStats) { if(cachedStats == null) { throw new IllegalArgumentException("cachedStats is null"); } synchronized (cachedStats) { String storeName = getName(); if (cachedStats.containsKey(storeName)) { return cachedStats.get(storeName); } StoreStats storeStats = new StoreStats(getName(), parentStats); cachedStats.put(storeName, storeStats); return storeStats; } } public StatTrackingStore(Store<ByteArray, byte[], byte[]> innerStore, StoreStats parentStats, Map<String, StoreStats> cachedStats) { super(innerStore); this.stats = getOrCreateStoreStats(cachedStats, parentStats); } public StatTrackingStore(Store<ByteArray, byte[], byte[]> innerStore, StoreStats parentStats) { super(innerStore); this.stats = new StoreStats(getName(), parentStats); } @Override public boolean delete(ByteArray key, Version version) throws VoldemortException { long start = System.nanoTime(); try { return super.delete(key, version); } catch(VoldemortException e) { stats.recordTime(Tracked.EXCEPTION, System.nanoTime() - start); throw e; } finally { stats.recordDeleteTime(System.nanoTime() - start, key.get().length); } } @Override public List<Version> getVersions(ByteArray key) throws VoldemortException { List<Version> result = null; long start = System.nanoTime(); try { result = super.getVersions(key); return result; } catch(VoldemortException e) { stats.recordTime(Tracked.EXCEPTION, System.nanoTime() - start); throw e; } finally { long duration = System.nanoTime() - start; boolean returningEmpty = true; if(result != null) { returningEmpty = result.size() == 0; } stats.recordGetVersionsTime(duration, returningEmpty); } } @Override public List<Versioned<byte[]>> get(ByteArray key, byte[] transforms) throws VoldemortException { List<Versioned<byte[]>> result = null; long start = System.nanoTime(); try { result = super.get(key, transforms); return result; } catch(VoldemortException e) { stats.recordTime(Tracked.EXCEPTION, System.nanoTime() - start); throw e; } finally { long duration = System.nanoTime() - start; long totalValueBytes = 0; boolean returningEmpty = true; if(result != null) { returningEmpty = result.size() == 0; for(Versioned<byte[]> bytes: result) { totalValueBytes += bytes.getValue().length; } } stats.recordGetTime(duration, returningEmpty, totalValueBytes, key.get().length); } } @Override public Map<ByteArray, List<Versioned<byte[]>>> getAll(Iterable<ByteArray> keys, Map<ByteArray, byte[]> transforms) throws VoldemortException { Map<ByteArray, List<Versioned<byte[]>>> result = null; long start = System.nanoTime(); try { result = super.getAll(keys, transforms); return result; } catch(VoldemortException e) { stats.recordTime(Tracked.EXCEPTION, System.nanoTime() - start); throw e; } finally { long duration = System.nanoTime() - start; long totalValueBytes = 0; long totalKeyBytes = 0; int requestedValues = 0; int returnedValues = 0; // Determine how many values were requested for(ByteArray k: keys) { totalKeyBytes += k.get().length; requestedValues++; } if(result != null) { // Determine the number of values being returned returnedValues = result.keySet().size(); // Determine the total size of the response for(List<Versioned<byte[]>> value: result.values()) { for(Versioned<byte[]> bytes: value) { totalValueBytes += bytes.getValue().length; } } } stats.recordGetAllTime(duration, requestedValues, returnedValues, totalValueBytes, totalKeyBytes); } } @Override public void put(ByteArray key, Versioned<byte[]> value, byte[] transforms) throws VoldemortException { long start = System.nanoTime(); try { super.put(key, value, transforms); } catch(ObsoleteVersionException e) { stats.recordTime(Tracked.OBSOLETE, System.nanoTime() - start); throw e; } catch(VoldemortException e) { stats.recordTime(Tracked.EXCEPTION, System.nanoTime() - start); throw e; } finally { stats.recordPutTimeAndSize(System.nanoTime() - start, value.getValue().length, key.get().length); } } @Override public Object getCapability(StoreCapabilityType capability) { if(StoreCapabilityType.STAT_TRACKER.equals(capability)) return this.stats; else return super.getCapability(capability); } public StoreStats getStats() { return stats; } @Override public List<Versioned<byte[]>> get(CompositeVoldemortRequest<ByteArray, byte[]> request) throws VoldemortException { List<Versioned<byte[]>> result = null; long start = System.nanoTime(); try { result = super.get(request); return result; } catch(VoldemortException e) { stats.recordTime(Tracked.EXCEPTION, System.nanoTime() - start); throw e; } finally { long duration = System.nanoTime() - start; long totalValueBytes = 0; boolean returningEmpty = true; if(result != null) { returningEmpty = result.size() == 0; for(Versioned<byte[]> bytes: result) { totalValueBytes += bytes.getValue().length; } } stats.recordGetTime(duration, returningEmpty, totalValueBytes, request.getKey().get().length); } } @Override // TODO: Validate all the keys in the request object public Map<ByteArray, List<Versioned<byte[]>>> getAll(CompositeVoldemortRequest<ByteArray, byte[]> request) throws VoldemortException { Map<ByteArray, List<Versioned<byte[]>>> result = null; long start = System.nanoTime(); try { result = super.getAll(request); return result; } catch(VoldemortException e) { stats.recordTime(Tracked.EXCEPTION, System.nanoTime() - start); throw e; } finally { long duration = System.nanoTime() - start; long totalValueBytes = 0; long totalKeyBytes = 0; int requestedValues = 0; int returnedValues = 0; // Determine how many values were requested for(ByteArray k: request.getIterableKeys()) { totalKeyBytes += k.get().length; requestedValues++; } if(result != null) { // Determine the number of values being returned returnedValues = result.keySet().size(); // Determine the total size of the response for(List<Versioned<byte[]>> value: result.values()) { for(Versioned<byte[]> bytes: value) { totalValueBytes += bytes.getValue().length; } } } stats.recordGetAllTime(duration, requestedValues, returnedValues, totalValueBytes, totalKeyBytes); } } @Override public void put(CompositeVoldemortRequest<ByteArray, byte[]> request) throws VoldemortException { long start = System.nanoTime(); try { super.put(request); } catch(ObsoleteVersionException e) { stats.recordTime(Tracked.OBSOLETE, System.nanoTime() - start); throw e; } catch(VoldemortException e) { stats.recordTime(Tracked.EXCEPTION, System.nanoTime() - start); throw e; } finally { stats.recordPutTimeAndSize(System.nanoTime() - start, request.getValue().getValue().length, request.getKey().get().length); } } @Override public boolean delete(CompositeVoldemortRequest<ByteArray, byte[]> request) throws VoldemortException { long start = System.nanoTime(); try { return super.delete(request); } catch(VoldemortException e) { stats.recordTime(Tracked.EXCEPTION, System.nanoTime() - start); throw e; } finally { stats.recordDeleteTime(System.nanoTime() - start, request.getKey().get().length); } } }