/*
 * 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;

import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;

import org.junit.Test;

import org.apache.geode.cache.DiskStore;
import org.apache.geode.cache.EntryNotFoundException;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.Scope;
import org.apache.geode.internal.Assert;
import org.apache.geode.internal.cache.entries.DiskEntry;

/**
 * Disk region recovery tests
 *
 * @since GemFire 5.1
 */
public class DiskRegRecoveryJUnitTest extends DiskRegionTestingBase {

  private static final int EMPTY_RVV_SIZE = 6;
  private static final int ENTRY_SIZE = 1024;

  private static boolean oplogsIDsNotifiedToRoll;

  private boolean proceedWithRolling;
  private boolean rollingDone;
  private boolean verifiedOplogs;
  private final Object verifiedSync = new Object();

  private final DiskRegionProperties diskProps = new DiskRegionProperties();

  @Override
  protected final void postSetUp() throws Exception {
    diskProps.setDiskDirs(dirs);
  }

  /**
   * Disk region recovery test for Persist only with sync writes. Test has four steps : STEP 1:
   * Create cache. Create Region. Put entries. Close cache. STEP 2: Create cache. Create Region with
   * the same name as that of in STEP 1. Put few more entries. Get and verify the entries put in
   * STEP 1 and STEP 2 STEP 3: Again Create cache. Create Region with the same name as that of in
   * STEP 1. Get and verify the entries put in STEP 1 and STEP 2. STEP 4: Create cache. Create
   * Region with the same name as that of in STEP 1. Get and verify the entries put in STEP 1 and
   * STEP 2.
   */
  @Test
  public void testDiskRegRecovery() {
    /**
     * STEP 1
     */
    diskProps.setPersistBackup(true);
    diskProps.setRegionName("RecoveryTestRegion");
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    verifyOplogSizeZeroAfterRecovery(region);
    final byte[] value = new byte[ENTRY_SIZE];
    Arrays.fill(value, (byte) 77);
    for (int i = 0; i < 100; i++) {
      region.put(i, value);
    }
    // for recovery test:
    try {
      region.put("100", new byte[1024]);
      region.put("101", "101");
      region.put("102", 'a');
      region.put("103", new Byte("103"));
      region.put("104", Boolean.TRUE);
      region.put("105", new Short("105"));
      region.put("106", 106);
      region.put("107", 107L);
      region.put("108", 108F);
      region.put("109", 109d);
    } catch (Exception ex) {
      ex.printStackTrace();
      fail("FAILED WHILE PUT:" + ex);
    }
    // Verifying the get operation:
    getByteArrVal("100", region);
    assertEquals("101", region.get("101"));
    assertEquals('a', region.get("102"));
    assertEquals(new Byte("103"), region.get("103"));
    assertEquals(Boolean.TRUE, region.get("104"));
    assertEquals(new Short("105"), region.get("105"));
    assertEquals(106, region.get("106"));
    assertEquals(107L, region.get("107"));
    assertEquals(108F, region.get("108"));
    assertEquals(109d, region.get("109"));
    int origSize = region.size();
    /**
     * close the cache after that create it again and then put few more values
     */
    if (cache != null) {
      cache.close();
    }

    /**
     * STEP 2: create the cache and region with the same name
     */
    try {
      try {
        cache = createCache();
      } catch (Exception e) {
        fail(" failure in creation of cache due to " + e);
      }
      // Create region
      diskProps.setPersistBackup(true);
      diskProps.setRegionName("RecoveryTestRegion");
      region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
      assertEquals(origSize, region.size());
      // Verifying the get operation:
      getByteArrVal("100", region);
      assertEquals("101", region.get("101"));
      assertEquals('a', region.get("102"));
      assertEquals(new Byte("103"), region.get("103"));
      assertEquals(Boolean.TRUE, region.get("104"));
      assertEquals(new Short("105"), region.get("105"));
      assertEquals(106, region.get("106"));
      assertEquals(107L, region.get("107"));
      assertEquals(108F, region.get("108"));
      assertEquals(109d, region.get("109"));
      // put few more entries
      region.put("110", "110");
      region.put("111", 'b');
      region.put("112", new Byte("112"));
      region.put("113", Boolean.FALSE);
      region.put("114", new Short("114"));
      region.put("115", 115);
      region.put("116", 116L);
      region.put("117", 117F);
      region.put("118", 118d);
      region.put("119", new byte[0]);
    } catch (Exception e) {
      logWriter.error("exception not expected", e);
      fail("failed while (in STEP 2) creating the cache and/or region" + e);
    }
    // Verifying the get operation:
    getByteArrVal("100", region);
    assertTrue(region.get("101").equals("101"));
    assertTrue(region.get("102").equals('a'));
    assertTrue(region.get("103").equals(new Byte("103")));
    assertTrue(region.get("104").equals(Boolean.TRUE));
    assertTrue(region.get("105").equals(new Short("105")));
    assertTrue(region.get("106").equals(106));
    assertTrue(region.get("107").equals(107L));
    assertTrue(region.get("108").equals(108F));
    assertTrue(region.get("109").equals(109d));
    assertTrue(region.get("110").equals("110"));
    assertTrue(region.get("111").equals('b'));
    assertTrue(region.get("112").equals(new Byte("112")));
    assertTrue(region.get("113").equals(Boolean.FALSE));
    assertTrue(region.get("114").equals(new Short("114")));
    assertTrue(region.get("115").equals(115));
    assertTrue(region.get("116").equals(116L));
    assertTrue(region.get("117").equals(117F));
    assertTrue(region.get("118").equals(118d));
    getByteArrValZeroLnth("119", region);
    /**
     * close the cache after that create it again
     */
    if (cache != null) {
      cache.close();
      if (logWriter.fineEnabled()) {
        logWriter.fine("Cache closed");
      }
    }

    /**
     * STEP 3: Create the cache and region And close the cache
     */
    try {
      try {
        cache = createCache();
      } catch (Exception e) {
        fail(" failure in creation of cache due to " + e);
      }
      if (logWriter.fineEnabled()) {
        logWriter.fine("Cache created to test the recovery..");
      }
      // Create region
      diskProps.setPersistBackup(true);
      diskProps.setRegionName("RecoveryTestRegion");
      region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    } catch (Exception e) {
      e.printStackTrace();
      fail("failed while (in STEP 3) creating the cache and/or region" + e);
    }
    // Verifying the get operation:
    getByteArrVal("100", region);
    assertTrue(region.get("101").equals("101"));
    assertTrue(region.get("102").equals('a'));
    assertTrue(region.get("103").equals(new Byte("103")));
    assertTrue(region.get("104").equals(Boolean.TRUE));
    assertTrue(region.get("105").equals(new Short("105")));
    assertTrue(region.get("106").equals(106));
    assertTrue(region.get("107").equals(107L));
    assertTrue(region.get("108").equals(108F));
    assertTrue(region.get("109").equals(109d));
    assertTrue(region.get("110").equals("110"));
    assertTrue(region.get("111").equals('b'));
    assertTrue(region.get("112").equals(new Byte("112")));
    assertTrue(region.get("113").equals(Boolean.FALSE));
    assertTrue(region.get("114").equals(new Short("114")));
    assertTrue(region.get("115").equals(115));
    assertTrue(region.get("116").equals(116L));
    assertTrue(region.get("117").equals(117F));
    assertTrue(region.get("118").equals(118d));
    getByteArrValZeroLnth("119", region);
    /**
     * close the cache after that create it again
     */
    if (cache != null) {
      cache.close();
      if (logWriter.fineEnabled()) {
        logWriter.fine("Cache closed");
      }
    }

    /**
     * STEP 4: Create the cache and region verify disk reg recovery And close the cache
     */
    try {
      try {
        cache = createCache();
      } catch (Exception e) {
        fail(" failure in creation of cache due to " + e);
      }
      if (logWriter.fineEnabled()) {
        logWriter.fine("Cache created to test the recovery..");
      }
      // Create region
      diskProps.setPersistBackup(true);
      diskProps.setRegionName("RecoveryTestRegion");
      region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    } catch (Exception e) {
      e.printStackTrace();
      fail("failed while (in STEP 4) creating the cache and/or region" + e);
    }
    // Get all the test values, put in STEP 1 & 2:
    // Verifying the get operation:
    getByteArrVal("100", region);
    assertTrue(region.get("101").equals("101"));
    assertTrue(region.get("102").equals('a'));
    assertTrue(region.get("103").equals(new Byte("103")));
    assertTrue(region.get("104").equals(Boolean.TRUE));
    assertTrue(region.get("105").equals(new Short("105")));
    assertTrue(region.get("106").equals(106));
    assertTrue(region.get("107").equals(107L));
    assertTrue(region.get("108").equals(108F));
    assertTrue(region.get("109").equals(109d));
    assertTrue(region.get("110").equals("110"));
    assertTrue(region.get("111").equals('b'));
    assertTrue(region.get("112").equals(new Byte("112")));
    assertTrue(region.get("113").equals(Boolean.FALSE));
    assertTrue(region.get("114").equals(new Short("114")));
    assertTrue(region.get("115").equals(115));
    assertTrue(region.get("116").equals(116L));
    assertTrue(region.get("117").equals(117F));
    assertTrue(region.get("118").equals(118d));
    getByteArrValZeroLnth("119", region);

    closeDown(); // closes disk file which will flush all buffers
  }

  /**
   * Disk region recovery test for Persist only with sync writes. Test has four steps : STEP 1:
   * Create cache. Create Region. Put entries. Close cache. STEP 2: Create cache. Create Region with
   * the same name as that of in STEP 1. Delete some entries. Close the Cache * 3: Again Create
   * cache. Create Region with the same name as that of in STEP 4) Verify that the entries got
   * deleted
   */
  @Test
  public void testBug39989_1() {
    /**
     * STEP 1
     */
    diskProps.setPersistBackup(true);
    diskProps.setRegionName("RecoveryTestRegion");
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    verifyOplogSizeZeroAfterRecovery(region);
    final byte[] value = new byte[ENTRY_SIZE];
    Arrays.fill(value, (byte) 77);
    for (int i = 0; i < 10; i++) {

      region.put(i, value);
    }

    /**
     * close the cache after that create it again and then put few more values
     */
    if (cache != null) {
      cache.close();
    }

    /**
     * STEP 2: create the cache and region with the same name
     */
    try {
      try {
        cache = createCache();
      } catch (Exception e) {
        fail(" failure in creation of cache due to " + e);
      }
      // Create region
      diskProps.setPersistBackup(true);
      diskProps.setRegionName("RecoveryTestRegion");
      region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
      // Remove the recovered entries
      for (int i = 0; i < 10; i++) {
        region.remove(i);
      }


    } catch (Exception e) {
      logWriter.error("exception not expected", e);
      fail("failed while (in STEP 2) creating the cache and/or region" + e);
    }
    /**
     * close the cache after that create it again
     */
    if (cache != null) {
      cache.close();
      if (logWriter.fineEnabled()) {
        logWriter.fine("Cache closed");
      }
    }

    /**
     * STEP 3: Create the cache and region And close the cache
     */
    try {
      try {
        cache = createCache();
      } catch (Exception e) {
        fail(" failure in creation of cache due to " + e);
      }
      if (logWriter.fineEnabled()) {
        logWriter.fine("Cache created to test the recovery..");
      }
      // Create region
      diskProps.setPersistBackup(true);
      diskProps.setRegionName("RecoveryTestRegion");
      region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
      // Size should be zero
      assertEquals(0, region.size());
    } catch (Exception e) {
      e.printStackTrace();
      fail("failed while (in STEP 3) creating the cache and/or region" + e);
    }

    closeDown(); // closes disk file which will flush all buffers
  }

