/** 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 Apr 23, 2007 */ package com.bigdata.service; import java.io.IOException; import java.util.List; import java.util.UUID; import com.bigdata.btree.IndexMetadata; import com.bigdata.btree.IIndex; import com.bigdata.journal.ITx; import com.bigdata.mdi.MetadataIndex; import com.bigdata.mdi.PartitionLocator; import com.bigdata.service.ndx.ClientIndexView; /** * Test suite for the {@link EmbeddedClient}. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public class TestEmbeddedClient extends AbstractEmbeddedFederationTestCase { public TestEmbeddedClient() { } public TestEmbeddedClient(String name) { super(name); } /** * Test ability to register a scale-out index, access it, and then drop the * index. */ public void test_registerIndex() { final String name = "testIndex"; final IndexMetadata metadata = new IndexMetadata(name,UUID.randomUUID()); metadata.setDeleteMarkers(true); // verify index does not exist. assertNull(fed.getIndex(name,ITx.UNISOLATED)); assertNull(fed.getIndex(name,ITx.READ_COMMITTED)); // register. fed.registerIndex(metadata); // obtain unisolated view. { final long tx = ITx.UNISOLATED; final IIndex ndx = fed.getIndex(name, tx); // verify view is non-null assertNotNull(ndx); // verify same index UUID. assertEquals(metadata.getIndexUUID(), ndx.getIndexMetadata() .getIndexUUID()); } // obtain read-committed view. { final long tx = ITx.READ_COMMITTED; final IIndex ndx = fed.getIndex(name, tx); // verify view is non-null assertNotNull(ndx); // verify same index UUID. assertEquals(metadata.getIndexUUID(), ndx.getIndexMetadata() .getIndexUUID()); } // drop the index. fed.dropIndex(name); // no longer available to read committed requests. assertNull(fed.getIndex(name, ITx.READ_COMMITTED)); // no longer available to unisolated requests. assertNull(fed.getIndex(name, ITx.UNISOLATED)); /* * @todo obtain a valid commit timestamp for the index during the period * in which it existed and verify that a historical view may still be * obtained for that timestamp. */ } /** * Tests the ability to statically partition a scale-out index. */ public void test_staticPartitioning() throws Exception { final String name = "testIndex"; final IndexMetadata metadata = new IndexMetadata(name,UUID.randomUUID()); metadata.setDeleteMarkers(true); UUID indexUUID = fed.registerIndex(metadata, new byte[][]{// new byte[]{}, new byte[]{5} }, new UUID[]{// dataService0.getServiceUUID(), dataService1.getServiceUUID() }); final int partitionId0 = 0; final int partitionId1 = 1; /* * Verify index is registered on each data service under the correct * name for that index partition. The index on each data service must * have the same indexUUID since they are just components of the same * scale-out index. */ assertIndexRegistered(dataService0, DataService.getIndexPartitionName( name, partitionId0), indexUUID); assertIndexRegistered(dataService1, DataService.getIndexPartitionName( name, partitionId1), indexUUID); /* * Verify metadata for index partition#0 on dataService0 * * @todo test more of the metadata for correctness. */ { IndexMetadata actual = dataService0.getIndexMetadata(DataService .getIndexPartitionName(name, partitionId0), ITx.UNISOLATED); // verify index partition exists on that data service. assertNotNull(actual); // partition metadata. assertEquals("partitionId", partitionId0, actual .getPartitionMetadata().getPartitionId()); assertEquals("leftSeparator", new byte[] {}, actual .getPartitionMetadata().getLeftSeparatorKey()); assertEquals("rightSeparator", new byte[] { 5 }, actual .getPartitionMetadata().getRightSeparatorKey()); // other metadata. assertEquals(metadata.getDeleteMarkers(),actual.getDeleteMarkers()); } /* * Verify metadata for index partition#1 on dataService1 */ { IndexMetadata actual = dataService1.getIndexMetadata(DataService .getIndexPartitionName(name, partitionId1), ITx.UNISOLATED); // verify index partition exists on that data service. assertNotNull(actual); // partition metadata assertEquals("partitionId", partitionId1, actual .getPartitionMetadata().getPartitionId()); assertEquals("leftSeparator", new byte[] {5}, actual .getPartitionMetadata().getLeftSeparatorKey()); assertEquals("rightSeparator", null, actual.getPartitionMetadata() .getRightSeparatorKey()); // other metadata assertEquals(metadata.getDeleteMarkers(),actual.getDeleteMarkers()); } } /** * Test of the routine responsible for identifying the split points in an * ordered set of keys for a batch index operation. Note that the routine * requires access to the partition definitions in the form of a * {@link MetadataIndex} in order to identify the split points in the * keys[]. */ public void test_splitKeys_staticPartitions01() throws IOException { final String name = "testIndex"; final IndexMetadata metadata = new IndexMetadata(name,UUID.randomUUID()); metadata.setDeleteMarkers(true); /* * Register and statically partition an index. */ fed.registerIndex(metadata, new byte[][]{// new byte[]{}, // keys less than 5... new byte[]{5} // keys GTE 5.... }, new UUID[]{// dataService0.getServiceUUID(), dataService1.getServiceUUID() }); /* * Request a view of that index. */ ClientIndexView ndx = (ClientIndexView) fed.getIndex(name,ITx.UNISOLATED); /* * Range count the index to verify that it is empty. */ assertEquals("rangeCount",0,ndx.rangeCount(null, null)); /* * Get metadata for the index partitions that we will need to verify * the splits. */ final PartitionLocator pmd0 = ndx.getMetadataIndex().get(new byte[]{}); final PartitionLocator pmd1 = ndx.getMetadataIndex().get(new byte[]{5}); assertNotNull("partition#0",pmd0); assertNotNull("partition#1",pmd1); /* * Setup data and test splitKeys(). * * Note: In this test there is a key that is an exact match on the * separator key between the index partitions. */ { final byte[][] keys = new byte[][] {// new byte[]{1}, // [0] new byte[]{2}, // [1] new byte[]{5}, // [2] new byte[]{6}, // [3] new byte[]{9} // [4] }; final List<Split> splits = ndx.splitKeys(ITx.UNISOLATED, 0, keys.length, keys); assertNotNull(splits); assertEquals("#splits", 2, splits.size()); assertEquals(new Split(pmd0, 0, 2), splits.get(0)); assertEquals(new Split(pmd1, 2, 5), splits.get(1)); } /* * Variant in which there are duplicates of the key that corresponds to * the rightSeparator for the 1st index partition. This causes a problem * where the binarySearch returns the index of ONE of the keys that is * equal to the rightSeparator key and we need to back up until we have * found the FIRST ONE. While not every example with duplicate keys * equal to the rightSeparator will trigger the problem, this example * will. */ { final byte[][] keys = new byte[][] {// new byte[]{1}, // [0] new byte[]{5}, // [1] new byte[]{5}, // [2] new byte[]{5}, // [3] new byte[]{9} // [4] }; final List<Split> splits = ndx.splitKeys(ITx.UNISOLATED, 0, keys.length, keys); assertNotNull(splits); assertEquals("#splits", 2, splits.size()); assertEquals(new Split(pmd0, 0, 1), splits.get(0)); assertEquals(new Split(pmd1, 1, 5), splits.get(1)); } /* * Setup data and test splitKeys(). * * Note: In this test there is NOT an exact match on the separator key * between the index partitions. This will result in a negative encoding * of the insertion point by the binary search routine. This test * verifies that the correct index is selected for the last key to enter * the first partition. */ { final byte[][] keys = new byte[][] {// new byte[]{1}, // [0] new byte[]{2}, // [1] new byte[]{4}, // [2] new byte[]{6}, // [3] new byte[]{9} // [4] }; final List<Split> splits = ndx.splitKeys(ITx.UNISOLATED, 0, keys.length, keys); assertNotNull(splits); assertEquals("#splits", 2, splits.size()); assertEquals(new Split(pmd0, 0, 3), splits.get(0)); assertEquals(new Split(pmd1, 3, 5), splits.get(1)); } } public void test_addDropIndex_twoPartitions() throws IOException { final String name = "testIndex"; final IndexMetadata metadata = new IndexMetadata(name,UUID.randomUUID()); metadata.setDeleteMarkers(true); /* * Register and statically partition an index. */ fed.registerIndex(metadata, new byte[][]{// new byte[]{}, // keys less than 5... new byte[]{5} // keys GTE 5.... }, new UUID[]{// dataService0.getServiceUUID(), dataService1.getServiceUUID() }); // view of that index. final IIndex ndx = fed.getIndex(name, ITx.UNISOLATED); assertNotNull("Expecting index to be registered", ndx); /* * Range count the index to verify that it is empty. */ assertEquals("rangeCount", 0, ndx.rangeCount()); // drop the index. fed.dropIndex(name); // request view of index. assertNull("Not expecting index to exist", fed.getIndex(name,ITx.UNISOLATED)); } }