/* 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 19, 2008 */ package com.bigdata.service; import java.io.IOException; import java.util.Properties; import java.util.UUID; import java.util.concurrent.ExecutionException; import com.bigdata.bfs.BigdataFileSystem.Options; import com.bigdata.btree.ITupleIterator; import com.bigdata.btree.IIndex; import com.bigdata.btree.ITuple; import com.bigdata.btree.IndexMetadata; import com.bigdata.btree.keys.TestKeyBuilder; import com.bigdata.btree.proc.BatchInsert.BatchInsertConstructor; import com.bigdata.journal.BufferMode; import com.bigdata.journal.ITx; /** * Test suite for the ability to re-open an {@link EmbeddedFederation}. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public class TestRestartSafe extends AbstractEmbeddedFederationTestCase { /** * */ public TestRestartSafe() { } /** * @param arg0 */ public TestRestartSafe(String arg0) { super(arg0); } /** * Overriden to specify the {@link BufferMode#Disk} mode. */ public Properties getProperties() { final Properties properties = new Properties(super.getProperties()); properties.setProperty(Options.BUFFER_MODE, BufferMode.Disk.toString()); return properties; } /** * Test creates a new embedded federation (this is done in setUp() by the * super class), registers a scale-out index with the metadata service * having an index partition on each of the data services and then writes * some data such that there is data for that scale-out index on each of the * data services. The federation is then closed and a new instance of the * federation is opened and we verify that the metadata and data services * were discovered, that the index is still registered, and that the data is * still in the index. We also verify that the next partition number * assigned to the metadata index is strictly ascending after restart. * * @throws IOException * @throws ExecutionException * @throws InterruptedException */ public void test_restartSafe() throws IOException, InterruptedException, ExecutionException { /* * Verify the #of data services and note the UUID for the data and * metadata services. */ assertEquals("#dataServices", 2, ((EmbeddedFederation) fed).getDataServiceCount()); final UUID metadataServiceUUID = fed.getMetadataService() .getServiceUUID(); final UUID dataService0UUID = ((EmbeddedFederation) fed) .getDataService(0).getServiceUUID(); final UUID dataService1UUID = ((EmbeddedFederation) fed) .getDataService(1).getServiceUUID(); /* * Register a scale-out index with data on each of the data services. */ final String name = "testIndex"; final IndexMetadata metadata = new IndexMetadata(name,UUID.randomUUID()); metadata.setDeleteMarkers(true); final UUID indexUUID = fed.registerIndex(metadata, new byte[][]{// new byte[]{}, new byte[]{5} }, new UUID[]{// dataService0.getServiceUUID(), dataService1.getServiceUUID() }); /* * Setup the data to write on the scale-out index. The keys are choosen * so that 1/2 of the data will show up on each of the data services. */ final int nentries = 10; final byte[][] keys = new byte[nentries][]; final byte[][] vals = new byte[nentries][]; for (int i = 0; i < nentries; i++) { keys[i] = TestKeyBuilder.asSortKey(i); vals[i] = new byte[4]; r.nextBytes(vals[i]); } /* * Write data on the index. */ { IIndex ndx = fed.getIndex(name,ITx.UNISOLATED); ndx.submit(0/*fromIndex*/,nentries/*toIndex*/, keys, vals, BatchInsertConstructor.RETURN_NO_VALUES, null/*handler*/); } /* * Verify read-back of the data on the index. */ { IIndex ndx = fed.getIndex(name,ITx.UNISOLATED); assertEquals(nentries, ndx.rangeCount(null, null)); ITupleIterator itr = ndx.rangeIterator(null, null); int i = 0; while(itr.hasNext()) { ITuple tuple = itr.next(); assertEquals(keys[i],tuple.getKey()); assertEquals(vals[i],tuple.getValue()); i++; } assertEquals(nentries, i); } // Have an index partition identifier assigned before restart. final int nextPartitionId0 = metadataService.nextPartitionId(name); final int nextPartitionId1 = metadataService.nextPartitionId(name); assertEquals("nextPartitionId",nextPartitionId0+1,nextPartitionId1); /* * Close down the embedded federation. * * See setUp() in the parent class. */ client.disconnect(true/*immediateShutdown*/); client = null; fed = null; dataService0 = null; dataService1 = null; metadataService = null; /* * Open the embedded federation again. * * See setUp() in the parent class. */ client = new EmbeddedClient(getProperties()); fed = client.connect(); assertEquals("#dataServices", 2, ((EmbeddedFederation) fed).ndataServices); dataService0 = ((EmbeddedFederation)fed).getDataService(0); dataService1 = ((EmbeddedFederation)fed).getDataService(1); metadataService = fed.getMetadataService(); /* * Verify the data and metadata service UUIDs. * * Note: there is only one metadata service so there is no uncertainty * about which UUID it must have. * * However, there are two data services. On restart either data service * could be assigned to either index ZERO or ONE in the dataServices[]. * Therefore we check to make sure that the service UUIDs for the data * services are (a) distinct; and (b) each one is the service UUID for * one of the expected data services. */ assertEquals("metadataService UUID", metadataServiceUUID, fed .getMetadataService().getServiceUUID()); // verify services have distinct UUIDs. assertNotSame(dataService0.getServiceUUID(), dataService1 .getServiceUUID()); // verify dataService[0] has one of the expected data service UUIDs. if (!dataService0.getServiceUUID().equals(dataService0UUID) && !dataService0.getServiceUUID().equals(dataService1UUID)) { fail("Not expecting data service with UUID: " + dataService0.getServiceUUID()); } // verify dataService[1] has one of the expected data service UUIDs. if (!dataService1.getServiceUUID().equals(dataService0UUID) && !dataService1.getServiceUUID().equals(dataService1UUID)) { fail("Not expecting data service with UUID: " + dataService1.getServiceUUID()); } /* * Verify the scale-out index is registered. */ assertNotNull(fed.getIndex(name,ITx.UNISOLATED)); assertEquals(indexUUID, fed.getIndex(name,ITx.UNISOLATED) .getIndexMetadata().getIndexUUID()); /* * Verify the next partition identifier assigned. */ assertEquals("nextPartitionId", nextPartitionId1 + 1, metadataService .nextPartitionId(name)); /* * Verify read-back of the data on the index. */ { final IIndex ndx = fed.getIndex(name,ITx.UNISOLATED); assertEquals(nentries, ndx.rangeCount()); final ITupleIterator itr = ndx.rangeIterator(); int i = 0; while(itr.hasNext()) { final ITuple tuple = itr.next(); assertEquals(keys[i],tuple.getKey()); assertEquals(vals[i],tuple.getValue()); i++; } assertEquals(nentries, i); } } }