  /**
   * Disk region recovery test for Persist only with sync writes. Test has four steps : STEP 1:
   * Create cache. Create Region. Put entries. Close cache. STEP 2: Create cache. Create Region with
   * the same name as that of in STEP 1. Delete some entries. 3) Recreate the deleted entries Close
   * the Cache * 3: Again Create cache. 4) check if the region creation is successful
   */
  @Test
  public void testBug39989_2() {
    /**
     * STEP 1
     */
    diskProps.setPersistBackup(true);
    diskProps.setRegionName("RecoveryTestRegion");
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    verifyOplogSizeZeroAfterRecovery(region);
    final byte[] value = new byte[ENTRY_SIZE];
    final byte[] value2 = new byte[ENTRY_SIZE + 1];
    Arrays.fill(value, (byte) 77);
    Arrays.fill(value2, (byte) 77);
    for (int i = 0; i < 10; i++) {
      region.put(i, value);
    }

    /**
     * close the cache after that create it again and then put few more values
     */
    if (cache != null) {
      cache.close();
    }

    /**
     * STEP 2: create the cache and region with the same name
     */
    try {
      try {
        cache = createCache();
      } catch (Exception e) {
        fail(" failure in creation of cache due to " + e);
      }
      // Create region
      diskProps.setPersistBackup(true);
      diskProps.setRegionName("RecoveryTestRegion");
      region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
      assertEquals(10, region.size());
      // Remove the recovered entries
      for (int i = 0; i < 10; i++) {
        region.remove(i);
      }

      // add new entries
      for (int i = 0; i < 10; i++) {
        region.put(i, value2);
      }


    } catch (Exception e) {
      logWriter.error("exception not expected", e);
      fail("failed while (in STEP 2) creating the cache and/or region" + e);
    }
    /**
     * close the cache after that create it again
     */
    if (cache != null) {
      cache.close();
      if (logWriter.fineEnabled()) {
        logWriter.fine("Cache closed");
      }
    }

    /**
     * STEP 3: Create the cache and region And close the cache
     */
    try {
      try {
        cache = createCache();
      } catch (Exception e) {
        fail(" failure in creation of cache due to " + e);
      }
      if (logWriter.fineEnabled()) {
        logWriter.fine("Cache created to test the recovery..");
      }
      // Create region
      diskProps.setPersistBackup(true);
      diskProps.setRegionName("RecoveryTestRegion");
      region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
      assertEquals(10, region.size());
    } catch (Exception e) {
      e.printStackTrace();
      fail("failed while (in STEP 3) creating the cache and/or region" + e);
    }

    closeDown(); // closes disk file which will flush all buffers
  }

