/** 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 Sep 7, 2007 */ package com.bigdata.btree; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.UUID; import junit.framework.TestCase; import org.apache.log4j.Logger; import com.bigdata.rawstore.WormAddressManager; import com.bigdata.util.Bytes; /** * Test suite for {@link IndexSegmentCheckpoint}. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public class TestIndexSegmentCheckpoint extends TestCase { private static final Logger log = Logger .getLogger(TestIndexSegmentCheckpoint.class); /** * */ public TestIndexSegmentCheckpoint() { super(); } /** * @param arg0 */ public TestIndexSegmentCheckpoint(String arg0) { super(arg0); } public void test_size() { log.warn("SIZE: " + IndexSegmentCheckpoint.SIZE); log.warn("UNUSED VERSION0: " + IndexSegmentCheckpoint.SIZEOF_UNUSED_VERSION0); log.warn("UNUSED VERSION1: " + IndexSegmentCheckpoint.SIZEOF_UNUSED_VERSION1); log.warn("UNUSED VERSION2: " + IndexSegmentCheckpoint.SIZEOF_UNUSED_VERSION2); // Verify that the size of the record has not changed over time. assertEquals("size",421,IndexSegmentCheckpoint.SIZE); } /** * Test the ability to create an {@link IndexSegmentCheckpoint} record, write * it on a file, and read back the same data from the file. The data for * this test are somewhat faked since there are assertions on legal metadata * and we can not write arbitrary values into the various fields. * * @throws IOException */ public void test_write_read01() throws IOException { /* * Note: allows records up to 64M in length. */ final int offsetBits = WormAddressManager.SCALE_OUT_OFFSET_BITS; /* * Fake a checkpoint record. The only parts of this that we need are the * addresses of the nodes and blobs. Those addresses MUST be formed as * relative to the BASE region of the file. The offsets encoded within * those addresses will be used to decode addresses in the non-BASE * regions of the file. * * Note: the checkpoint ctor has a variety of assertions so that * constrains how we can generate this fake checkpoint record. */ final IndexSegmentCheckpoint checkpoint; final long extentLeaves = 216; final long offsetLeaves = IndexSegmentCheckpoint.SIZE; final long offsetNodes; final long offsetBlobs; final long extentNodes; final long extentBlobs; final int height = 1; final int nleaves = 5; final int nnodes = 1; final int nentries = 29; final int maxNodeOrLeafLength = 128; // arbitrary non-zero value. // final long addrLeaves; // final long addrNodes; final long addrRoot; // final long addrBlobs; final long addrBloom; final long addrMetadata; final long addrFirstLeaf; final long addrLastLeaf; final long length; final boolean compactingMerge = true; // @todo also test when false. final boolean useChecksums = true; // @todo also test when false. final UUID segmentUUID = UUID.randomUUID(); final long commitTime = System.currentTimeMillis(); { // Used to encode the addresses. WormAddressManager am = new WormAddressManager(offsetBits); // addrLeaves = am.toAddr(extentLeaves, IndexSegmentRegion.BASE // .encodeOffset(offsetLeaves)); extentNodes = 123; offsetNodes = offsetLeaves + extentLeaves; // addrNodes = am.toAddr(extentNodes, IndexSegmentRegion.BASE // .encodeOffset(offsetNodes)); // Note: only one node and it is the root, so addrRoot==addrNodes addrRoot = am.toAddr((int)extentNodes, IndexSegmentRegion.BASE .encodeOffset(offsetNodes)); addrFirstLeaf = addrRoot; addrLastLeaf = addrRoot; extentBlobs = Bytes.megabyte32 * 20; offsetBlobs = offsetNodes + extentNodes; // addrBlobs = am.toAddr(extentBlobs, IndexSegmentRegion.BASE // .encodeOffset(offsetBlobs)); addrBloom = 0L; final int sizeMetadata = 712; final long offsetMetadata = offsetBlobs + extentBlobs; addrMetadata = am.toAddr(sizeMetadata, IndexSegmentRegion.BASE .encodeOffset(offsetMetadata)); length = offsetMetadata + sizeMetadata; checkpoint = new IndexSegmentCheckpoint( offsetBits,// height,// nleaves,// nnodes,// nentries,// maxNodeOrLeafLength,// offsetLeaves,extentLeaves,// offsetNodes,extentNodes,// offsetBlobs,extentBlobs,// addrRoot,// addrMetadata,// addrBloom, // addrFirstLeaf,// addrLastLeaf,// length,// compactingMerge,// useChecksums,// segmentUUID,// commitTime// ); if(log.isInfoEnabled()) log.info("Checkpoint: "+checkpoint); } final IndexSegmentCheckpoint expected = new IndexSegmentCheckpoint( offsetBits, height, nleaves, nnodes, nentries, maxNodeOrLeafLength, offsetLeaves, extentLeaves, offsetNodes, extentNodes, offsetBlobs, extentBlobs, addrRoot, addrMetadata, addrBloom, addrFirstLeaf, addrLastLeaf, length, compactingMerge, useChecksums, segmentUUID, commitTime); if(log.isInfoEnabled()) log.info("Expected: "+expected); final File tmp = File.createTempFile("test", "ndx"); tmp.deleteOnExit(); final RandomAccessFile raf = new RandomAccessFile(tmp,"rw"); try { // the checkpoint record (starting at 0L in the file). expected.write(raf); // extend to full size. raf.getChannel().truncate(length); // seek near the end. raf.seek(length-128); // write up to the end of the file. raf.write(new byte[128]); // // additional bytes for the nodes/leaves. // raf.write(new byte[maxNodeOrLeafLength]); // // // force to disk. // raf.getChannel().force(true); // // raf.close(); // // raf = new RandomAccessFile(tmp,"r"); // read back from the file. final IndexSegmentCheckpoint actual = new IndexSegmentCheckpoint(raf); if(log.isInfoEnabled()) log.info("Actual: "+actual); assertEquals("offsetBits",offsetBits,actual.offsetBits); assertEquals("height",height,actual.height); assertEquals("nleaves",nleaves,actual.nleaves); assertEquals("nnodes",nnodes,actual.nnodes); assertEquals("nentries",nentries,actual.nentries); assertEquals("maxNodeOrLeafLength",maxNodeOrLeafLength,actual.maxNodeOrLeafLength); assertEquals("offsetLeaves",offsetLeaves,actual.offsetLeaves); assertEquals("extentLeaves",extentLeaves,actual.extentLeaves); assertEquals("offsetNodes",offsetNodes,actual.offsetNodes); assertEquals("extentNodes",extentNodes,actual.extentNodes); assertEquals("offsetBlobs",offsetBlobs,actual.offsetBlobs); assertEquals("extentBlobs",extentBlobs,actual.extentBlobs); assertEquals("addrRoot",addrRoot,actual.addrRoot); assertEquals("addrMetadata",addrMetadata,actual.addrMetadata); assertEquals("addrBloom",addrBloom,actual.addrBloom); assertEquals("length",length,actual.length); assertEquals("compactingMerge",compactingMerge,actual.compactingMerge); assertEquals("segmentUUID",segmentUUID,actual.segmentUUID); assertEquals("commitTime",commitTime,actual.commitTime); } finally { try {raf.close();} catch(Throwable t) {/*ignore*/} tmp.delete(); } } }