/* Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Created on Feb 13, 2008 */ package com.bigdata.service; import java.util.UUID; import com.bigdata.btree.IIndex; import com.bigdata.btree.IndexMetadata; import com.bigdata.btree.proc.AbstractKeyArrayIndexProcedure.ResultBuffer; import com.bigdata.btree.proc.BatchLookup.BatchLookupConstructor; import com.bigdata.journal.ITx; /** * Test of basic index operations. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public class TestBasicIndexStuff extends AbstractEmbeddedFederationTestCase { /** * */ public TestBasicIndexStuff() { } /** * @param arg0 */ public TestBasicIndexStuff(String arg0) { super(arg0); } // /** // * Test verifies the behavior of the {@link IDataService} when requesting an // * operation for an index that is not registered on that data service. // * <p> // * Note: This test is very important. Clients depends on // * {@link StaleLocatorException} being thrown when an index partition has // * been split, joined or moved in order to automatically refresh their cache // * information and reissue their request. // * // * @throws Exception // * // * FIXME Revisit this test. The {@link StaleLocatorException} should be // * thrown only if a registered index has been split, joined or moved. If an // * index simply does not exist or was dropped then // * {@link NoSuchIndexException} should be thrown. This means that this test // * will have to be written either directly in terms of states where a split, // * join or move has occurred or using the {@link ResourceManager} to fake // * the condition. // */ // public void test_noSuchIndex() throws Exception { // // final String name = "testIndex"; // // assertNull(fed.getIndex(name,ITx.UNISOLATED)); // // /* // * Try various operations and make sure that they all throw the expected // * exception. // */ // // // obtaining index metadata // try { // // dataService0.getIndexMetadata(name, ITx.UNISOLATED); // // } catch (Exception ex) { // // if (!isInnerCause(ex, StaleLocatorException.class)) { // // fail("Expecting: " + StaleLocatorException.class + ", not " // + ex, ex); // // } // // System.err.print("Ignoring expected exception: "); // getInnerCause(ex, StaleLocatorException.class).printStackTrace(System.err); // // } // //// // obtaining index statistics //// try { //// //// dataService0.getStatistics(name); //// //// } catch (Exception ex) { //// //// assertTrue( isInnerCause(ex, StaleLocatorException.class)); //// //// System.err.print("Ignoring expected exception: "); //// getInnerCause(ex, StaleLocatorException.class).printStackTrace(System.err); //// //// } // // // running a procedure // try { // // dataService0.submit( // ITx.UNISOLATED, // name, // new RangeCountProcedure(false/* exact */, // false/*deleted*/, null, null)).get(); // // } catch (Exception ex) { // // assertTrue( isInnerCause(ex, StaleLocatorException.class)); // // System.err.print("Ignoring expected exception: "); // getInnerCause(ex, StaleLocatorException.class).printStackTrace(System.err); // // } // // // range iterator // try { // // dataService0 // .rangeIterator(ITx.UNISOLATED, name, null/* fromKey */, // null/* toKey */, 0/* capacity */, // IRangeQuery.DEFAULT, null/*filter*/); // // } catch (Exception ex) { // // assertTrue( isInnerCause(ex, StaleLocatorException.class) ); // // System.err.print("Ignoring expected exception: "); // getInnerCause(ex, StaleLocatorException.class).printStackTrace(System.err); // // } // // } /** * Tests basics with a single scale-out index having a single partition. * * @throws Exception */ public void test_onePartition() throws Exception { final String name = "testIndex"; final IndexMetadata metadata = new IndexMetadata(name, UUID .randomUUID()); metadata.setDeleteMarkers(true); fed.registerIndex(metadata); IIndex ndx = fed.getIndex(name,ITx.UNISOLATED); assertEquals("indexUUID", metadata.getIndexUUID(), ndx.getIndexMetadata() .getIndexUUID()); // the index is empty. assertFalse(ndx.contains(new byte[]{1})); // the key is not in the index. assertEquals(null, ndx.lookup(new byte[]{1})); // insert a key-value pair. assertNull(ndx.insert(new byte[]{1}, new byte[]{1})); // verify index reports value exists for the key. assertTrue(ndx.contains(new byte[]{1})); // verify correct value in the index. assertEquals(new byte[]{1}, ndx.lookup(new byte[]{1})); // verify some range counts. assertEquals(0, ndx.rangeCount(new byte[] {}, new byte[] { 1 })); assertEquals(1, ndx.rangeCount(new byte[] {}, new byte[] { 2 })); assertEquals(1, ndx.rangeCount(new byte[] { 1 }, new byte[] { 2 })); assertEquals(0, ndx.rangeCount(null, new byte[] { 1 })); assertEquals(1, ndx.rangeCount(new byte[] { 1 }, null)); assertEquals(1, ndx.rangeCount(null, new byte[] { 2 })); assertEquals(1, ndx.rangeCount(null, null)); // verify iterator for the same queries. assertSameIterator(new byte[][]{}, ndx.rangeIterator(new byte[] {}, new byte[] { 1 })); assertSameIterator(new byte[][]{new byte[]{1}}, ndx.rangeIterator(new byte[] {}, new byte[] { 2 })); assertSameIterator(new byte[][]{new byte[]{1}}, ndx.rangeIterator(new byte[] { 1 }, new byte[] { 2 })); assertSameIterator(new byte[][]{}, ndx.rangeIterator(null, new byte[] { 1 })); assertSameIterator(new byte[][]{new byte[]{1}}, ndx.rangeIterator(new byte[] { 1 }, null)); assertSameIterator(new byte[][]{new byte[]{1}}, ndx.rangeIterator(null, new byte[] { 2 })); assertSameIterator(new byte[][]{new byte[]{1}}, ndx.rangeIterator(null, null)); // remove the index entry. assertEquals(new byte[] { 1 }, ndx.remove(new byte[] { 1 })); // the index is empty. assertFalse(ndx.contains(new byte[] { 1 })); // the key is not in the index. assertEquals(null, ndx.lookup(new byte[] { 1 })); /* * verify some range counts. * * Note: the range counts do NOT immediately adjust when keys are * removed since deletion markers are written into those entries. The * relevant index partition(s) need to be compacted for those deletion * markers to be removed and the range counts adjusted to match. */ assertEquals(0, ndx.rangeCount(new byte[] {}, new byte[] { 1 })); assertEquals(1, ndx.rangeCount(new byte[] {}, new byte[] { 2 })); assertEquals(1, ndx.rangeCount(new byte[] { 1 }, new byte[] { 2 })); assertEquals(0, ndx.rangeCount(null, new byte[] { 1 })); assertEquals(1, ndx.rangeCount(new byte[] { 1 }, null)); assertEquals(1, ndx.rangeCount(null, new byte[] { 2 })); assertEquals(1, ndx.rangeCount(null, null)); // verify iterator for the same queries. assertSameIterator(new byte[][]{}, ndx.rangeIterator(new byte[] {}, new byte[] { 1 })); assertSameIterator(new byte[][]{}, ndx.rangeIterator(new byte[] {}, new byte[] { 2 })); assertSameIterator(new byte[][]{}, ndx.rangeIterator(new byte[] { 1 }, new byte[] { 2 })); assertSameIterator(new byte[][]{}, ndx.rangeIterator(null, new byte[] { 1 })); assertSameIterator(new byte[][]{}, ndx.rangeIterator(new byte[] { 1 }, null)); assertSameIterator(new byte[][]{}, ndx.rangeIterator(null, new byte[] { 2 })); assertSameIterator(new byte[][]{}, ndx.rangeIterator(null, null)); } /** * Tests a variety of operations on a scale-out index with two index * partitions. */ public void test_twoPartitions() throws Exception { final String name = "testIndex"; final IndexMetadata metadata = new IndexMetadata(name,UUID.randomUUID()); metadata.setDeleteMarkers(true); final int partitionId0 = 0; final int partitionId1 = 1; fed.registerIndex(metadata, new byte[][]{// new byte[]{}, new byte[]{5} }, new UUID[]{// dataService0.getServiceUUID(), dataService1.getServiceUUID() }); IIndex ndx = fed.getIndex(name,ITx.UNISOLATED); // the index is empty. assertFalse(ndx.contains(new byte[]{1})); assertFalse(ndx.contains(new byte[]{5})); // the key is not in the index. assertEquals(null, ndx.lookup(new byte[]{1})); assertEquals(null, ndx.lookup(new byte[]{5})); // insert a key-value pair into each partition. assertNull(ndx.insert(new byte[]{1}, new byte[]{1})); assertNull(ndx.insert(new byte[]{5}, new byte[]{5})); // verify index reports value exists for the key. assertTrue(ndx.contains(new byte[]{1})); assertTrue(ndx.contains(new byte[]{5})); // verify correct value in the index. assertEquals(new byte[]{1}, ndx.lookup(new byte[]{1})); assertEquals(new byte[]{5}, ndx.lookup(new byte[]{5})); // verify correct value in the index on the correct data service. assertEquals(new byte[] { 1 }, ((ResultBuffer) dataService0.submit( ITx.UNISOLATED,// DataService.getIndexPartitionName(name, partitionId0),// BatchLookupConstructor.INSTANCE.newInstance(// metadata, // 0,// fromIndex 1,// toIndex new byte[][] { new byte[] { 1 } },// keys null //vals )).get()).getResult(0)); // assertEquals(new byte[] { 5 }, ((ResultBuffer) dataService1.submit( ITx.UNISOLATED,// DataService.getIndexPartitionName(name, partitionId1),// BatchLookupConstructor.INSTANCE.newInstance(// metadata,// 0,// fromIndex 1,// toIndex new byte[][] { new byte[] { 5 } },// keys null//vals )).get()).getResult(0)); // verify some range counts. assertEquals(0,ndx.rangeCount(new byte[]{}, new byte[]{1})); assertEquals(1,ndx.rangeCount(new byte[]{}, new byte[]{2})); assertEquals(1,ndx.rangeCount(new byte[]{1}, new byte[]{2})); assertEquals(0,ndx.rangeCount(null, new byte[]{1})); assertEquals(2,ndx.rangeCount(new byte[]{1},null)); assertEquals(1,ndx.rangeCount(null,new byte[]{2})); assertEquals(2,ndx.rangeCount(null,null)); // verify range iterator for the same cases as range count. assertSameIterator(new byte[][] {},// ndx.rangeIterator(new byte[] {}, new byte[] { 1 })); assertSameIterator(new byte[][] {// new byte[] { 1 } // }, ndx.rangeIterator(new byte[] {}, new byte[] { 2 })); assertSameIterator(new byte[][] {// new byte[] { 1 }// }, ndx.rangeIterator(new byte[] {1}, new byte[] { 2 })); assertSameIterator(new byte[][] {},// ndx.rangeIterator(null, new byte[] { 1 })); assertSameIterator(new byte[][] {// new byte[] { 1 },// new byte[] { 5 } // }, ndx.rangeIterator(new byte[] {1}, null)); assertSameIterator(new byte[][] {// new byte[] { 1 }// }, ndx.rangeIterator(null, new byte[] {2})); assertSameIterator(new byte[][] {// new byte[] { 1 },// new byte[] { 5 } // }, ndx.rangeIterator(null, null)); // remove the index entry. assertEquals(new byte[] { 1 }, ndx.remove(new byte[] { 1 })); // verify that this entry is gone (actually it is marked as deleted). assertFalse(ndx.contains(new byte[] { 1 })); // the key is not in the index. assertEquals(null, ndx.lookup(new byte[] { 1 })); /* * verify some range counts. * * Note: the range counts do NOT immediately adjust when keys are * removed since deletion markers are written into those entries. The * relevant index partition(s) need to be compacted for those deletion * markers to be removed and the range counts adjusted to match. */ assertEquals(0,ndx.rangeCount(new byte[]{}, new byte[]{1})); assertEquals(1,ndx.rangeCount(new byte[]{}, new byte[]{2})); assertEquals(1,ndx.rangeCount(new byte[]{1}, new byte[]{2})); assertEquals(0,ndx.rangeCount(null, new byte[]{1})); assertEquals(2,ndx.rangeCount(new byte[]{1},null)); assertEquals(1,ndx.rangeCount(null,new byte[]{2})); assertEquals(2,ndx.rangeCount(null,null)); /* * Verify the range iterator for the same cases as the range count. * * Note: Unlike rangeCount, the range iterator filters out deleted * entries so the deleted entry {1} MUST NOT be visited by any of these * iterators. */ assertSameIterator(new byte[][] {},// ndx.rangeIterator(new byte[] {}, new byte[] { 1 })); assertSameIterator(new byte[][] {},// ndx.rangeIterator(new byte[] {}, new byte[] { 2 })); assertSameIterator(new byte[][] {},// ndx.rangeIterator(new byte[] {1}, new byte[] { 2 })); assertSameIterator(new byte[][] {},// ndx.rangeIterator(null, new byte[] { 1 })); assertSameIterator(new byte[][] {// new byte[] { 5 } // }, ndx.rangeIterator(new byte[] {1}, null)); assertSameIterator(new byte[][] {},// ndx.rangeIterator(null, new byte[] {2})); assertSameIterator(new byte[][] {// new byte[] { 5 } // }, ndx.rangeIterator(null, null)); // remove the other index entry. assertEquals(new byte[]{5},(byte[])ndx.remove(new byte[]{5})); // verify that this entry is gone (actually it is marked as deleted). assertFalse(ndx.contains(new byte[]{5})); // the key is not in the index. assertEquals(null,(byte[])ndx.lookup(new byte[]{5})); /* * verify some range counts -- they are unchanged since the deleted keys * are still counted until the index parition(s) are compacted. */ assertEquals(0,ndx.rangeCount(new byte[]{}, new byte[]{1})); assertEquals(1,ndx.rangeCount(new byte[]{}, new byte[]{2})); assertEquals(1,ndx.rangeCount(new byte[]{1}, new byte[]{2})); assertEquals(0,ndx.rangeCount(null, new byte[]{1})); assertEquals(2,ndx.rangeCount(new byte[]{1},null)); assertEquals(1,ndx.rangeCount(null,new byte[]{2})); assertEquals(2,ndx.rangeCount(null,null)); /* * verify range iterator for the same cases as range count. * * Note: Unlike rangeCount, the range iterator filters out deleted * entries so all of these cases will be an empty iterator. */ assertSameIterator(new byte[][] {},// ndx.rangeIterator(new byte[] {}, new byte[] { 1 })); assertSameIterator(new byte[][]{},// ndx.rangeIterator(new byte[] {}, new byte[] { 2 })); assertSameIterator(new byte[][] {},// ndx.rangeIterator(new byte[] {1}, new byte[] { 2 })); assertSameIterator(new byte[][] {},// ndx.rangeIterator(null, new byte[] { 1 })); assertSameIterator(new byte[][] {},// ndx.rangeIterator(new byte[] {1}, null)); assertSameIterator(new byte[][] {},// ndx.rangeIterator(null, new byte[] {2})); assertSameIterator(new byte[][] {},// ndx.rangeIterator(null, null)); } }