/* * 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.cache.partitioned; import org.junit.experimental.categories.Category; import org.junit.Test; import static org.junit.Assert.*; import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase; import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase; import org.apache.geode.test.junit.categories.DistributedTest; import java.util.Properties; import org.apache.geode.cache.CacheClosedException; import org.apache.geode.cache.CacheException; import org.apache.geode.cache.Declarable; import org.apache.geode.cache.EntryEvent; import org.apache.geode.cache.Region; import org.apache.geode.cache.util.CacheWriterAdapter; import org.apache.geode.cache30.CacheSerializableRunnable; import org.apache.geode.internal.cache.DiskStoreImpl; import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.test.dunit.AsyncInvocation; import org.apache.geode.test.dunit.IgnoredException; import org.apache.geode.test.dunit.ThreadUtils; import org.apache.geode.test.dunit.Host; import org.apache.geode.test.dunit.VM; import org.apache.geode.test.dunit.Wait; /** * Tests the basic use cases for PR persistence. * */ @Category(DistributedTest.class) public class PersistPRKRFDUnitTest extends PersistentPartitionedRegionTestBase { private static final int NUM_BUCKETS = 15; private static final int MAX_WAIT = 30 * 1000; static Object lockObject = new Object(); /** * do a put/modify/destroy while closing disk store * * to turn on debug, add following parameter in local.conf: hydra.VmPrms-extraVMArgs += * "-Ddisk.KRF_DEBUG=true"; */ @Test public void testCloseDiskStoreWhenPut() { final String title = "testCloseDiskStoreWhenPut:"; Host host = Host.getHost(0); VM vm0 = host.getVM(0); createPR(vm0, 0); createData(vm0, 0, 10, "a"); vm0.invoke(new CacheSerializableRunnable(title + "server add writer") { public void run2() throws CacheException { Region region = getRootRegion(PR_REGION_NAME); // let the region to hold on the put until diskstore is closed if (!DiskStoreImpl.KRF_DEBUG) { region.getAttributesMutator().setCacheWriter(new MyWriter()); } } }); // create test AsyncInvocation async1 = vm0.invokeAsync(new CacheSerializableRunnable(title + "async create") { public void run2() throws CacheException { Region region = getRootRegion(PR_REGION_NAME); IgnoredException expect = IgnoredException.addIgnoredException("CacheClosedException"); try { region.put(10, "b"); fail("Expect CacheClosedException here"); } catch (CacheClosedException cce) { System.out.println(title + cce.getMessage()); if (DiskStoreImpl.KRF_DEBUG) { assert cce.getMessage().contains("The disk store is closed."); } else { assert cce.getMessage().contains("The disk store is closed"); } } finally { expect.remove(); } } }); vm0.invoke(new CacheSerializableRunnable(title + "close disk store") { public void run2() throws CacheException { GemFireCacheImpl gfc = (GemFireCacheImpl) getCache(); Wait.pause(500); gfc.closeDiskStores(); synchronized (lockObject) { lockObject.notify(); } } }); ThreadUtils.join(async1, MAX_WAIT); closeCache(vm0); // update createPR(vm0, 0); vm0.invoke(new CacheSerializableRunnable(title + "server add writer") { public void run2() throws CacheException { Region region = getRootRegion(PR_REGION_NAME); // let the region to hold on the put until diskstore is closed if (!DiskStoreImpl.KRF_DEBUG) { region.getAttributesMutator().setCacheWriter(new MyWriter()); } } }); async1 = vm0.invokeAsync(new CacheSerializableRunnable(title + "async update") { public void run2() throws CacheException { Region region = getRootRegion(PR_REGION_NAME); IgnoredException expect = IgnoredException.addIgnoredException("CacheClosedException"); try { region.put(1, "b"); fail("Expect CacheClosedException here"); } catch (CacheClosedException cce) { System.out.println(title + cce.getMessage()); if (DiskStoreImpl.KRF_DEBUG) { assert cce.getMessage().contains("The disk store is closed."); } else { assert cce.getMessage().contains("The disk store is closed"); } } finally { expect.remove(); } } }); vm0.invoke(new CacheSerializableRunnable(title + "close disk store") { public void run2() throws CacheException { GemFireCacheImpl gfc = (GemFireCacheImpl) getCache(); Wait.pause(500); gfc.closeDiskStores(); synchronized (lockObject) { lockObject.notify(); } } }); ThreadUtils.join(async1, MAX_WAIT); closeCache(vm0); // destroy createPR(vm0, 0); vm0.invoke(new CacheSerializableRunnable(title + "server add writer") { public void run2() throws CacheException { Region region = getRootRegion(PR_REGION_NAME); // let the region to hold on the put until diskstore is closed if (!DiskStoreImpl.KRF_DEBUG) { region.getAttributesMutator().setCacheWriter(new MyWriter()); } } }); async1 = vm0.invokeAsync(new CacheSerializableRunnable(title + "async destroy") { public void run2() throws CacheException { Region region = getRootRegion(PR_REGION_NAME); IgnoredException expect = IgnoredException.addIgnoredException("CacheClosedException"); try { region.destroy(2, "b"); fail("Expect CacheClosedException here"); } catch (CacheClosedException cce) { System.out.println(title + cce.getMessage()); if (DiskStoreImpl.KRF_DEBUG) { assert cce.getMessage().contains("The disk store is closed."); } else { assert cce.getMessage().contains("The disk store is closed"); } } finally { expect.remove(); } } }); vm0.invoke(new CacheSerializableRunnable(title + "close disk store") { public void run2() throws CacheException { GemFireCacheImpl gfc = (GemFireCacheImpl) getCache(); Wait.pause(500); gfc.closeDiskStores(); synchronized (lockObject) { lockObject.notify(); } } }); ThreadUtils.join(async1, MAX_WAIT); checkData(vm0, 0, 10, "a"); checkData(vm0, 10, 11, null); closeCache(vm0); } private static class MyWriter extends CacheWriterAdapter implements Declarable { public MyWriter() {} public void init(Properties props) {} public void beforeCreate(EntryEvent event) { try { synchronized (lockObject) { lockObject.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } public void beforeUpdate(EntryEvent event) { try { synchronized (lockObject) { lockObject.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } public void beforeDestroy(EntryEvent event) { try { synchronized (lockObject) { lockObject.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } } }