gt:         int nW2 = paf.statsGetWriteCount();
context: /*
   * Copyright 2009-2020 Tilmann Zaeschke
   *
   * 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.zoodb.test.index;
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertNull;
  import static org.junit.Assert.assertTrue;
  import static org.junit.Assert.fail;
  
  import java.util.ConcurrentModificationException;
  import java.util.Iterator;
  import java.util.LinkedHashSet;
  import java.util.NoSuchElementException;
  import java.util.Random;
  import java.util.Set;
  
  import javax.jdo.JDOUserException;
  
  import org.junit.AfterClass;
  import org.junit.BeforeClass;
  import org.junit.Test;
  import org.zoodb.internal.server.DiskIO.PAGE_TYPE;
  import org.zoodb.internal.server.IOResourceProvider;
  import org.zoodb.internal.server.StorageRootInMemory;
  import org.zoodb.internal.server.index.IndexFactory;
  import org.zoodb.internal.server.index.LongLongIndex;
  import org.zoodb.internal.server.index.LongLongIndex.LongLongUIndex;
  import org.zoodb.internal.server.index.PagedOidIndex;
  import org.zoodb.internal.server.index.PagedOidIndex.FilePos;
  import org.zoodb.internal.util.CloseableIterator;
  import org.zoodb.tools.ZooConfig;
  
  public class TestOidIndex {
  
      /** Adjust this when adjusting page size! */
      private static final int MAX_DEPTH = 8;  //128
      //private static final int MAX_DEPTH = 4;  //1024
      private static final int PAGE_SIZE = 128;
      
      @BeforeClass
      public static void setUp() {
      	// Adjust MAX_DEPTH accordingly!
      	ZooConfig.setFilePageSize(PAGE_SIZE);
      }
  
      @AfterClass
      public static void tearDown() {
      	ZooConfig.setFilePageSize(ZooConfig.FILE_PAGE_SIZE_DEFAULT);
      }
  
      @SuppressWarnings("unused")
  	private static void println(String s) {
      	//System.out.println();
      }
      
      private IOResourceProvider createPageAccessFile() {
      	return new StorageRootInMemory(ZooConfig.getFilePageSize()).createChannel();
      }
      
      @Test
      public void testAddStrongCheck() {
          final int MAX = 5000;
          IOResourceProvider paf = createPageAccessFile();
          PagedOidIndex ind = new PagedOidIndex(paf);
          for (int i = 1000; i < 1000+MAX; i++) {
              ind.insertLong(i, 32, 32+i);
              //			println("Inserting: " + i);
              //Now check every entry!!!
              for (int j = 1000; j <= i; j++) {
                  FilePos fp2 = ind.findOid(j);
                  if (fp2==null) {
                      ind.print();
                      throw new RuntimeException("j=" + j + "   i=" + i);
                  }
              }
          }
          println("Index size: nInner=" + ind.statsGetInnerN() + "  nLeaf=" + 
                  ind.statsGetLeavesN());
  
          assertNull( ind.findOid(-1) );
          assertNull( ind.findOid(0) );
          assertNull( ind.findOid(999) );
          assertNull( ind.findOid(1000 + MAX) );
      }
  
      @Test
      public void testAdd() {
          final int MAX = 1000000;
          IOResourceProvider paf = createPageAccessFile();
          PagedOidIndex ind = new PagedOidIndex(paf);
          for (int i = 1000; i < 1000+MAX; i++) {
              ind.insertLong(i, 32, 32+i);
          }
          println("Index size: nInner=" + ind.statsGetInnerN() + "  nLeaf=" + 
                  ind.statsGetLeavesN());
  
          for (int i = 1000; i < 1000+MAX; i++) {
              FilePos fp = ind.findOid(i);
              //			println(" Looking up: " + i);
              assertEquals( 32, fp.getPage() );
              assertEquals( 32+i, fp.getOffs() );
          }
  
          assertNull( ind.findOid(-1) );
          assertNull( ind.findOid(0) );
          assertNull( ind.findOid(999) );
          assertNull( ind.findOid(1000 + MAX) );
  
          println("inner: "+ ind.statsGetInnerN() + " outer: " + ind.statsGetLeavesN());
          double epp = MAX / ind.statsGetLeavesN();
          println("Entires per page: " + epp);
      }
  
      @Test
      public void testIterator() {
          final int MAX = 1000000;
          IOResourceProvider paf = createPageAccessFile();
          PagedOidIndex ind = new PagedOidIndex(paf);
  
          Iterator<FilePos> iter = ind.iterator();
          assertFalse(iter.hasNext());
  
          for (int i = 1000; i < 1000+MAX; i++) {
              ind.insertLong(i, 32, 32+i);
          }
  
          iter = ind.iterator();
          long prev = -1;
          int n = 0;
          while (iter.hasNext()) {
              long l = iter.next().getOID();
              assertTrue( l > prev );
              if (prev > 0) {
                  assertEquals( prev+1, l );
              }
              prev = l;
              n++;
          }
          assertEquals(MAX, n);
      }
  
      @Test
      public void testInverseIterator() {
          final int MAX = 3000;
          IOResourceProvider paf = createPageAccessFile();
          PagedOidIndex ind = new PagedOidIndex(paf);
          for (int i = 1000; i < 1000+MAX; i++) {
              ind.insertLong(i, 32, 32+i);
          }
          Iterator<FilePos> iter = ind.descendingIterator();
          long prev = 1000+MAX;
          int n = MAX;
          while (iter.hasNext()) {
              long l = iter.next().getOID();
              assertTrue("l=" + l + " prev = "+ prev, l < prev );
              assertEquals("l=" + l + " prev = "+ (prev-1),  prev-1, l );
              prev = l;
              n--;
          }
          assertEquals(0, n);
      }
  
  
      @Test
      public void testDelete() {
          final int MAX = 1000000;
          IOResourceProvider paf = createPageAccessFile();
          PagedOidIndex ind = new PagedOidIndex(paf);
          //Fill index
          for (int i = 1000; i < 1000+MAX; i++) {
              ind.insertLong(i, 32, 32+i);
          }
  
          //		TreeSet<Long> toDelete = new TreeSet<Long>();
          //		Random rnd = new Random();
          //		for (int i = 0; i < MAX*10; i++) {
          //			toDelete.add( (long)rnd.nextInt(MAX)+1000 );
          //		}
          //TODO use the following after fixing the above
          Set<Long> toDelete = new LinkedHashSet<Long>();
          Random rnd = new Random();
          while (toDelete.size() < MAX*0.95) {
              toDelete.add( (long)rnd.nextInt(MAX)+1000 );
          }
  
          println("Index size before delete: nInner=" + ind.statsGetInnerN() + "  nLeaf=" + 
                  ind.statsGetLeavesN());
          int nIPagesBefore = ind.statsGetInnerN();
          int nLPagesBefore = ind.statsGetLeavesN();
          for (long l: toDelete) {
              ind.removeOid(l);
          }
          println("Index size after delete: nInner=" + ind.statsGetInnerN() + "  nLeaf=" + 
                  ind.statsGetLeavesN());
  
          for (int i = 1000; i < 1000+MAX; i++) {
              FilePos fp = ind.findOid(i);
              if (toDelete.contains((long)i)) {
                  assertNull(fp);
              } else {
                  //			println(" Looking up: " + i);
                  assertEquals( 32, fp.getPage() );
                  assertEquals( 32+i, fp.getOffs() );
              }
          }
  
          //test iteration and size
          Iterator<FilePos> iter = ind.iterator();
          long prev = -1;
          int n = 0;
          while (iter.hasNext()) {
              long l = iter.next().getOID();
              assertTrue( l > prev );
              assertFalse(toDelete.contains(l));
              prev = l;
              n++;
          }
          assertEquals(MAX-toDelete.size(), n);
  
  
          //Reduced inner pages
          assertTrue(nIPagesBefore >= ind.statsGetInnerN());
          //largely reduced lef pages
          assertTrue(nLPagesBefore + " -> " + ind.statsGetLeavesN(), 
                  nLPagesBefore/2 > ind.statsGetLeavesN());
      }
  
      @Test
      public void testDeleteAll() {
          final int MAX = 1000000;
          IOResourceProvider paf = createPageAccessFile();
          PagedOidIndex ind = new PagedOidIndex(paf);
  
          //first a simple delete on empty index
          try {
              ind.removeOid(0);
          	fail();
          } catch (NoSuchElementException e) {
          	//good!
          }
  
          //Fill index
          for (int i = 1000; i < 1000+MAX; i++) {
              ind.insertLong(i, 32, 32+i);
          }
  
          println("Index size before delete: nInner=" + ind.statsGetInnerN() + "  nLeaf=" + 
                  ind.statsGetLeavesN());
  //        int nIPagesBefore = ind.statsGetInnerN();
          int nLPagesBefore = ind.statsGetLeavesN();
  
          //delete index
          for (int i = 1000; i < 1000+MAX; i++) {
              long prev = ind.removeOid(i);
              assertEquals((32L<<32L) + 32L + i, prev);
          }
  
          println("Index size after delete: nInner=" + ind.statsGetInnerN() + "  nLeaf=" + 
                  ind.statsGetLeavesN());
          for (int i = 1000; i < 1000+MAX; i++) {
              FilePos fp = ind.findOid(i);
              assertNull(fp);
          }
  
          //test iteration and size
          Iterator<FilePos> iter = ind.iterator();
          long prev = -1;
          int n = 0;
          while (iter.hasNext()) {
              long l = iter.next().getOID();
              assertTrue( l > prev );
              prev = l;
              n++;
          }
          assertEquals(0, n);
  
  
          //Reduced inner pages
          assertTrue(ind.statsGetInnerN() <= 1);
          //largely reduced leaf pages
          assertTrue(nLPagesBefore + " -> " + ind.statsGetLeavesN(), ind.statsGetLeavesN() <= 1);
  
  
          //and finally, try adding something again
          for (int i = 1000; i < 1000+1000; i++) {
              ind.insertLong(i, 32, 32+i);
              //		println("Inserting: " + i);
              //Now check every entry!!!
              for (int j = 1000; j <= i; j++) {
                  FilePos fp2 = ind.findOid(j);
                  if (fp2 == null) {
                      ind.print();
                      fail();
                  }
              }
          }
      }
  
      /**
       * Test that only necessary pages get dirty.
       */
      @Test
      public void testDirtyPages() {
          //When increasing this number, also increase the assertion limit!
          final int MAX = 1000000;
          IOResourceProvider paf = createPageAccessFile();
          PagedOidIndex ind = new PagedOidIndex(paf);
          //Fill index
          for (int i = 1000; i < 1000+MAX; i++) {
              ind.insertLong(i, 32, 32+i);
          }
  
          //		int nW0 = paf.statsGetWriteCount();
          paf.writeIndex(ind::write);
          int nW1 = paf.statsGetWriteCount();
          ind.insertLong(MAX * 2, 32, 32);
          paf.writeIndex(ind::write);
  