  /**
   * To validate the get operation performed on a byte array.
   */
  private void getByteArrVal(String key, Region region) {
    byte[] val = (byte[]) region.get(key);
    // verify that the retrieved byte[] equals to the value put initially.
    // val should be an unitialized array of bytes of length 1024
    assertEquals(1024, val.length);
    for (int i = 0; i < 1024; i++) {
      assertEquals(0, val[i]);
    }
  }

  /**
   * to validate the get operation performed on a byte array of length zero
   */
  private boolean getByteArrValZeroLnth(String key, Region region) {
    Object val0 = null;
    byte[] val2 = new byte[0];
    try {
      val0 = region.get(key);
    } catch (Exception ex) {
      ex.printStackTrace();
      fail("Failed to get the value on disk");
    }
    // verify that the retrieved byte[] equals to the value put initially.
    boolean result = false;
    byte[] x = null;
    x = (byte[]) val0;
    // verify that the value of the entry is an instance of byte []
    assertTrue("the value of the entry having key 119 is NOT an" + " instance of byte []",
        val0 instanceof byte[]);

    result = x.length == val2.length;

    if (!result) {
      fail("The lenghth of byte[] put at 119th key obtained from disk "
          + "is not euqal to the lenght of byte[] put initially");
    }
    return result;
  }

  private void verifyOplogSizeZeroAfterRecovery(Region region) {
    assertEquals(
        Oplog.OPLOG_MAGIC_SEQ_REC_SIZE * 2 + Oplog.OPLOG_DISK_STORE_REC_SIZE * 2 + EMPTY_RVV_SIZE
            + Oplog.OPLOG_GEMFIRE_VERSION_REC_SIZE * 2,
        ((LocalRegion) region).getDiskRegion().testHook_getChild().getOplogSize());
  }

