Java tutorial
/*------------------------------------------------------------------------------------------------- _______ __ _ _______ _______ ______ ______ |_____| | \ | | |______ | \ |_____] | | | \_| | ______| |_____/ |_____] Copyright (c) 2016, antsdb.com and/or its affiliates. All rights reserved. *-xguo0<@ This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License, version 3, as published by the Free Software Foundation. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt> -------------------------------------------------------------------------------------------------*/ package com.antsdb.saltedfish.nosql; import java.io.File; import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel.MapMode; import java.util.ArrayList; import java.util.Base64; import java.util.Collections; import java.util.List; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.lang.StringUtils; import com.antsdb.saltedfish.cpp.BluntHeap; import com.antsdb.saltedfish.cpp.FishSkipList; import com.antsdb.saltedfish.cpp.KeyBytes; import com.antsdb.saltedfish.cpp.Unsafe; import com.antsdb.saltedfish.cpp.VariableLengthLongComparator; import com.antsdb.saltedfish.nosql.MemTabletReadOnly.ListNode; import com.antsdb.saltedfish.util.BytesUtil; import com.antsdb.saltedfish.util.CommandLineHelper; import com.antsdb.saltedfish.util.UberUtil; /** * * @author wgu0 */ public class DumpRow implements CommandLineHelper { int tableId; byte[] key; long pKey; File home; List<File> files = new ArrayList<>(); List<Tablet> tablets = new ArrayList<>(); boolean isVerbose; BluntHeap heap = new BluntHeap(); private SpaceManager spaceman; private boolean dumpHex; private boolean dumpValues; private class Tablet { File file; MappedByteBuffer buf; } public static void main(String[] args) throws Exception { new DumpRow().run(args); } private Options getOptions() { Options options = new Options(); options.addOption("h", "help", false, "print help"); options.addOption(null, "home", true, "data directory"); options.addOption("v", null, false, "verbose"); options.addOption(null, "hex", false, "hex dump of the row"); options.addOption(null, "values", false, "value dump of the row"); return options; } private void run(String[] args) throws Exception { CommandLine line = parse(getOptions(), args); // help if (line.hasOption("help")) { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("dumprow <table id> <row key base64>", getOptions()); return; } // arguments if (line.getArgList().size() != 2) { println("error: invalid command line arguments"); return; } this.tableId = Integer.parseInt(line.getArgList().get(0)); this.key = Base64.getDecoder().decode(line.getArgList().get(1)); this.pKey = KeyBytes.allocSet(this.heap, this.key).getAddress(); // options this.home = new File(line.getOptionValue("home")); this.isVerbose = line.hasOption('v'); this.dumpHex = line.hasOption("hex"); this.dumpValues = line.hasOption("values"); // validate if (!this.home.isDirectory()) { println("error: invalid home directory {}", this.home); return; } if (!new File(this.home, "checkpoint.bin").exists()) { println("error: invalid home directory {}", this.home); return; } // init space manager this.spaceman = new SpaceManager(this.home, false); spaceman.init(); // proceed dump(); } private void findTabletFiles(File dir) { for (File i : dir.listFiles()) { if (i.isDirectory()) { findTabletFiles(i); continue; } if (!i.getName().endsWith(".tbl")) { continue; } if (MemTablet.getTableId(i) == this.tableId) { this.files.add(i); } } } private void dump() throws Exception { if (this.isVerbose) { String str = BytesUtil.toHex(this.key); str = StringUtils.replace(str, "\n", "\n "); println("key: %s", str); } // find tablet files this.findTabletFiles(this.home); Collections.sort(this.files); Collections.reverse(this.files); // create mapped buffers for (File i : this.files) { try (RandomAccessFile raf = new RandomAccessFile(i, "r")) { Tablet tablet = new Tablet(); this.tablets.add(tablet); tablet.buf = raf.getChannel().map(MapMode.READ_ONLY, 0, i.length()); ; tablet.file = i; } if (isVerbose) { println("loading file: %s", i); } } // find row List<Long> sprows = new ArrayList<>(); for (Tablet tablet : this.tablets) { MappedByteBuffer buf = tablet.buf; long addr = UberUtil.getAddress(buf); BluntHeap heap = new BluntHeap(addr + MemTablet.HEADER_SIZE, 0); heap.position(buf.capacity() - MemTablet.HEADER_SIZE); FishSkipList slist = FishSkipList.alloc(heap, new VariableLengthLongComparator()); long pHead = slist.get(this.pKey); if (pHead == 0) { continue; } dumpRowVersions(tablet, heap, pHead, sprows); } // dump each row for (long spRow : sprows) { dumpRow(spRow); } } private void dumpRow(long spRow) throws Exception { println("row:%x %s", spRow, this.spaceman.getLocation(spRow)); long pRow = this.spaceman.toMemory(spRow); Row row = Row.fromMemoryPointer(pRow, 0); if (this.dumpValues) { println("%s", row.toString()); } if (this.dumpHex) { int len = row.getLength(); println("%s", BytesUtil.toHex(pRow, len)); } } private void dumpRowVersions(Tablet tablet, BluntHeap heap, long pHead, List<Long> sprows) { int oHead = Unsafe.getInt(pHead); println("revision list found at %s@%x", tablet.file, heap.getAddress(oHead) + MemTablet.HEADER_SIZE); for (ListNode i = ListNode.create(heap.getAddress(0), oHead); i != null; i = i.getNextNode()) { long version = i.getVersion(); long spRow = i.getSpacePointer(); sprows.add(spRow); println("@%x version=%x sprow=%x", i.getOffset() + MemTablet.HEADER_SIZE, version, spRow); } } }