Repository: aurora Updated Branches: refs/heads/master 1a391d75f -> 9a93955a1
Implement custom MyBatis cache to record cache statistics. This swaps out our use of the MyBatis default cache with a custom one backed by Guava. The benefit of this is that we can now plumb cache statistics out which is helpful in debugging performance problems with MyBatis. Reviewed at https://reviews.apache.org/r/45821/ Project: http://git-wip-us.apache.org/repos/asf/aurora/repo Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/9a93955a Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/9a93955a Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/9a93955a Branch: refs/heads/master Commit: 9a93955a159cd2e2c55002d9c3c75004e5654351 Parents: 1a391d7 Author: Zameer Manji <[email protected]> Authored: Wed Apr 6 16:10:17 2016 -0700 Committer: Zameer Manji <[email protected]> Committed: Wed Apr 6 16:10:17 2016 -0700 ---------------------------------------------------------------------- .../scheduler/storage/db/MyBatisCacheImpl.java | 119 +++++++++++++++++++ .../scheduler/storage/db/AttributeMapper.xml | 4 +- .../scheduler/storage/db/TaskConfigMapper.xml | 4 +- .../aurora/scheduler/storage/db/TaskMapper.xml | 4 +- .../storage/db/MyBatisCacheImplTest.java | 52 ++++++++ 5 files changed, 180 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aurora/blob/9a93955a/src/main/java/org/apache/aurora/scheduler/storage/db/MyBatisCacheImpl.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/storage/db/MyBatisCacheImpl.java b/src/main/java/org/apache/aurora/scheduler/storage/db/MyBatisCacheImpl.java new file mode 100644 index 0000000..d9d406f --- /dev/null +++ b/src/main/java/org/apache/aurora/scheduler/storage/db/MyBatisCacheImpl.java @@ -0,0 +1,119 @@ +/** + * 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 org.apache.aurora.scheduler.storage.db; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReadWriteLock; + +import com.google.common.base.Preconditions; +import com.google.common.base.Supplier; +import com.google.common.cache.CacheBuilder; +import com.google.common.primitives.Ints; + +import org.apache.aurora.common.stats.StatImpl; +import org.apache.aurora.common.stats.Stats; +import org.apache.ibatis.cache.Cache; + +import static java.util.Objects.requireNonNull; + +public class MyBatisCacheImpl implements Cache { + private com.google.common.cache.Cache<Object, Object> delegate; + private final String id; + private Integer size; + private final AtomicInteger clearCount = new AtomicInteger(0); + + public MyBatisCacheImpl(String id) { + this.id = requireNonNull(id); + } + + public void setSize(Integer size) { + this.size = requireNonNull(size); + initCache(); + } + + private void initCache() { + Preconditions.checkState(delegate == null); + requireNonNull(size); + + delegate = CacheBuilder.newBuilder() + .maximumSize(size) + .recordStats() + .softValues() + .build(); + initStats(); + } + + private void initStats() { + makeStat("request_count", () -> delegate.stats().requestCount()); + makeStat("hit_count", () -> delegate.stats().hitCount()); + makeStat("hit_rate", () -> delegate.stats().hitRate()); + makeStat("miss_count", () -> delegate.stats().missCount()); + makeStat("miss_rate", () -> delegate.stats().missRate()); + makeStat("eviction_count", () -> delegate.stats().evictionCount()); + makeStat("size", () -> delegate.size()); + makeStat("clear_count", clearCount::get); + } + + private <T extends Number> void makeStat(String name, Supplier<T> supplier) { + String prefix = "db_storage_mybatis_cache_" + id + "_"; + Stats.export(new StatImpl<Number>(prefix + name) { + @Override + public Number read() { + return supplier.get(); + } + }); + } + + @Override + public String getId() { + return id; + } + + @Override + public void putObject(Object key, Object value) { + if (key == null || value == null) { + return; + } + delegate.put(key, value); + } + + @Override + public Object getObject(Object key) { + return delegate.getIfPresent(key); + } + + @Override + public Object removeObject(Object key) { + delegate.invalidate(key); + // MyBatis says the return value is not used. + return null; + } + + @Override + public void clear() { + delegate.invalidateAll(); + clearCount.incrementAndGet(); + } + + @Override + public int getSize() { + return Ints.saturatedCast(delegate.size()); + } + + @Override + public ReadWriteLock getReadWriteLock() { + // MyBatis says this value is no longer used. + return null; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/9a93955a/src/main/resources/org/apache/aurora/scheduler/storage/db/AttributeMapper.xml ---------------------------------------------------------------------- diff --git a/src/main/resources/org/apache/aurora/scheduler/storage/db/AttributeMapper.xml b/src/main/resources/org/apache/aurora/scheduler/storage/db/AttributeMapper.xml index 41519de..91c76ca 100644 --- a/src/main/resources/org/apache/aurora/scheduler/storage/db/AttributeMapper.xml +++ b/src/main/resources/org/apache/aurora/scheduler/storage/db/AttributeMapper.xml @@ -3,7 +3,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.apache.aurora.scheduler.storage.db.AttributeMapper"> - <cache size="50000" readOnly="true" /> + <cache type="org.apache.aurora.scheduler.storage.db.MyBatisCacheImpl"> + <property name="size" value="50000"/> + </cache> <insert id="insert"> INSERT INTO host_attributes ( host, http://git-wip-us.apache.org/repos/asf/aurora/blob/9a93955a/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskConfigMapper.xml ---------------------------------------------------------------------- diff --git a/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskConfigMapper.xml b/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskConfigMapper.xml index fd272cc..5218967 100644 --- a/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskConfigMapper.xml +++ b/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskConfigMapper.xml @@ -17,7 +17,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.apache.aurora.scheduler.storage.db.TaskConfigMapper"> - <cache size="1000" readOnly="true" /> + <cache type="org.apache.aurora.scheduler.storage.db.MyBatisCacheImpl"> + <property name="size" value="1000"/> + </cache> <insert id="insert" useGeneratedKeys="true" keyColumn="id" keyProperty="result.id"> INSERT INTO task_configs ( job_key_id, http://git-wip-us.apache.org/repos/asf/aurora/blob/9a93955a/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskMapper.xml ---------------------------------------------------------------------- diff --git a/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskMapper.xml b/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskMapper.xml index 0219bf3..fb78a39 100644 --- a/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskMapper.xml +++ b/src/main/resources/org/apache/aurora/scheduler/storage/db/TaskMapper.xml @@ -17,7 +17,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.apache.aurora.scheduler.storage.db.TaskMapper"> - <cache size="10000" readOnly="true" /> + <cache type="org.apache.aurora.scheduler.storage.db.MyBatisCacheImpl"> + <property name="size" value="10000"/> + </cache> <insert id="insertScheduledTask" useGeneratedKeys="true" keyColumn="id" keyProperty="result.id"> INSERT INTO tasks ( task_id, http://git-wip-us.apache.org/repos/asf/aurora/blob/9a93955a/src/test/java/org/apache/aurora/scheduler/storage/db/MyBatisCacheImplTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/aurora/scheduler/storage/db/MyBatisCacheImplTest.java b/src/test/java/org/apache/aurora/scheduler/storage/db/MyBatisCacheImplTest.java new file mode 100644 index 0000000..1ed1a12 --- /dev/null +++ b/src/test/java/org/apache/aurora/scheduler/storage/db/MyBatisCacheImplTest.java @@ -0,0 +1,52 @@ +/** + * 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 org.apache.aurora.scheduler.storage.db; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class MyBatisCacheImplTest { + private MyBatisCacheImpl cache; + + @Before + public void setUp() { + cache = new MyBatisCacheImpl("cache.id"); + } + + @Test(expected = NullPointerException.class) + public void testExceptionWithoutSize() { + cache.getSize(); + } + + @Test + public void testGetAndSet() { + String key = "key"; + String value = "value"; + + cache.setSize(100); + + assertNull(cache.getObject(key)); + + cache.putObject(key, value); + + assertEquals(cache.getObject(key), value); + + cache.clear(); + + assertNull(cache.getObject(key)); + } +}