  @Test
  public void testNoEvictionDuringRecoveryIfNoGIIRecoverValuesTrue() {
    String oldValue = System.getProperty(DiskStoreImpl.RECOVER_VALUE_PROPERTY_NAME);
    String oldLruValue = System.getProperty(DiskStoreImpl.RECOVER_LRU_VALUES_PROPERTY_NAME);
    System.setProperty(DiskStoreImpl.RECOVER_VALUE_PROPERTY_NAME, "true");
    System.setProperty(DiskStoreImpl.RECOVER_LRU_VALUES_PROPERTY_NAME, "true");
    try {
      diskProps.setDiskDirs(dirs);
      diskProps.setPersistBackup(true);
      int overflowCapacity = 5;
      diskProps.setOverFlowCapacity(overflowCapacity);
      diskProps.setRegionName("RecoveryTestRegion");
      region = DiskRegionHelperFactory.getSyncOverFlowAndPersistRegion(cache, diskProps);

      int size = 1000;

      for (int i = 0; i < size; i++) {
        region.put(i, i);
      }
      region.close();
      region = DiskRegionHelperFactory.getSyncOverFlowAndPersistRegion(cache, diskProps);

      int serilizedValuesInVm = 0;
      for (int i = 0; i < size; i++) {
        try {
          Object value = ((LocalRegion) region).getValueInVM(i);
          if (value instanceof CachedDeserializable) {
            serilizedValuesInVm++;
          }
        } catch (EntryNotFoundException e) {
          fail("Entry not found not expected but occurred ");
        }
      }
      // Test to see if values are in serialized form, when disk recovery is performed.
      if (serilizedValuesInVm != overflowCapacity) {
        // overflowCapacity - number of max items region will hold.
        fail("Values are not in default Serialized form, when it was loaded from disk.");
      }

      // verifyOplogSizeZeroAfterRecovery(region);
      for (int i = 0; i < size; i++) {
        Assert.assertTrue(region.get(i).equals(i));
      }
      // region.close();
    } finally {
      if (oldValue != null) {
        System.setProperty(DiskStoreImpl.RECOVER_VALUE_PROPERTY_NAME, oldValue);
      } else {
        System.clearProperty(DiskStoreImpl.RECOVER_VALUE_PROPERTY_NAME);
      }

      if (oldLruValue != null) {
        System.setProperty(DiskStoreImpl.RECOVER_LRU_VALUES_PROPERTY_NAME, oldLruValue);
      } else {
        System.clearProperty(DiskStoreImpl.RECOVER_LRU_VALUES_PROPERTY_NAME);
      }
    }
  }

  @Test
  public void testNoEvictionDuringRecoveryIfNoGIIRecoverValuesFalse() {
    String oldValue = System.getProperty(DiskStoreImpl.RECOVER_VALUE_PROPERTY_NAME);
    System.setProperty(DiskStoreImpl.RECOVER_VALUE_PROPERTY_NAME, "false");
    try {
      diskProps.setDiskDirs(dirs);
      diskProps.setPersistBackup(true);
      diskProps.setOverFlowCapacity(1);
      diskProps.setRegionName("RecoveryTestRegion");
      region = DiskRegionHelperFactory.getSyncOverFlowAndPersistRegion(cache, diskProps);

      for (int i = 0; i < 1000; i++) {
        region.put(i, i);
      }

      region.close();

      region = DiskRegionHelperFactory.getSyncOverFlowAndPersistRegion(cache, diskProps);

      for (int i = 0; i < 1000; i++) {
        try {
          ((LocalRegion) region).getValueInVM(i);
        } catch (EntryNotFoundException e) {
          fail("Entry not found not expected but occurred ");
        }
      }

      // verifyOplogSizeZeroAfterRecovery(region);
      for (int i = 0; i < 1000; i++) {
        try {
          Assert.assertTrue(((LocalRegion) region).getValueInVM(i) == null);
        } catch (EntryNotFoundException e) {
          fail("Entry not found not expected but occurred ");
        }
      }
      for (int i = 0; i < 1000; i++) {
        try {
          Assert.assertTrue(
              ((LocalRegion) region).getValueOnDisk(i).equals(i));
        } catch (EntryNotFoundException e) {
          fail("Entry not found not expected but occurred ");
        }
      }
      // region.close();
    } finally {
      if (oldValue != null) {
        System.setProperty(DiskStoreImpl.RECOVER_VALUE_PROPERTY_NAME, oldValue);
      } else {
        System.clearProperty(DiskStoreImpl.RECOVER_VALUE_PROPERTY_NAME);
      }
    }
  }

  @Test
  public void testEmptyRegionRecover() {
    diskProps.setDiskDirs(dirs);
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    Assert.assertTrue(region.size() == 0);
    verifyOplogSizeZeroAfterRecovery(region);
    region.close();
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    Assert.assertTrue(region.size() == 0);
    verifyOplogSizeZeroAfterRecovery(region);
    region.close();
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    Assert.assertTrue(region.size() == 0);
    verifyOplogSizeZeroAfterRecovery(region);
    region.close();
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    Assert.assertTrue(region.size() == 0);
    verifyOplogSizeZeroAfterRecovery(region);
    region.close();
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    Assert.assertTrue(region.size() == 0);
    verifyOplogSizeZeroAfterRecovery(region);
    // region.close();
  }

