com.gemstone.gemfire.internal.cache.Bug37500JUnitTest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-junit Show documentation
Show all versions of gemfire-junit Show documentation
SnappyData store based off Pivotal GemFireXD
/*
* Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
*
* 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. See accompanying
* LICENSE file.
*/
package com.gemstone.gemfire.internal.cache;
import com.gemstone.gemfire.cache.Scope;
import java.io.File;
/**
* This is a bugtest for bug 37500.
*
* @author Dinesh Patel
* @author Mitul Bid
*
*/
public class Bug37500JUnitTest extends DiskRegionTestingBase
{
/** The disk region configuration object for the test */
private DiskRegionProperties diskProps = new DiskRegionProperties();
/** The key for entry1 */
static final String KEY1 = "KEY1";
/** The key for entry2 */
static final String KEY2 = "KEY2";
/** Boolean to indicate the roller thread to proceed */
static volatile boolean proceedForRolling = false;
/**
* Boolean to decide whether we want to allow roller to run ( used via
* CacheObserver callback
*/
static volatile boolean notifyRoller = false;
/**
* Constructor
*
* @param name -
* Name of the test instance
*/
public Bug37500JUnitTest(String name) {
super(name);
}
/**
* This test does the following:
* 1. Create a disk-region with following configurations :
* dirSize = 2000 bytes
* maxOplogSize = 500 bytes
* rolling = true
* syncMode = true
* approx size on disk for operations = 440 bytes
*
* 2.Make Roller go into WAIT state via CacheObserverAdapter.beforeGoingToCompact
* callback
* 3.Put 440 bytes , it will go in oplog1
* 4.Put another 440 bytes ,it will go in oplog1
* 5.Put 440 bytes , switching will be caused, it will go in oplog2, Roller
* will remained blocked (step 2)
* 6.Put 440 bytes , it will go in oplog2, oplog2 will now be full
* 7.Notify the Roller and put 440 bytes , this will try further switching.
* The put will fail with exception due to bug 37500. The put thread takes an
* entry level lock for entry2 ( the one with KEY2) and tries to write to disk
* but there is no free space left, so it goes into wait, expecting Roller to
* free up the space. The roller, which has now been notified to run, tries to
* roll entry2 for which it seeks entry level lock which has been acquired by
* put-thread. So the put thread eventually comes out of the wait with
* DiskAccessException
*
* Another scenario for this bug is, once the disk space was getting exhausted ,
* the entry operation threads which had already taken a lock on Entry got
* stuck trying to seek the Oplog Lock. The switching thread had acquired the
* Oplog.lock & was waiting for the roller thread to free disk space. Since
* the roller needed to acquire Entry lock to roll, it was unable to do so
* because of entry operation threads. This would cause the entry operation
* threads to get DiskAccessException after completing the stipulated wait.
* The Roller was able to free space only when it has rolled all the relevant
* entries which could happen only when the entry operation threads released
* the entry lock after getting DiskAccessException.
*
*
* @throws Exception
*/
public void testBug37500() throws Exception
{
final int MAX_OPLOG_SIZE = 1000;
diskProps.setMaxOplogSize(MAX_OPLOG_SIZE);
diskProps.setPersistBackup(true);
diskProps.setRolling(true);
diskProps.setSynchronous(false);
File testdir = new File("bug37500-diskDir");
testdir.mkdir();
testdir.deleteOnExit();
diskProps.setDiskDirsAndSizes(new File[] { testdir }, new int[] { 2000 });
LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER = true;
region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
CacheObserver old = CacheObserverHolder
.setInstance(new CacheObserverAdapter() {
public void beforeGoingToCompact()
{
if (!proceedForRolling) {
synchronized (Bug37500JUnitTest.class) {
if (!proceedForRolling) {
try {
cache.getLogger().info(
"beforeGoingToCompact :: going into wait");
Bug37500JUnitTest.class.wait();
}
catch (InterruptedException e) {
cache.getLogger().info("Roller interrupted");
fail("interrupted");
}
cache.getLogger().info(
"beforeGoingToCompact :: coming out of wait");
}
}
}
}
public void beforeSwitchingOplog()
{
if (notifyRoller) {
cache.getLogger().info(
"beforeSwitchingOplog :: going to notify Roller");
synchronized (Bug37500JUnitTest.class) {
proceedForRolling = true;
Bug37500JUnitTest.class.notify();
cache.getLogger().info(
"beforeSwitchingOplog :: notified the Roller");
}
}
}
});
cache.getLogger().info("goin to put no. 1");
// put 440 bytes , it will go in oplog1
region.put(KEY1, new byte[420]);
cache.getLogger().info("goin to put no. 2");
// put another 440 bytes ,it will go in oplog1
region.put(KEY2, new byte[420]);
cache.getLogger().info("goin to put no. 3");
// put 440 bytes , switching will be caused, it will go in oplog2 (value
// size increased to 432 as key wont be written to disk for UPDATE)
region.put(KEY1, new byte[432]);
cache.getLogger().info("goin to put no. 4");
// put 440 bytes , it will go in oplog2
region.put(KEY1, new byte[432]);
notifyRoller = true;
cache.getLogger().info("goin to put no. 5");
// put 440 bytes , this will try further switching
region.put(KEY2, new byte[432]);
LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER = false;
CacheObserverHolder.setInstance(old);
closeDown();
}
}