  @Test
  public void testReadCorruptedFile() {
    diskProps.setDiskDirs(dirs);
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);

    byte[] value = new byte[1024];

    region.put("1", value);
    region.put("2", value);
    region.put("3", value);
    File oplogFile = null;
    try {
      oplogFile = ((LocalRegion) region).getDiskRegion().testHook_getChild().getOplogFileForTest();
    } catch (Exception e) {
      logWriter.error(
          "Exception in synching data present in the buffers of RandomAccessFile of Oplog, to the disk",
          e);
      fail("Test failed because synching of data present in buffer of RandomAccesFile ");
    }
    region.close();
    try {
      FileInputStream fis = new FileInputStream(oplogFile);
      DataInputStream dis = new DataInputStream(new BufferedInputStream(fis, 1024 * 1024));
      byte[] values = new byte[1000 * 3];
      dis.read(values);
      dis.close();
      fis.close();
      FileOutputStream fos = new FileOutputStream(oplogFile);
      fos.write(values);
      fos.close();

    } catch (FileNotFoundException e) {
      fail(" file expected to be there but not found");
    } catch (IOException e) {
      fail(" exception due to" + e);
    }

    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);

    Assert.assertTrue(region.size() == 2, "Expected size to be 2 but it is " + region.size());
    // region.close();
  }

  @Test
  public void testForceCompactionForRegionWithRollingDisabled() throws Exception {
    diskProps.setDiskDirs(dirs);
    diskProps.setMaxOplogSize(2048 + (18 * 2) + 15 * 7);
    diskProps.setRolling(false);
    diskProps.setAllowForceCompaction(true);
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    // region created

    LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER = false;

    // set cache observer to check oplogs rolling
    CacheObserver co = CacheObserverHolder.setInstance(new CacheObserverAdapter() {
      @Override
      public void afterHavingCompacted() {
        synchronized (region) {
          if (!rollingDone) {
            rollingDone = true;
          } else {
            fail("rollingDone was set before actually rolling");
          }
        }
      }
    });

    byte[] value = new byte[900]; // two values per oplog
    region.put("0", value);
    region.put("1", value);
    region.put("2", value);
    region.put("3", value);
    region.put("4", value);
    region.put("5", value);
    region.put("6", value);
    region.put("7", value);
    region.put("8", value);
    region.put("9", value);

    LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER = true;

    // Should have nothing to roll because each oplog still has
    // both entries in it as live.
    // start force rolling on the region
    // get array of oplog IDs being picked up for rolling
    oplogsIDsNotifiedToRoll = ((LocalRegion) region).getDiskStore().forceCompaction();
    assertEquals(false, oplogsIDsNotifiedToRoll);

    // now destroy all "odd" entries; This should allow each oplog to be compacted
    region.remove("1");
    region.remove("3");
    region.remove("5");
    region.remove("7");
    region.remove("9");
    oplogsIDsNotifiedToRoll = ((LocalRegion) region).getDiskStore().forceCompaction();
    assertEquals(true, oplogsIDsNotifiedToRoll);
    assertEquals(true, rollingDone);

    synchronized (region) {
      boolean condition = ((LocalRegion) region).getDiskRegion().getOplogToBeCompacted() == null;
      Assert.assertTrue(condition, "Oplogs still remain after having compacted");
    }
    LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER = false;
  }

  /**
   * This tests the case where potential of writing a dummy byte was there. The case would be
   * compactor terminating early. The create is present in both Htree as well as Oplog. When
   * recovery is done, the create is added to the Oplog createdEntrySet. Now while compactor
   * iterates over the entries in the region, it skips the created entry because its Htree Offset is
   * > -1. As a result it leaves it in created set & so when the compactor processes the created Set
   * it thinks that the entry is now referenced in the any of the subsequent oplogs & thus
   * overwrites it with a byte[].
   */
  @Test
  public void testVestigialCreatesInOplog() throws Exception {
    diskProps.setDiskDirs(dirs);
    diskProps.setMaxOplogSize(40);
    diskProps.setPersistBackup(true);
    diskProps.setRegionName("VestigialCreatesTestRegion");
    diskProps.setRolling(true);

    // create sync persist region.
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    System.err.println(
        "<ExpectedException action=add>" + "KillCompactorException" + "</ExpectedException>");
    logWriter
        .info("<ExpectedException action=add>" + "KillCompactorException" + "</ExpectedException>");
    try {
      CacheObserver cob = CacheObserverHolder.setInstance(new CacheObserverAdapter() {
        @Override
        public void beforeDeletingCompactedOplog(Oplog compactedOplog) {
          // killed compactor after rolling but before deleting oplogs
          throw new DiskStoreImpl.KillCompactorException();
        }
      });
      LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER = true;
      region.put("key1", "Testing");
      region.put("key2", "Vestigial");
      region.put("key3", "Creates");
      region.put("key4", "Into");
      region.put("key5", "Oplog");

      // ((LocalRegion)region).getDiskStore().forceCompaction();

      if (cache != null) {
        cache.close();
      }
      LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER = false;
      CacheObserverHolder.setInstance(new CacheObserverAdapter());
    } finally {
      System.err.println(
          "<ExpectedException action=remove>" + "KillCompactorException" + "</ExpectedException>");
      logWriter.info(
          "<ExpectedException action=remove>" + "KillCompactorException" + "</ExpectedException>");
    }

    cache = createCache();
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    assertTrue("Expected region size is 5 but got it as " + region.entrySet().size(),
        region.entrySet().size() == 5);
    assertEquals(region.get("key1"), "Testing");
    Thread.sleep(5);
    if (cache != null) {
      cache.close();
    }
    LocalRegion.ISSUE_CALLBACKS_TO_CACHE_OBSERVER = false;
    CacheObserverHolder.setInstance(new CacheObserverAdapter());
    cache = createCache();
    region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
    assertTrue("Expected region size is 5 but got it as " + region.entrySet().size(),
        region.entrySet().size() == 5);
    assertTrue(region.get("key1").equals("Testing"));
  }

  @Test
  public void testDiskIDFieldsForPersistOnlyRecoverValuesTrue() throws Exception {
    String oldValue = System.getProperty(DiskStoreImpl.RECOVER_VALUE_PROPERTY_NAME);
    System.setProperty(DiskStoreImpl.RECOVER_VALUE_PROPERTY_NAME, "true");
    try {
      diskProps.setDiskDirs(dirs);
      diskProps.setMaxOplogSize(1024);
      diskProps.setPersistBackup(true);
      diskProps.setRegionName("testDiskIDFieldsForPersistOnlyRecoverValuesTrue");
      diskProps.setRolling(false);
      // create sync persist region.
      region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);

      // the creates which will go in first oplog
      for (int i = 0; i < 3; ++i) {
        region.put("" + i, "" + i);
      }
      // Ensure that next few entries go in the second oplog while the first set
      // of entries go in the first oplog
      region.forceRolling();
      for (int i = 3; i < 6; ++i) {
        region.put("" + i, "" + i);
      }

      region.close();

      diskProps.setRolling(false);
      region = DiskRegionHelperFactory.getSyncPersistOnlyRegion(cache, diskProps, Scope.LOCAL);
      // Now verify the DiskIds of each of the siz entries & the values.
      LocalRegion rgn = (LocalRegion) region;
      byte b = 0;
      b = EntryBits.setSerialized(b, true);
      b = EntryBits.setRecoveredFromDisk(b, true);
      b = EntryBits.setWithVersions(b, true);

      // TODO need to wait for async recovery
      for (int i = 0; i < 3; ++i) {
        DiskEntry de = (DiskEntry) rgn.basicGetEntry("" + i);
        DiskId did = de.getDiskId();
        assertTrue(did.getKeyId() > 0);
        assertEquals(1, did.getOplogId());
        assertTrue(did.getOffsetInOplog() > -1);
        assertEquals(b, did.getUserBits());
        assertTrue(did.getValueLength() > 0);
        assertEquals("" + i, rgn.get("" + i));
        assertTrue(did.getKeyId() > 0);
        assertFalse(de.isValueNull());
      }
      // this last oplog does not have a krf because this disk store has not
      // been closed. So its value should be in memory now.
      for (int i = 3; i < 6; ++i) {
        DiskEntry de = (DiskEntry) rgn.basicGetEntry("" + i);
        DiskId did = de.getDiskId();
        assertTrue(did.getKeyId() > 0);
